react-native-web-serial-api 0.0.3 → 0.2.0
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.
- package/README.md +198 -104
- package/TESTING.md +542 -0
- package/android/build.gradle +16 -2
- package/android/src/main/java/dev/webserialapi/NativeUsbSerialModule.java +74 -11
- package/android/src/main/java/dev/webserialapi/PortPickerActivity.java +61 -59
- package/bin/expose-serial.js +205 -0
- package/lib/commonjs/UsbSerial.js +58 -26
- package/lib/commonjs/UsbSerial.js.map +1 -1
- package/lib/commonjs/WebSerial.js +273 -77
- package/lib/commonjs/WebSerial.js.map +1 -1
- package/lib/commonjs/index.js +15 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/lib/dom-exception.js +176 -0
- package/lib/commonjs/lib/dom-exception.js.map +1 -0
- package/lib/commonjs/lib/event-target.js +140 -0
- package/lib/commonjs/lib/event-target.js.map +1 -0
- package/lib/commonjs/lib/promise.js +23 -0
- package/lib/commonjs/lib/promise.js.map +1 -0
- package/lib/commonjs/lib/web-streams.js +42 -0
- package/lib/commonjs/lib/web-streams.js.map +1 -0
- package/lib/commonjs/testing/device-fixture.js +70 -0
- package/lib/commonjs/testing/device-fixture.js.map +1 -0
- package/lib/commonjs/testing/expose.js +91 -0
- package/lib/commonjs/testing/expose.js.map +1 -0
- package/lib/commonjs/testing/harness.js +98 -0
- package/lib/commonjs/testing/harness.js.map +1 -0
- package/lib/commonjs/testing/in-memory-serial-transport.js +653 -0
- package/lib/commonjs/testing/in-memory-serial-transport.js.map +1 -0
- package/lib/commonjs/testing/index.js +153 -0
- package/lib/commonjs/testing/index.js.map +1 -0
- package/lib/commonjs/testing/install-in-memory-serial-transport.js +54 -0
- package/lib/commonjs/testing/install-in-memory-serial-transport.js.map +1 -0
- package/lib/commonjs/testing/serial-client.js +277 -0
- package/lib/commonjs/testing/serial-client.js.map +1 -0
- package/lib/commonjs/testing/simulated-device.js +164 -0
- package/lib/commonjs/testing/simulated-device.js.map +1 -0
- package/lib/commonjs/testing/test-suite.js +142 -0
- package/lib/commonjs/testing/test-suite.js.map +1 -0
- package/lib/commonjs/transport.js +61 -0
- package/lib/commonjs/transport.js.map +1 -0
- package/lib/commonjs/websocket/WebSocketSerialTransport.js +659 -0
- package/lib/commonjs/websocket/WebSocketSerialTransport.js.map +1 -0
- package/lib/commonjs/websocket/bridge.js +234 -0
- package/lib/commonjs/websocket/bridge.js.map +1 -0
- package/lib/commonjs/websocket/index.js +33 -0
- package/lib/commonjs/websocket/index.js.map +1 -0
- package/lib/commonjs/websocket/protocol.js +55 -0
- package/lib/commonjs/websocket/protocol.js.map +1 -0
- package/lib/commonjs/websocket/serial-device-bridge.js +130 -0
- package/lib/commonjs/websocket/serial-device-bridge.js.map +1 -0
- package/lib/typescript/src/UsbSerial.d.ts +24 -67
- package/lib/typescript/src/UsbSerial.d.ts.map +1 -1
- package/lib/typescript/src/WebSerial.d.ts +16 -7
- package/lib/typescript/src/WebSerial.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/lib/dom-exception.d.ts +100 -0
- package/lib/typescript/src/lib/dom-exception.d.ts.map +1 -0
- package/lib/typescript/src/lib/event-target.d.ts +55 -0
- package/lib/typescript/src/lib/event-target.d.ts.map +1 -0
- package/lib/typescript/src/lib/promise.d.ts +11 -0
- package/lib/typescript/src/lib/promise.d.ts.map +1 -0
- package/lib/typescript/src/lib/web-streams.d.ts +9 -0
- package/lib/typescript/src/lib/web-streams.d.ts.map +1 -0
- package/lib/typescript/src/testing/device-fixture.d.ts +70 -0
- package/lib/typescript/src/testing/device-fixture.d.ts.map +1 -0
- package/lib/typescript/src/testing/expose.d.ts +71 -0
- package/lib/typescript/src/testing/expose.d.ts.map +1 -0
- package/lib/typescript/src/testing/harness.d.ts +34 -0
- package/lib/typescript/src/testing/harness.d.ts.map +1 -0
- package/lib/typescript/src/testing/in-memory-serial-transport.d.ts +216 -0
- package/lib/typescript/src/testing/in-memory-serial-transport.d.ts.map +1 -0
- package/lib/typescript/src/testing/index.d.ts +33 -0
- package/lib/typescript/src/testing/index.d.ts.map +1 -0
- package/lib/typescript/src/testing/install-in-memory-serial-transport.d.ts +25 -0
- package/lib/typescript/src/testing/install-in-memory-serial-transport.d.ts.map +1 -0
- package/lib/typescript/src/testing/serial-client.d.ts +62 -0
- package/lib/typescript/src/testing/serial-client.d.ts.map +1 -0
- package/lib/typescript/src/testing/simulated-device.d.ts +127 -0
- package/lib/typescript/src/testing/simulated-device.d.ts.map +1 -0
- package/lib/typescript/src/testing/test-suite.d.ts +75 -0
- package/lib/typescript/src/testing/test-suite.d.ts.map +1 -0
- package/lib/typescript/src/transport.d.ts +131 -0
- package/lib/typescript/src/transport.d.ts.map +1 -0
- package/lib/typescript/src/websocket/WebSocketSerialTransport.d.ts +111 -0
- package/lib/typescript/src/websocket/WebSocketSerialTransport.d.ts.map +1 -0
- package/lib/typescript/src/websocket/bridge.d.ts +66 -0
- package/lib/typescript/src/websocket/bridge.d.ts.map +1 -0
- package/lib/typescript/src/websocket/index.d.ts +19 -0
- package/lib/typescript/src/websocket/index.d.ts.map +1 -0
- package/lib/typescript/src/websocket/protocol.d.ts +64 -0
- package/lib/typescript/src/websocket/protocol.d.ts.map +1 -0
- package/lib/typescript/src/websocket/serial-device-bridge.d.ts +32 -0
- package/lib/typescript/src/websocket/serial-device-bridge.d.ts.map +1 -0
- package/package.json +57 -3
- package/src/UsbSerial.ts +65 -90
- package/src/WebSerial.ts +351 -113
- package/src/index.ts +6 -8
- package/src/lib/dom-exception.ts +129 -60
- package/src/lib/event-target.ts +58 -21
- package/src/lib/promise.ts +7 -7
- package/src/lib/web-streams.ts +43 -0
- package/src/testing/device-fixture.ts +150 -0
- package/src/testing/expose.ts +147 -0
- package/src/testing/harness.ts +124 -0
- package/src/testing/in-memory-serial-transport.ts +840 -0
- package/src/testing/index.ts +90 -0
- package/src/testing/install-in-memory-serial-transport.ts +65 -0
- package/src/testing/serial-client.ts +313 -0
- package/src/testing/simulated-device.ts +193 -0
- package/src/testing/test-suite.ts +186 -0
- package/src/transport.ts +200 -0
- package/src/websocket/WebSocketSerialTransport.ts +796 -0
- package/src/websocket/bridge.ts +299 -0
- package/src/websocket/index.ts +38 -0
- package/src/websocket/protocol.ts +101 -0
- package/src/websocket/serial-device-bridge.ts +160 -0
- package/babel.config.js +0 -3
- package/biome.json +0 -35
- package/example/.watchmanconfig +0 -1
- package/example/App.tsx +0 -71
- package/example/__tests__/App.test.tsx +0 -16
- package/example/__tests__/connectEvents.test.tsx +0 -81
- package/example/__tests__/getPorts.test.tsx +0 -140
- package/example/android/app/build.gradle +0 -120
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +0 -10
- package/example/android/app/src/debug/AndroidManifest.xml +0 -9
- package/example/android/app/src/main/AndroidManifest.xml +0 -38
- package/example/android/app/src/main/java/dev/uzlopak/MainActivity.kt +0 -22
- package/example/android/app/src/main/java/dev/uzlopak/MainApplication.kt +0 -41
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +0 -3
- package/example/android/app/src/main/res/values/styles.xml +0 -9
- package/example/android/build.gradle +0 -22
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/example/android/gradle.properties +0 -47
- package/example/android/gradlew +0 -252
- package/example/android/gradlew.bat +0 -94
- package/example/android/settings.gradle +0 -6
- package/example/app.json +0 -4
- package/example/babel.config.js +0 -21
- package/example/biome.json +0 -47
- package/example/deploy.sh +0 -11
- package/example/index.html +0 -26
- package/example/index.js +0 -9
- package/example/index.web.js +0 -8
- package/example/jest.config.js +0 -12
- package/example/metro.config.js +0 -58
- package/example/package-lock.json +0 -14510
- package/example/package.json +0 -48
- package/example/react-native.config.js +0 -17
- package/example/src/components/AppBar.tsx +0 -73
- package/example/src/components/Menu.tsx +0 -90
- package/example/src/components/SingleChoiceDialog.tsx +0 -120
- package/example/src/screens/ConnectScreen.tsx +0 -195
- package/example/src/screens/DevicesScreen.tsx +0 -252
- package/example/src/screens/TerminalScreen.tsx +0 -572
- package/example/src/settings.ts +0 -43
- package/example/src/theme.ts +0 -19
- package/example/src/util/TextUtil.ts +0 -129
- package/example/tsconfig.json +0 -10
- package/example/vite.config.mjs +0 -55
- package/scripts/deploy-release.sh +0 -127
- package/tsconfig.build.json +0 -7
- package/tsconfig.json +0 -20
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A runtime-agnostic suite runner for serial device tests. Write a set of
|
|
3
|
+
* `SerialTest`s once and run them anywhere a {@link SerialPort} exists:
|
|
4
|
+
*
|
|
5
|
+
* - in Jest against a {@link DeviceHandle} simulator (in-memory),
|
|
6
|
+
* - on a device / emulator over a real or WebSocket-backed port, and
|
|
7
|
+
* - against BOTH, then {@link compareTestResults} to prove the device matches
|
|
8
|
+
* the simulator case-for-case.
|
|
9
|
+
*
|
|
10
|
+
* Each test receives an opened, host-side {@link SerialClient}; by default one
|
|
11
|
+
* client is shared across the whole suite (open once, close at the end), which
|
|
12
|
+
* matches how a request/response protocol session behaves. Pass `shared: false`
|
|
13
|
+
* to open and close a fresh client per test. The runner never throws — it
|
|
14
|
+
* collects a {@link SerialTestResult} per case — so it is safe to drive an
|
|
15
|
+
* on-device Self-Test screen.
|
|
16
|
+
*
|
|
17
|
+
* @example One suite, two transports, compared
|
|
18
|
+
* const sim = await runTestSuite(myTests, await virtualPort());
|
|
19
|
+
* const dev = await runTestSuite(myTests, realPort);
|
|
20
|
+
* const rows = compareTestResults(sim, dev); // a row passes when both agree
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type {SerialOptions, SerialPort} from '../WebSerial';
|
|
24
|
+
import {errorMessage} from './harness';
|
|
25
|
+
import {SerialClient} from './serial-client';
|
|
26
|
+
|
|
27
|
+
export type SerialTestResult = {
|
|
28
|
+
name: string;
|
|
29
|
+
passed: boolean;
|
|
30
|
+
error?: string;
|
|
31
|
+
durationMs: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** One test case. `run` receives an already-opened client (typically per the
|
|
35
|
+
* suite's {@link TestClient}; `SerialClient` by default). */
|
|
36
|
+
export type SerialTest<C = SerialClient> = {
|
|
37
|
+
name: string;
|
|
38
|
+
run(client: C): Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** Progress hooks so a UI can render results live as each test completes. */
|
|
42
|
+
export type SerialTestProgress = {
|
|
43
|
+
/** Called just before a test starts running. */
|
|
44
|
+
onStart?: (name: string, index: number, total: number) => void;
|
|
45
|
+
/** Called after each test completes (pass or fail). */
|
|
46
|
+
onResult?: (result: SerialTestResult) => void;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* How to build (and tear down) the per-suite client from a port. Provide this to
|
|
51
|
+
* run a higher-level protocol client (e.g. an HCI / NMEA framer built on a
|
|
52
|
+
* {@link SerialClient}) instead of the raw client. `connect` must also open the
|
|
53
|
+
* port; `disconnect` must release it (a `SerialClient.close()` does both).
|
|
54
|
+
*/
|
|
55
|
+
export type TestClient<C> = {
|
|
56
|
+
connect(port: SerialPort): Promise<C>;
|
|
57
|
+
disconnect(client: C): Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type RunTestSuiteOptions<C = SerialClient> = {
|
|
61
|
+
/** `SerialOptions` for the default client's `open()`. Default {baudRate: 115200}. */
|
|
62
|
+
open?: SerialOptions;
|
|
63
|
+
/** Open/close a fresh client per test instead of sharing one. Default false. */
|
|
64
|
+
shared?: boolean;
|
|
65
|
+
/** Build a protocol client over the port (defaults to an opened SerialClient). */
|
|
66
|
+
client?: TestClient<C>;
|
|
67
|
+
progress?: SerialTestProgress;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
function defaultClientFactory(open?: SerialOptions): TestClient<SerialClient> {
|
|
71
|
+
return {
|
|
72
|
+
async connect(port) {
|
|
73
|
+
const client = new SerialClient(port);
|
|
74
|
+
await client.open(open);
|
|
75
|
+
return client;
|
|
76
|
+
},
|
|
77
|
+
disconnect: client => client.close(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Run `tests` against an already-acquired `port`, collecting one result per
|
|
83
|
+
* case. With the default (shared) client the port is opened once and closed at
|
|
84
|
+
* the end; with `shared: false` each test gets a fresh open/close. Never throws.
|
|
85
|
+
*/
|
|
86
|
+
export async function runTestSuite<C = SerialClient>(
|
|
87
|
+
tests: SerialTest<C>[],
|
|
88
|
+
port: SerialPort,
|
|
89
|
+
options: RunTestSuiteOptions<C> = {},
|
|
90
|
+
): Promise<SerialTestResult[]> {
|
|
91
|
+
const factory = (options.client ??
|
|
92
|
+
defaultClientFactory(options.open)) as TestClient<C>;
|
|
93
|
+
const shared = options.shared ?? true;
|
|
94
|
+
const progress = options.progress;
|
|
95
|
+
const results: SerialTestResult[] = [];
|
|
96
|
+
|
|
97
|
+
let sharedClient: C | null = null;
|
|
98
|
+
if (shared) {
|
|
99
|
+
try {
|
|
100
|
+
sharedClient = await factory.connect(port);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
const result: SerialTestResult = {
|
|
103
|
+
name: 'open serial port',
|
|
104
|
+
passed: false,
|
|
105
|
+
error: errorMessage(e),
|
|
106
|
+
durationMs: 0,
|
|
107
|
+
};
|
|
108
|
+
progress?.onResult?.(result);
|
|
109
|
+
return [result];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const total = tests.length;
|
|
114
|
+
try {
|
|
115
|
+
for (let i = 0; i < total; i++) {
|
|
116
|
+
const test = tests[i];
|
|
117
|
+
progress?.onStart?.(test.name, i, total);
|
|
118
|
+
const start = Date.now();
|
|
119
|
+
let perTest: C | null = null;
|
|
120
|
+
let result: SerialTestResult;
|
|
121
|
+
try {
|
|
122
|
+
if (!shared) perTest = await factory.connect(port);
|
|
123
|
+
const client = shared ? (sharedClient as C) : (perTest as C);
|
|
124
|
+
await test.run(client);
|
|
125
|
+
result = {
|
|
126
|
+
name: test.name,
|
|
127
|
+
passed: true,
|
|
128
|
+
durationMs: Date.now() - start,
|
|
129
|
+
};
|
|
130
|
+
} catch (e) {
|
|
131
|
+
result = {
|
|
132
|
+
name: test.name,
|
|
133
|
+
passed: false,
|
|
134
|
+
error: errorMessage(e),
|
|
135
|
+
durationMs: Date.now() - start,
|
|
136
|
+
};
|
|
137
|
+
} finally {
|
|
138
|
+
if (perTest) await factory.disconnect(perTest).catch(() => {});
|
|
139
|
+
}
|
|
140
|
+
results.push(result);
|
|
141
|
+
progress?.onResult?.(result);
|
|
142
|
+
}
|
|
143
|
+
} finally {
|
|
144
|
+
if (sharedClient) await factory.disconnect(sharedClient).catch(() => {});
|
|
145
|
+
}
|
|
146
|
+
return results;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Compare two runs of the same suite case-by-case. A row passes when both runs
|
|
151
|
+
* agree (both passed or both failed), so the `candidate` is judged equivalent to
|
|
152
|
+
* the `reference` rather than judged on its own. Cases the candidate produced
|
|
153
|
+
* that the reference never ran are surfaced as failing `candidate: …` rows.
|
|
154
|
+
*/
|
|
155
|
+
export function compareTestResults(
|
|
156
|
+
reference: SerialTestResult[],
|
|
157
|
+
candidate: SerialTestResult[],
|
|
158
|
+
): SerialTestResult[] {
|
|
159
|
+
const candidateByName = new Map(candidate.map(r => [r.name, r]));
|
|
160
|
+
|
|
161
|
+
const candidateOnly = candidate
|
|
162
|
+
.filter(r => !reference.some(s => s.name === r.name))
|
|
163
|
+
.map(r => ({
|
|
164
|
+
name: `candidate: ${r.name}`,
|
|
165
|
+
passed: false,
|
|
166
|
+
error: r.error ?? 'candidate produced an unexpected result',
|
|
167
|
+
durationMs: r.durationMs,
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
const compared = reference.map(s => {
|
|
171
|
+
const r = candidateByName.get(s.name);
|
|
172
|
+
const identical = !!r && r.passed === s.passed;
|
|
173
|
+
return {
|
|
174
|
+
name: s.name,
|
|
175
|
+
passed: identical,
|
|
176
|
+
error: identical
|
|
177
|
+
? undefined
|
|
178
|
+
: `reference ${s.passed ? 'passed' : 'failed'}, candidate ${
|
|
179
|
+
r ? (r.passed ? 'passed' : 'failed') : 'did not respond'
|
|
180
|
+
}${r?.error ? `: ${r.error}` : ''}`,
|
|
181
|
+
durationMs: r?.durationMs ?? 0,
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return [...candidateOnly, ...compared];
|
|
186
|
+
}
|
package/src/transport.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hardware-transport abstraction for the Web Serial polyfill.
|
|
3
|
+
*
|
|
4
|
+
* `SerialTransport` is the single interface that the `Serial`/`SerialPort`
|
|
5
|
+
* classes depend on to talk to "the device". The production implementation
|
|
6
|
+
* (`UsbSerialModule`, backed by the `NativeUsbSerial` TurboModule — see
|
|
7
|
+
* {@link ./UsbSerial}) and the in-memory test/dev double
|
|
8
|
+
* (`InMemorySerialTransport` — see {@link ./testing/in-memory-serial-transport}) both
|
|
9
|
+
* implement it.
|
|
10
|
+
*
|
|
11
|
+
* This module is intentionally free of any `react-native` import. That is what
|
|
12
|
+
* lets the virtual transport — and therefore the conformance suite built on top
|
|
13
|
+
* of it — run unchanged under Node/Jest, in a browser, and on a device.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// UsbSerialPort.ControlLine enum
|
|
17
|
+
export type ControlLine = 'RTS' | 'CTS' | 'DTR' | 'DSR' | 'CD' | 'RI';
|
|
18
|
+
|
|
19
|
+
// UsbSerialPort.FlowControl enum
|
|
20
|
+
export type FlowControl =
|
|
21
|
+
| 'NONE'
|
|
22
|
+
| 'RTS_CTS'
|
|
23
|
+
| 'DTR_DSR'
|
|
24
|
+
| 'XON_XOFF'
|
|
25
|
+
| 'XON_XOFF_INLINE';
|
|
26
|
+
|
|
27
|
+
export type PortFilter = {
|
|
28
|
+
usbVendorId?: number;
|
|
29
|
+
usbProductId?: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type PortPickerLabels = {
|
|
33
|
+
titleSelectPort?: string;
|
|
34
|
+
titleNoPortsAvailable?: string;
|
|
35
|
+
messageNoPortsAvailable?: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type PortId = {
|
|
39
|
+
deviceId: number;
|
|
40
|
+
portNumber: number;
|
|
41
|
+
usbVendorId: number;
|
|
42
|
+
usbProductId: number;
|
|
43
|
+
/**
|
|
44
|
+
* Whether the app currently holds Android USB permission to access this
|
|
45
|
+
* device (via the system attach dialog or a prior permission request).
|
|
46
|
+
*/
|
|
47
|
+
hasPermission: boolean;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type DataEvent = {
|
|
51
|
+
deviceId: number;
|
|
52
|
+
portNumber: number;
|
|
53
|
+
data: number[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type ErrorEvent = {
|
|
57
|
+
deviceId: number;
|
|
58
|
+
portNumber: number;
|
|
59
|
+
error: string;
|
|
60
|
+
/**
|
|
61
|
+
* Optional spec error name (e.g. "BreakError", "BufferOverrunError",
|
|
62
|
+
* "FramingError", "ParityError") for a typed read error. When present the
|
|
63
|
+
* polyfill surfaces a DOMException of that name on the readable stream
|
|
64
|
+
* (otherwise it defaults to "NetworkError"); the WPT-derived spec tests in
|
|
65
|
+
* src/__tests__/conformance-suite.ts exercise this (BreakError,
|
|
66
|
+
* BufferOverrunError).
|
|
67
|
+
*/
|
|
68
|
+
errorName?: string;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type ConnectEvent = {
|
|
72
|
+
deviceId: number;
|
|
73
|
+
usbVendorId: number;
|
|
74
|
+
usbProductId: number;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Parity = {
|
|
78
|
+
NONE: 0,
|
|
79
|
+
ODD: 1,
|
|
80
|
+
EVEN: 2,
|
|
81
|
+
MARK: 3,
|
|
82
|
+
SPACE: 4,
|
|
83
|
+
} as const;
|
|
84
|
+
|
|
85
|
+
export const DataBits = {
|
|
86
|
+
FIVE: 5,
|
|
87
|
+
SIX: 6,
|
|
88
|
+
SEVEN: 7,
|
|
89
|
+
EIGHT: 8,
|
|
90
|
+
} as const;
|
|
91
|
+
|
|
92
|
+
export const StopBits = {
|
|
93
|
+
ONE: 1,
|
|
94
|
+
ONE_FIVE: 3,
|
|
95
|
+
TWO: 2,
|
|
96
|
+
} as const;
|
|
97
|
+
|
|
98
|
+
export type OpenOptions = {
|
|
99
|
+
baudRate: number;
|
|
100
|
+
dataBits?: number;
|
|
101
|
+
stopBits?: number;
|
|
102
|
+
parity?: number;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const DEFAULT_OPEN_OPTIONS: Required<Omit<OpenOptions, 'baudRate'>> = {
|
|
106
|
+
dataBits: DataBits.EIGHT,
|
|
107
|
+
stopBits: StopBits.ONE,
|
|
108
|
+
parity: Parity.NONE,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/** Handle returned by the `on*` subscription methods. */
|
|
112
|
+
export type Subscription = {remove: () => void};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The contract every serial transport must satisfy. It mirrors the JS-friendly
|
|
116
|
+
* surface of `UsbSerialModule` exactly, so `UsbSerialModule implements
|
|
117
|
+
* SerialTransport` is a faithful 1:1 and any conforming double (e.g.
|
|
118
|
+
* `InMemorySerialTransport`) is a drop-in replacement.
|
|
119
|
+
*
|
|
120
|
+
* Ports are addressed by the pair `(deviceId, portNumber)`. Inbound bytes,
|
|
121
|
+
* read errors and device attach/detach arrive through the `on*` subscriptions.
|
|
122
|
+
*/
|
|
123
|
+
export interface SerialTransport {
|
|
124
|
+
// Discovery & permission
|
|
125
|
+
findAllDrivers(): Promise<ReadonlyArray<PortId>>;
|
|
126
|
+
showPortPicker(
|
|
127
|
+
filter: ReadonlyArray<PortFilter>,
|
|
128
|
+
labels?: PortPickerLabels,
|
|
129
|
+
): Promise<PortId>;
|
|
130
|
+
requestPermission(deviceId: number): Promise<boolean>;
|
|
131
|
+
|
|
132
|
+
// Lifecycle
|
|
133
|
+
open(
|
|
134
|
+
deviceId: number,
|
|
135
|
+
portNumber: number,
|
|
136
|
+
options: OpenOptions,
|
|
137
|
+
): Promise<void>;
|
|
138
|
+
close(deviceId: number, portNumber: number): Promise<void>;
|
|
139
|
+
isOpen(deviceId: number, portNumber: number): boolean;
|
|
140
|
+
|
|
141
|
+
// I/O
|
|
142
|
+
write(
|
|
143
|
+
deviceId: number,
|
|
144
|
+
portNumber: number,
|
|
145
|
+
data: number[],
|
|
146
|
+
timeout?: number,
|
|
147
|
+
): Promise<void>;
|
|
148
|
+
startReading(deviceId: number, portNumber: number): Promise<void>;
|
|
149
|
+
stopReading(deviceId: number, portNumber: number): Promise<void>;
|
|
150
|
+
|
|
151
|
+
// Parameters
|
|
152
|
+
setParameters(
|
|
153
|
+
deviceId: number,
|
|
154
|
+
portNumber: number,
|
|
155
|
+
options: OpenOptions,
|
|
156
|
+
): Promise<void>;
|
|
157
|
+
|
|
158
|
+
// Control signals
|
|
159
|
+
setDTR(deviceId: number, portNumber: number, value: boolean): Promise<void>;
|
|
160
|
+
setRTS(deviceId: number, portNumber: number, value: boolean): Promise<void>;
|
|
161
|
+
getDTR(deviceId: number, portNumber: number): Promise<boolean>;
|
|
162
|
+
getRTS(deviceId: number, portNumber: number): Promise<boolean>;
|
|
163
|
+
getCD(deviceId: number, portNumber: number): Promise<boolean>;
|
|
164
|
+
getCTS(deviceId: number, portNumber: number): Promise<boolean>;
|
|
165
|
+
getDSR(deviceId: number, portNumber: number): Promise<boolean>;
|
|
166
|
+
getRI(deviceId: number, portNumber: number): Promise<boolean>;
|
|
167
|
+
getControlLines(deviceId: number, portNumber: number): Promise<ControlLine[]>;
|
|
168
|
+
getSupportedControlLines(
|
|
169
|
+
deviceId: number,
|
|
170
|
+
portNumber: number,
|
|
171
|
+
): Promise<ControlLine[]>;
|
|
172
|
+
|
|
173
|
+
// Flow control
|
|
174
|
+
setFlowControl(
|
|
175
|
+
deviceId: number,
|
|
176
|
+
portNumber: number,
|
|
177
|
+
flowControl: FlowControl,
|
|
178
|
+
): Promise<void>;
|
|
179
|
+
getFlowControl(deviceId: number, portNumber: number): Promise<FlowControl>;
|
|
180
|
+
getSupportedFlowControl(
|
|
181
|
+
deviceId: number,
|
|
182
|
+
portNumber: number,
|
|
183
|
+
): Promise<FlowControl[]>;
|
|
184
|
+
|
|
185
|
+
// Misc
|
|
186
|
+
setBreak(deviceId: number, portNumber: number, value: boolean): Promise<void>;
|
|
187
|
+
purgeHwBuffers(
|
|
188
|
+
deviceId: number,
|
|
189
|
+
portNumber: number,
|
|
190
|
+
purgeWriteBuffers: boolean,
|
|
191
|
+
purgeReadBuffers: boolean,
|
|
192
|
+
): Promise<void>;
|
|
193
|
+
getSerial(deviceId: number, portNumber: number): Promise<string>;
|
|
194
|
+
|
|
195
|
+
// Event subscriptions
|
|
196
|
+
onData(listener: (event: DataEvent) => void): Subscription;
|
|
197
|
+
onError(listener: (event: ErrorEvent) => void): Subscription;
|
|
198
|
+
onConnect(listener: (event: ConnectEvent) => void): Subscription;
|
|
199
|
+
onDisconnect(listener: (event: ConnectEvent) => void): Subscription;
|
|
200
|
+
}
|