@depz/sensor-sdk 0.2.2 → 0.4.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 +13 -5
- package/dist/dataset.d.ts.map +1 -1
- package/dist/dataset.js +66 -2
- package/dist/dataset.js.map +1 -1
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +25 -2
- package/dist/discovery.js.map +1 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol/bno055.d.ts +101 -0
- package/dist/protocol/bno055.d.ts.map +1 -0
- package/dist/protocol/bno055.js +105 -0
- package/dist/protocol/bno055.js.map +1 -0
- package/dist/protocol/identity.d.ts +1 -1
- package/dist/protocol/identity.d.ts.map +1 -1
- package/dist/protocol/identity.js +6 -0
- package/dist/protocol/identity.js.map +1 -1
- package/dist/protocol/vl53l7.d.ts +77 -0
- package/dist/protocol/vl53l7.d.ts.map +1 -0
- package/dist/protocol/vl53l7.js +99 -0
- package/dist/protocol/vl53l7.js.map +1 -0
- package/dist/protocol/vl53lx.d.ts +72 -0
- package/dist/protocol/vl53lx.d.ts.map +1 -0
- package/dist/protocol/vl53lx.js +87 -0
- package/dist/protocol/vl53lx.js.map +1 -0
- package/dist/sensors/bno055/bno055.d.ts +207 -0
- package/dist/sensors/bno055/bno055.d.ts.map +1 -0
- package/dist/sensors/bno055/bno055.js +547 -0
- package/dist/sensors/bno055/bno055.js.map +1 -0
- package/dist/sensors/bno055/regs.d.ts +271 -0
- package/dist/sensors/bno055/regs.d.ts.map +1 -0
- package/dist/sensors/bno055/regs.js +366 -0
- package/dist/sensors/bno055/regs.js.map +1 -0
- package/dist/sensors/bno086/bno086.d.ts +13 -0
- package/dist/sensors/bno086/bno086.d.ts.map +1 -1
- package/dist/sensors/bno086/bno086.js +26 -1
- package/dist/sensors/bno086/bno086.js.map +1 -1
- package/dist/sensors/bno086/sh2.d.ts.map +1 -1
- package/dist/sensors/bno086/sh2.js +5 -2
- package/dist/sensors/bno086/sh2.js.map +1 -1
- package/dist/sensors/vl53l7/vl53l7.d.ts +97 -0
- package/dist/sensors/vl53l7/vl53l7.d.ts.map +1 -0
- package/dist/sensors/vl53l7/vl53l7.js +138 -0
- package/dist/sensors/vl53l7/vl53l7.js.map +1 -0
- package/dist/sensors/vl53l8/assets/index.d.ts +5 -1
- package/dist/sensors/vl53l8/assets/index.d.ts.map +1 -1
- package/dist/sensors/vl53l8/assets/index.js +7 -1
- package/dist/sensors/vl53l8/assets/index.js.map +1 -1
- package/dist/sensors/vl53l8/assets/l7ch.d.ts +12 -0
- package/dist/sensors/vl53l8/assets/l7ch.d.ts.map +1 -0
- package/dist/sensors/vl53l8/assets/l7ch.js +18 -0
- package/dist/sensors/vl53l8/assets/l7ch.js.map +1 -0
- package/dist/sensors/vl53l8/assets/l7cx.d.ts +14 -0
- package/dist/sensors/vl53l8/assets/l7cx.d.ts.map +1 -0
- package/dist/sensors/vl53l8/assets/l7cx.js +20 -0
- package/dist/sensors/vl53l8/assets/l7cx.js.map +1 -0
- package/dist/sensors/vl53l8/cnh.d.ts +4 -3
- package/dist/sensors/vl53l8/cnh.d.ts.map +1 -1
- package/dist/sensors/vl53l8/cnh.js +4 -3
- package/dist/sensors/vl53l8/cnh.js.map +1 -1
- package/dist/sensors/vl53l8/uld.d.ts +50 -9
- package/dist/sensors/vl53l8/uld.d.ts.map +1 -1
- package/dist/sensors/vl53l8/uld.js +241 -35
- package/dist/sensors/vl53l8/uld.js.map +1 -1
- package/dist/sensors/vl53l8/vl53l8.d.ts +8 -3
- package/dist/sensors/vl53l8/vl53l8.d.ts.map +1 -1
- package/dist/sensors/vl53l8/vl53l8.js +12 -7
- package/dist/sensors/vl53l8/vl53l8.js.map +1 -1
- package/dist/sensors/vl53lx/decode.d.ts +70 -0
- package/dist/sensors/vl53lx/decode.d.ts.map +1 -0
- package/dist/sensors/vl53lx/decode.js +108 -0
- package/dist/sensors/vl53lx/decode.js.map +1 -0
- package/dist/sensors/vl53lx/uld/arith.d.ts +23 -0
- package/dist/sensors/vl53lx/uld/arith.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/arith.js +42 -0
- package/dist/sensors/vl53lx/uld/arith.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/core.d.ts +359 -0
- package/dist/sensors/vl53lx/uld/bare/core.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/core.js +1112 -0
- package/dist/sensors/vl53lx/uld/bare/core.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/driver.d.ts +100 -0
- package/dist/sensors/vl53lx/uld/bare/driver.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/driver.js +226 -0
- package/dist/sensors/vl53lx/uld/bare/driver.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/hist.d.ts +180 -0
- package/dist/sensors/vl53lx/uld/bare/hist.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/hist.js +949 -0
- package/dist/sensors/vl53lx/uld/bare/hist.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/image.d.ts +53 -0
- package/dist/sensors/vl53lx/uld/bare/image.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/image.js +108 -0
- package/dist/sensors/vl53lx/uld/bare/image.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/imath.d.ts +39 -0
- package/dist/sensors/vl53lx/uld/bare/imath.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/imath.js +99 -0
- package/dist/sensors/vl53lx/uld/bare/imath.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/index.d.ts +22 -0
- package/dist/sensors/vl53lx/uld/bare/index.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/index.js +22 -0
- package/dist/sensors/vl53lx/uld/bare/index.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/nvm.d.ts +85 -0
- package/dist/sensors/vl53lx/uld/bare/nvm.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/nvm.js +148 -0
- package/dist/sensors/vl53lx/uld/bare/nvm.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/regs.d.ts +54 -0
- package/dist/sensors/vl53lx/uld/bare/regs.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/regs.js +496 -0
- package/dist/sensors/vl53lx/uld/bare/regs.js.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/tuning.d.ts +15 -0
- package/dist/sensors/vl53lx/uld/bare/tuning.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/bare/tuning.js +303 -0
- package/dist/sensors/vl53lx/uld/bare/tuning.js.map +1 -0
- package/dist/sensors/vl53lx/uld/base.d.ts +134 -0
- package/dist/sensors/vl53lx/uld/base.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/base.js +171 -0
- package/dist/sensors/vl53lx/uld/base.js.map +1 -0
- package/dist/sensors/vl53lx/uld/l0x.d.ts +334 -0
- package/dist/sensors/vl53lx/uld/l0x.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/l0x.js +1532 -0
- package/dist/sensors/vl53lx/uld/l0x.js.map +1 -0
- package/dist/sensors/vl53lx/uld/l1.d.ts +69 -0
- package/dist/sensors/vl53lx/uld/l1.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/l1.js +262 -0
- package/dist/sensors/vl53lx/uld/l1.js.map +1 -0
- package/dist/sensors/vl53lx/uld/l3.d.ts +25 -0
- package/dist/sensors/vl53lx/uld/l3.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/l3.js +51 -0
- package/dist/sensors/vl53lx/uld/l3.js.map +1 -0
- package/dist/sensors/vl53lx/uld/l4.d.ts +20 -0
- package/dist/sensors/vl53lx/uld/l4.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/l4.js +95 -0
- package/dist/sensors/vl53lx/uld/l4.js.map +1 -0
- package/dist/sensors/vl53lx/uld/link.d.ts +42 -0
- package/dist/sensors/vl53lx/uld/link.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/link.js +28 -0
- package/dist/sensors/vl53lx/uld/link.js.map +1 -0
- package/dist/sensors/vl53lx/uld/registry.d.ts +68 -0
- package/dist/sensors/vl53lx/uld/registry.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/registry.js +139 -0
- package/dist/sensors/vl53lx/uld/registry.js.map +1 -0
- package/dist/sensors/vl53lx/uld/vl53l1-die.d.ts +190 -0
- package/dist/sensors/vl53lx/uld/vl53l1-die.d.ts.map +1 -0
- package/dist/sensors/vl53lx/uld/vl53l1-die.js +457 -0
- package/dist/sensors/vl53lx/uld/vl53l1-die.js.map +1 -0
- package/dist/sensors/vl53lx/vl53lx.d.ts +332 -0
- package/dist/sensors/vl53lx/vl53lx.d.ts.map +1 -0
- package/dist/sensors/vl53lx/vl53lx.js +694 -0
- package/dist/sensors/vl53lx/vl53lx.js.map +1 -0
- package/package.json +9 -2
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VL53L 1D ToF family — VL53L0X, VL53L1CX, VL53L1CB, VL53L3CX, VL53L4CD,
|
|
3
|
+
* VL53L4CX — over the `APP_VL53L0_4` register bridge (contracts/12).
|
|
4
|
+
*
|
|
5
|
+
* The MCU is a thin I2C bridge that knows no sensor; every ULD runs here on
|
|
6
|
+
* the host (`uld/`). Two axes pick how a board is driven (`uld/registry.ts`):
|
|
7
|
+
* the **product** (whose parameter set to load — normally the part the
|
|
8
|
+
* board's device name carries; naming a neighbour borrows its driver) and the
|
|
9
|
+
* **driver kind** (`uld`, `ulp` or `histogram`). Every product answers with
|
|
10
|
+
* the same `Vl53lxMeasurement`; what differs is `supports(group)`.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors the Python reference `depz_sensor_sdk.vl53lx`. TS-only difference:
|
|
13
|
+
* the product-level description is `identifyProduct()`, because
|
|
14
|
+
* `DepzDevice.identify()` already classifies the firmware.
|
|
15
|
+
*/
|
|
16
|
+
import { DepzDevice, StreamQueue } from "../../device/device.js";
|
|
17
|
+
import { DepzError, DepzTimeoutError, StatusError } from "../../errors.js";
|
|
18
|
+
import { Status } from "../../protocol/common.js";
|
|
19
|
+
import { XFER_MAX, XSHUT_OFF, XSHUT_ON, XSHUT_RESET, packReadReg, packSetI2cSpeed, packWriteReg, packXshut, unpackRegData, unpackStream, } from "../../protocol/vl53l4.js";
|
|
20
|
+
import { Vl53lxCmd, Vl53lxRpt, packVl53lxSetAddrWidth, packVl53lxStartStream, unpackVl53lxInfo, } from "../../protocol/vl53lx.js";
|
|
21
|
+
import { chunkedRead, chunkedWrite } from "../reg-bridge.js";
|
|
22
|
+
import { BridgePlatform } from "./uld/base.js";
|
|
23
|
+
import { ProtocolError, Vl53Error } from "./uld/link.js";
|
|
24
|
+
import * as registry from "./uld/registry.js";
|
|
25
|
+
export { XSHUT_OFF, XSHUT_ON, XSHUT_RESET };
|
|
26
|
+
/**
|
|
27
|
+
* Statuses that mean "this distance is real". A histogram product reports 6
|
|
28
|
+
* on the first frame of a stream and 11 on a merged pulse: use this, not
|
|
29
|
+
* `status === 0`, as the validity test on histogram products.
|
|
30
|
+
*/
|
|
31
|
+
export const PLOTTABLE_STATUSES = [0, 6, 11];
|
|
32
|
+
function toVl53lxMeasurement(timestampUs, m, bins = null) {
|
|
33
|
+
return {
|
|
34
|
+
timestampUs,
|
|
35
|
+
distanceMm: m.distanceMm,
|
|
36
|
+
status: m.status,
|
|
37
|
+
statusText: m.statusText,
|
|
38
|
+
signalKcps: m.signalKcps,
|
|
39
|
+
ambientKcps: m.ambientKcps,
|
|
40
|
+
sigmaMm: m.sigmaMm,
|
|
41
|
+
spads: m.spads,
|
|
42
|
+
targets: [...m.targets],
|
|
43
|
+
extra: { ...m.extra },
|
|
44
|
+
bins,
|
|
45
|
+
valid: m.status === 0,
|
|
46
|
+
plottable: PLOTTABLE_STATUSES.includes(m.status),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The distances a chart should draw for one measurement: the plottable
|
|
51
|
+
* targets in driver order, or the single distance on a light driver.
|
|
52
|
+
*/
|
|
53
|
+
export function plotDistances(m) {
|
|
54
|
+
if (m.targets.length > 0) {
|
|
55
|
+
return m.targets.filter((t) => PLOTTABLE_STATUSES.includes(t.status)).map((t) => t.distanceMm);
|
|
56
|
+
}
|
|
57
|
+
return PLOTTABLE_STATUSES.includes(m.status) ? [m.distanceMm] : [];
|
|
58
|
+
}
|
|
59
|
+
/** The first plottable target, or null when the frame produced nothing usable. */
|
|
60
|
+
export function primaryTarget(m) {
|
|
61
|
+
for (const t of m.targets)
|
|
62
|
+
if (PLOTTABLE_STATUSES.includes(t.status))
|
|
63
|
+
return t;
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function isThenable(x) {
|
|
67
|
+
return typeof x === "object" && x !== null && typeof x.then === "function";
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A board of the VL53L 1D family (firmware `APP_VL53L0_4`).
|
|
71
|
+
*
|
|
72
|
+
* `init()` binds the (product, driver kind) pair and runs the ULD's
|
|
73
|
+
* sensorInit; `configure()` re-initialises and applies the ranging
|
|
74
|
+
* configuration — call it before every run. Then `startRanging()` arms the MCU
|
|
75
|
+
* stream and measurements arrive via `onMeasurement` / `measurements()` /
|
|
76
|
+
* `getMeasurement()`. Configuration must not change while ranging.
|
|
77
|
+
*
|
|
78
|
+
* This generic class serves any product (read from the board's device name,
|
|
79
|
+
* or `product` at init); the per-product subclasses (`Vl53l0x`...) fix it.
|
|
80
|
+
*/
|
|
81
|
+
export class Vl53lx extends DepzDevice {
|
|
82
|
+
/** The product this class drives; null = read it from the device name. */
|
|
83
|
+
static PRODUCT = null;
|
|
84
|
+
driverInst = null;
|
|
85
|
+
productName = null;
|
|
86
|
+
driverKindName = null;
|
|
87
|
+
caveat = null;
|
|
88
|
+
boardNameCache = null;
|
|
89
|
+
measureCbs = [];
|
|
90
|
+
measureQueues = [];
|
|
91
|
+
rangingFlag = false;
|
|
92
|
+
streamParseErrorCount = 0;
|
|
93
|
+
/** Keeps asynchronous histogram decodes in frame order. */
|
|
94
|
+
decodeChain = Promise.resolve();
|
|
95
|
+
/** MCU timestamp of the latest register read (poll-mode measurements). */
|
|
96
|
+
lastRegTimestampUs = 0n;
|
|
97
|
+
sleepImpl;
|
|
98
|
+
platform;
|
|
99
|
+
/**
|
|
100
|
+
* The `BridgeDevice` the ULD ports talk to: register transfers split at the
|
|
101
|
+
* bridge's 253-byte limit; a non-OK status or a missing answer surfaces as
|
|
102
|
+
* `ProtocolError`, exactly what the ports catch.
|
|
103
|
+
*/
|
|
104
|
+
bridge = {
|
|
105
|
+
readReg: async (addr, length) => {
|
|
106
|
+
try {
|
|
107
|
+
return await chunkedRead(addr, length, {
|
|
108
|
+
chunkSize: XFER_MAX,
|
|
109
|
+
readChunk: async (a, n) => {
|
|
110
|
+
const rep = await this.request(Vl53lxCmd.ReadReg, packReadReg(a, n), {
|
|
111
|
+
matcher: DepzDevice.expectReport(Vl53lxRpt.RegData, unpackRegData),
|
|
112
|
+
timeoutMs: 2000,
|
|
113
|
+
});
|
|
114
|
+
return { data: rep.data, timestampUs: rep.timestampUs };
|
|
115
|
+
},
|
|
116
|
+
onTimestamp: (ts) => {
|
|
117
|
+
this.lastRegTimestampUs = ts;
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
throw Vl53lx.asProtocolError(err, true);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
writeReg: async (addr, data) => {
|
|
126
|
+
try {
|
|
127
|
+
await chunkedWrite(addr, data, {
|
|
128
|
+
chunkSize: XFER_MAX,
|
|
129
|
+
writeChunk: (a, chunk) => this.request(Vl53lxCmd.WriteReg, packWriteReg(a, chunk), {
|
|
130
|
+
okCompletes: true,
|
|
131
|
+
timeoutMs: 2000,
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
throw Vl53lx.asProtocolError(err);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
setI2cSpeed: async (khz) => {
|
|
140
|
+
try {
|
|
141
|
+
await this.request(Vl53lxCmd.SetI2cSpeed, packSetI2cSpeed(khz), { okCompletes: true });
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
throw Vl53lx.asProtocolError(err);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
setAddrWidth: async (width) => {
|
|
148
|
+
try {
|
|
149
|
+
await this.request(Vl53lxCmd.SetAddrWidth, packVl53lxSetAddrWidth(width), {
|
|
150
|
+
okCompletes: true,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
throw Vl53lx.asProtocolError(err);
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
clearI2cErrors: async () => {
|
|
158
|
+
// A resetting die NACKs its own address for a moment; only the driver
|
|
159
|
+
// knows those NACKs were expected, so the host zeroes the counter once
|
|
160
|
+
// its init is through. A v2.00 bridge does not know the command.
|
|
161
|
+
try {
|
|
162
|
+
await this.request(Vl53lxCmd.ClearI2cErrors, new Uint8Array(0), { okCompletes: true });
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
if (err instanceof StatusError && err.status === Status.ErrInvalidCmd) {
|
|
166
|
+
throw new DepzError("the board's firmware predates APP_VL53L0_4_v0.24 (protocol v2.01) " +
|
|
167
|
+
"and cannot clear its I2C error counter — reflash it");
|
|
168
|
+
}
|
|
169
|
+
throw Vl53lx.asProtocolError(err);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
xshut: async (action) => {
|
|
173
|
+
try {
|
|
174
|
+
await this.request(Vl53lxCmd.Xshut, packXshut(action), {
|
|
175
|
+
okCompletes: true,
|
|
176
|
+
timeoutMs: 1000,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
throw Vl53lx.asProtocolError(err);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* A reset makes the die NACK for a moment (the VL53L0X soft reset does it);
|
|
186
|
+
* the driver waits those out, and they are no bus fault.
|
|
187
|
+
*/
|
|
188
|
+
async sensorInit(drv) {
|
|
189
|
+
await drv.sensorInit();
|
|
190
|
+
await this.bridge.clearI2cErrors();
|
|
191
|
+
}
|
|
192
|
+
/** StatusError / DepzTimeoutError (and a short register read) → ProtocolError. */
|
|
193
|
+
static asProtocolError(err, shortReadToo = false) {
|
|
194
|
+
if (err instanceof StatusError || err instanceof DepzTimeoutError) {
|
|
195
|
+
return new ProtocolError(err.message);
|
|
196
|
+
}
|
|
197
|
+
// chunkedRead reports a short reply as a plain DepzError.
|
|
198
|
+
if (shortReadToo && err instanceof DepzError && err.constructor === DepzError) {
|
|
199
|
+
return new ProtocolError(err.message);
|
|
200
|
+
}
|
|
201
|
+
return err;
|
|
202
|
+
}
|
|
203
|
+
constructor(transport, opts) {
|
|
204
|
+
super(transport, opts);
|
|
205
|
+
this.sleepImpl = opts?.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
206
|
+
this.platform = new BridgePlatform(this.bridge, (ms) => this.sleepImpl(ms));
|
|
207
|
+
}
|
|
208
|
+
get classProduct() {
|
|
209
|
+
return this.constructor.PRODUCT;
|
|
210
|
+
}
|
|
211
|
+
// ── identity ─────────────────────────────────────────────────────────────
|
|
212
|
+
/**
|
|
213
|
+
* The board's device name (bootloader metablock), e.g.
|
|
214
|
+
* `DEPZ ToF Sensor VL53L4CX USB v2.1 TOVJALN523`. Read once, then cached.
|
|
215
|
+
*/
|
|
216
|
+
async boardName() {
|
|
217
|
+
if (this.boardNameCache === null)
|
|
218
|
+
this.boardNameCache = await this.getDeviceName();
|
|
219
|
+
return this.boardNameCache;
|
|
220
|
+
}
|
|
221
|
+
/** The product the device name carries, or null on an unstamped board. */
|
|
222
|
+
async detected() {
|
|
223
|
+
return registry.productFromBoardName(await this.boardName());
|
|
224
|
+
}
|
|
225
|
+
/** The product init() bound (null before init). */
|
|
226
|
+
get product() {
|
|
227
|
+
return this.productName;
|
|
228
|
+
}
|
|
229
|
+
get driverKind() {
|
|
230
|
+
return this.driverKindName;
|
|
231
|
+
}
|
|
232
|
+
/** The ULD port in use — escape hatch for product-specific calls. */
|
|
233
|
+
get driver() {
|
|
234
|
+
if (this.driverInst === null)
|
|
235
|
+
throw new DepzError("call init() first");
|
|
236
|
+
return this.driverInst;
|
|
237
|
+
}
|
|
238
|
+
get initialized() {
|
|
239
|
+
return this.driverInst !== null;
|
|
240
|
+
}
|
|
241
|
+
/** The driver kinds a product has (default: this board's). */
|
|
242
|
+
async driverKinds(product) {
|
|
243
|
+
const name = product || this.classProduct || (await this.detected());
|
|
244
|
+
return name ? registry.driverKinds(name) : [];
|
|
245
|
+
}
|
|
246
|
+
// ── lifecycle ────────────────────────────────────────────────────────────
|
|
247
|
+
/**
|
|
248
|
+
* Bind the (product, driver kind) pair and initialise the sensor.
|
|
249
|
+
*
|
|
250
|
+
* `product` defaults to this class's product, else the board's device name;
|
|
251
|
+
* `driver` defaults to the product's first kind (`uld`, else `ulp`, else
|
|
252
|
+
* `histogram`). A pair the table has no row for throws
|
|
253
|
+
* `NotImplementedError` naming what the product has.
|
|
254
|
+
*/
|
|
255
|
+
async init(driver, opts = {}) {
|
|
256
|
+
this.requireNotRanging();
|
|
257
|
+
const name = opts.product || this.classProduct || (await this.detected());
|
|
258
|
+
if (!name) {
|
|
259
|
+
throw new DepzError(`board '${await this.boardName()}' carries no product number — pass product explicitly`);
|
|
260
|
+
}
|
|
261
|
+
const kind = driver || registry.driverKinds(name)[0];
|
|
262
|
+
if (kind === undefined) {
|
|
263
|
+
throw new registry.NotImplementedError(`${name} has no driver in this build`);
|
|
264
|
+
}
|
|
265
|
+
const [DriverCls, caveat] = registry.driverFor(name, kind);
|
|
266
|
+
// Sticky on the bridge and 2 after a reset: set before the first register
|
|
267
|
+
// access, model id included.
|
|
268
|
+
await this.bridge.setAddrWidth(DriverCls.ADDR_WIDTH);
|
|
269
|
+
const drv = new DriverCls(this.platform, name);
|
|
270
|
+
await this.sensorInit(drv);
|
|
271
|
+
this.driverInst = drv;
|
|
272
|
+
this.productName = name;
|
|
273
|
+
this.driverKindName = kind;
|
|
274
|
+
this.caveat = caveat;
|
|
275
|
+
}
|
|
276
|
+
/** Everything about what is connected (needs init()). */
|
|
277
|
+
async identifyProduct() {
|
|
278
|
+
const drv = this.driver;
|
|
279
|
+
const modelId = await drv.modelId();
|
|
280
|
+
const detected = await this.detected();
|
|
281
|
+
return {
|
|
282
|
+
board: await this.boardName(),
|
|
283
|
+
detected,
|
|
284
|
+
product: this.productName,
|
|
285
|
+
driver: this.driverKindName,
|
|
286
|
+
driverClass: drv.constructor.name,
|
|
287
|
+
kinds: registry.driverKinds(this.productName),
|
|
288
|
+
modelId,
|
|
289
|
+
modelIdOk: registry.modelIdOk(this.productName, modelId),
|
|
290
|
+
supports: new Set(drv.SUPPORTS),
|
|
291
|
+
modes: [...drv.MODES],
|
|
292
|
+
reachMm: registry.reachMm(detected || this.productName),
|
|
293
|
+
driverReachMm: await drv.reachMm(),
|
|
294
|
+
budgetMs: drv.BUDGET_MS,
|
|
295
|
+
budgetChoices: this.budgetChoices(),
|
|
296
|
+
histogram: drv.HISTOGRAM,
|
|
297
|
+
maxKhz: drv.MAX_KHZ,
|
|
298
|
+
caveat: this.caveat,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The lines a UI should show about the chosen pair: product named by hand,
|
|
303
|
+
* a borrowed driver, a pair that reaches less than the board is rated for,
|
|
304
|
+
* the driver's caveat.
|
|
305
|
+
*/
|
|
306
|
+
async notes() {
|
|
307
|
+
const drv = this.driver;
|
|
308
|
+
const detected = await this.detected();
|
|
309
|
+
const out = [];
|
|
310
|
+
if (detected === null) {
|
|
311
|
+
out.push(`${this.productName}: board name carries no product number, named by hand`);
|
|
312
|
+
}
|
|
313
|
+
else if (detected !== this.productName) {
|
|
314
|
+
out.push(`${this.productName}: borrowing this driver - the board says it is a ${detected}`);
|
|
315
|
+
}
|
|
316
|
+
const rated = registry.reachMm(detected || this.productName);
|
|
317
|
+
const reach = await drv.reachMm();
|
|
318
|
+
if (rated && reach && reach < rated) {
|
|
319
|
+
out.push(`${this.productName}/${this.driverKindName}: this pair reaches ${reach} mm, the board ` +
|
|
320
|
+
`is rated ${rated} mm - past ${reach} mm the phase is out of the valid window and ` +
|
|
321
|
+
"frames come back with status 4");
|
|
322
|
+
}
|
|
323
|
+
if (this.caveat)
|
|
324
|
+
out.push(`${this.productName}/${this.driverKindName}: ${this.caveat}`);
|
|
325
|
+
return out;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Whether this product/driver serves an optional capability group: mode,
|
|
329
|
+
* timing, offset, calib_offset, xtalk, calib_xtalk, thresholds,
|
|
330
|
+
* signal_thresh, sigma_thresh, roi, temp_update, refspad.
|
|
331
|
+
*/
|
|
332
|
+
supports(group) {
|
|
333
|
+
return this.driver.SUPPORTS.has(group);
|
|
334
|
+
}
|
|
335
|
+
/** Named ranging modes, first = what init leaves; [] if none. */
|
|
336
|
+
get modes() {
|
|
337
|
+
return [...this.driver.MODES];
|
|
338
|
+
}
|
|
339
|
+
// ── sensor power (XSHUT) and bridge diagnostics ─────────────────────────
|
|
340
|
+
/**
|
|
341
|
+
* Drive XSHUT: XSHUT_OFF / XSHUT_ON / XSHUT_RESET (1 ms pulse + 5 ms wait;
|
|
342
|
+
* the host confirms the boot). OFF and RESET stop the stream; the sensor
|
|
343
|
+
* then holds none of the configuration — init() again.
|
|
344
|
+
*/
|
|
345
|
+
async xshut(action) {
|
|
346
|
+
await this.request(Vl53lxCmd.Xshut, packXshut(action), { okCompletes: true, timeoutMs: 1000 });
|
|
347
|
+
this.rangingFlag = false;
|
|
348
|
+
this.driverInst = null;
|
|
349
|
+
}
|
|
350
|
+
/** RPT_VL53_INFO — the bridge's own counters; safe while streaming. */
|
|
351
|
+
bridgeInfo() {
|
|
352
|
+
return this.request(Vl53lxCmd.GetInfo, undefined, {
|
|
353
|
+
matcher: DepzDevice.expectReport(Vl53lxRpt.Info, unpackVl53lxInfo),
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
// ── configuration (init() first; not while ranging) ─────────────────────
|
|
357
|
+
/**
|
|
358
|
+
* Re-initialise the sensor and apply a ranging configuration. The re-init
|
|
359
|
+
* is deliberate (the only way to know what the configuration registers
|
|
360
|
+
* hold). `mode` goes on before the budget; `offsetMm` / `xtalkKcps`
|
|
361
|
+
* re-apply a stored calibration; `signalKcps` goes on last. An unsupported
|
|
362
|
+
* group is refused before the re-init.
|
|
363
|
+
*/
|
|
364
|
+
async configure(opts = {}) {
|
|
365
|
+
this.requireNotRanging();
|
|
366
|
+
const drv = this.driver;
|
|
367
|
+
const offset = opts.offsetMm != null ? this.need("offset") : null;
|
|
368
|
+
const xtalk = opts.xtalkKcps != null ? this.need("xtalk") : null;
|
|
369
|
+
const signal = opts.signalKcps != null ? this.need("signal_thresh") : null;
|
|
370
|
+
await this.sensorInit(drv);
|
|
371
|
+
if (opts.mode != null)
|
|
372
|
+
await drv.setMode(opts.mode);
|
|
373
|
+
await drv.setRangeTiming(opts.budgetMs ?? 50, opts.interMs ?? 0);
|
|
374
|
+
if (offset)
|
|
375
|
+
await offset.setOffset(opts.offsetMm);
|
|
376
|
+
if (xtalk)
|
|
377
|
+
await xtalk.setXtalk(opts.xtalkKcps);
|
|
378
|
+
if (signal)
|
|
379
|
+
await signal.setSignalThreshold(opts.signalKcps);
|
|
380
|
+
}
|
|
381
|
+
/** → [timingBudgetMs, interMeasurementMs]; 0 for the period = continuous. */
|
|
382
|
+
getRangeTiming() {
|
|
383
|
+
return this.driver.getRangeTiming();
|
|
384
|
+
}
|
|
385
|
+
/** The ranging mode in use, or null on a product without modes. */
|
|
386
|
+
async getMode() {
|
|
387
|
+
return this.supports("mode") ? this.driver.getMode() : null;
|
|
388
|
+
}
|
|
389
|
+
/** The only budgets accepted right now (ascending), or [] for any in range. */
|
|
390
|
+
budgetChoices() {
|
|
391
|
+
return [...this.driver.budgetChoices()];
|
|
392
|
+
}
|
|
393
|
+
/** The nearest budget this product will actually accept. */
|
|
394
|
+
snapBudget(budgetMs) {
|
|
395
|
+
const choices = this.budgetChoices();
|
|
396
|
+
if (choices.length > 0) {
|
|
397
|
+
let best = choices[0];
|
|
398
|
+
for (const c of choices)
|
|
399
|
+
if (Math.abs(c - budgetMs) < Math.abs(best - budgetMs))
|
|
400
|
+
best = c;
|
|
401
|
+
return best;
|
|
402
|
+
}
|
|
403
|
+
const [low, high] = this.driver.BUDGET_MS;
|
|
404
|
+
return Math.max(low, Math.min(high, budgetMs));
|
|
405
|
+
}
|
|
406
|
+
// Capability-gated passthroughs. Each throws DepzError on a product/driver
|
|
407
|
+
// that does not serve the group (see supports()).
|
|
408
|
+
getOffsetMm() {
|
|
409
|
+
return this.need("offset").getOffset();
|
|
410
|
+
}
|
|
411
|
+
async setOffsetMm(offsetMm) {
|
|
412
|
+
this.requireNotRanging();
|
|
413
|
+
await this.need("offset").setOffset(offsetMm);
|
|
414
|
+
}
|
|
415
|
+
getXtalkKcps() {
|
|
416
|
+
return this.need("xtalk").getXtalk();
|
|
417
|
+
}
|
|
418
|
+
async setXtalkKcps(xtalkKcps) {
|
|
419
|
+
this.requireNotRanging();
|
|
420
|
+
await this.need("xtalk").setXtalk(xtalkKcps);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Offset calibration against a flat target at `targetDistMm`; returns the
|
|
424
|
+
* offset now programmed. Store it on the host (sensor RAM, lost on reset).
|
|
425
|
+
*/
|
|
426
|
+
async calibrateOffset(targetDistMm, nbSamples) {
|
|
427
|
+
this.requireNotRanging();
|
|
428
|
+
return this.need("calib_offset").calibrateOffset(targetDistMm, nbSamples);
|
|
429
|
+
}
|
|
430
|
+
/** Crosstalk calibration; returns the xtalk now programmed (kcps). */
|
|
431
|
+
async calibrateXtalk(targetDistMm, nbSamples) {
|
|
432
|
+
this.requireNotRanging();
|
|
433
|
+
return this.need("calib_xtalk").calibrateXtalk(targetDistMm, nbSamples);
|
|
434
|
+
}
|
|
435
|
+
/** → [distanceLowMm, distanceHighMm, window]. */
|
|
436
|
+
getDetectionThresholds() {
|
|
437
|
+
return this.need("thresholds").getDetectionThresholds();
|
|
438
|
+
}
|
|
439
|
+
/** Arm the distance-window interrupt; stays armed until the next init/configure. */
|
|
440
|
+
async setDetectionThresholds(distanceLowMm, distanceHighMm, window) {
|
|
441
|
+
this.requireNotRanging();
|
|
442
|
+
await this.need("thresholds").setDetectionThresholds(distanceLowMm, distanceHighMm, window);
|
|
443
|
+
}
|
|
444
|
+
getSignalThresholdKcps() {
|
|
445
|
+
return this.need("signal_thresh").getSignalThreshold();
|
|
446
|
+
}
|
|
447
|
+
async setSignalThresholdKcps(signalKcps) {
|
|
448
|
+
this.requireNotRanging();
|
|
449
|
+
await this.need("signal_thresh").setSignalThreshold(signalKcps);
|
|
450
|
+
}
|
|
451
|
+
getSigmaThresholdMm() {
|
|
452
|
+
return this.need("sigma_thresh").getSigmaThreshold();
|
|
453
|
+
}
|
|
454
|
+
async setSigmaThresholdMm(sigmaMm) {
|
|
455
|
+
this.requireNotRanging();
|
|
456
|
+
await this.need("sigma_thresh").setSigmaThreshold(sigmaMm);
|
|
457
|
+
}
|
|
458
|
+
/** → [x, y] SPAD window size. */
|
|
459
|
+
getRoi() {
|
|
460
|
+
return this.need("roi").getRoi();
|
|
461
|
+
}
|
|
462
|
+
async setRoi(x, y) {
|
|
463
|
+
this.requireNotRanging();
|
|
464
|
+
await this.need("roi").setRoi(x, y);
|
|
465
|
+
}
|
|
466
|
+
getRoiCenter() {
|
|
467
|
+
return this.need("roi").getRoiCenter();
|
|
468
|
+
}
|
|
469
|
+
async setRoiCenter(centerSpad) {
|
|
470
|
+
this.requireNotRanging();
|
|
471
|
+
await this.need("roi").setRoiCenter(centerSpad);
|
|
472
|
+
}
|
|
473
|
+
/** Re-run VHV after an ambient change over 8 °C. */
|
|
474
|
+
async startTemperatureUpdate() {
|
|
475
|
+
this.requireNotRanging();
|
|
476
|
+
await this.need("temp_update").startTemperatureUpdate();
|
|
477
|
+
}
|
|
478
|
+
/** VL53L0X: re-measure the reference SPADs → [count, isAperture]. */
|
|
479
|
+
async performRefSpadManagement() {
|
|
480
|
+
this.requireNotRanging();
|
|
481
|
+
return this.need("refspad").performRefSpadManagement();
|
|
482
|
+
}
|
|
483
|
+
// ── ranging ──────────────────────────────────────────────────────────────
|
|
484
|
+
/**
|
|
485
|
+
* Start the sensor's ranging loop and arm the MCU stream: one
|
|
486
|
+
* RPT_VL53_STREAM per INT edge, followed on the MCU by the driver's
|
|
487
|
+
* interrupt-release writes.
|
|
488
|
+
*/
|
|
489
|
+
async startRanging() {
|
|
490
|
+
this.requireNotRanging();
|
|
491
|
+
const drv = this.driver;
|
|
492
|
+
await drv.startRanging();
|
|
493
|
+
const [addr, length] = drv.streamBlock();
|
|
494
|
+
await this.request(Vl53lxCmd.StartStream, packVl53lxStartStream(addr, length, drv.CLEAR_STEPS), { okCompletes: true });
|
|
495
|
+
this.rangingFlag = true;
|
|
496
|
+
}
|
|
497
|
+
async stopRanging() {
|
|
498
|
+
if (!this.rangingFlag)
|
|
499
|
+
return;
|
|
500
|
+
// Clear host state and stop the sensor even if the STOP_STREAM ack fails.
|
|
501
|
+
try {
|
|
502
|
+
await this.request(Vl53lxCmd.StopStream, undefined, { okCompletes: true });
|
|
503
|
+
}
|
|
504
|
+
finally {
|
|
505
|
+
this.rangingFlag = false;
|
|
506
|
+
await this.driver.stopRanging();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
get ranging() {
|
|
510
|
+
return this.rangingFlag;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Single poll-mode measurement: start ranging, wait for data-ready, read,
|
|
514
|
+
* release the interrupt, stop. Rejects while the stream runs.
|
|
515
|
+
*/
|
|
516
|
+
async measureOnce(timeoutMs = 1000) {
|
|
517
|
+
this.requireNotRanging();
|
|
518
|
+
const drv = this.driver;
|
|
519
|
+
await drv.startRanging();
|
|
520
|
+
let m;
|
|
521
|
+
let bins = null;
|
|
522
|
+
try {
|
|
523
|
+
await drv.waitDataReady(timeoutMs / 1000);
|
|
524
|
+
if (drv.HISTOGRAM) {
|
|
525
|
+
const [addr, length] = drv.streamBlock();
|
|
526
|
+
const h = drv;
|
|
527
|
+
bins = await h.binData(await this.platform.rdMulti(addr, length));
|
|
528
|
+
m = h.toMeasurement(bins);
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
m = await drv.readMeasurement();
|
|
532
|
+
}
|
|
533
|
+
await drv.clearInterrupt();
|
|
534
|
+
}
|
|
535
|
+
finally {
|
|
536
|
+
await drv.stopRanging();
|
|
537
|
+
}
|
|
538
|
+
return toVl53lxMeasurement(this.lastRegTimestampUs, m, bins);
|
|
539
|
+
}
|
|
540
|
+
/** Subscribe to streamed measurements. Returns an unsubscribe function. */
|
|
541
|
+
onMeasurement(cb) {
|
|
542
|
+
this.measureCbs.push(cb);
|
|
543
|
+
return () => {
|
|
544
|
+
this.measureCbs = this.measureCbs.filter((c) => c !== cb);
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
/** Async iterator over measurements — bounded, drop-oldest (contract 07 §3). */
|
|
548
|
+
measurements(maxsize = 64) {
|
|
549
|
+
const queue = new StreamQueue(maxsize, () => {
|
|
550
|
+
this.measureQueues = this.measureQueues.filter((q) => q !== queue);
|
|
551
|
+
deregister();
|
|
552
|
+
});
|
|
553
|
+
this.measureQueues.push(queue);
|
|
554
|
+
const deregister = this.registerStream(queue);
|
|
555
|
+
return queue;
|
|
556
|
+
}
|
|
557
|
+
/** Wait for the next streamed measurement. */
|
|
558
|
+
async getMeasurement(timeoutMs = 2000) {
|
|
559
|
+
const queue = new StreamQueue(1);
|
|
560
|
+
this.measureQueues.push(queue);
|
|
561
|
+
const deregister = this.registerStream(queue);
|
|
562
|
+
let timer;
|
|
563
|
+
try {
|
|
564
|
+
const result = await Promise.race([
|
|
565
|
+
queue.next(),
|
|
566
|
+
new Promise((_, reject) => {
|
|
567
|
+
timer = setTimeout(() => reject(new DepzTimeoutError(Vl53lxRpt.Stream, timeoutMs)), timeoutMs);
|
|
568
|
+
}),
|
|
569
|
+
]);
|
|
570
|
+
if (result.done === true)
|
|
571
|
+
throw new DepzError("device closed");
|
|
572
|
+
return result.value;
|
|
573
|
+
}
|
|
574
|
+
finally {
|
|
575
|
+
if (timer !== undefined)
|
|
576
|
+
clearTimeout(timer);
|
|
577
|
+
this.measureQueues = this.measureQueues.filter((q) => q !== queue);
|
|
578
|
+
deregister();
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/** Stream reports dropped because the driver failed to decode them. */
|
|
582
|
+
get streamParseErrors() {
|
|
583
|
+
return this.streamParseErrorCount;
|
|
584
|
+
}
|
|
585
|
+
/** Drop counters of all live measurement queues (diagnostics). */
|
|
586
|
+
get streamDroppedCounts() {
|
|
587
|
+
return this.measureQueues.map((q) => q.droppedCount);
|
|
588
|
+
}
|
|
589
|
+
// ── internal ─────────────────────────────────────────────────────────────
|
|
590
|
+
need(group) {
|
|
591
|
+
const drv = this.driver;
|
|
592
|
+
if (!drv.SUPPORTS.has(group)) {
|
|
593
|
+
throw new DepzError(`${this.productName}/${this.driverKindName} does not support '${group}'` +
|
|
594
|
+
(this.caveat ? ` (${this.caveat})` : ""));
|
|
595
|
+
}
|
|
596
|
+
return drv;
|
|
597
|
+
}
|
|
598
|
+
requireNotRanging() {
|
|
599
|
+
if (this.rangingFlag)
|
|
600
|
+
throw new DepzError("stopRanging() first — the stream owns the bus");
|
|
601
|
+
}
|
|
602
|
+
emit(out) {
|
|
603
|
+
for (const cb of [...this.measureCbs])
|
|
604
|
+
cb(out);
|
|
605
|
+
for (const q of [...this.measureQueues])
|
|
606
|
+
q.push(out);
|
|
607
|
+
}
|
|
608
|
+
handleReport(pkt) {
|
|
609
|
+
if (pkt.cmd !== Vl53lxRpt.Stream || pkt.payload.length < 12)
|
|
610
|
+
return false;
|
|
611
|
+
const drv = this.driverInst;
|
|
612
|
+
if (drv === null)
|
|
613
|
+
return true;
|
|
614
|
+
const sample = unpackStream(pkt.payload);
|
|
615
|
+
// Decoded exactly once per sample: the histogram driver steps its own
|
|
616
|
+
// frame-pair state on every frame it sees.
|
|
617
|
+
try {
|
|
618
|
+
if (!drv.HISTOGRAM) {
|
|
619
|
+
this.emit(toVl53lxMeasurement(sample.timestampUs, drv.decode(sample.data)));
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
const h = drv;
|
|
623
|
+
const bins = h.binData(sample.data);
|
|
624
|
+
if (!isThenable(bins)) {
|
|
625
|
+
this.emit(toVl53lxMeasurement(sample.timestampUs, h.toMeasurement(bins), bins));
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
// An async binData: keep frames in order through one chain.
|
|
629
|
+
this.decodeChain = this.decodeChain.then(async () => {
|
|
630
|
+
try {
|
|
631
|
+
const b = await bins;
|
|
632
|
+
this.emit(toVl53lxMeasurement(sample.timestampUs, h.toMeasurement(b), b));
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
this.streamParseErrorCount += 1;
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
// A bad sample must not kill the read pump.
|
|
641
|
+
this.streamParseErrorCount += 1;
|
|
642
|
+
}
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* VL53L0X (2 m, 1-byte register addresses, 400 kHz): ULD API 1.0.4 with
|
|
648
|
+
* ranging profiles, offset and crosstalk calibration, ref-SPAD management.
|
|
649
|
+
*/
|
|
650
|
+
export class Vl53l0x extends Vl53lx {
|
|
651
|
+
static PRODUCT = "VL53L0X";
|
|
652
|
+
}
|
|
653
|
+
/** VL53L1CX (4 m): VL53L1X ULD (short / long) or the histogram driver. */
|
|
654
|
+
export class Vl53l1cx extends Vl53lx {
|
|
655
|
+
static PRODUCT = "VL53L1CX";
|
|
656
|
+
}
|
|
657
|
+
/** VL53L1CB (8 m, cover-glass module): same die and drivers as VL53L1CX. */
|
|
658
|
+
export class Vl53l1cb extends Vl53lx {
|
|
659
|
+
static PRODUCT = "VL53L1CB";
|
|
660
|
+
}
|
|
661
|
+
/** VL53L3CX (3 m): ST's ULP driver (single target) or the histogram driver. */
|
|
662
|
+
export class Vl53l3cx extends Vl53lx {
|
|
663
|
+
static PRODUCT = "VL53L3CX";
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* VL53L4CX (6 m): the histogram driver only — to run it light, borrow a
|
|
667
|
+
* sibling's with `init(undefined, { product: "VL53L4CD" })`.
|
|
668
|
+
*/
|
|
669
|
+
export class Vl53l4cx extends Vl53lx {
|
|
670
|
+
static PRODUCT = "VL53L4CX";
|
|
671
|
+
}
|
|
672
|
+
/** Class per product (VL53L4CD on this firmware uses the generic class). */
|
|
673
|
+
export const VL53LX_CLASS_BY_PRODUCT = {
|
|
674
|
+
VL53L0X: Vl53l0x,
|
|
675
|
+
VL53L1CX: Vl53l1cx,
|
|
676
|
+
VL53L1CB: Vl53l1cb,
|
|
677
|
+
VL53L3CX: Vl53l3cx,
|
|
678
|
+
VL53L4CX: Vl53l4cx,
|
|
679
|
+
};
|
|
680
|
+
/**
|
|
681
|
+
* Pick the 1D-family class (contract 12 §1): the production PID model, then
|
|
682
|
+
* the product the device name carries, then the generic class.
|
|
683
|
+
*/
|
|
684
|
+
export function resolveVl53lxClass(usbModel, deviceName) {
|
|
685
|
+
let product = (usbModel ?? "").toUpperCase() || null;
|
|
686
|
+
if (product === null || !registry.PRODUCTS.includes(product)) {
|
|
687
|
+
product = registry.productFromBoardName(deviceName ?? "");
|
|
688
|
+
}
|
|
689
|
+
return VL53LX_CLASS_BY_PRODUCT[product ?? ""] ?? Vl53lx;
|
|
690
|
+
}
|
|
691
|
+
export const VL53LX_PRODUCTS = registry.PRODUCTS;
|
|
692
|
+
export const VL53LX_DRIVER_KINDS = registry.DRIVER_KINDS;
|
|
693
|
+
export { ProtocolError, Vl53Error };
|
|
694
|
+
//# sourceMappingURL=vl53lx.js.map
|