@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.
Files changed (130) hide show
  1. package/README.md +69 -0
  2. package/dist/dataset.d.ts +93 -0
  3. package/dist/dataset.d.ts.map +1 -0
  4. package/dist/dataset.js +253 -0
  5. package/dist/dataset.js.map +1 -0
  6. package/dist/device/device.d.ts +185 -0
  7. package/dist/device/device.d.ts.map +1 -0
  8. package/dist/device/device.js +421 -0
  9. package/dist/device/device.js.map +1 -0
  10. package/dist/device/link.d.ts +62 -0
  11. package/dist/device/link.d.ts.map +1 -0
  12. package/dist/device/link.js +130 -0
  13. package/dist/device/link.js.map +1 -0
  14. package/dist/discovery.d.ts +109 -0
  15. package/dist/discovery.d.ts.map +1 -0
  16. package/dist/discovery.js +281 -0
  17. package/dist/discovery.js.map +1 -0
  18. package/dist/errors.d.ts +39 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +69 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/index.d.ts +42 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +31 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/protocol/bno086.d.ts +36 -0
  27. package/dist/protocol/bno086.d.ts.map +1 -0
  28. package/dist/protocol/bno086.js +38 -0
  29. package/dist/protocol/bno086.js.map +1 -0
  30. package/dist/protocol/common.d.ts +103 -0
  31. package/dist/protocol/common.d.ts.map +1 -0
  32. package/dist/protocol/common.js +121 -0
  33. package/dist/protocol/common.js.map +1 -0
  34. package/dist/protocol/crc.d.ts +17 -0
  35. package/dist/protocol/crc.d.ts.map +1 -0
  36. package/dist/protocol/crc.js +55 -0
  37. package/dist/protocol/crc.js.map +1 -0
  38. package/dist/protocol/framing.d.ts +65 -0
  39. package/dist/protocol/framing.d.ts.map +1 -0
  40. package/dist/protocol/framing.js +152 -0
  41. package/dist/protocol/framing.js.map +1 -0
  42. package/dist/protocol/fwdepz.d.ts +21 -0
  43. package/dist/protocol/fwdepz.d.ts.map +1 -0
  44. package/dist/protocol/fwdepz.js +46 -0
  45. package/dist/protocol/fwdepz.js.map +1 -0
  46. package/dist/protocol/identity.d.ts +14 -0
  47. package/dist/protocol/identity.d.ts.map +1 -0
  48. package/dist/protocol/identity.js +28 -0
  49. package/dist/protocol/identity.js.map +1 -0
  50. package/dist/protocol/sr04.d.ts +38 -0
  51. package/dist/protocol/sr04.d.ts.map +1 -0
  52. package/dist/protocol/sr04.js +58 -0
  53. package/dist/protocol/sr04.js.map +1 -0
  54. package/dist/protocol/usb-ids.d.ts +60 -0
  55. package/dist/protocol/usb-ids.d.ts.map +1 -0
  56. package/dist/protocol/usb-ids.js +79 -0
  57. package/dist/protocol/usb-ids.js.map +1 -0
  58. package/dist/protocol/vl53l8.d.ts +59 -0
  59. package/dist/protocol/vl53l8.d.ts.map +1 -0
  60. package/dist/protocol/vl53l8.js +116 -0
  61. package/dist/protocol/vl53l8.js.map +1 -0
  62. package/dist/sensors/bno086/bno086.d.ts +197 -0
  63. package/dist/sensors/bno086/bno086.d.ts.map +1 -0
  64. package/dist/sensors/bno086/bno086.js +543 -0
  65. package/dist/sensors/bno086/bno086.js.map +1 -0
  66. package/dist/sensors/bno086/reports.d.ts +289 -0
  67. package/dist/sensors/bno086/reports.d.ts.map +1 -0
  68. package/dist/sensors/bno086/reports.js +397 -0
  69. package/dist/sensors/bno086/reports.js.map +1 -0
  70. package/dist/sensors/bno086/sh2.d.ts +307 -0
  71. package/dist/sensors/bno086/sh2.d.ts.map +1 -0
  72. package/dist/sensors/bno086/sh2.js +480 -0
  73. package/dist/sensors/bno086/sh2.js.map +1 -0
  74. package/dist/sensors/bno086/shtp.d.ts +98 -0
  75. package/dist/sensors/bno086/shtp.d.ts.map +1 -0
  76. package/dist/sensors/bno086/shtp.js +205 -0
  77. package/dist/sensors/bno086/shtp.js.map +1 -0
  78. package/dist/sensors/sr04.d.ts +65 -0
  79. package/dist/sensors/sr04.d.ts.map +1 -0
  80. package/dist/sensors/sr04.js +121 -0
  81. package/dist/sensors/sr04.js.map +1 -0
  82. package/dist/sensors/vl53l8/assets/ch.d.ts +16 -0
  83. package/dist/sensors/vl53l8/assets/ch.d.ts.map +1 -0
  84. package/dist/sensors/vl53l8/assets/ch.js +22 -0
  85. package/dist/sensors/vl53l8/assets/ch.js.map +1 -0
  86. package/dist/sensors/vl53l8/assets/cx.d.ts +16 -0
  87. package/dist/sensors/vl53l8/assets/cx.d.ts.map +1 -0
  88. package/dist/sensors/vl53l8/assets/cx.js +22 -0
  89. package/dist/sensors/vl53l8/assets/cx.js.map +1 -0
  90. package/dist/sensors/vl53l8/assets/decode.d.ts +7 -0
  91. package/dist/sensors/vl53l8/assets/decode.d.ts.map +1 -0
  92. package/dist/sensors/vl53l8/assets/decode.js +35 -0
  93. package/dist/sensors/vl53l8/assets/decode.js.map +1 -0
  94. package/dist/sensors/vl53l8/assets/index.d.ts +19 -0
  95. package/dist/sensors/vl53l8/assets/index.d.ts.map +1 -0
  96. package/dist/sensors/vl53l8/assets/index.js +11 -0
  97. package/dist/sensors/vl53l8/assets/index.js.map +1 -0
  98. package/dist/sensors/vl53l8/cnh.d.ts +113 -0
  99. package/dist/sensors/vl53l8/cnh.d.ts.map +1 -0
  100. package/dist/sensors/vl53l8/cnh.js +299 -0
  101. package/dist/sensors/vl53l8/cnh.js.map +1 -0
  102. package/dist/sensors/vl53l8/uld.d.ts +346 -0
  103. package/dist/sensors/vl53l8/uld.d.ts.map +1 -0
  104. package/dist/sensors/vl53l8/uld.js +1388 -0
  105. package/dist/sensors/vl53l8/uld.js.map +1 -0
  106. package/dist/sensors/vl53l8/vl53l8.d.ts +182 -0
  107. package/dist/sensors/vl53l8/vl53l8.d.ts.map +1 -0
  108. package/dist/sensors/vl53l8/vl53l8.js +411 -0
  109. package/dist/sensors/vl53l8/vl53l8.js.map +1 -0
  110. package/dist/transport/loopback.d.ts +18 -0
  111. package/dist/transport/loopback.d.ts.map +1 -0
  112. package/dist/transport/loopback.js +53 -0
  113. package/dist/transport/loopback.js.map +1 -0
  114. package/dist/transport/node.d.ts +51 -0
  115. package/dist/transport/node.d.ts.map +1 -0
  116. package/dist/transport/node.js +123 -0
  117. package/dist/transport/node.js.map +1 -0
  118. package/dist/transport/replay.d.ts +68 -0
  119. package/dist/transport/replay.d.ts.map +1 -0
  120. package/dist/transport/replay.js +196 -0
  121. package/dist/transport/replay.js.map +1 -0
  122. package/dist/transport/types.d.ts +23 -0
  123. package/dist/transport/types.d.ts.map +1 -0
  124. package/dist/transport/types.js +7 -0
  125. package/dist/transport/types.js.map +1 -0
  126. package/dist/transport/webserial.d.ts +69 -0
  127. package/dist/transport/webserial.d.ts.map +1 -0
  128. package/dist/transport/webserial.js +196 -0
  129. package/dist/transport/webserial.js.map +1 -0
  130. package/package.json +77 -0
