ota-hub-reactjs 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DeviceConnectionState, AddConnectionProps } from "../base/device-whisperer.js";
|
|
2
2
|
export declare class UsbTransport {
|
|
3
3
|
device: USBDevice;
|
|
4
|
-
|
|
4
|
+
controlInterface: number;
|
|
5
|
+
dataInterface: number;
|
|
5
6
|
endpointIn: number;
|
|
6
7
|
endpointOut: number;
|
|
7
8
|
private static readonly SET_LINE_CODING;
|
|
@@ -14,7 +14,8 @@ import { useEffect } from "react";
|
|
|
14
14
|
// usb-transport.ts
|
|
15
15
|
export class UsbTransport {
|
|
16
16
|
constructor(device) {
|
|
17
|
-
this.
|
|
17
|
+
this.controlInterface = 0;
|
|
18
|
+
this.dataInterface = 1;
|
|
18
19
|
this.endpointIn = 0;
|
|
19
20
|
this.endpointOut = 0;
|
|
20
21
|
this.device = device;
|
|
@@ -27,25 +28,40 @@ export class UsbTransport {
|
|
|
27
28
|
if (this.device.configuration === null) {
|
|
28
29
|
await this.device.selectConfiguration(1);
|
|
29
30
|
}
|
|
30
|
-
// Find the CDC Data interface (usually class 10) or just the first one with Bulk endpoints
|
|
31
31
|
const interfaces = this.device.configuration?.interfaces || [];
|
|
32
|
-
let
|
|
33
|
-
|
|
32
|
+
let ctrlIface;
|
|
33
|
+
let dataIface;
|
|
34
|
+
dataIface = interfaces.find(iface => {
|
|
34
35
|
const endpoints = iface.alternate.endpoints;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
return endpoints.some(e => e.direction === 'in' && e.type === 'bulk') &&
|
|
37
|
+
endpoints.some(e => e.direction === 'out' && e.type === 'bulk');
|
|
38
|
+
});
|
|
39
|
+
if (dataIface) {
|
|
40
|
+
this.dataInterface = dataIface.interfaceNumber;
|
|
41
|
+
ctrlIface = interfaces.find(i => i.interfaceNumber === this.dataInterface - 1)
|
|
42
|
+
|| interfaces.find(i => i.alternate.interfaceClass === 2);
|
|
43
|
+
this.controlInterface = ctrlIface ? ctrlIface.interfaceNumber : this.dataInterface;
|
|
44
|
+
}
|
|
45
|
+
if (!dataIface) {
|
|
46
|
+
throw new Error("No serial-compatible Bulk interface found.");
|
|
47
|
+
}
|
|
48
|
+
// Note: On Android, if the OS has claimed Interface 0, this first call will fail.
|
|
49
|
+
try {
|
|
50
|
+
if (this.controlInterface !== this.dataInterface) {
|
|
51
|
+
await this.device.claimInterface(this.controlInterface);
|
|
40
52
|
}
|
|
41
53
|
}
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
catch (e) {
|
|
55
|
+
console.warn("Could not claim Control Interface (OS locked?). Proceeding to Data...", e);
|
|
56
|
+
// We continue, but setSignals might fail later.
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await this.device.claimInterface(this.dataInterface);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new Error(`Failed to claim Data Interface. Android OS has locked the device driver. Try using a 'Vendor Specific' USB Class device or a native Serial App workaround.`);
|
|
44
63
|
}
|
|
45
|
-
|
|
46
|
-
await this.device.claimInterface(this.interfaceNumber);
|
|
47
|
-
// Map endpoints
|
|
48
|
-
const endpoints = targetInterface.alternate.endpoints;
|
|
64
|
+
const endpoints = dataIface.alternate.endpoints;
|
|
49
65
|
this.endpointIn = endpoints.find(e => e.direction === 'in' && e.type === 'bulk').endpointNumber;
|
|
50
66
|
this.endpointOut = endpoints.find(e => e.direction === 'out' && e.type === 'bulk').endpointNumber;
|
|
51
67
|
await this.setBaudRate(baudRate);
|
|
@@ -57,7 +73,6 @@ export class UsbTransport {
|
|
|
57
73
|
async write(data) {
|
|
58
74
|
if (!this.device.opened)
|
|
59
75
|
return;
|
|
60
|
-
// Cast to 'unknown' then 'BufferSource' to satisfy the strict type definition
|
|
61
76
|
await this.device.transferOut(this.endpointOut, data);
|
|
62
77
|
}
|
|
63
78
|
/**
|
|
@@ -85,14 +100,13 @@ export class UsbTransport {
|
|
|
85
100
|
async setSignals({ dtr, rts }) {
|
|
86
101
|
if (!this.device.opened)
|
|
87
102
|
return;
|
|
88
|
-
// CDC-ACM: DTR is bit 0, RTS is bit 1
|
|
89
103
|
const value = (Number(dtr) | (Number(rts) << 1));
|
|
90
104
|
await this.device.controlTransferOut({
|
|
91
105
|
requestType: 'class',
|
|
92
106
|
recipient: 'interface',
|
|
93
107
|
request: UsbTransport.SET_CONTROL_LINE_STATE,
|
|
94
108
|
value: value,
|
|
95
|
-
index: this.
|
|
109
|
+
index: this.controlInterface
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
async setBaudRate(baud) {
|
|
@@ -102,20 +116,31 @@ export class UsbTransport {
|
|
|
102
116
|
// 4 bytes: baud (LE), 1 byte: stop bits, 1 byte: parity, 1 byte: data bits
|
|
103
117
|
const buffer = new ArrayBuffer(7);
|
|
104
118
|
const view = new DataView(buffer);
|
|
105
|
-
view.setUint32(0, baud, true);
|
|
106
|
-
view.setUint8(4, 0);
|
|
107
|
-
view.setUint8(5, 0);
|
|
108
|
-
view.setUint8(6, 8);
|
|
119
|
+
view.setUint32(0, baud, true);
|
|
120
|
+
view.setUint8(4, 0);
|
|
121
|
+
view.setUint8(5, 0);
|
|
122
|
+
view.setUint8(6, 8);
|
|
109
123
|
await this.device.controlTransferOut({
|
|
110
124
|
requestType: 'class',
|
|
111
125
|
recipient: 'interface',
|
|
112
126
|
request: UsbTransport.SET_LINE_CODING,
|
|
113
127
|
value: 0,
|
|
114
|
-
index: this.
|
|
128
|
+
index: this.controlInterface
|
|
115
129
|
}, buffer);
|
|
116
130
|
}
|
|
117
131
|
async disconnect() {
|
|
118
132
|
if (this.device.opened) {
|
|
133
|
+
// Release both
|
|
134
|
+
try {
|
|
135
|
+
await this.device.releaseInterface(this.dataInterface);
|
|
136
|
+
}
|
|
137
|
+
catch (e) { }
|
|
138
|
+
if (this.controlInterface !== this.dataInterface) {
|
|
139
|
+
try {
|
|
140
|
+
await this.device.releaseInterface(this.controlInterface);
|
|
141
|
+
}
|
|
142
|
+
catch (e) { }
|
|
143
|
+
}
|
|
119
144
|
await this.device.close();
|
|
120
145
|
}
|
|
121
146
|
}
|
package/package.json
CHANGED