@depz/sensor-sdk 0.1.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 +69 -0
- package/dist/dataset.d.ts +93 -0
- package/dist/dataset.d.ts.map +1 -0
- package/dist/dataset.js +253 -0
- package/dist/dataset.js.map +1 -0
- package/dist/device/device.d.ts +185 -0
- package/dist/device/device.d.ts.map +1 -0
- package/dist/device/device.js +421 -0
- package/dist/device/device.js.map +1 -0
- package/dist/device/link.d.ts +62 -0
- package/dist/device/link.d.ts.map +1 -0
- package/dist/device/link.js +130 -0
- package/dist/device/link.js.map +1 -0
- package/dist/discovery.d.ts +109 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +281 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +69 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/bno086.d.ts +36 -0
- package/dist/protocol/bno086.d.ts.map +1 -0
- package/dist/protocol/bno086.js +38 -0
- package/dist/protocol/bno086.js.map +1 -0
- package/dist/protocol/common.d.ts +103 -0
- package/dist/protocol/common.d.ts.map +1 -0
- package/dist/protocol/common.js +121 -0
- package/dist/protocol/common.js.map +1 -0
- package/dist/protocol/crc.d.ts +17 -0
- package/dist/protocol/crc.d.ts.map +1 -0
- package/dist/protocol/crc.js +55 -0
- package/dist/protocol/crc.js.map +1 -0
- package/dist/protocol/framing.d.ts +65 -0
- package/dist/protocol/framing.d.ts.map +1 -0
- package/dist/protocol/framing.js +152 -0
- package/dist/protocol/framing.js.map +1 -0
- package/dist/protocol/fwdepz.d.ts +21 -0
- package/dist/protocol/fwdepz.d.ts.map +1 -0
- package/dist/protocol/fwdepz.js +46 -0
- package/dist/protocol/fwdepz.js.map +1 -0
- package/dist/protocol/identity.d.ts +14 -0
- package/dist/protocol/identity.d.ts.map +1 -0
- package/dist/protocol/identity.js +28 -0
- package/dist/protocol/identity.js.map +1 -0
- package/dist/protocol/sr04.d.ts +38 -0
- package/dist/protocol/sr04.d.ts.map +1 -0
- package/dist/protocol/sr04.js +58 -0
- package/dist/protocol/sr04.js.map +1 -0
- package/dist/protocol/usb-ids.d.ts +60 -0
- package/dist/protocol/usb-ids.d.ts.map +1 -0
- package/dist/protocol/usb-ids.js +79 -0
- package/dist/protocol/usb-ids.js.map +1 -0
- package/dist/protocol/vl53l8.d.ts +59 -0
- package/dist/protocol/vl53l8.d.ts.map +1 -0
- package/dist/protocol/vl53l8.js +116 -0
- package/dist/protocol/vl53l8.js.map +1 -0
- package/dist/sensors/bno086/bno086.d.ts +197 -0
- package/dist/sensors/bno086/bno086.d.ts.map +1 -0
- package/dist/sensors/bno086/bno086.js +543 -0
- package/dist/sensors/bno086/bno086.js.map +1 -0
- package/dist/sensors/bno086/reports.d.ts +289 -0
- package/dist/sensors/bno086/reports.d.ts.map +1 -0
- package/dist/sensors/bno086/reports.js +397 -0
- package/dist/sensors/bno086/reports.js.map +1 -0
- package/dist/sensors/bno086/sh2.d.ts +307 -0
- package/dist/sensors/bno086/sh2.d.ts.map +1 -0
- package/dist/sensors/bno086/sh2.js +480 -0
- package/dist/sensors/bno086/sh2.js.map +1 -0
- package/dist/sensors/bno086/shtp.d.ts +98 -0
- package/dist/sensors/bno086/shtp.d.ts.map +1 -0
- package/dist/sensors/bno086/shtp.js +205 -0
- package/dist/sensors/bno086/shtp.js.map +1 -0
- package/dist/sensors/sr04.d.ts +65 -0
- package/dist/sensors/sr04.d.ts.map +1 -0
- package/dist/sensors/sr04.js +121 -0
- package/dist/sensors/sr04.js.map +1 -0
- package/dist/sensors/vl53l8/assets/ch.d.ts +16 -0
- package/dist/sensors/vl53l8/assets/ch.d.ts.map +1 -0
- package/dist/sensors/vl53l8/assets/ch.js +22 -0
- package/dist/sensors/vl53l8/assets/ch.js.map +1 -0
- package/dist/sensors/vl53l8/assets/cx.d.ts +16 -0
- package/dist/sensors/vl53l8/assets/cx.d.ts.map +1 -0
- package/dist/sensors/vl53l8/assets/cx.js +22 -0
- package/dist/sensors/vl53l8/assets/cx.js.map +1 -0
- package/dist/sensors/vl53l8/assets/decode.d.ts +7 -0
- package/dist/sensors/vl53l8/assets/decode.d.ts.map +1 -0
- package/dist/sensors/vl53l8/assets/decode.js +35 -0
- package/dist/sensors/vl53l8/assets/decode.js.map +1 -0
- package/dist/sensors/vl53l8/assets/index.d.ts +19 -0
- package/dist/sensors/vl53l8/assets/index.d.ts.map +1 -0
- package/dist/sensors/vl53l8/assets/index.js +11 -0
- package/dist/sensors/vl53l8/assets/index.js.map +1 -0
- package/dist/sensors/vl53l8/cnh.d.ts +113 -0
- package/dist/sensors/vl53l8/cnh.d.ts.map +1 -0
- package/dist/sensors/vl53l8/cnh.js +299 -0
- package/dist/sensors/vl53l8/cnh.js.map +1 -0
- package/dist/sensors/vl53l8/uld.d.ts +346 -0
- package/dist/sensors/vl53l8/uld.d.ts.map +1 -0
- package/dist/sensors/vl53l8/uld.js +1388 -0
- package/dist/sensors/vl53l8/uld.js.map +1 -0
- package/dist/sensors/vl53l8/vl53l8.d.ts +182 -0
- package/dist/sensors/vl53l8/vl53l8.d.ts.map +1 -0
- package/dist/sensors/vl53l8/vl53l8.js +411 -0
- package/dist/sensors/vl53l8/vl53l8.js.map +1 -0
- package/dist/transport/loopback.d.ts +18 -0
- package/dist/transport/loopback.d.ts.map +1 -0
- package/dist/transport/loopback.js +53 -0
- package/dist/transport/loopback.js.map +1 -0
- package/dist/transport/node.d.ts +51 -0
- package/dist/transport/node.d.ts.map +1 -0
- package/dist/transport/node.js +123 -0
- package/dist/transport/node.js.map +1 -0
- package/dist/transport/replay.d.ts +68 -0
- package/dist/transport/replay.d.ts.map +1 -0
- package/dist/transport/replay.js +196 -0
- package/dist/transport/replay.js.map +1 -0
- package/dist/transport/types.d.ts +23 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +7 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/transport/webserial.d.ts +69 -0
- package/dist/transport/webserial.d.ts.map +1 -0
- package/dist/transport/webserial.js +196 -0
- package/dist/transport/webserial.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js transport over the optional `serialport` peer dependency.
|
|
3
|
+
* Import via `@depz/sensor-sdk/node` only — never from the root export, so
|
|
4
|
+
* browser bundles stay serialport-free.
|
|
5
|
+
*/
|
|
6
|
+
import { listDepzDevicesFrom, openDeviceFrom, } from "../discovery.js";
|
|
7
|
+
async function loadSerialport() {
|
|
8
|
+
try {
|
|
9
|
+
const mod = (await import("serialport"));
|
|
10
|
+
return { SerialPort: mod.SerialPort, list: () => mod.SerialPort.list() };
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
throw new Error("the optional peer dependency 'serialport' is required for NodeSerialTransport " +
|
|
14
|
+
"(npm i serialport)", { cause: err });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** Enumerate system serial ports (Node only). */
|
|
18
|
+
export async function listSerialPorts() {
|
|
19
|
+
const { list } = await loadSerialport();
|
|
20
|
+
return list();
|
|
21
|
+
}
|
|
22
|
+
export class NodeSerialTransport {
|
|
23
|
+
path;
|
|
24
|
+
info;
|
|
25
|
+
port = null;
|
|
26
|
+
queue = [];
|
|
27
|
+
waiter = null;
|
|
28
|
+
ended = false;
|
|
29
|
+
disconnectCbs = [];
|
|
30
|
+
constructor(path, serialNumber) {
|
|
31
|
+
this.path = path;
|
|
32
|
+
this.info = { path, serialNumber };
|
|
33
|
+
}
|
|
34
|
+
async open(opts) {
|
|
35
|
+
const { SerialPort } = await loadSerialport();
|
|
36
|
+
const port = new SerialPort({
|
|
37
|
+
path: this.path,
|
|
38
|
+
baudRate: opts?.baudRate ?? 115200,
|
|
39
|
+
autoOpen: false,
|
|
40
|
+
});
|
|
41
|
+
await new Promise((resolve, reject) => port.open((err) => (err ? reject(err) : resolve())));
|
|
42
|
+
port.on("data", (data) => {
|
|
43
|
+
this.queue.push(new Uint8Array(data));
|
|
44
|
+
this.waiter?.();
|
|
45
|
+
});
|
|
46
|
+
port.on("close", () => this.end());
|
|
47
|
+
port.on("error", () => this.end());
|
|
48
|
+
this.port = port;
|
|
49
|
+
}
|
|
50
|
+
end() {
|
|
51
|
+
if (this.ended)
|
|
52
|
+
return;
|
|
53
|
+
this.ended = true;
|
|
54
|
+
this.waiter?.();
|
|
55
|
+
const cbs = this.disconnectCbs;
|
|
56
|
+
this.disconnectCbs = [];
|
|
57
|
+
cbs.forEach((cb) => cb());
|
|
58
|
+
}
|
|
59
|
+
async write(data) {
|
|
60
|
+
const port = this.port;
|
|
61
|
+
if (!port || !port.isOpen)
|
|
62
|
+
throw new Error("port not open");
|
|
63
|
+
await new Promise((resolve, reject) => port.write(data, (err) => (err ? reject(err) : resolve())));
|
|
64
|
+
}
|
|
65
|
+
async *readable() {
|
|
66
|
+
for (;;) {
|
|
67
|
+
while (this.queue.length === 0) {
|
|
68
|
+
if (this.ended)
|
|
69
|
+
return;
|
|
70
|
+
await new Promise((resolve) => (this.waiter = resolve));
|
|
71
|
+
this.waiter = null;
|
|
72
|
+
}
|
|
73
|
+
yield this.queue.shift();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async close() {
|
|
77
|
+
const port = this.port;
|
|
78
|
+
if (port && port.isOpen) {
|
|
79
|
+
await new Promise((resolve) => port.close(() => resolve()));
|
|
80
|
+
}
|
|
81
|
+
this.end();
|
|
82
|
+
}
|
|
83
|
+
onDisconnect(cb) {
|
|
84
|
+
this.disconnectCbs.push(cb);
|
|
85
|
+
return () => {
|
|
86
|
+
this.disconnectCbs = this.disconnectCbs.filter((c) => c !== cb);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ── discovery (Node / serialport — full behavior) ─────────────────────────────
|
|
91
|
+
function toPortInfo(p) {
|
|
92
|
+
return {
|
|
93
|
+
path: p.path,
|
|
94
|
+
serialNumber: p.serialNumber,
|
|
95
|
+
usbVid: p.vendorId !== undefined ? parseInt(p.vendorId, 16) : undefined,
|
|
96
|
+
usbPid: p.productId !== undefined ? parseInt(p.productId, 16) : undefined,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const nodeFactory = (port) => new NodeSerialTransport(port.path, port.serialNumber);
|
|
100
|
+
/**
|
|
101
|
+
* Enumerate DEPZ devices on the system's serial ports (Node only).
|
|
102
|
+
*
|
|
103
|
+
* With `matchUsb` (default) only ports carrying a known DEPZ (vid,pid) are
|
|
104
|
+
* probed — fast, and it never pokes unrelated ports. Set `matchUsb: false`
|
|
105
|
+
* for a legacy probe-everything scan.
|
|
106
|
+
*/
|
|
107
|
+
export async function listDepzDevices(opts = {}) {
|
|
108
|
+
const ports = (await listSerialPorts()).map(toPortInfo);
|
|
109
|
+
return listDepzDevicesFrom(ports, nodeFactory, opts);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Open the right sensor class for `target` over `serialport` (Node only).
|
|
113
|
+
*
|
|
114
|
+
* `target` is a port path (string), a candidate index (number, sorted by USB
|
|
115
|
+
* iSerial), a `DeviceInfo` from `listDepzDevices()`, or omitted for the
|
|
116
|
+
* lowest-serial candidate. Throws `NoDepzDeviceError` when nothing matches —
|
|
117
|
+
* it never grabs an arbitrary system port. See {@link openDeviceFrom}.
|
|
118
|
+
*/
|
|
119
|
+
export async function openDevice(target, opts = {}) {
|
|
120
|
+
const ports = (await listSerialPorts()).map(toPortInfo);
|
|
121
|
+
return openDeviceFrom(ports, nodeFactory, target, opts);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/transport/node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.depzrec` capture and replay transports (contracts/08_RECORDING_FORMAT.md).
|
|
3
|
+
* Mirrors the Python reference `depz_sensor_sdk.transport.record_replay`.
|
|
4
|
+
*/
|
|
5
|
+
import type { SerialTransport, SerialTransportInfo } from "./types.js";
|
|
6
|
+
export declare const RECORDING_SCHEMA = "depz.rec/1";
|
|
7
|
+
/**
|
|
8
|
+
* Wraps any transport and tees both directions into `.depzrec` JSONL text.
|
|
9
|
+
* Get the capture with `dump()` (line 1 is the header; browser-friendly —
|
|
10
|
+
* no filesystem involved).
|
|
11
|
+
*/
|
|
12
|
+
export declare class RecordingTransport implements SerialTransport {
|
|
13
|
+
private readonly inner;
|
|
14
|
+
private readonly lines;
|
|
15
|
+
private readonly t0;
|
|
16
|
+
constructor(inner: SerialTransport, opts?: {
|
|
17
|
+
headerExtra?: Record<string, unknown>;
|
|
18
|
+
});
|
|
19
|
+
get info(): SerialTransportInfo;
|
|
20
|
+
/** The capture so far as `.depzrec` file content. */
|
|
21
|
+
dump(): string;
|
|
22
|
+
private emit;
|
|
23
|
+
open(opts?: {
|
|
24
|
+
baudRate?: number;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
write(data: Uint8Array): Promise<void>;
|
|
27
|
+
readable(): AsyncIterableIterator<Uint8Array>;
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
onDisconnect(cb: () => void): () => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Replays the `rx` side of a `.depzrec` capture **causally**: an rx event
|
|
33
|
+
* is released only after the host has written at least as many tx bytes as
|
|
34
|
+
* preceded that event in the recording. Without this gating a replay would
|
|
35
|
+
* deliver responses before the SDK even sends the requests.
|
|
36
|
+
*
|
|
37
|
+
* `strictTx` additionally asserts the written bytes match the recorded tx
|
|
38
|
+
* stream byte-for-byte (protocol regression mode). `realtime` paces rx
|
|
39
|
+
* events by their recorded timestamps.
|
|
40
|
+
*/
|
|
41
|
+
export declare class ReplayTransport implements SerialTransport {
|
|
42
|
+
readonly info: SerialTransportInfo;
|
|
43
|
+
/** Parsed header line (unknown fields preserved, contract 08). */
|
|
44
|
+
readonly header: Record<string, unknown>;
|
|
45
|
+
private readonly rx;
|
|
46
|
+
private readonly txStream;
|
|
47
|
+
private readonly realtime;
|
|
48
|
+
private readonly strictTx;
|
|
49
|
+
private txWritten;
|
|
50
|
+
private rxIdx;
|
|
51
|
+
private closedFlag;
|
|
52
|
+
private waiters;
|
|
53
|
+
private disconnectCbs;
|
|
54
|
+
constructor(content: string, opts?: {
|
|
55
|
+
realtime?: boolean;
|
|
56
|
+
strictTx?: boolean;
|
|
57
|
+
});
|
|
58
|
+
/** True once every recorded rx event has been delivered. */
|
|
59
|
+
get exhausted(): boolean;
|
|
60
|
+
open(): Promise<void>;
|
|
61
|
+
private notifyAll;
|
|
62
|
+
private waitChange;
|
|
63
|
+
write(data: Uint8Array): Promise<void>;
|
|
64
|
+
readable(): AsyncIterableIterator<Uint8Array>;
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
onDisconnect(cb: () => void): () => void;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/transport/replay.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEvE,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAgB7C;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAqB;gBAE5B,KAAK,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE;IAUpF,IAAI,IAAI,IAAI,mBAAmB,CAE9B;IAED,qDAAqD;IACrD,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,IAAI;IAMZ,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrC,QAAQ,IAAI,qBAAqB,CAAC,UAAU,CAAC;IAOpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAGzC;AASD;;;;;;;;;GASG;AACH,qBAAa,eAAgB,YAAW,eAAe;IACrD,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAsB;IACxD,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEzC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,aAAa,CAAyB;gBAElC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE;IA0B9E,4DAA4D;IAC5D,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAIZ,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBrC,QAAQ,IAAI,qBAAqB,CAAC,UAAU,CAAC;IAwB9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAMzC"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.depzrec` capture and replay transports (contracts/08_RECORDING_FORMAT.md).
|
|
3
|
+
* Mirrors the Python reference `depz_sensor_sdk.transport.record_replay`.
|
|
4
|
+
*/
|
|
5
|
+
import { LinkClosedError } from "../errors.js";
|
|
6
|
+
export const RECORDING_SCHEMA = "depz.rec/1";
|
|
7
|
+
function bytesToHex(data) {
|
|
8
|
+
let s = "";
|
|
9
|
+
for (const b of data)
|
|
10
|
+
s += b.toString(16).padStart(2, "0");
|
|
11
|
+
return s;
|
|
12
|
+
}
|
|
13
|
+
function hexToBytes(hex) {
|
|
14
|
+
const out = new Uint8Array(hex.length >>> 1);
|
|
15
|
+
for (let i = 0; i < out.length; i++) {
|
|
16
|
+
out[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Wraps any transport and tees both directions into `.depzrec` JSONL text.
|
|
22
|
+
* Get the capture with `dump()` (line 1 is the header; browser-friendly —
|
|
23
|
+
* no filesystem involved).
|
|
24
|
+
*/
|
|
25
|
+
export class RecordingTransport {
|
|
26
|
+
inner;
|
|
27
|
+
lines = [];
|
|
28
|
+
t0 = performance.now();
|
|
29
|
+
constructor(inner, opts) {
|
|
30
|
+
this.inner = inner;
|
|
31
|
+
const header = {
|
|
32
|
+
schema: RECORDING_SCHEMA,
|
|
33
|
+
created_utc: new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
34
|
+
...opts?.headerExtra,
|
|
35
|
+
};
|
|
36
|
+
this.lines.push(JSON.stringify(header));
|
|
37
|
+
}
|
|
38
|
+
get info() {
|
|
39
|
+
return this.inner.info;
|
|
40
|
+
}
|
|
41
|
+
/** The capture so far as `.depzrec` file content. */
|
|
42
|
+
dump() {
|
|
43
|
+
return this.lines.join("\n") + "\n";
|
|
44
|
+
}
|
|
45
|
+
emit(dir, data) {
|
|
46
|
+
if (data.length === 0)
|
|
47
|
+
return;
|
|
48
|
+
const t = Math.max(0, Math.round((performance.now() - this.t0) * 1000));
|
|
49
|
+
this.lines.push(JSON.stringify({ t, dir, data: bytesToHex(data) }));
|
|
50
|
+
}
|
|
51
|
+
open(opts) {
|
|
52
|
+
return this.inner.open(opts);
|
|
53
|
+
}
|
|
54
|
+
async write(data) {
|
|
55
|
+
// Record before the (async) write completes so an rx caused by this tx
|
|
56
|
+
// can never be captured ahead of it — replay causality depends on it.
|
|
57
|
+
this.emit("tx", data);
|
|
58
|
+
await this.inner.write(data);
|
|
59
|
+
}
|
|
60
|
+
async *readable() {
|
|
61
|
+
for await (const chunk of this.inner.readable()) {
|
|
62
|
+
this.emit("rx", chunk);
|
|
63
|
+
yield chunk;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
close() {
|
|
67
|
+
return this.inner.close();
|
|
68
|
+
}
|
|
69
|
+
onDisconnect(cb) {
|
|
70
|
+
return this.inner.onDisconnect(cb);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Replays the `rx` side of a `.depzrec` capture **causally**: an rx event
|
|
75
|
+
* is released only after the host has written at least as many tx bytes as
|
|
76
|
+
* preceded that event in the recording. Without this gating a replay would
|
|
77
|
+
* deliver responses before the SDK even sends the requests.
|
|
78
|
+
*
|
|
79
|
+
* `strictTx` additionally asserts the written bytes match the recorded tx
|
|
80
|
+
* stream byte-for-byte (protocol regression mode). `realtime` paces rx
|
|
81
|
+
* events by their recorded timestamps.
|
|
82
|
+
*/
|
|
83
|
+
export class ReplayTransport {
|
|
84
|
+
info = { path: "replay" };
|
|
85
|
+
/** Parsed header line (unknown fields preserved, contract 08). */
|
|
86
|
+
header;
|
|
87
|
+
rx = [];
|
|
88
|
+
txStream;
|
|
89
|
+
realtime;
|
|
90
|
+
strictTx;
|
|
91
|
+
txWritten = 0;
|
|
92
|
+
rxIdx = 0;
|
|
93
|
+
closedFlag = false;
|
|
94
|
+
waiters = [];
|
|
95
|
+
disconnectCbs = [];
|
|
96
|
+
constructor(content, opts) {
|
|
97
|
+
this.realtime = opts?.realtime ?? false;
|
|
98
|
+
this.strictTx = opts?.strictTx ?? false;
|
|
99
|
+
const lines = content.split("\n").filter((l) => l.trim().length > 0);
|
|
100
|
+
this.header =
|
|
101
|
+
lines.length > 0 ? JSON.parse(lines[0]) : {};
|
|
102
|
+
const txChunks = [];
|
|
103
|
+
let txLen = 0;
|
|
104
|
+
for (const line of lines.slice(1)) {
|
|
105
|
+
const ev = JSON.parse(line);
|
|
106
|
+
const data = hexToBytes(ev.data);
|
|
107
|
+
if (ev.dir === "rx") {
|
|
108
|
+
this.rx.push({ tUs: ev.t, data, txPrefix: txLen });
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
txChunks.push(data);
|
|
112
|
+
txLen += data.length;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
this.txStream = new Uint8Array(txLen);
|
|
116
|
+
let off = 0;
|
|
117
|
+
for (const chunk of txChunks) {
|
|
118
|
+
this.txStream.set(chunk, off);
|
|
119
|
+
off += chunk.length;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** True once every recorded rx event has been delivered. */
|
|
123
|
+
get exhausted() {
|
|
124
|
+
return this.rxIdx >= this.rx.length;
|
|
125
|
+
}
|
|
126
|
+
async open() { }
|
|
127
|
+
notifyAll() {
|
|
128
|
+
const waiters = this.waiters;
|
|
129
|
+
this.waiters = [];
|
|
130
|
+
for (const w of waiters)
|
|
131
|
+
w();
|
|
132
|
+
}
|
|
133
|
+
waitChange() {
|
|
134
|
+
return new Promise((resolve) => this.waiters.push(resolve));
|
|
135
|
+
}
|
|
136
|
+
async write(data) {
|
|
137
|
+
if (this.closedFlag)
|
|
138
|
+
throw new LinkClosedError("replay transport closed");
|
|
139
|
+
if (this.strictTx) {
|
|
140
|
+
const expected = this.txStream.subarray(this.txWritten, this.txWritten + data.length);
|
|
141
|
+
let mismatch = expected.length !== data.length;
|
|
142
|
+
for (let i = 0; !mismatch && i < data.length; i++) {
|
|
143
|
+
if (expected[i] !== data[i])
|
|
144
|
+
mismatch = true;
|
|
145
|
+
}
|
|
146
|
+
if (mismatch) {
|
|
147
|
+
throw new Error(`replay strictTx mismatch at offset ${this.txWritten}: ` +
|
|
148
|
+
`expected ${bytesToHex(expected)}, got ${bytesToHex(data)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
this.txWritten += data.length;
|
|
152
|
+
this.notifyAll();
|
|
153
|
+
}
|
|
154
|
+
async *readable() {
|
|
155
|
+
const t0 = performance.now();
|
|
156
|
+
while (!this.closedFlag) {
|
|
157
|
+
if (this.exhausted) {
|
|
158
|
+
// Recording drained: behave like a silent port until close().
|
|
159
|
+
await this.waitChange();
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const ev = this.rx[this.rxIdx];
|
|
163
|
+
if (this.txWritten < ev.txPrefix) {
|
|
164
|
+
await this.waitChange();
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (this.realtime) {
|
|
168
|
+
const dueMs = t0 + ev.tUs / 1000;
|
|
169
|
+
const waitMs = dueMs - performance.now();
|
|
170
|
+
if (waitMs > 0)
|
|
171
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
172
|
+
if (this.closedFlag)
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.rxIdx += 1;
|
|
176
|
+
yield ev.data;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async close() {
|
|
180
|
+
if (this.closedFlag)
|
|
181
|
+
return;
|
|
182
|
+
this.closedFlag = true;
|
|
183
|
+
this.notifyAll();
|
|
184
|
+
const cbs = this.disconnectCbs;
|
|
185
|
+
this.disconnectCbs = [];
|
|
186
|
+
for (const cb of cbs)
|
|
187
|
+
cb();
|
|
188
|
+
}
|
|
189
|
+
onDisconnect(cb) {
|
|
190
|
+
this.disconnectCbs.push(cb);
|
|
191
|
+
return () => {
|
|
192
|
+
this.disconnectCbs = this.disconnectCbs.filter((c) => c !== cb);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=replay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/transport/replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-transport abstraction (contracts/07_SDK_FACADE.md §1 "link").
|
|
3
|
+
* WebSerial (browser), serialport (Node), loopback (tests) and .depzrec
|
|
4
|
+
* replay all implement this. The SDK core touches nothing else.
|
|
5
|
+
*/
|
|
6
|
+
export interface SerialTransportInfo {
|
|
7
|
+
usbVendorId?: number;
|
|
8
|
+
usbProductId?: number;
|
|
9
|
+
path?: string;
|
|
10
|
+
serialNumber?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface SerialTransport {
|
|
13
|
+
open(opts?: {
|
|
14
|
+
baudRate?: number;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
write(data: Uint8Array): Promise<void>;
|
|
17
|
+
/** Raw chunks as they arrive; ends on close/disconnect. */
|
|
18
|
+
readable(): AsyncIterableIterator<Uint8Array>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
readonly info: SerialTransportInfo;
|
|
21
|
+
onDisconnect(cb: () => void): () => void;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,2DAA2D;IAC3D,QAAQ,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC1C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-transport abstraction (contracts/07_SDK_FACADE.md §1 "link").
|
|
3
|
+
* WebSerial (browser), serialport (Node), loopback (tests) and .depzrec
|
|
4
|
+
* replay all implement this. The SDK core touches nothing else.
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSerial transport (Chrome/Edge, secure context). The `SerialPort` must be
|
|
3
|
+
* obtained by the app inside a user gesture (`navigator.serial.requestPort()`)
|
|
4
|
+
* and passed here — the SDK never triggers the permission picker itself.
|
|
5
|
+
*/
|
|
6
|
+
import { type DeviceInfo, type ListOptions, type OpenDeviceOptions, type OpenTarget } from "../discovery.js";
|
|
7
|
+
import type { DepzDevice } from "../device/device.js";
|
|
8
|
+
import type { SerialTransport, SerialTransportInfo } from "./types.js";
|
|
9
|
+
export interface WebSerialPortLike {
|
|
10
|
+
open(options: {
|
|
11
|
+
baudRate: number;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
getInfo(): {
|
|
15
|
+
usbVendorId?: number;
|
|
16
|
+
usbProductId?: number;
|
|
17
|
+
};
|
|
18
|
+
readable: ReadableStream<Uint8Array> | null;
|
|
19
|
+
writable: WritableStream<Uint8Array> | null;
|
|
20
|
+
addEventListener?(type: "disconnect", cb: () => void): void;
|
|
21
|
+
removeEventListener?(type: "disconnect", cb: () => void): void;
|
|
22
|
+
}
|
|
23
|
+
/** Feature-detect Web Serial support in the current environment. */
|
|
24
|
+
export declare function isWebSerialSupported(): boolean;
|
|
25
|
+
/** Previously-granted ports (survive page reloads per origin+device). */
|
|
26
|
+
export declare function getGrantedPorts(): Promise<WebSerialPortLike[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Watch physical connect events; used by the firmware-update flow to
|
|
29
|
+
* re-acquire a device after it reboots. Returns an unsubscribe function.
|
|
30
|
+
*/
|
|
31
|
+
export declare function watchConnect(cb: (port: WebSerialPortLike) => void): () => void;
|
|
32
|
+
export declare class WebSerialTransport implements SerialTransport {
|
|
33
|
+
private port;
|
|
34
|
+
readonly info: SerialTransportInfo;
|
|
35
|
+
private reader;
|
|
36
|
+
private writer;
|
|
37
|
+
private disconnectCbs;
|
|
38
|
+
private disconnectHandler;
|
|
39
|
+
constructor(port: WebSerialPortLike);
|
|
40
|
+
open(opts?: {
|
|
41
|
+
baudRate?: number;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
write(data: Uint8Array): Promise<void>;
|
|
44
|
+
readable(): AsyncIterableIterator<Uint8Array>;
|
|
45
|
+
close(): Promise<void>;
|
|
46
|
+
onDisconnect(cb: () => void): () => void;
|
|
47
|
+
private fireDisconnect;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Probe the already-granted WebSerial ports and return the DEPZ devices among
|
|
51
|
+
* them, ordered by DEVICE serial (GET_SERIAL) — the USB iSerial is unavailable
|
|
52
|
+
* in the browser, so the serial is read over the protocol. By default every
|
|
53
|
+
* granted port is probed (`matchUsb: false`) since a granted port is
|
|
54
|
+
* user-curated; pass `matchUsb: true` to probe only known-DEPZ vid/pids.
|
|
55
|
+
*/
|
|
56
|
+
export declare function listDepzDevices(opts?: ListOptions): Promise<DeviceInfo[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Open the right sensor class for a granted WebSerial port.
|
|
59
|
+
*
|
|
60
|
+
* `target` is a `WebSerialPortLike` (typically fresh from
|
|
61
|
+
* `navigator.serial.requestPort()`), a granted-port path string / `DeviceInfo`
|
|
62
|
+
* from `listDepzDevices()`, a candidate index (number, ordered by device
|
|
63
|
+
* serial), or omitted for the smallest-serial DEPZ candidate. `opts.serial`
|
|
64
|
+
* selects the candidate whose device serial matches exactly. Selection probes
|
|
65
|
+
* the granted ports; explicit targets open directly. Throws
|
|
66
|
+
* `NoDepzDeviceError` when nothing matches.
|
|
67
|
+
*/
|
|
68
|
+
export declare function openDevice(target?: OpenTarget | WebSerialPortLike, opts?: OpenDeviceOptions): Promise<DepzDevice>;
|
|
69
|
+
//# sourceMappingURL=webserial.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webserial.d.ts","sourceRoot":"","sources":["../../src/transport/webserial.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAML,KAAK,UAAU,EAEf,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGvE,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC5C,gBAAgB,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC5D,mBAAmB,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAChE;AAaD,oEAAoE;AACpE,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,yEAAyE;AACzE,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAGpE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAS9E;AAED,qBAAa,kBAAmB,YAAW,eAAe;IAO5C,OAAO,CAAC,IAAI;IANxB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,OAAO,CAAC,MAAM,CAAwD;IACtE,OAAO,CAAC,MAAM,CAAwD;IACtE,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,iBAAiB,CAA6B;gBAElC,IAAI,EAAE,iBAAiB;IAKrC,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrC,QAAQ,IAAI,qBAAqB,CAAC,UAAU,CAAC;IAmB9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB5B,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAOxC,OAAO,CAAC,cAAc;CAKvB;AAkCD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAQnF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,MAAM,CAAC,EAAE,UAAU,GAAG,iBAAiB,EACvC,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,UAAU,CAAC,CAiBrB"}
|