@@ -0,0 +1,421 @@
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 { BusyError, DepzError, DepzTimeoutError, DeviceLostError, LinkClosedError, StatusError, } from "../errors.js";
14
+ import { Cmd, Rpt, Status, UNSOLICITED, packSyncPinConfig, packSyncTime, syncTimeOffsetRtt, unpackSequenceError, unpackStatus, unpackSyncPinConfig, unpackSyncTime, unpackTemperature, unpackText, } from "../protocol/common.js";
15
+ import { parseSoftwareName } from "../protocol/identity.js";
16
+ import { CrcType } from "../protocol/framing.js";
17
+ import { DepzLink } from "./link.js";
18
+ export const DEFAULT_TIMEOUT_MS = 200;
19
+ /** Monotonic host clock in µs — the host side of all time-sync math. */
20
+ export function hostNowUs() {
21
+ return BigInt(Math.round(performance.now() * 1000));
22
+ }
23
+ // ── request correlation ──────────────────────────────────────────────────────
24
+ /** Returned by a matcher to decline a packet. */
25
+ export const NO_MATCH = Symbol("depz.NO_MATCH");
26
+ // ── stream queues ────────────────────────────────────────────────────────────
27
+ /**
28
+ * Bounded drop-oldest async stream (contract 07 §3). Doubles as the async
29
+ * iterator returned by e.g. `Sr04.measurements()`; `droppedCount` is the
30
+ * monotonic count of items evicted while the consumer lagged.
31
+ */
32
+ export class StreamQueue {
33
+ droppedCount = 0;
34
+ maxsize;
35
+ onDone;
36
+ buf = [];
37
+ waiters = [];
38
+ closed = false;
39
+ constructor(maxsize, onDone) {
40
+ this.maxsize = Math.max(1, maxsize);
41
+ this.onDone = onDone;
42
+ }
43
+ /** Producer side: enqueue, evicting the oldest item when full. */
44
+ push(item) {
45
+ if (this.closed)
46
+ return;
47
+ const waiter = this.waiters.shift();
48
+ if (waiter) {
49
+ waiter({ value: item, done: false });
50
+ return;
51
+ }
52
+ if (this.buf.length >= this.maxsize) {
53
+ this.buf.shift();
54
+ this.droppedCount += 1;
55
+ }
56
+ this.buf.push(item);
57
+ }
58
+ /** End the stream; buffered items are still drained by the consumer. */
59
+ close() {
60
+ if (this.closed)
61
+ return;
62
+ this.closed = true;
63
+ for (const waiter of this.waiters.splice(0)) {
64
+ waiter({ value: undefined, done: true });
65
+ }
66
+ }
67
+ next() {
68
+ const item = this.buf.shift();
69
+ if (item !== undefined)
70
+ return Promise.resolve({ value: item, done: false });
71
+ if (this.closed)
72
+ return Promise.resolve({ value: undefined, done: true });
73
+ return new Promise((resolve) => this.waiters.push(resolve));
74
+ }
75
+ return() {
76
+ this.close();
77
+ this.onDone?.();
78
+ return Promise.resolve({ value: undefined, done: true });
79
+ }
80
+ [Symbol.asyncIterator]() {
81
+ return this;
82
+ }
83
+ }
84
+ /**
85
+ * Connection to one DEPZ device in application mode. Construct over any
86
+ * `SerialTransport`, then `await open()` before use.
87
+ */
88
+ export class DepzDevice {
89
+ timeoutMs;
90
+ link;
91
+ transport;
92
+ pending = new Map();
93
+ eventCbs = [];
94
+ streams = [];
95
+ timeSyncState = null;
96
+ closing = false;
97
+ torndown = false;
98
+ constructor(transport, opts) {
99
+ this.transport = transport;
100
+ this.timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
101
+ this.link = new DepzLink(transport, { txCrcType: opts?.txCrcType ?? CrcType.None });
102
+ this.link.onParserEvent((ev) => this.handleParserEvent(ev));
103
+ this.link.onClose(() => this.handleLinkClosed());
104
+ }
105
+ // ── lifecycle ──────────────────────────────────────────────────────────────
106
+ /** Open the transport and start the read pump. */
107
+ async open() {
108
+ await this.transport.open();
109
+ this.link.start();
110
+ }
111
+ async close() {
112
+ this.closing = true;
113
+ await this.link.close();
114
+ }
115
+ get stats() {
116
+ return this.link.stats;
117
+ }
118
+ handleLinkClosed() {
119
+ if (this.torndown)
120
+ return;
121
+ this.torndown = true;
122
+ if (this.closing) {
123
+ this.failAllPending(new LinkClosedError("device closed"));
124
+ }
125
+ else {
126
+ this.failAllPending(new DeviceLostError("transport closed"));
127
+ this.emitEvent({ type: "disconnected", reason: "transport closed" });
128
+ }
129
+ for (const s of [...this.streams])
130
+ s.close();
131
+ }
132
+ failAllPending(error) {
133
+ const all = [...this.pending.values()];
134
+ this.pending.clear();
135
+ for (const p of all) {
136
+ clearTimeout(p.timer);
137
+ p.reject(error);
138
+ }
139
+ }
140
+ // ── dispatch (read-pump context) ───────────────────────────────────────────
141
+ handleParserEvent(ev) {
142
+ if (ev.type === "packet") {
143
+ this.dispatch(ev);
144
+ }
145
+ else if (ev.type === "crcError") {
146
+ this.emitEvent({ type: "linkCrcError", cmd: ev.cmd, seq: ev.seq });
147
+ }
148
+ else {
149
+ this.emitEvent({ type: "trash", data: ev.data });
150
+ }
151
+ }
152
+ dispatch(pkt) {
153
+ if (pkt.cmd === Rpt.Status && pkt.payload.length >= 2) {
154
+ const rep = unpackStatus(pkt.payload);
155
+ if (rep.cmd !== UNSOLICITED) {
156
+ const pending = this.pending.get(rep.cmd);
157
+ if (pending !== undefined) {
158
+ if (rep.status === Status.ErrBusy) {
159
+ this.settle(pending, { error: new BusyError(rep.cmd) });
160
+ }
161
+ else if (rep.status !== Status.Ok) {
162
+ this.settle(pending, { error: new StatusError(rep.cmd, rep.status) });
163
+ }
164
+ else if (pending.okCompletes) {
165
+ this.settle(pending, { value: undefined });
166
+ }
167
+ // else: OK ack while waiting for the data report — leave the
168
+ // pending request in flight untouched.
169
+ return;
170
+ }
171
+ }
172
+ this.emitEvent({ type: "unsolicitedStatus", status: rep.status });
173
+ return;
174
+ }
175
+ // Give pending matchers first shot at any non-status packet.
176
+ for (const p of [...this.pending.values()]) {
177
+ if (p.matcher === null)
178
+ continue;
179
+ const result = p.matcher(pkt);
180
+ if (result !== NO_MATCH) {
181
+ this.settle(p, { value: result });
182
+ return;
183
+ }
184
+ }
185
+ if (pkt.cmd === Rpt.SequenceError && pkt.payload.length === 2) {
186
+ const rep = unpackSequenceError(pkt.payload);
187
+ this.emitEvent({
188
+ type: "sequenceError",
189
+ expectedSeq: rep.expectedSeq,
190
+ receivedSeq: rep.receivedSeq,
191
+ reportedByDevice: true,
192
+ });
193
+ return;
194
+ }
195
+ if (pkt.cmd === Rpt.Text && pkt.payload.length > 0) {
196
+ const rep = unpackText(pkt.payload);
197
+ this.emitEvent({ type: "text", cmd: rep.cmd, text: rep.text });
198
+ return;
199
+ }
200
+ if (pkt.cmd === Rpt.Temperature && pkt.payload.length === 10) {
201
+ const rep = unpackTemperature(pkt.payload);
202
+ this.emitEvent({
203
+ type: "temperature",
204
+ timestampUs: rep.timestampUs,
205
+ celsius: rep.rawDecidegrees / 10,
206
+ });
207
+ return;
208
+ }
209
+ if (this.handleReport(pkt))
210
+ return;
211
+ // Unknown/unrouted report: keep it visible so new firmware is debuggable.
212
+ this.emitEvent({ type: "text", cmd: pkt.cmd, text: toHex(pkt.payload) });
213
+ }
214
+ settle(p, outcome) {
215
+ clearTimeout(p.timer);
216
+ this.pending.delete(p.cmd);
217
+ if (outcome.error !== undefined)
218
+ p.reject(outcome.error);
219
+ else
220
+ p.resolve(outcome.value);
221
+ }
222
+ /**
223
+ * Hook for sensor subclasses: route streaming reports here. Return true
224
+ * when the packet was consumed. Runs after status/matcher/common-report
225
+ * routing, on the read-pump context.
226
+ */
227
+ handleReport(pkt) {
228
+ void pkt;
229
+ return false;
230
+ }
231
+ /** Register a stream to be closed on device teardown. */
232
+ registerStream(stream) {
233
+ this.streams.push(stream);
234
+ return () => {
235
+ this.streams = this.streams.filter((s) => s !== stream);
236
+ };
237
+ }
238
+ // ── events ─────────────────────────────────────────────────────────────────
239
+ /**
240
+ * Subscribe to unsolicited/diagnostic events (read-pump context; do not
241
+ * block). Returns an unsubscribe function.
242
+ */
243
+ onEvent(cb) {
244
+ this.eventCbs.push(cb);
245
+ return () => {
246
+ this.eventCbs = this.eventCbs.filter((c) => c !== cb);
247
+ };
248
+ }
249
+ emitEvent(event) {
250
+ for (const cb of [...this.eventCbs])
251
+ cb(event);
252
+ }
253
+ // ── TX / requests ──────────────────────────────────────────────────────────
254
+ /**
255
+ * Send `cmd` and wait for its correlated completion (contract 02 §1).
256
+ *
257
+ * Exactly one of the completion paths must be configured:
258
+ * - `okCompletes` — RPT_STATUS(cmd, OK) resolves with undefined;
259
+ * - `matcher` — first packet for which the matcher returns non-`NO_MATCH`
260
+ * resolves with the matcher's return value.
261
+ * Non-OK RPT_STATUS echoing `cmd` always rejects (BusyError for ERR_BUSY,
262
+ * StatusError otherwise). One in-flight request per opcode.
263
+ */
264
+ async request(cmd, payload = new Uint8Array(0), opts = {}) {
265
+ const { matcher, okCompletes = false } = opts;
266
+ if (matcher === undefined && !okCompletes) {
267
+ throw new DepzError("configure matcher or okCompletes");
268
+ }
269
+ if (this.pending.has(cmd))
270
+ throw new BusyError(cmd);
271
+ const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
272
+ const result = new Promise((resolve, reject) => {
273
+ const timer = setTimeout(() => {
274
+ this.pending.delete(cmd);
275
+ reject(new DepzTimeoutError(cmd, timeoutMs));
276
+ }, timeoutMs);
277
+ this.pending.set(cmd, {
278
+ cmd,
279
+ matcher: matcher ?? null,
280
+ okCompletes,
281
+ resolve: resolve,
282
+ reject,
283
+ timer,
284
+ });
285
+ });
286
+ // Mark handled so an early rejection (timeout/disconnect racing the
287
+ // write) never surfaces as an unhandled rejection; the caller still
288
+ // receives it through the returned promise.
289
+ void result.catch(() => undefined);
290
+ try {
291
+ await this.link.send(cmd, payload);
292
+ }
293
+ catch (err) {
294
+ const p = this.pending.get(cmd);
295
+ if (p !== undefined) {
296
+ clearTimeout(p.timer);
297
+ this.pending.delete(cmd);
298
+ }
299
+ throw err;
300
+ }
301
+ return result;
302
+ }
303
+ /** Matcher for a typed report identified by its report ID alone. */
304
+ static expectReport(reportId, unpack) {
305
+ return (pkt) => (pkt.cmd === reportId ? unpack(pkt.payload) : NO_MATCH);
306
+ }
307
+ /** Matcher for RPT_TEXT echoing `requestCmd`. */
308
+ static expectText(requestCmd) {
309
+ return (pkt) => {
310
+ if (pkt.cmd !== Rpt.Text || pkt.payload.length === 0 || pkt.payload[0] !== requestCmd) {
311
+ return NO_MATCH;
312
+ }
313
+ return unpackText(pkt.payload).text;
314
+ };
315
+ }
316
+ // ── common commands (contract 02) ──────────────────────────────────────────
317
+ getDeviceName() {
318
+ return this.request(Cmd.GetDeviceName, undefined, {
319
+ matcher: DepzDevice.expectText(Cmd.GetDeviceName),
320
+ });
321
+ }
322
+ getSoftwareName() {
323
+ return this.request(Cmd.GetNameActiveSoftware, undefined, {
324
+ matcher: DepzDevice.expectText(Cmd.GetNameActiveSoftware),
325
+ });
326
+ }
327
+ getSerialNumber() {
328
+ return this.request(Cmd.GetSerial, undefined, {
329
+ matcher: DepzDevice.expectText(Cmd.GetSerial),
330
+ });
331
+ }
332
+ /** Classify the running firmware (contract 02 §4). */
333
+ async identify() {
334
+ return parseSoftwareName(await this.getSoftwareName());
335
+ }
336
+ /** Last cached MCU temperature in °C (device refreshes ~2 Hz). */
337
+ async readMcuTemperature() {
338
+ const rep = await this.request(Cmd.GetMcuTemperature, undefined, {
339
+ matcher: DepzDevice.expectReport(Rpt.Temperature, unpackTemperature),
340
+ });
341
+ return rep.rawDecidegrees / 10;
342
+ }
343
+ /** NTP-style sync; keeps the lowest-RTT sample (contract 02 §5). */
344
+ async syncTime(samples = 5) {
345
+ let best = null;
346
+ for (let i = 0; i < Math.max(1, samples); i++) {
347
+ const t1 = hostNowUs();
348
+ const rep = await this.request(Cmd.SyncTime, packSyncTime(t1), {
349
+ matcher: DepzDevice.expectReport(Rpt.SyncTime, unpackSyncTime),
350
+ });
351
+ const t4 = hostNowUs();
352
+ const { offsetUs, rttUs } = syncTimeOffsetRtt(t1, rep.mcuRxUs, rep.mcuTxUs, t4);
353
+ if (best === null || rttUs < best.rttUs) {
354
+ best = { offsetUs, rttUs, syncedAtHostUs: t4 };
355
+ }
356
+ }
357
+ this.timeSyncState = best;
358
+ return best;
359
+ }
360
+ get timeSync() {
361
+ return this.timeSyncState;
362
+ }
363
+ /** Device µs → host monotonic µs (requires a prior `syncTime`). */
364
+ toHostTimeUs(deviceTsUs) {
365
+ if (this.timeSyncState === null)
366
+ throw new DepzError("call syncTime() first");
367
+ return deviceTsUs - this.timeSyncState.offsetUs;
368
+ }
369
+ async getReportPayloadCrc() {
370
+ return this.request(Cmd.GetPayloadCrcType, undefined, {
371
+ matcher: DepzDevice.expectReport(Rpt.PayloadCrcType, (p) => p[0]),
372
+ });
373
+ }
374
+ /** Set the device→host payload CRC mode (host→device is per-packet). */
375
+ async setReportPayloadCrc(crcType) {
376
+ await this.request(Cmd.SetPayloadCrcType, Uint8Array.of(crcType), { okCompletes: true });
377
+ }
378
+ getSyncPin(pin) {
379
+ return this.request(Cmd.GetSyncPinConfig, Uint8Array.of(pin), {
380
+ matcher: DepzDevice.expectReport(Rpt.SyncPinConfig, unpackSyncPinConfig),
381
+ });
382
+ }
383
+ async setSyncPin(config) {
384
+ await this.request(Cmd.SetSyncPinConfig, packSyncPinConfig(config), { okCompletes: true });
385
+ }
386
+ /** DEVICE_RESET: device ACKs then reboots; the link will drop. */
387
+ async reset() {
388
+ await this.request(Cmd.DeviceReset, undefined, { okCompletes: true });
389
+ }
390
+ /**
391
+ * Ask the device to reboot into the resident bootloader and close this
392
+ * connection. Re-discovery/flash flow lives in the bootloader module
393
+ * (contract 06).
394
+ */
395
+ async enterBootloaderMode() {
396
+ await this.request(Cmd.Bootloader, undefined, { okCompletes: true });
397
+ await this.close();
398
+ }
399
+ }
400
+ /**
401
+ * Software-sync several devices to the common host monotonic clock.
402
+ *
403
+ * Runs `syncTime()` on each device so that every device's `toHostTimeUs()`
404
+ * maps its own timestamps onto ONE shared host timeline — the basis for
405
+ * correlating reports from multiple sensors live. Returns a Map
406
+ * {device → TimeSync}. Mirrors the Python reference `sync_time_all`.
407
+ */
408
+ export async function syncTimeAll(devices, samples = 5) {
409
+ const out = new Map();
410
+ for (const dev of devices) {
411
+ out.set(dev, await dev.syncTime(samples));
412
+ }
413
+ return out;
414
+ }
415
+ function toHex(data) {
416
+ let s = "";
417
+ for (const b of data)
418
+ s += b.toString(16).padStart(2, "0");
419
+ return s;
420
+ }
421
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/device/device.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * DepzLink: packet-level pump over a byte transport
3
+ * (contracts/07_SDK_FACADE.md §1 layer 1→2 boundary).
4
+ *
5
+ * Owns the read pump (`transport.readable()` → `PacketParser`), the
6
+ * auto-incrementing TX sequence counter, and the link statistics. Packet
7
+ * routing/correlation lives one layer up in `DepzDevice`.
8
+ */
9
+ import { CrcType, type PacketEvent, type ParserEvent } from "../protocol/framing.js";
10
+ import type { SerialTransport } from "../transport/types.js";
11
+ /** Link statistics (contract 07 §2 `stats`). */
12
+ export interface LinkStats {
13
+ rxPackets: number;
14
+ txPackets: number;
15
+ rxBytes: number;
16
+ txBytes: number;
17
+ crcErrors: number;
18
+ headerErrors: number;
19
+ trashBytes: number;
20
+ /** Host-observed gaps in the device→host seq counter (mod 256). */
21
+ seqGaps: number;
22
+ }
23
+ export declare class DepzLink {
24
+ readonly stats: LinkStats;
25
+ private readonly transport;
26
+ private readonly txCrcType;
27
+ private readonly parser;
28
+ private txSeq;
29
+ private lastRxSeq;
30
+ private started;
31
+ private closeFired;
32
+ private packetCbs;
33
+ private parserCbs;
34
+ private closeCbs;
35
+ private unsubDisconnect;
36
+ constructor(transport: SerialTransport, opts?: {
37
+ txCrcType?: CrcType;
38
+ });
39
+ /**
40
+ * Begin the read pump. Must be called exactly once, after the transport
41
+ * is open. Ends (and fires `onClose`) when the transport's readable
42
+ * iterator finishes or the transport reports a disconnect.
43
+ */
44
+ start(): void;
45
+ private pump;
46
+ private handleParserEvent;
47
+ private trackSeq;
48
+ /** Frame and write one packet with the next TX seq (wraps at 0xFF). */
49
+ send(cmd: number, payload?: Uint8Array): Promise<void>;
50
+ /** Subscribe to decoded packets. Returns an unsubscribe function. */
51
+ onPacket(cb: (pkt: PacketEvent) => void): () => void;
52
+ /**
53
+ * Subscribe to all parser events, including CRC errors and trash
54
+ * (diagnostics; the device layer maps these to `DeviceEvent`s).
55
+ */
56
+ onParserEvent(cb: (ev: ParserEvent) => void): () => void;
57
+ /** Subscribe to link teardown (fires once). Returns an unsubscribe. */
58
+ onClose(cb: () => void): () => void;
59
+ private fireClose;
60
+ close(): Promise<void>;
61
+ }
62
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/device/link.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEL,OAAO,EAEP,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,gDAAgD;AAChD,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,QAAQ;IACnB,QAAQ,CAAC,KAAK,EAAE,SAAS,CASvB;IAEF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,SAAS,CAAwC;IACzD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,eAAe,CAA6B;gBAExC,SAAS,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE;IAKtE;;;;OAIG;IACH,KAAK,IAAI,IAAI;YAOC,IAAI;IAYlB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,QAAQ;IAOhB,uEAAuE;IACjE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,UAA8B,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/E,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAOpD;;;OAGG;IACH,aAAa,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAOxD,uEAAuE;IACvE,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAOnC,OAAO,CAAC,SAAS;IAOX,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * DepzLink: packet-level pump over a byte transport
3
+ * (contracts/07_SDK_FACADE.md §1 layer 1→2 boundary).
4
+ *
5
+ * Owns the read pump (`transport.readable()` → `PacketParser`), the
6
+ * auto-incrementing TX sequence counter, and the link statistics. Packet
7
+ * routing/correlation lives one layer up in `DepzDevice`.
8
+ */
9
+ import { buildPacket, CrcType, PacketParser, } from "../protocol/framing.js";
10
+ export class DepzLink {
11
+ stats = {
12
+ rxPackets: 0,
13
+ txPackets: 0,
14
+ rxBytes: 0,
15
+ txBytes: 0,
16
+ crcErrors: 0,
17
+ headerErrors: 0,
18
+ trashBytes: 0,
19
+ seqGaps: 0,
20
+ };
21
+ transport;
22
+ txCrcType;
23
+ parser = new PacketParser();
24
+ txSeq = 0;
25
+ lastRxSeq = null;
26
+ started = false;
27
+ closeFired = false;
28
+ packetCbs = [];
29
+ parserCbs = [];
30
+ closeCbs = [];
31
+ unsubDisconnect = null;
32
+ constructor(transport, opts) {
33
+ this.transport = transport;
34
+ this.txCrcType = opts?.txCrcType ?? CrcType.None;
35
+ }
36
+ /**
37
+ * Begin the read pump. Must be called exactly once, after the transport
38
+ * is open. Ends (and fires `onClose`) when the transport's readable
39
+ * iterator finishes or the transport reports a disconnect.
40
+ */
41
+ start() {
42
+ if (this.started)
43
+ throw new Error("DepzLink already started");
44
+ this.started = true;
45
+ this.unsubDisconnect = this.transport.onDisconnect(() => this.fireClose());
46
+ void this.pump();
47
+ }
48
+ async pump() {
49
+ try {
50
+ for await (const chunk of this.transport.readable()) {
51
+ this.stats.rxBytes += chunk.length;
52
+ for (const ev of this.parser.feed(chunk))
53
+ this.handleParserEvent(ev);
54
+ this.stats.headerErrors = this.parser.headerErrors;
55
+ }
56
+ }
57
+ finally {
58
+ this.fireClose();
59
+ }
60
+ }
61
+ handleParserEvent(ev) {
62
+ if (ev.type === "packet") {
63
+ this.stats.rxPackets += 1;
64
+ this.trackSeq(ev.seq);
65
+ }
66
+ else if (ev.type === "crcError") {
67
+ this.stats.crcErrors += 1;
68
+ }
69
+ else {
70
+ this.stats.trashBytes += ev.data.length;
71
+ }
72
+ for (const cb of [...this.parserCbs])
73
+ cb(ev);
74
+ if (ev.type === "packet") {
75
+ for (const cb of [...this.packetCbs])
76
+ cb(ev);
77
+ }
78
+ }
79
+ trackSeq(seq) {
80
+ if (this.lastRxSeq !== null && seq !== ((this.lastRxSeq + 1) & 0xff)) {
81
+ this.stats.seqGaps += 1;
82
+ }
83
+ this.lastRxSeq = seq;
84
+ }
85
+ /** Frame and write one packet with the next TX seq (wraps at 0xFF). */
86
+ async send(cmd, payload = new Uint8Array(0)) {
87
+ const frame = buildPacket(cmd, payload, this.txSeq, this.txCrcType);
88
+ this.txSeq = (this.txSeq + 1) & 0xff;
89
+ await this.transport.write(frame);
90
+ this.stats.txPackets += 1;
91
+ this.stats.txBytes += frame.length;
92
+ }
93
+ /** Subscribe to decoded packets. Returns an unsubscribe function. */
94
+ onPacket(cb) {
95
+ this.packetCbs.push(cb);
96
+ return () => {
97
+ this.packetCbs = this.packetCbs.filter((c) => c !== cb);
98
+ };
99
+ }
100
+ /**
101
+ * Subscribe to all parser events, including CRC errors and trash
102
+ * (diagnostics; the device layer maps these to `DeviceEvent`s).
103
+ */
104
+ onParserEvent(cb) {
105
+ this.parserCbs.push(cb);
106
+ return () => {
107
+ this.parserCbs = this.parserCbs.filter((c) => c !== cb);
108
+ };
109
+ }
110
+ /** Subscribe to link teardown (fires once). Returns an unsubscribe. */
111
+ onClose(cb) {
112
+ this.closeCbs.push(cb);
113
+ return () => {
114
+ this.closeCbs = this.closeCbs.filter((c) => c !== cb);
115
+ };
116
+ }
117
+ fireClose() {
118
+ if (this.closeFired)
119
+ return;
120
+ this.closeFired = true;
121
+ this.unsubDisconnect?.();
122
+ for (const cb of [...this.closeCbs])
123
+ cb();
124
+ }
125
+ async close() {
126
+ await this.transport.close();
127
+ this.fireClose();
128
+ }
129
+ }
130
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/device/link.ts"],"names":[],"mappings":"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"}