@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
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @depz/sensor-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the **DEPZ USB sensor line** — three USB CDC-ACM sensors that
|
|
4
|
+
speak one shared framed protocol, usable from **the browser (WebSerial)** and
|
|
5
|
+
**Node (serialport)**:
|
|
6
|
+
|
|
7
|
+
- **HC-SR04** — ultrasonic distance
|
|
8
|
+
- **VL53L8CX / VL53L8CH** — 8×8 multizone Time-of-Flight (host runs the ST ULD)
|
|
9
|
+
- **BNO086** — 9-axis IMU (host runs the SH-2 stack)
|
|
10
|
+
|
|
11
|
+
Pure ESM, zero runtime dependencies on the browser path (`serialport` is an
|
|
12
|
+
optional peer used only by the `./node` entry). Mirrors the Python
|
|
13
|
+
[`depz-sensor-sdk`](https://pypi.org/project/depz-sensor-sdk/) byte-for-byte via
|
|
14
|
+
shared golden test vectors.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @depz/sensor-sdk
|
|
20
|
+
# for Node serial access also:
|
|
21
|
+
npm install serialport
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick start (browser, WebSerial)
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { openDevice } from "@depz/sensor-sdk/web";
|
|
28
|
+
|
|
29
|
+
const port = await navigator.serial.requestPort(); // user gesture
|
|
30
|
+
const dev = await openDevice(port);
|
|
31
|
+
// dev is the correctly-typed sensor class (Sr04 | Vl53l8Cx/Ch | Bno086)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick start (Node)
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { openDevice, listDepzDevices } from "@depz/sensor-sdk/node";
|
|
38
|
+
|
|
39
|
+
const dev = await openDevice(); // default: the DEPZ device with the smallest serial
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Selecting a device (contract 02 §4.3)
|
|
43
|
+
|
|
44
|
+
Selection is by **USB identity**: only ports with a known DEPZ (vid,pid) are
|
|
45
|
+
considered, ordered by serial — the same rules across Node and browser (in the
|
|
46
|
+
browser the serial comes from a `GET_SERIAL` probe of granted ports).
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
await openDevice(); // default — smallest serial
|
|
50
|
+
await openDevice(0); // by INDEX — Nth candidate, sorted by serial
|
|
51
|
+
await openDevice(1); // second SR04 when two are plugged in
|
|
52
|
+
await openDevice(undefined, { serial: "UMPVOB2461" }); // by exact USB SERIAL
|
|
53
|
+
await openDevice("/dev/ttyACM0"); // explicit port path (Node)
|
|
54
|
+
|
|
55
|
+
for (const info of await listDepzDevices()) // enumerate candidates first
|
|
56
|
+
console.log(info.path, info.sensorType, info.serialNumber);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
No DEPZ candidate → throws (never falls back to the first system port), matching
|
|
60
|
+
the Python `open_device()` semantics.
|
|
61
|
+
|
|
62
|
+
Entry points: `@depz/sensor-sdk` (core, transport-agnostic), `@depz/sensor-sdk/web`
|
|
63
|
+
(WebSerial), `@depz/sensor-sdk/node` (serialport). See `docs/` for the per-sensor
|
|
64
|
+
guides and the generated API reference.
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT. Bundled VL53L8 sensor-firmware blobs are © STMicroelectronics
|
|
69
|
+
(BSD-3-Clause).
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.depzdata` datasets: decoded, multi-device, time-synced recording &
|
|
3
|
+
* playback (contracts/09_DATASET_FORMAT.md). Mirrors the Python
|
|
4
|
+
* `depz_sensor_sdk.dataset` module; browser-safe (no Node APIs).
|
|
5
|
+
*/
|
|
6
|
+
import type { DepzDevice } from "./device/device.js";
|
|
7
|
+
export declare const DATASET_SCHEMA = "depz.dataset/1";
|
|
8
|
+
export interface DatasetDeviceMeta {
|
|
9
|
+
serial?: string;
|
|
10
|
+
sensor_type?: string;
|
|
11
|
+
software_name?: string;
|
|
12
|
+
time_sync: {
|
|
13
|
+
offset_us: number;
|
|
14
|
+
rtt_us: number;
|
|
15
|
+
};
|
|
16
|
+
[k: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface DatasetHeader {
|
|
19
|
+
schema: string;
|
|
20
|
+
created_utc: string;
|
|
21
|
+
devices: Record<string, DatasetDeviceMeta>;
|
|
22
|
+
note?: string;
|
|
23
|
+
[k: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface DatasetRecord {
|
|
26
|
+
deviceId: string;
|
|
27
|
+
tHostUs: number;
|
|
28
|
+
kind: string;
|
|
29
|
+
value: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
/** Accumulates a dataset in memory; `dump()` gives the JSONL file content. */
|
|
32
|
+
export declare class DatasetWriter {
|
|
33
|
+
private lines;
|
|
34
|
+
recordsWritten: number;
|
|
35
|
+
constructor(devices: Record<string, DatasetDeviceMeta>, note?: string);
|
|
36
|
+
write(deviceId: string, tHostUs: number, kind: string, value: Record<string, unknown>): void;
|
|
37
|
+
dump(): string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Hooks live devices into a DatasetWriter on one shared host timeline.
|
|
41
|
+
* Call `await recorder.add(device)` for each device (runs syncTime), then
|
|
42
|
+
* `start()`; `stop()` unhooks; `dump()` returns the file content.
|
|
43
|
+
*/
|
|
44
|
+
export declare class DatasetRecorder {
|
|
45
|
+
private opts;
|
|
46
|
+
private entries;
|
|
47
|
+
private writer;
|
|
48
|
+
constructor(opts?: {
|
|
49
|
+
note?: string;
|
|
50
|
+
vl53l8Layers?: boolean;
|
|
51
|
+
});
|
|
52
|
+
add(device: DepzDevice, deviceId?: string, syncSamples?: number): Promise<string>;
|
|
53
|
+
start(): void;
|
|
54
|
+
private hook;
|
|
55
|
+
stop(): void;
|
|
56
|
+
get recordsWritten(): number;
|
|
57
|
+
dump(): string;
|
|
58
|
+
}
|
|
59
|
+
/** Parse a `.depzdata` file; records come back merged by host time. */
|
|
60
|
+
export declare class DatasetReader {
|
|
61
|
+
readonly header: DatasetHeader;
|
|
62
|
+
readonly records: DatasetRecord[];
|
|
63
|
+
constructor(content: string);
|
|
64
|
+
get devices(): Record<string, DatasetDeviceMeta>;
|
|
65
|
+
get durationUs(): number;
|
|
66
|
+
}
|
|
67
|
+
export type PlayerState = "idle" | "playing" | "paused" | "done";
|
|
68
|
+
/**
|
|
69
|
+
* Timeline player: paced delivery with play/pause/seek/speed — the engine
|
|
70
|
+
* behind the viewer's playback mode.
|
|
71
|
+
*/
|
|
72
|
+
export declare class DatasetPlayer {
|
|
73
|
+
readonly reader: DatasetReader;
|
|
74
|
+
private idx;
|
|
75
|
+
private timer;
|
|
76
|
+
private stateCbs;
|
|
77
|
+
private recordCbs;
|
|
78
|
+
private _state;
|
|
79
|
+
speed: number;
|
|
80
|
+
constructor(reader: DatasetReader);
|
|
81
|
+
get state(): PlayerState;
|
|
82
|
+
/** Current position in µs from the first record. */
|
|
83
|
+
get positionUs(): number;
|
|
84
|
+
onRecord(cb: (r: DatasetRecord) => void): () => void;
|
|
85
|
+
onState(cb: (s: PlayerState) => void): () => void;
|
|
86
|
+
private setState;
|
|
87
|
+
play(): void;
|
|
88
|
+
pause(): void;
|
|
89
|
+
/** Seek to µs offset from the start; delivery resumes from there. */
|
|
90
|
+
seekUs(offsetUs: number): void;
|
|
91
|
+
private scheduleNext;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=dataset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"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"}
|
package/dist/dataset.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.depzdata` datasets: decoded, multi-device, time-synced recording &
|
|
3
|
+
* playback (contracts/09_DATASET_FORMAT.md). Mirrors the Python
|
|
4
|
+
* `depz_sensor_sdk.dataset` module; browser-safe (no Node APIs).
|
|
5
|
+
*/
|
|
6
|
+
export const DATASET_SCHEMA = "depz.dataset/1";
|
|
7
|
+
/** Accumulates a dataset in memory; `dump()` gives the JSONL file content. */
|
|
8
|
+
export class DatasetWriter {
|
|
9
|
+
lines;
|
|
10
|
+
recordsWritten = 0;
|
|
11
|
+
constructor(devices, note) {
|
|
12
|
+
const header = {
|
|
13
|
+
schema: DATASET_SCHEMA,
|
|
14
|
+
created_utc: new Date().toISOString().replace(/\.\d+Z$/, "Z"),
|
|
15
|
+
devices,
|
|
16
|
+
};
|
|
17
|
+
if (note)
|
|
18
|
+
header.note = note;
|
|
19
|
+
this.lines = [JSON.stringify(header)];
|
|
20
|
+
}
|
|
21
|
+
write(deviceId, tHostUs, kind, value) {
|
|
22
|
+
this.lines.push(JSON.stringify({ d: deviceId, t: tHostUs, k: kind, v: value }));
|
|
23
|
+
this.recordsWritten += 1;
|
|
24
|
+
}
|
|
25
|
+
dump() {
|
|
26
|
+
return this.lines.join("\n") + "\n";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Hooks live devices into a DatasetWriter on one shared host timeline.
|
|
31
|
+
* Call `await recorder.add(device)` for each device (runs syncTime), then
|
|
32
|
+
* `start()`; `stop()` unhooks; `dump()` returns the file content.
|
|
33
|
+
*/
|
|
34
|
+
export class DatasetRecorder {
|
|
35
|
+
opts;
|
|
36
|
+
entries = [];
|
|
37
|
+
writer = null;
|
|
38
|
+
constructor(opts = {}) {
|
|
39
|
+
this.opts = opts;
|
|
40
|
+
}
|
|
41
|
+
async add(device, deviceId, syncSamples = 5) {
|
|
42
|
+
if (this.writer)
|
|
43
|
+
throw new Error("add() all devices before start()");
|
|
44
|
+
const id = deviceId ?? `d${this.entries.length}`;
|
|
45
|
+
const sync = await device.syncTime(syncSamples);
|
|
46
|
+
const meta = {
|
|
47
|
+
time_sync: { offset_us: Number(sync.offsetUs), rtt_us: Number(sync.rttUs) },
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
meta.serial = await device.getSerialNumber();
|
|
51
|
+
const ident = await device.identify();
|
|
52
|
+
meta.software_name = ident.softwareName;
|
|
53
|
+
meta.sensor_type = ident.sensorType ?? "unknown";
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* identity is best-effort */
|
|
57
|
+
}
|
|
58
|
+
this.entries.push({ id, device, offsetUs: sync.offsetUs, meta });
|
|
59
|
+
return id;
|
|
60
|
+
}
|
|
61
|
+
start() {
|
|
62
|
+
if (this.writer)
|
|
63
|
+
return;
|
|
64
|
+
this.writer = new DatasetWriter(Object.fromEntries(this.entries.map((e) => [e.id, e.meta])), this.opts.note);
|
|
65
|
+
for (const entry of this.entries) {
|
|
66
|
+
entry.unsub = this.hook(entry);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
hook(entry) {
|
|
70
|
+
const writer = this.writer;
|
|
71
|
+
const dev = entry.device;
|
|
72
|
+
const toHost = (tsUs) => Number(tsUs - entry.offsetUs);
|
|
73
|
+
if (typeof dev.onMeasurement === "function") {
|
|
74
|
+
return dev.onMeasurement((m) => {
|
|
75
|
+
writer.write(entry.id, toHost(m.timestampUs), "sr04", {
|
|
76
|
+
echo_us: m.echoTimeUs,
|
|
77
|
+
source: m.source,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (typeof dev.onFrame === "function") {
|
|
82
|
+
const layers = this.opts.vl53l8Layers ?? false;
|
|
83
|
+
return dev.onFrame((f) => {
|
|
84
|
+
const n = f.resolution;
|
|
85
|
+
const v = {
|
|
86
|
+
resolution: n,
|
|
87
|
+
silicon_temp_degc: f.siliconTempDegc,
|
|
88
|
+
distance_mm: Array.from(f.distanceMm.subarray(0, n)),
|
|
89
|
+
target_status: Array.from(f.targetStatus.subarray(0, n)),
|
|
90
|
+
nb_target_detected: Array.from(f.nbTargetDetected.subarray(0, n)),
|
|
91
|
+
};
|
|
92
|
+
if (layers) {
|
|
93
|
+
v.signal_per_spad = Array.from(f.signalPerSpad.subarray(0, n));
|
|
94
|
+
v.ambient_per_spad = Array.from(f.ambientPerSpad.subarray(0, n));
|
|
95
|
+
v.range_sigma_mm = Array.from(f.rangeSigmaMm.subarray(0, n));
|
|
96
|
+
v.reflectance = Array.from(f.reflectance.subarray(0, n));
|
|
97
|
+
}
|
|
98
|
+
writer.write(entry.id, toHost(f.timestampUs), "vl53l8", v);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return () => { };
|
|
102
|
+
}
|
|
103
|
+
stop() {
|
|
104
|
+
for (const e of this.entries) {
|
|
105
|
+
e.unsub?.();
|
|
106
|
+
e.unsub = undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
get recordsWritten() {
|
|
110
|
+
return this.writer?.recordsWritten ?? 0;
|
|
111
|
+
}
|
|
112
|
+
dump() {
|
|
113
|
+
if (!this.writer)
|
|
114
|
+
throw new Error("recorder never started");
|
|
115
|
+
return this.writer.dump();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** Parse a `.depzdata` file; records come back merged by host time. */
|
|
119
|
+
export class DatasetReader {
|
|
120
|
+
header;
|
|
121
|
+
records;
|
|
122
|
+
constructor(content) {
|
|
123
|
+
const lines = content.split("\n").filter((l) => l.trim().length > 0);
|
|
124
|
+
if (lines.length === 0)
|
|
125
|
+
throw new Error("empty dataset");
|
|
126
|
+
this.header = JSON.parse(lines[0]);
|
|
127
|
+
if (!String(this.header.schema ?? "").startsWith("depz.dataset/")) {
|
|
128
|
+
throw new Error("not a depz.dataset file");
|
|
129
|
+
}
|
|
130
|
+
const raw = lines.slice(1).map((l) => {
|
|
131
|
+
const ev = JSON.parse(l);
|
|
132
|
+
return { deviceId: ev.d, tHostUs: ev.t, kind: ev.k, value: ev.v };
|
|
133
|
+
});
|
|
134
|
+
// Per-device order is monotonic; a stable sort merges exactly.
|
|
135
|
+
this.records = raw
|
|
136
|
+
.map((r, i) => [r, i])
|
|
137
|
+
.sort((a, b) => a[0].tHostUs - b[0].tHostUs || a[1] - b[1])
|
|
138
|
+
.map(([r]) => r);
|
|
139
|
+
}
|
|
140
|
+
get devices() {
|
|
141
|
+
return this.header.devices ?? {};
|
|
142
|
+
}
|
|
143
|
+
get durationUs() {
|
|
144
|
+
if (this.records.length === 0)
|
|
145
|
+
return 0;
|
|
146
|
+
return this.records[this.records.length - 1].tHostUs - this.records[0].tHostUs;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Timeline player: paced delivery with play/pause/seek/speed — the engine
|
|
151
|
+
* behind the viewer's playback mode.
|
|
152
|
+
*/
|
|
153
|
+
export class DatasetPlayer {
|
|
154
|
+
reader;
|
|
155
|
+
idx = 0;
|
|
156
|
+
timer = null;
|
|
157
|
+
stateCbs = [];
|
|
158
|
+
recordCbs = [];
|
|
159
|
+
_state = "idle";
|
|
160
|
+
speed = 1.0;
|
|
161
|
+
constructor(reader) {
|
|
162
|
+
this.reader = reader;
|
|
163
|
+
}
|
|
164
|
+
get state() {
|
|
165
|
+
return this._state;
|
|
166
|
+
}
|
|
167
|
+
/** Current position in µs from the first record. */
|
|
168
|
+
get positionUs() {
|
|
169
|
+
const recs = this.reader.records;
|
|
170
|
+
if (recs.length === 0 || this.idx === 0)
|
|
171
|
+
return 0;
|
|
172
|
+
return recs[Math.min(this.idx, recs.length) - 1].tHostUs - recs[0].tHostUs;
|
|
173
|
+
}
|
|
174
|
+
onRecord(cb) {
|
|
175
|
+
this.recordCbs.push(cb);
|
|
176
|
+
return () => {
|
|
177
|
+
this.recordCbs = this.recordCbs.filter((c) => c !== cb);
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
onState(cb) {
|
|
181
|
+
this.stateCbs.push(cb);
|
|
182
|
+
return () => {
|
|
183
|
+
this.stateCbs = this.stateCbs.filter((c) => c !== cb);
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
setState(s) {
|
|
187
|
+
this._state = s;
|
|
188
|
+
this.stateCbs.forEach((cb) => cb(s));
|
|
189
|
+
}
|
|
190
|
+
play() {
|
|
191
|
+
if (this._state === "playing")
|
|
192
|
+
return;
|
|
193
|
+
if (this.idx >= this.reader.records.length)
|
|
194
|
+
this.idx = 0;
|
|
195
|
+
this.setState("playing");
|
|
196
|
+
this.scheduleNext();
|
|
197
|
+
}
|
|
198
|
+
pause() {
|
|
199
|
+
if (this.timer)
|
|
200
|
+
clearTimeout(this.timer);
|
|
201
|
+
this.timer = null;
|
|
202
|
+
if (this._state === "playing")
|
|
203
|
+
this.setState("paused");
|
|
204
|
+
}
|
|
205
|
+
/** Seek to µs offset from the start; delivery resumes from there. */
|
|
206
|
+
seekUs(offsetUs) {
|
|
207
|
+
const recs = this.reader.records;
|
|
208
|
+
if (recs.length === 0)
|
|
209
|
+
return;
|
|
210
|
+
const target = recs[0].tHostUs + offsetUs;
|
|
211
|
+
let lo = 0;
|
|
212
|
+
let hi = recs.length;
|
|
213
|
+
while (lo < hi) {
|
|
214
|
+
const mid = (lo + hi) >> 1;
|
|
215
|
+
if (recs[mid].tHostUs < target)
|
|
216
|
+
lo = mid + 1;
|
|
217
|
+
else
|
|
218
|
+
hi = mid;
|
|
219
|
+
}
|
|
220
|
+
this.idx = lo;
|
|
221
|
+
if (this._state === "playing") {
|
|
222
|
+
this.pause();
|
|
223
|
+
this.play();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
scheduleNext() {
|
|
227
|
+
const recs = this.reader.records;
|
|
228
|
+
if (this.idx >= recs.length) {
|
|
229
|
+
this.setState("done");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const rec = recs[this.idx];
|
|
233
|
+
const emit = () => {
|
|
234
|
+
this.idx += 1;
|
|
235
|
+
this.recordCbs.forEach((cb) => cb(rec));
|
|
236
|
+
if (this._state === "playing")
|
|
237
|
+
this.scheduleNext();
|
|
238
|
+
};
|
|
239
|
+
if (this.speed <= 0 || this.idx === 0) {
|
|
240
|
+
emit();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const prev = recs[this.idx - 1];
|
|
244
|
+
const gapMs = (rec.tHostUs - prev.tHostUs) / 1000 / this.speed;
|
|
245
|
+
if (gapMs <= 1) {
|
|
246
|
+
emit();
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
this.timer = setTimeout(emit, gapMs);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=dataset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset.js","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DepzDevice: request correlation, events, common commands
|
|
3
|
+
* (contracts/02_COMMON_COMMANDS.md, 07_SDK_FACADE.md).
|
|
4
|
+
*
|
|
5
|
+
* Behavioral rules per contract 07 §3: correlation by echoed request opcode
|
|
6
|
+
* (never seq), one in-flight request per opcode, 200 ms default timeout,
|
|
7
|
+
* bounded drop-oldest stream queues, callbacks run on the read-pump context.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the Python reference `depz_sensor_sdk.device.DeviceBase`. The read
|
|
10
|
+
* pump only starts in `open()`, after the (sub)class constructor finished —
|
|
11
|
+
* subclass stream state always exists before the first dispatch.
|
|
12
|
+
*/
|
|
13
|
+
import { type SyncPinConfig } from "../protocol/common.js";
|
|
14
|
+
import { type Identity } from "../protocol/identity.js";
|
|
15
|
+
import { CrcType, type PacketEvent } from "../protocol/framing.js";
|
|
16
|
+
import type { SerialTransport } from "../transport/types.js";
|
|
17
|
+
import { DepzLink, type LinkStats } from "./link.js";
|
|
18
|
+
export declare const DEFAULT_TIMEOUT_MS = 200;
|
|
19
|
+
/** Unsolicited/diagnostic events, mirrored from the Python event classes. */
|
|
20
|
+
export type DeviceEvent = {
|
|
21
|
+
type: "sequenceError";
|
|
22
|
+
expectedSeq: number;
|
|
23
|
+
receivedSeq: number;
|
|
24
|
+
/** true: device saw a gap in host TX (RPT 0x84). */
|
|
25
|
+
reportedByDevice: boolean;
|
|
26
|
+
} | {
|
|
27
|
+
type: "linkCrcError";
|
|
28
|
+
cmd: number;
|
|
29
|
+
seq: number;
|
|
30
|
+
} | {
|
|
31
|
+
type: "trash";
|
|
32
|
+
data: Uint8Array;
|
|
33
|
+
} | {
|
|
34
|
+
type: "unsolicitedStatus";
|
|
35
|
+
status: number;
|
|
36
|
+
} | {
|
|
37
|
+
type: "text";
|
|
38
|
+
cmd: number;
|
|
39
|
+
text: string;
|
|
40
|
+
} | {
|
|
41
|
+
type: "temperature";
|
|
42
|
+
timestampUs: bigint;
|
|
43
|
+
celsius: number;
|
|
44
|
+
} | {
|
|
45
|
+
type: "disconnected";
|
|
46
|
+
reason: string;
|
|
47
|
+
};
|
|
48
|
+
/** Result of `syncTime()` (contract 02 §5). offset = device − host clock. */
|
|
49
|
+
export interface TimeSync {
|
|
50
|
+
offsetUs: bigint;
|
|
51
|
+
rttUs: bigint;
|
|
52
|
+
syncedAtHostUs: bigint;
|
|
53
|
+
}
|
|
54
|
+
/** Monotonic host clock in µs — the host side of all time-sync math. */
|
|
55
|
+
export declare function hostNowUs(): bigint;
|
|
56
|
+
/** Returned by a matcher to decline a packet. */
|
|
57
|
+
export declare const NO_MATCH: unique symbol;
|
|
58
|
+
/**
|
|
59
|
+
* Claims a packet for an in-flight request: return the parsed result, or
|
|
60
|
+
* `NO_MATCH` to let other consumers see the packet.
|
|
61
|
+
*/
|
|
62
|
+
export type Matcher<T> = (pkt: PacketEvent) => T | typeof NO_MATCH;
|
|
63
|
+
export interface RequestOptions<T> {
|
|
64
|
+
/** First shot at every non-status packet while the request is pending. */
|
|
65
|
+
matcher?: Matcher<T>;
|
|
66
|
+
/** Resolve on RPT_STATUS(cmd, OK) — for commands whose success reply is the ack. */
|
|
67
|
+
okCompletes?: boolean;
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Bounded drop-oldest async stream (contract 07 §3). Doubles as the async
|
|
72
|
+
* iterator returned by e.g. `Sr04.measurements()`; `droppedCount` is the
|
|
73
|
+
* monotonic count of items evicted while the consumer lagged.
|
|
74
|
+
*/
|
|
75
|
+
export declare class StreamQueue<T> implements AsyncIterableIterator<T> {
|
|
76
|
+
droppedCount: number;
|
|
77
|
+
private readonly maxsize;
|
|
78
|
+
private readonly onDone;
|
|
79
|
+
private buf;
|
|
80
|
+
private waiters;
|
|
81
|
+
private closed;
|
|
82
|
+
constructor(maxsize: number, onDone?: () => void);
|
|
83
|
+
/** Producer side: enqueue, evicting the oldest item when full. */
|
|
84
|
+
push(item: T): void;
|
|
85
|
+
/** End the stream; buffered items are still drained by the consumer. */
|
|
86
|
+
close(): void;
|
|
87
|
+
next(): Promise<IteratorResult<T>>;
|
|
88
|
+
return(): Promise<IteratorResult<T>>;
|
|
89
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
|
|
90
|
+
}
|
|
91
|
+
export interface DeviceOptions {
|
|
92
|
+
timeoutMs?: number;
|
|
93
|
+
txCrcType?: CrcType;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Connection to one DEPZ device in application mode. Construct over any
|
|
97
|
+
* `SerialTransport`, then `await open()` before use.
|
|
98
|
+
*/
|
|
99
|
+
export declare class DepzDevice {
|
|
100
|
+
timeoutMs: number;
|
|
101
|
+
protected readonly link: DepzLink;
|
|
102
|
+
private readonly transport;
|
|
103
|
+
private readonly pending;
|
|
104
|
+
private eventCbs;
|
|
105
|
+
private streams;
|
|
106
|
+
private timeSyncState;
|
|
107
|
+
private closing;
|
|
108
|
+
private torndown;
|
|
109
|
+
constructor(transport: SerialTransport, opts?: DeviceOptions);
|
|
110
|
+
/** Open the transport and start the read pump. */
|
|
111
|
+
open(): Promise<void>;
|
|
112
|
+
close(): Promise<void>;
|
|
113
|
+
get stats(): LinkStats;
|
|
114
|
+
private handleLinkClosed;
|
|
115
|
+
private failAllPending;
|
|
116
|
+
private handleParserEvent;
|
|
117
|
+
private dispatch;
|
|
118
|
+
private settle;
|
|
119
|
+
/**
|
|
120
|
+
* Hook for sensor subclasses: route streaming reports here. Return true
|
|
121
|
+
* when the packet was consumed. Runs after status/matcher/common-report
|
|
122
|
+
* routing, on the read-pump context.
|
|
123
|
+
*/
|
|
124
|
+
protected handleReport(pkt: PacketEvent): boolean;
|
|
125
|
+
/** Register a stream to be closed on device teardown. */
|
|
126
|
+
protected registerStream(stream: {
|
|
127
|
+
close(): void;
|
|
128
|
+
}): () => void;
|
|
129
|
+
/**
|
|
130
|
+
* Subscribe to unsolicited/diagnostic events (read-pump context; do not
|
|
131
|
+
* block). Returns an unsubscribe function.
|
|
132
|
+
*/
|
|
133
|
+
onEvent(cb: (ev: DeviceEvent) => void): () => void;
|
|
134
|
+
protected emitEvent(event: DeviceEvent): void;
|
|
135
|
+
/**
|
|
136
|
+
* Send `cmd` and wait for its correlated completion (contract 02 §1).
|
|
137
|
+
*
|
|
138
|
+
* Exactly one of the completion paths must be configured:
|
|
139
|
+
* - `okCompletes` — RPT_STATUS(cmd, OK) resolves with undefined;
|
|
140
|
+
* - `matcher` — first packet for which the matcher returns non-`NO_MATCH`
|
|
141
|
+
* resolves with the matcher's return value.
|
|
142
|
+
* Non-OK RPT_STATUS echoing `cmd` always rejects (BusyError for ERR_BUSY,
|
|
143
|
+
* StatusError otherwise). One in-flight request per opcode.
|
|
144
|
+
*/
|
|
145
|
+
request<T = void>(cmd: number, payload?: Uint8Array, opts?: RequestOptions<T>): Promise<T>;
|
|
146
|
+
/** Matcher for a typed report identified by its report ID alone. */
|
|
147
|
+
static expectReport<T>(reportId: number, unpack: (payload: Uint8Array) => T): Matcher<T>;
|
|
148
|
+
/** Matcher for RPT_TEXT echoing `requestCmd`. */
|
|
149
|
+
static expectText(requestCmd: number): Matcher<string>;
|
|
150
|
+
getDeviceName(): Promise<string>;
|
|
151
|
+
getSoftwareName(): Promise<string>;
|
|
152
|
+
getSerialNumber(): Promise<string>;
|
|
153
|
+
/** Classify the running firmware (contract 02 §4). */
|
|
154
|
+
identify(): Promise<Identity>;
|
|
155
|
+
/** Last cached MCU temperature in °C (device refreshes ~2 Hz). */
|
|
156
|
+
readMcuTemperature(): Promise<number>;
|
|
157
|
+
/** NTP-style sync; keeps the lowest-RTT sample (contract 02 §5). */
|
|
158
|
+
syncTime(samples?: number): Promise<TimeSync>;
|
|
159
|
+
get timeSync(): TimeSync | null;
|
|
160
|
+
/** Device µs → host monotonic µs (requires a prior `syncTime`). */
|
|
161
|
+
toHostTimeUs(deviceTsUs: bigint): bigint;
|
|
162
|
+
getReportPayloadCrc(): Promise<CrcType>;
|
|
163
|
+
/** Set the device→host payload CRC mode (host→device is per-packet). */
|
|
164
|
+
setReportPayloadCrc(crcType: CrcType): Promise<void>;
|
|
165
|
+
getSyncPin(pin: number): Promise<SyncPinConfig>;
|
|
166
|
+
setSyncPin(config: SyncPinConfig): Promise<void>;
|
|
167
|
+
/** DEVICE_RESET: device ACKs then reboots; the link will drop. */
|
|
168
|
+
reset(): Promise<void>;
|
|
169
|
+
/**
|
|
170
|
+
* Ask the device to reboot into the resident bootloader and close this
|
|
171
|
+
* connection. Re-discovery/flash flow lives in the bootloader module
|
|
172
|
+
* (contract 06).
|
|
173
|
+
*/
|
|
174
|
+
enterBootloaderMode(): Promise<void>;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Software-sync several devices to the common host monotonic clock.
|
|
178
|
+
*
|
|
179
|
+
* Runs `syncTime()` on each device so that every device's `toHostTimeUs()`
|
|
180
|
+
* maps its own timestamps onto ONE shared host timeline — the basis for
|
|
181
|
+
* correlating reports from multiple sensors live. Returns a Map
|
|
182
|
+
* {device → TimeSync}. Mirrors the Python reference `sync_time_all`.
|
|
183
|
+
*/
|
|
184
|
+
export declare function syncTimeAll(devices: Iterable<DepzDevice>, samples?: number): Promise<Map<DepzDevice, TimeSync>>;
|
|
185
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/device/device.ts"],"names":[],"mappings":"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"}
|