depz-sensor-viewer 0.1.0__tar.gz

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 (45) hide show
  1. depz_sensor_viewer-0.1.0/LICENSE +24 -0
  2. depz_sensor_viewer-0.1.0/PKG-INFO +126 -0
  3. depz_sensor_viewer-0.1.0/README.md +97 -0
  4. depz_sensor_viewer-0.1.0/depz_sensor_viewer/__init__.py +20 -0
  5. depz_sensor_viewer-0.1.0/depz_sensor_viewer/__main__.py +85 -0
  6. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/_shell.html +0 -0
  7. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/_shell-OjB6t2Lf.js +1 -0
  8. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/_shell.device-Dvx5Zdes.js +1 -0
  9. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/_shell.sr04-CBRbeLBo.js +1 -0
  10. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/_shell.vl53l8-BZzrVhll.js +1 -0
  11. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/bno086-BdGSxQhT.js +1 -0
  12. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/ch-C1KNK-D_.js +1 -0
  13. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/cx-CjIH97gt.js +1 -0
  14. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/decode-Df9gWAmG.js +1 -0
  15. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/drawer-tp8Ve4XX.js +7 -0
  16. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/hard-drive-download-CiLio_Qa.js +1 -0
  17. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/index-24Jof1S1.js +23 -0
  18. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/index-BWsQo9z2.js +1 -0
  19. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/index-CPWyjtxf.css +1 -0
  20. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/index-D25gIFiM.js +1 -0
  21. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/no-sensors-dlWAvVTM.js +1 -0
  22. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/player-BWmOhyhC.js +1 -0
  23. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/player-y738b7ua.js +1 -0
  24. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/sdk-CKmeJlcd.js +5 -0
  25. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/select-CpZwi1z4.js +41 -0
  26. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/sr04-CR_LdUR2.js +1 -0
  27. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/styles-DJf_tZnd.css +1 -0
  28. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/toggle-group-B78YQPsC.js +1 -0
  29. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/vl53l8-CSnMy9IO.js +7 -0
  30. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/vl53l8-heatmap-CK6xdPbq.js +1 -0
  31. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/wm-wjrQ-9yQ.js +1 -0
  32. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/assets/x-BhSOIcNA.js +1 -0
  33. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/index.html +0 -0
  34. depz_sensor_viewer-0.1.0/depz_sensor_viewer/_static/samples/dataset_dual_sr04.depzdata +11 -0
  35. depz_sensor_viewer-0.1.0/depz_sensor_viewer/launcher.py +33 -0
  36. depz_sensor_viewer-0.1.0/depz_sensor_viewer/permissions.py +176 -0
  37. depz_sensor_viewer-0.1.0/depz_sensor_viewer/server.py +304 -0
  38. depz_sensor_viewer-0.1.0/depz_sensor_viewer.egg-info/PKG-INFO +126 -0
  39. depz_sensor_viewer-0.1.0/depz_sensor_viewer.egg-info/SOURCES.txt +43 -0
  40. depz_sensor_viewer-0.1.0/depz_sensor_viewer.egg-info/dependency_links.txt +1 -0
  41. depz_sensor_viewer-0.1.0/depz_sensor_viewer.egg-info/entry_points.txt +2 -0
  42. depz_sensor_viewer-0.1.0/depz_sensor_viewer.egg-info/requires.txt +3 -0
  43. depz_sensor_viewer-0.1.0/depz_sensor_viewer.egg-info/top_level.txt +1 -0
  44. depz_sensor_viewer-0.1.0/pyproject.toml +46 -0
  45. depz_sensor_viewer-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DEPZ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ The bundled/derived VL53L8 advanced-DCI codecs are (c) STMicroelectronics,
24
+ licensed under BSD-3-Clause.
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: depz-sensor-viewer
3
+ Version: 0.1.0
4
+ Summary: Local standalone launcher for the DEPZ sensor web viewer — bypasses browser WebSerial by talking to devices over pyserial.
5
+ Author: DEPZ
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/depz-ai/depz-sensor-sdk-and-viewer
8
+ Project-URL: Repository, https://github.com/depz-ai/depz-sensor-sdk-and-viewer
9
+ Keywords: depz,sensor,viewer,webserial,pyserial,vl53l8,bno086,hc-sr04
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
21
+ Classifier: Intended Audience :: Developers
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: depz-sensor-sdk
26
+ Requires-Dist: aiohttp>=3.9
27
+ Requires-Dist: pyserial>=3.5
28
+ Dynamic: license-file
29
+
30
+ # depz-sensor-viewer
31
+
32
+ A local, standalone launcher for the DEPZ sensor web viewer. It runs a tiny
33
+ localhost web server that serves the viewer SPA **and** talks to your DEPZ
34
+ sensors over [`pyserial`](https://pyserial.readthedocs.io/) — so the UI never
35
+ touches the browser **WebSerial** API.
36
+
37
+ ## Why
38
+
39
+ The hosted viewer uses the browser's WebSerial API, which means:
40
+
41
+ - a **port-picker prompt** every time you connect,
42
+ - **Chrome-only** support, and
43
+ - failures under some enterprise / managed-Chrome policies that disable
44
+ WebSerial entirely.
45
+
46
+ This launcher sidesteps all of that. The Python process opens the serial port
47
+ locally with `pyserial` and pipes raw bytes to the SPA over a WebSocket. No
48
+ prompt, no WebSerial, works in any browser pointed at `localhost`.
49
+
50
+ ## Install & run
51
+
52
+ ```bash
53
+ pipx install depz-sensor-viewer
54
+ depz-sensor-viewer
55
+ ```
56
+
57
+ This starts the server on `http://127.0.0.1:8765` (or a random free port if
58
+ 8765 is taken) and opens your browser. Options:
59
+
60
+ ```
61
+ depz-sensor-viewer --port 9000 # pick a port (0 = random free)
62
+ depz-sensor-viewer --host 127.0.0.1 # bind address (localhost by default)
63
+ depz-sensor-viewer --no-browser # just start the server
64
+ ```
65
+
66
+ Press **Ctrl-C** to stop.
67
+
68
+ ## Linux: serial permissions
69
+
70
+ On Linux, opening `/dev/ttyACM*` requires membership in the `dialout` group.
71
+ If devices don't open, add yourself and re-login:
72
+
73
+ ```bash
74
+ sudo usermod -aG dialout $USER
75
+ # then log out and back in (or: newgrp dialout)
76
+ ```
77
+
78
+ The viewer diagnoses this for you at `GET /api/permissions` and shows the fix in
79
+ the UI. `ModemManager` can also briefly grab a freshly-plugged CDC device; retry
80
+ after a second, or `sudo systemctl mask ModemManager` if it persists.
81
+
82
+ ## HTTP / WebSocket contract
83
+
84
+ The bundled SPA detects standalone mode and drives devices through this fixed
85
+ interface (served by `depz_sensor_viewer.server`):
86
+
87
+ | Endpoint | Response |
88
+ | --- | --- |
89
+ | `GET /api/health` | `{"standalone": true, "version": "<pkg>"}` |
90
+ | `GET /api/devices` | `{"devices": [{path, usb_vid, usb_pid, serial, sensor_type, usb_model_hint}]}` |
91
+ | `GET /api/permissions` | `{ok, os, issues, fix: {command, explanation}}` |
92
+ | `WS /ws/serial?path=<port>&baud=<n>` | raw byte pipe (see below) |
93
+
94
+ `/api/devices` enumerates only ports whose USB identity is a known DEPZ device
95
+ (via the SDK's USB table); it does **not** open the ports. `baud` defaults to
96
+ `115200` and is nominal for the CDC-ACM devices.
97
+
98
+ **`/ws/serial` framing:**
99
+
100
+ - client → server **binary** frame → `serial.write(bytes)`
101
+ - server → client **binary** frame ← bytes read from the serial port
102
+ - **text** frames carry JSON control/status:
103
+ - server: `{"opened": true, "path": ..., "baud": ...}` right after open
104
+ - server: `{"error": "...", "code": "...", "fix": {...}}` on failure
105
+ (permission errors include the per-OS `fix`)
106
+ - client: `{"cmd": "set_baud", "baud": <int>}` (optional)
107
+
108
+ The port is closed when the WebSocket closes.
109
+
110
+ ## Building the bundled SPA
111
+
112
+ The wheel ships the built SPA under `depz_sensor_viewer/_static/`. To (re)build
113
+ it from the repo's TypeScript viewer:
114
+
115
+ ```bash
116
+ python packages/depz-sensor-viewer/scripts/bundle_spa.py
117
+ ```
118
+
119
+ This runs `bun run build` at the repo root and copies `dist/client/**` into
120
+ `_static/`. Pass `--skip-build` to copy an existing `dist/client/` without
121
+ rebuilding. Until you run it, the package ships a placeholder `index.html` that
122
+ points here — the API endpoints above are live regardless.
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,97 @@
1
+ # depz-sensor-viewer
2
+
3
+ A local, standalone launcher for the DEPZ sensor web viewer. It runs a tiny
4
+ localhost web server that serves the viewer SPA **and** talks to your DEPZ
5
+ sensors over [`pyserial`](https://pyserial.readthedocs.io/) — so the UI never
6
+ touches the browser **WebSerial** API.
7
+
8
+ ## Why
9
+
10
+ The hosted viewer uses the browser's WebSerial API, which means:
11
+
12
+ - a **port-picker prompt** every time you connect,
13
+ - **Chrome-only** support, and
14
+ - failures under some enterprise / managed-Chrome policies that disable
15
+ WebSerial entirely.
16
+
17
+ This launcher sidesteps all of that. The Python process opens the serial port
18
+ locally with `pyserial` and pipes raw bytes to the SPA over a WebSocket. No
19
+ prompt, no WebSerial, works in any browser pointed at `localhost`.
20
+
21
+ ## Install & run
22
+
23
+ ```bash
24
+ pipx install depz-sensor-viewer
25
+ depz-sensor-viewer
26
+ ```
27
+
28
+ This starts the server on `http://127.0.0.1:8765` (or a random free port if
29
+ 8765 is taken) and opens your browser. Options:
30
+
31
+ ```
32
+ depz-sensor-viewer --port 9000 # pick a port (0 = random free)
33
+ depz-sensor-viewer --host 127.0.0.1 # bind address (localhost by default)
34
+ depz-sensor-viewer --no-browser # just start the server
35
+ ```
36
+
37
+ Press **Ctrl-C** to stop.
38
+
39
+ ## Linux: serial permissions
40
+
41
+ On Linux, opening `/dev/ttyACM*` requires membership in the `dialout` group.
42
+ If devices don't open, add yourself and re-login:
43
+
44
+ ```bash
45
+ sudo usermod -aG dialout $USER
46
+ # then log out and back in (or: newgrp dialout)
47
+ ```
48
+
49
+ The viewer diagnoses this for you at `GET /api/permissions` and shows the fix in
50
+ the UI. `ModemManager` can also briefly grab a freshly-plugged CDC device; retry
51
+ after a second, or `sudo systemctl mask ModemManager` if it persists.
52
+
53
+ ## HTTP / WebSocket contract
54
+
55
+ The bundled SPA detects standalone mode and drives devices through this fixed
56
+ interface (served by `depz_sensor_viewer.server`):
57
+
58
+ | Endpoint | Response |
59
+ | --- | --- |
60
+ | `GET /api/health` | `{"standalone": true, "version": "<pkg>"}` |
61
+ | `GET /api/devices` | `{"devices": [{path, usb_vid, usb_pid, serial, sensor_type, usb_model_hint}]}` |
62
+ | `GET /api/permissions` | `{ok, os, issues, fix: {command, explanation}}` |
63
+ | `WS /ws/serial?path=<port>&baud=<n>` | raw byte pipe (see below) |
64
+
65
+ `/api/devices` enumerates only ports whose USB identity is a known DEPZ device
66
+ (via the SDK's USB table); it does **not** open the ports. `baud` defaults to
67
+ `115200` and is nominal for the CDC-ACM devices.
68
+
69
+ **`/ws/serial` framing:**
70
+
71
+ - client → server **binary** frame → `serial.write(bytes)`
72
+ - server → client **binary** frame ← bytes read from the serial port
73
+ - **text** frames carry JSON control/status:
74
+ - server: `{"opened": true, "path": ..., "baud": ...}` right after open
75
+ - server: `{"error": "...", "code": "...", "fix": {...}}` on failure
76
+ (permission errors include the per-OS `fix`)
77
+ - client: `{"cmd": "set_baud", "baud": <int>}` (optional)
78
+
79
+ The port is closed when the WebSocket closes.
80
+
81
+ ## Building the bundled SPA
82
+
83
+ The wheel ships the built SPA under `depz_sensor_viewer/_static/`. To (re)build
84
+ it from the repo's TypeScript viewer:
85
+
86
+ ```bash
87
+ python packages/depz-sensor-viewer/scripts/bundle_spa.py
88
+ ```
89
+
90
+ This runs `bun run build` at the repo root and copies `dist/client/**` into
91
+ `_static/`. Pass `--skip-build` to copy an existing `dist/client/` without
92
+ rebuilding. Until you run it, the package ships a placeholder `index.html` that
93
+ points here — the API endpoints above are live regardless.
94
+
95
+ ## License
96
+
97
+ MIT
@@ -0,0 +1,20 @@
1
+ """depz-sensor-viewer — local standalone launcher for the DEPZ sensor web viewer.
2
+
3
+ Bypasses the browser's WebSerial API: instead of the SPA opening serial ports in
4
+ Chrome (with its port-picker prompt and enterprise-policy pitfalls), this package
5
+ runs a tiny local aiohttp server that opens the ports with *pyserial* and exposes
6
+ them to the bundled SPA over a WebSocket byte pipe.
7
+
8
+ The server contract the SPA relies on (see :mod:`depz_sensor_viewer.server`):
9
+
10
+ - ``GET /api/health`` → ``{"standalone": true, "version": ...}``
11
+ - ``GET /api/devices`` → ``{"devices": [{path, usb_vid, usb_pid, ...}]}``
12
+ - ``GET /api/permissions`` → ``{ok, os, issues, fix}`` per-OS serial diagnostics
13
+ - ``WS /ws/serial?path&baud`` → raw byte pipe (binary frames), JSON control text frames
14
+ """
15
+
16
+ from .server import build_app
17
+
18
+ __version__ = "0.1.0"
19
+
20
+ __all__ = ["build_app", "__version__"]
@@ -0,0 +1,85 @@
1
+ """depz-sensor-viewer entry point.
2
+
3
+ Starts a localhost aiohttp server that serves the bundled DEPZ sensor SPA and
4
+ bridges serial ports over WebSocket (see :mod:`depz_sensor_viewer.server`), then
5
+ opens the browser at the served URL. Only host/port/browser/logging are
6
+ CLI-controlled — the device is chosen in the SPA.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import logging
13
+ import sys
14
+
15
+ from aiohttp import web
16
+
17
+ from .launcher import find_free_port, open_browser
18
+ from .server import build_app
19
+
20
+ _LOGGER = logging.getLogger("depz_sensor_viewer")
21
+
22
+ DEFAULT_PORT = 8765
23
+
24
+
25
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
26
+ p = argparse.ArgumentParser(
27
+ prog="depz-sensor-viewer",
28
+ description="Local standalone launcher for the DEPZ sensor web viewer "
29
+ "(bypasses browser WebSerial — talks to devices via pyserial).",
30
+ )
31
+ p.add_argument(
32
+ "--port", type=int, default=DEFAULT_PORT,
33
+ help=f"HTTP port (default: {DEFAULT_PORT}; falls back to a random free "
34
+ "port if it's taken).",
35
+ )
36
+ p.add_argument("--host", default="127.0.0.1", help="Bind address (default: 127.0.0.1).")
37
+ p.add_argument("--no-browser", action="store_true", help="Don't auto-open the browser.")
38
+ p.add_argument("--logging-level", default="INFO")
39
+ return p.parse_args(argv)
40
+
41
+
42
+ def _resolve_port(host: str, want: int) -> int:
43
+ """Use the requested port if free; otherwise fall back to a random one."""
44
+ if want == 0:
45
+ return find_free_port(host)
46
+ with socket_ctx() as s:
47
+ try:
48
+ s.bind((host, want))
49
+ return want
50
+ except OSError:
51
+ _LOGGER.warning("port %d is busy; picking a free port instead", want)
52
+ return find_free_port(host)
53
+
54
+
55
+ def socket_ctx():
56
+ import socket
57
+
58
+ return socket.socket(socket.AF_INET, socket.SOCK_STREAM)
59
+
60
+
61
+ def main(argv: list[str] | None = None) -> int:
62
+ args = parse_args(argv)
63
+ logging.basicConfig(
64
+ level=args.logging_level.upper(),
65
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
66
+ )
67
+
68
+ port = _resolve_port(args.host, args.port)
69
+ url = f"http://{args.host}:{port}"
70
+
71
+ app = build_app()
72
+
73
+ print(f"[depz-sensor-viewer] serving at {url}", file=sys.stderr)
74
+ if not args.no_browser:
75
+ open_browser(url)
76
+
77
+ try:
78
+ web.run_app(app, host=args.host, port=port, print=None, handle_signals=True)
79
+ except KeyboardInterrupt: # pragma: no cover - graceful Ctrl-C
80
+ pass
81
+ return 0
82
+
83
+
84
+ if __name__ == "__main__":
85
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ import{a1 as n,a2 as o,r as a,j as s,a3 as c}from"./index-24Jof1S1.js";function u(){const{phase:t}=n(),e=o();return a.useEffect(()=>{t!=="connected"&&e({to:"/"})},[t,e]),t!=="connected"?null:s.jsx(c,{})}export{u as component};
@@ -0,0 +1 @@
1
+ import{c as Z,r as a,u as j,j as s,P as N,h as O,e as ve,b as C,A as y,i as Se,f as ee,a1 as te,t as E,B as k,N as ge,k as we}from"./index-24Jof1S1.js";import{B as xe,T as ye,a as J,V as X}from"./index-BWsQo9z2.js";import{a as Ce,k as Pe}from"./select-CpZwi1z4.js";import{H as Ee}from"./hard-drive-download-CiLio_Qa.js";const Re=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],je=Z("rotate-ccw",Re);const Te=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],Ae=Z("trash-2",Te);function Ne(e,r){return a.useReducer((t,l)=>r[t][l]??t,e)}var F="ScrollArea",[re]=ve(F),[_e,v]=re(F),oe=a.forwardRef((e,r)=>{const{__scopeScrollArea:t,type:l="hover",dir:o,scrollHideDelay:n=600,...c}=e,[i,d]=a.useState(null),[h,u]=a.useState(null),[m,f]=a.useState(null),[p,g]=a.useState(null),[T,B]=a.useState(null),[x,_]=a.useState(0),[U,L]=a.useState(0),[D,A]=a.useState(!1),[z,M]=a.useState(!1),b=j(r,P=>d(P)),S=Ce(o);return s.jsx(_e,{scope:t,type:l,dir:S,scrollHideDelay:n,scrollArea:i,viewport:h,onViewportChange:u,content:m,onContentChange:f,scrollbarX:p,onScrollbarXChange:g,scrollbarXEnabled:D,onScrollbarXEnabledChange:A,scrollbarY:T,onScrollbarYChange:B,scrollbarYEnabled:z,onScrollbarYEnabledChange:M,onCornerWidthChange:_,onCornerHeightChange:L,children:s.jsx(N.div,{dir:S,...c,ref:b,style:{position:"relative","--radix-scroll-area-corner-width":x+"px","--radix-scroll-area-corner-height":U+"px",...e.style}})})});oe.displayName=F;var ne="ScrollAreaViewport",le=a.forwardRef((e,r)=>{const{__scopeScrollArea:t,children:l,nonce:o,...n}=e,c=v(ne,t),i=a.useRef(null),d=j(r,i,c.onViewportChange);return s.jsxs(s.Fragment,{children:[s.jsx("style",{dangerouslySetInnerHTML:{__html:"[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}"},nonce:o}),s.jsx(N.div,{"data-radix-scroll-area-viewport":"",...n,ref:d,style:{overflowX:c.scrollbarXEnabled?"scroll":"hidden",overflowY:c.scrollbarYEnabled?"scroll":"hidden",...e.style},children:s.jsx("div",{ref:c.onContentChange,style:{minWidth:"100%",display:"table"},children:l})})]})});le.displayName=ne;var w="ScrollAreaScrollbar",$=a.forwardRef((e,r)=>{const{forceMount:t,...l}=e,o=v(w,e.__scopeScrollArea),{onScrollbarXEnabledChange:n,onScrollbarYEnabledChange:c}=o,i=e.orientation==="horizontal";return a.useEffect(()=>(i?n(!0):c(!0),()=>{i?n(!1):c(!1)}),[i,n,c]),o.type==="hover"?s.jsx(Le,{...l,ref:r,forceMount:t}):o.type==="scroll"?s.jsx(De,{...l,ref:r,forceMount:t}):o.type==="auto"?s.jsx(se,{...l,ref:r,forceMount:t}):o.type==="always"?s.jsx(q,{...l,ref:r}):null});$.displayName=w;var Le=a.forwardRef((e,r)=>{const{forceMount:t,...l}=e,o=v(w,e.__scopeScrollArea),[n,c]=a.useState(!1);return a.useEffect(()=>{const i=o.scrollArea;let d=0;if(i){const h=()=>{window.clearTimeout(d),c(!0)},u=()=>{d=window.setTimeout(()=>c(!1),o.scrollHideDelay)};return i.addEventListener("pointerenter",h),i.addEventListener("pointerleave",u),()=>{window.clearTimeout(d),i.removeEventListener("pointerenter",h),i.removeEventListener("pointerleave",u)}}},[o.scrollArea,o.scrollHideDelay]),s.jsx(O,{present:t||n,children:s.jsx(se,{"data-state":n?"visible":"hidden",...l,ref:r})})}),De=a.forwardRef((e,r)=>{const{forceMount:t,...l}=e,o=v(w,e.__scopeScrollArea),n=e.orientation==="horizontal",c=V(()=>d("SCROLL_END"),100),[i,d]=Ne("hidden",{hidden:{SCROLL:"scrolling"},scrolling:{SCROLL_END:"idle",POINTER_ENTER:"interacting"},interacting:{SCROLL:"interacting",POINTER_LEAVE:"idle"},idle:{HIDE:"hidden",SCROLL:"scrolling",POINTER_ENTER:"interacting"}});return a.useEffect(()=>{if(i==="idle"){const h=window.setTimeout(()=>d("HIDE"),o.scrollHideDelay);return()=>window.clearTimeout(h)}},[i,o.scrollHideDelay,d]),a.useEffect(()=>{const h=o.viewport,u=n?"scrollLeft":"scrollTop";if(h){let m=h[u];const f=()=>{const p=h[u];m!==p&&(d("SCROLL"),c()),m=p};return h.addEventListener("scroll",f),()=>h.removeEventListener("scroll",f)}},[o.viewport,n,d,c]),s.jsx(O,{present:t||i!=="hidden",children:s.jsx(q,{"data-state":i==="hidden"?"hidden":"visible",...l,ref:r,onPointerEnter:C(e.onPointerEnter,()=>d("POINTER_ENTER")),onPointerLeave:C(e.onPointerLeave,()=>d("POINTER_LEAVE"))})})}),se=a.forwardRef((e,r)=>{const t=v(w,e.__scopeScrollArea),{forceMount:l,...o}=e,[n,c]=a.useState(!1),i=e.orientation==="horizontal",d=V(()=>{if(t.viewport){const h=t.viewport.offsetWidth<t.viewport.scrollWidth,u=t.viewport.offsetHeight<t.viewport.scrollHeight;c(i?h:u)}},10);return R(t.viewport,d),R(t.content,d),s.jsx(O,{present:l||n,children:s.jsx(q,{"data-state":n?"visible":"hidden",...o,ref:r})})}),q=a.forwardRef((e,r)=>{const{orientation:t="vertical",...l}=e,o=v(w,e.__scopeScrollArea),n=a.useRef(null),c=a.useRef(0),[i,d]=a.useState({content:0,viewport:0,scrollbar:{size:0,paddingStart:0,paddingEnd:0}}),h=ue(i.viewport,i.content),u={...l,sizes:i,onSizesChange:d,hasThumb:h>0&&h<1,onThumbChange:f=>n.current=f,onThumbPointerUp:()=>c.current=0,onThumbPointerDown:f=>c.current=f};function m(f,p){return Oe(f,c.current,i,p)}return t==="horizontal"?s.jsx(ze,{...u,ref:r,onThumbPositionChange:()=>{if(o.viewport&&n.current){const f=o.viewport.scrollLeft,p=K(f,i,o.dir);n.current.style.transform=`translate3d(${p}px, 0, 0)`}},onWheelScroll:f=>{o.viewport&&(o.viewport.scrollLeft=f)},onDragScroll:f=>{o.viewport&&(o.viewport.scrollLeft=m(f,o.dir))}}):t==="vertical"?s.jsx(Me,{...u,ref:r,onThumbPositionChange:()=>{if(o.viewport&&n.current){const f=o.viewport.scrollTop,p=K(f,i);n.current.style.transform=`translate3d(0, ${p}px, 0)`}},onWheelScroll:f=>{o.viewport&&(o.viewport.scrollTop=f)},onDragScroll:f=>{o.viewport&&(o.viewport.scrollTop=m(f))}}):null}),ze=a.forwardRef((e,r)=>{const{sizes:t,onSizesChange:l,...o}=e,n=v(w,e.__scopeScrollArea),[c,i]=a.useState(),d=a.useRef(null),h=j(r,d,n.onScrollbarXChange);return a.useEffect(()=>{d.current&&i(getComputedStyle(d.current))},[d]),s.jsx(ce,{"data-orientation":"horizontal",...o,ref:h,sizes:t,style:{bottom:0,left:n.dir==="rtl"?"var(--radix-scroll-area-corner-width)":0,right:n.dir==="ltr"?"var(--radix-scroll-area-corner-width)":0,"--radix-scroll-area-thumb-width":I(t)+"px",...e.style},onThumbPointerDown:u=>e.onThumbPointerDown(u.x),onDragScroll:u=>e.onDragScroll(u.x),onWheelScroll:(u,m)=>{if(n.viewport){const f=n.viewport.scrollLeft+u.deltaX;e.onWheelScroll(f),fe(f,m)&&u.preventDefault()}},onResize:()=>{d.current&&n.viewport&&c&&l({content:n.viewport.scrollWidth,viewport:n.viewport.offsetWidth,scrollbar:{size:d.current.clientWidth,paddingStart:W(c.paddingLeft),paddingEnd:W(c.paddingRight)}})}})}),Me=a.forwardRef((e,r)=>{const{sizes:t,onSizesChange:l,...o}=e,n=v(w,e.__scopeScrollArea),[c,i]=a.useState(),d=a.useRef(null),h=j(r,d,n.onScrollbarYChange);return a.useEffect(()=>{d.current&&i(getComputedStyle(d.current))},[d]),s.jsx(ce,{"data-orientation":"vertical",...o,ref:h,sizes:t,style:{top:0,right:n.dir==="ltr"?0:void 0,left:n.dir==="rtl"?0:void 0,bottom:"var(--radix-scroll-area-corner-height)","--radix-scroll-area-thumb-height":I(t)+"px",...e.style},onThumbPointerDown:u=>e.onThumbPointerDown(u.y),onDragScroll:u=>e.onDragScroll(u.y),onWheelScroll:(u,m)=>{if(n.viewport){const f=n.viewport.scrollTop+u.deltaY;e.onWheelScroll(f),fe(f,m)&&u.preventDefault()}},onResize:()=>{d.current&&n.viewport&&c&&l({content:n.viewport.scrollHeight,viewport:n.viewport.offsetHeight,scrollbar:{size:d.current.clientHeight,paddingStart:W(c.paddingTop),paddingEnd:W(c.paddingBottom)}})}})}),[ke,ae]=re(w),ce=a.forwardRef((e,r)=>{const{__scopeScrollArea:t,sizes:l,hasThumb:o,onThumbChange:n,onThumbPointerUp:c,onThumbPointerDown:i,onThumbPositionChange:d,onDragScroll:h,onWheelScroll:u,onResize:m,...f}=e,p=v(w,t),[g,T]=a.useState(null),B=j(r,b=>T(b)),x=a.useRef(null),_=a.useRef(""),U=p.viewport,L=l.content-l.viewport,D=y(u),A=y(d),z=V(m,10);function M(b){if(x.current){const S=b.clientX-x.current.left,P=b.clientY-x.current.top;h({x:S,y:P})}}return a.useEffect(()=>{const b=S=>{const P=S.target;g?.contains(P)&&D(S,L)};return document.addEventListener("wheel",b,{passive:!1}),()=>document.removeEventListener("wheel",b,{passive:!1})},[U,g,L,D]),a.useEffect(A,[l,A]),R(g,z),R(p.content,z),s.jsx(ke,{scope:t,scrollbar:g,hasThumb:o,onThumbChange:y(n),onThumbPointerUp:y(c),onThumbPositionChange:A,onThumbPointerDown:y(i),children:s.jsx(N.div,{...f,ref:B,style:{position:"absolute",...f.style},onPointerDown:C(e.onPointerDown,b=>{b.button===0&&(b.target.setPointerCapture(b.pointerId),x.current=g.getBoundingClientRect(),_.current=document.body.style.webkitUserSelect,document.body.style.webkitUserSelect="none",p.viewport&&(p.viewport.style.scrollBehavior="auto"),M(b))}),onPointerMove:C(e.onPointerMove,M),onPointerUp:C(e.onPointerUp,b=>{const S=b.target;S.hasPointerCapture(b.pointerId)&&S.releasePointerCapture(b.pointerId),document.body.style.webkitUserSelect=_.current,p.viewport&&(p.viewport.style.scrollBehavior=""),x.current=null})})})}),H="ScrollAreaThumb",ie=a.forwardRef((e,r)=>{const{forceMount:t,...l}=e,o=ae(H,e.__scopeScrollArea);return s.jsx(O,{present:t||o.hasThumb,children:s.jsx(He,{ref:r,...l})})}),He=a.forwardRef((e,r)=>{const{__scopeScrollArea:t,style:l,...o}=e,n=v(H,t),c=ae(H,t),{onThumbPositionChange:i}=c,d=j(r,m=>c.onThumbChange(m)),h=a.useRef(void 0),u=V(()=>{h.current&&(h.current(),h.current=void 0)},100);return a.useEffect(()=>{const m=n.viewport;if(m){const f=()=>{if(u(),!h.current){const p=Ie(m,i);h.current=p,i()}};return i(),m.addEventListener("scroll",f),()=>m.removeEventListener("scroll",f)}},[n.viewport,u,i]),s.jsx(N.div,{"data-state":c.hasThumb?"visible":"hidden",...o,ref:d,style:{width:"var(--radix-scroll-area-thumb-width)",height:"var(--radix-scroll-area-thumb-height)",...l},onPointerDownCapture:C(e.onPointerDownCapture,m=>{const p=m.target.getBoundingClientRect(),g=m.clientX-p.left,T=m.clientY-p.top;c.onThumbPointerDown({x:g,y:T})}),onPointerUp:C(e.onPointerUp,c.onThumbPointerUp)})});ie.displayName=H;var G="ScrollAreaCorner",de=a.forwardRef((e,r)=>{const t=v(G,e.__scopeScrollArea),l=!!(t.scrollbarX&&t.scrollbarY);return t.type!=="scroll"&&l?s.jsx(We,{...e,ref:r}):null});de.displayName=G;var We=a.forwardRef((e,r)=>{const{__scopeScrollArea:t,...l}=e,o=v(G,t),[n,c]=a.useState(0),[i,d]=a.useState(0),h=!!(n&&i);return R(o.scrollbarX,()=>{const u=o.scrollbarX?.offsetHeight||0;o.onCornerHeightChange(u),d(u)}),R(o.scrollbarY,()=>{const u=o.scrollbarY?.offsetWidth||0;o.onCornerWidthChange(u),c(u)}),h?s.jsx(N.div,{...l,ref:r,style:{width:n,height:i,position:"absolute",right:o.dir==="ltr"?0:void 0,left:o.dir==="rtl"?0:void 0,bottom:0,...e.style}}):null});function W(e){return e?parseInt(e,10):0}function ue(e,r){const t=e/r;return isNaN(t)?0:t}function I(e){const r=ue(e.viewport,e.content),t=e.scrollbar.paddingStart+e.scrollbar.paddingEnd,l=(e.scrollbar.size-t)*r;return Math.max(l,18)}function Oe(e,r,t,l="ltr"){const o=I(t),n=o/2,c=r||n,i=o-c,d=t.scrollbar.paddingStart+c,h=t.scrollbar.size-t.scrollbar.paddingEnd-i,u=t.content-t.viewport,m=l==="ltr"?[0,u]:[u*-1,0];return he([d,h],m)(e)}function K(e,r,t="ltr"){const l=I(r),o=r.scrollbar.paddingStart+r.scrollbar.paddingEnd,n=r.scrollbar.size-o,c=r.content-r.viewport,i=n-l,d=t==="ltr"?[0,c]:[c*-1,0],h=Pe(e,d);return he([0,c],[0,i])(h)}function he(e,r){return t=>{if(e[0]===e[1]||r[0]===r[1])return r[0];const l=(r[1]-r[0])/(e[1]-e[0]);return r[0]+l*(t-e[0])}}function fe(e,r){return e>0&&e<r}var Ie=(e,r=()=>{})=>{let t={left:e.scrollLeft,top:e.scrollTop},l=0;return(function o(){const n={left:e.scrollLeft,top:e.scrollTop},c=t.left!==n.left,i=t.top!==n.top;(c||i)&&r(),t=n,l=window.requestAnimationFrame(o)})(),()=>window.cancelAnimationFrame(l)};function V(e,r){const t=y(e),l=a.useRef(0);return a.useEffect(()=>()=>window.clearTimeout(l.current),[]),a.useCallback(()=>{window.clearTimeout(l.current),l.current=window.setTimeout(t,r)},[t,r])}function R(e,r){const t=y(r);Se(()=>{let l=0;if(e){const o=new ResizeObserver(()=>{cancelAnimationFrame(l),l=window.requestAnimationFrame(t)});return o.observe(e),()=>{window.cancelAnimationFrame(l),o.unobserve(e)}}},[e,t])}var me=oe,Ve=le,Be=de;const pe=a.forwardRef(({className:e,children:r,...t},l)=>s.jsxs(me,{ref:l,className:ee("relative overflow-hidden",e),...t,children:[s.jsx(Ve,{className:"h-full w-full rounded-[inherit]",children:r}),s.jsx(be,{}),s.jsx(Be,{})]}));pe.displayName=me.displayName;const be=a.forwardRef(({className:e,orientation:r="vertical",...t},l)=>s.jsx($,{ref:l,orientation:r,className:ee("flex touch-none select-none transition-colors",r==="vertical"&&"h-full w-2.5 border-l border-l-transparent p-[1px]",r==="horizontal"&&"h-2.5 flex-col border-t border-t-transparent p-[1px]",e),...t,children:s.jsx(ie,{className:"relative flex-1 rounded-full bg-border"})}));be.displayName=$.displayName;const Q=300;function Ue(e){const{type:r,...t}=e;return Object.entries(t).map(([o,n])=>{const c=typeof n=="bigint"?n.toString():n instanceof Uint8Array?`[${n.length} bytes]`:typeof n=="object"&&n!==null?JSON.stringify(n,(i,d)=>typeof d=="bigint"?d.toString():d):String(n);return`${o}=${c}`}).join(" ")}function Y(e){return e instanceof Error?e.message:String(e)}function Xe(e){const[r,t]=a.useState([]),l=a.useRef(0);a.useEffect(()=>e?e.onEvent(c=>{const i=new Date,d=i.toTimeString().slice(0,8)+"."+String(i.getMilliseconds()).padStart(3,"0"),h={id:l.current++,at:d,type:c.type,detail:Ue(c)};t(u=>u.length>=Q?[...u.slice(u.length-Q+1),h]:[...u,h])}):void 0,[e]);const o=a.useCallback(()=>t([]),[]);return{log:r,clear:o}}function Ye(){const{identity:e,deviceName:r,serialNumber:t}=te();if(!e)return null;const l=[["Software",e.softwareName],["Version",e.version||"—"],["Mode",e.mode],["Sensor type",e.sensorType??"—"],["Device name",r||"—"],["Serial number",t||"—"]];return s.jsxs("div",{className:"space-y-2",children:[e.mode==="bootloader"&&s.jsx(xe,{variant:"destructive",children:"bootloader mode"}),l.map(([o,n])=>s.jsxs("div",{className:"flex justify-between gap-4 text-sm",children:[s.jsx("span",{className:"text-muted-foreground",children:o}),s.jsx("span",{className:"truncate text-right font-mono text-xs leading-5",children:n})]},o))]})}function Fe({device:e,danger:r=!0}){const t=a.useCallback(async()=>{try{const n=await e.readMcuTemperature();E.success(`MCU temperature: ${n.toFixed(1)} °C`)}catch(n){E.error(`Temperature read failed: ${Y(n)}`)}},[e]),l=a.useCallback(async()=>{try{await e.reset(),E.info("Reset command sent — the device will drop off and re-enumerate.")}catch(n){E.error(`Reset failed: ${Y(n)}`)}},[e]),o=a.useCallback(async()=>{try{await e.enterBootloaderMode(),E.info("Bootloader command sent — the device will re-enumerate in bootloader mode.")}catch(n){E.error(`Enter bootloader failed: ${Y(n)}`)}},[e]);return s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsxs(k,{variant:"outline",size:"sm",onClick:()=>{t()},children:[s.jsx(ye,{className:"size-4"}),"Read MCU temperature"]}),r&&s.jsxs(s.Fragment,{children:[s.jsxs(k,{variant:"outline",size:"sm",onClick:()=>{l()},children:[s.jsx(je,{className:"size-4"}),"Reset device"]}),s.jsxs(k,{variant:"outline",size:"sm",onClick:()=>{o()},children:[s.jsx(Ee,{className:"size-4"}),"Enter bootloader"]})]})]})}function $e({log:e,onClear:r,className:t="h-96"}){return s.jsxs("div",{children:[s.jsx("div",{className:"mb-2 flex items-center justify-end",children:s.jsxs(k,{variant:"ghost",size:"sm",onClick:r,children:[s.jsx(Ae,{className:"size-4"}),"Clear"]})}),s.jsx(pe,{className:`rounded-md border bg-muted/30 ${t}`,children:s.jsxs("div",{className:"p-3 font-mono text-xs leading-5",children:[e.length===0&&s.jsx("p",{className:"text-muted-foreground",children:"No events yet — unsolicited status, text, temperature and link-error events show up here."}),e.map(l=>s.jsxs("div",{className:"flex gap-2 whitespace-nowrap",children:[s.jsx("span",{className:"text-muted-foreground",children:l.at}),s.jsx("span",{className:l.type==="disconnected"||l.type==="linkCrcError"||l.type==="sequenceError"||l.type==="trash"?"text-destructive":"text-foreground",children:l.type}),s.jsx("span",{className:"text-muted-foreground",children:l.detail})]},l.id))]})})]})}function Ze(){const{variant:e}=ge(),r=we(),{device:t,identity:l}=te(),{log:o,clear:n}=Xe(t);if(!t||!l)return s.jsx(J,{page:"device",children:null});const c=s.jsx(X,{title:"Identity",description:l.mode==="bootloader"?"bootloader":void 0,children:s.jsx(Ye,{})}),i=s.jsx(X,{title:"Actions",description:r?"reset & bootloader are Pro tools":void 0,children:s.jsx(Fe,{device:t,danger:r})}),d=r?s.jsx(X,{pro:!0,title:"Event log",description:"Raw device events (dev.onEvent)",className:"min-w-0",children:s.jsx($e,{log:o,onClear:n,className:e===2?"h-[28rem]":"h-96"})}):null;return s.jsx(J,{page:"device",children:e===3?s.jsxs("div",{className:"space-y-10",children:[c,i,d]}):s.jsxs("div",{className:r?"grid gap-6 lg:grid-cols-[minmax(0,20rem)_1fr]":"grid max-w-xl gap-6",style:e===2?{gap:"0.5rem"}:void 0,children:[s.jsxs("div",{className:e===2?"grid gap-2":"space-y-6",children:[c,i]}),d]})})}export{Ze as component};
@@ -0,0 +1 @@
1
+ import{N as u,j as s,k as n,B as h}from"./index-24Jof1S1.js";import{c as p,d as a,e as l,f as o,g as c,h as x,a as d,i as f,u as S,s as N}from"./sr04-CR_LdUR2.js";import{D as v,a as w,S as D,b,c as y,d as g,e as B}from"./drawer-tp8Ve4XX.js";import{a as C,V as t,f as V,g as F}from"./index-BWsQo9z2.js";import"./toggle-group-B78YQPsC.js";import"./select-CpZwi1z4.js";function E(){const{variant:e}=u(),r=p();return s.jsx(C,{page:"sr04",children:r?e===2?s.jsx(T,{page:r}):e===3?s.jsx(k,{page:r}):s.jsx(P,{page:r}):s.jsx("p",{className:"text-sm text-muted-foreground",children:"The connected device is not an SR04 sensor."})})}function j({page:e}){const r=n(),m=S(e.ring,e.windowMs);return s.jsx(V,{children:N(m,r).map(i=>s.jsx(F,{label:i.label,value:i.value,sub:i.sub},i.label))})}function P({page:e}){const r=n();return s.jsxs("div",{className:"grid gap-6",children:[s.jsx(t,{title:"Distance",description:"Live strip chart · timeouts marked red in the bottom lane",actions:s.jsxs(s.Fragment,{children:[s.jsx(l,{page:e}),s.jsx(o,{page:e}),r&&s.jsx(c,{page:e}),r&&s.jsx(x,{page:e})]}),children:s.jsx(a,{page:e,className:"h-72 w-full"})}),s.jsx(j,{page:e}),s.jsx(t,{pro:!0,title:"Sensor settings",description:"Applied immediately; the loop picks them up on the fly.",children:s.jsx(d,{sr04:e.sr04})})]})}function T({page:e}){const r=n();return s.jsxs("div",{className:"grid gap-2",children:[s.jsx(t,{title:"SR04 // Range telemetry",flush:!0,actions:s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"v2-led mr-1","data-on":e.looping,title:e.looping?"loop running":"loop stopped"}),s.jsx(l,{page:e}),s.jsx(o,{page:e}),r&&s.jsx(c,{page:e}),r&&s.jsx(x,{page:e})]}),children:s.jsx(a,{page:e,className:"h-[22rem] w-full"})}),s.jsx(j,{page:e}),s.jsx(t,{pro:!0,title:"Acquisition parameters",description:"applied live",children:s.jsx(d,{sr04:e.sr04})})]})}function k({page:e}){const r=n();return s.jsxs(s.Fragment,{children:[s.jsx(f,{page:e,className:"text-center"}),s.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-3",children:[s.jsx(o,{page:e,size:"lg",className:"h-12 rounded-full px-8"}),s.jsx(l,{page:e}),r&&s.jsx(c,{page:e}),r&&s.jsx(x,{page:e}),r&&s.jsxs(v,{children:[s.jsx(w,{asChild:!0,children:s.jsxs(h,{variant:"outline",size:"sm",className:"rounded-full",children:[s.jsx(D,{className:"size-4"}),"Settings"]})}),s.jsx(b,{children:s.jsxs("div",{className:"mx-auto w-full max-w-2xl pb-8",children:[s.jsxs(y,{children:[s.jsx(g,{children:"Sensor settings"}),s.jsx(B,{children:"Applied immediately; the loop picks them up on the fly."})]}),s.jsx("div",{className:"px-4",children:s.jsx(d,{sr04:e.sr04})})]})})]})]}),s.jsx(t,{title:"",className:"mt-2",children:s.jsx(a,{page:e,className:"h-64 w-full"})}),s.jsx("div",{className:"flex justify-center",children:s.jsx(j,{page:e})})]})}export{E as component};
@@ -0,0 +1 @@
1
+ import{a1 as g,j as e,N as p,k as v,r as V,B as S}from"./index-24Jof1S1.js";import{V as c,H as w}from"./vl53l8-heatmap-CK6xdPbq.js";import{e as h,u as N,b,a as x,V as d,d as o,c as u}from"./vl53l8-CSnMy9IO.js";import{D as y,a as L,S as D,b as C,c as z,d as F,e as M}from"./drawer-tp8Ve4XX.js";import{S as T,b as B,d as H,e as A,f as P}from"./select-CpZwi1z4.js";import{a as E,V as n,f as G,g as R}from"./index-BWsQo9z2.js";import"./toggle-group-B78YQPsC.js";function Q(){const{identity:a,vl53l8:s,vl53l8SdkMissing:l}=g();let t;return s?t=e.jsx(k,{dev:s}):l?t=e.jsx(h,{}):a?.sensorType!=="vl53l8"?t=e.jsx("p",{className:"text-sm text-muted-foreground",children:"The connected device is not a VL53L8 sensor."}):t=e.jsx(h,{}),e.jsx(E,{page:"vl53l8",children:t})}function k({dev:a}){const{variant:s}=p(),l=v(),t=N(a),[f,i]=V.useState("distance"),r=l?f:"distance";return t.state.phase!=="ready"?e.jsx(n,{title:"VL53L8 initialization",description:"firmware upload over USB",children:e.jsx(b,{session:t,pro:l})}):s===2?e.jsx($,{session:t,pro:l,layer:r,setLayer:i}):s===3?e.jsx(I,{session:t,pro:l,layer:r,setLayer:i}):e.jsx(q,{session:t,pro:l,layer:r,setLayer:i})}function m({layer:a,setLayer:s}){return e.jsxs(T,{value:a,onValueChange:l=>s(l),children:[e.jsx(B,{className:"h-8 w-36 text-xs",children:e.jsx(H,{})}),e.jsx(A,{children:w.map(l=>e.jsx(P,{value:l.value,className:"text-xs",children:l.label},l.value))})]})}function j({session:a,pro:s}){const l=a.frame,t=a.state.config,i=[{label:"Grid",value:t.resolution===64?"8×8":"4×4",sub:`${t.frequencyHz} Hz target`},{label:"Frames",value:String(a.state.frameCount)},{label:"Silicon temp",value:l?`${l.siliconTempDegc.toFixed(0)} °C`:"—"}];return s&&i.push({label:"Mode",value:t.rangingMode===3?"Autonomous":"Continuous"},{label:"Integration",value:`${t.integrationMs} ms`},{label:"Sharpener",value:`${t.sharpenerPct} %`}),e.jsx(G,{children:i.map(r=>e.jsx(R,{label:r.label,value:r.value,sub:r.sub},r.label))})}function q({session:a,pro:s,layer:l,setLayer:t}){return e.jsxs("div",{className:"grid gap-6",children:[e.jsx(n,{title:"Zone heatmap",description:"Hover a cell for the full zone readout",actions:e.jsxs(e.Fragment,{children:[s&&e.jsx(m,{layer:l,setLayer:t}),e.jsx(x,{session:a}),e.jsx(d,{session:a}),s&&e.jsx(o,{session:a})]}),children:e.jsx(c,{session:a,layer:l,showGlyphs:s,className:"mx-auto aspect-square w-full max-w-xl"})}),e.jsx(j,{session:a,pro:s}),e.jsx(n,{title:"Ranging configuration",description:"Applied immediately",children:e.jsx(u,{session:a,pro:s})})]})}function $({session:a,pro:s,layer:l,setLayer:t}){return e.jsxs("div",{className:"grid gap-2 xl:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)]",children:[e.jsx(n,{title:"VL53L8 // zone matrix",flush:!0,className:"xl:row-span-2",actions:e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"v2-led mr-1","data-on":a.state.ranging}),s&&e.jsx(m,{layer:l,setLayer:t}),e.jsx(x,{session:a}),e.jsx(d,{session:a})]}),children:e.jsx(c,{session:a,layer:l,showGlyphs:s,className:"aspect-square w-full"})}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(j,{session:a,pro:s}),e.jsx(n,{title:"Ranging parameters",actions:s?e.jsx(o,{session:a}):void 0,children:e.jsx(u,{session:a,pro:s})})]})]})}function I({session:a,pro:s,layer:l,setLayer:t}){return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"text-center",children:e.jsxs("p",{className:"text-xs font-medium uppercase tracking-[0.2em] text-muted-foreground",children:["VL53L8 · ",a.state.config.resolution===64?"8×8":"4×4"," time-of-flight"]})}),e.jsx(c,{session:a,layer:l,showGlyphs:s,className:"mx-auto aspect-square w-full max-w-2xl"}),e.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-3",children:[e.jsx(d,{session:a,size:"lg",className:"h-12 rounded-full px-8"}),s&&e.jsx(m,{layer:l,setLayer:t}),e.jsx(x,{session:a}),s&&e.jsx(o,{session:a}),e.jsxs(y,{children:[e.jsx(L,{asChild:!0,children:e.jsxs(S,{variant:"outline",size:"sm",className:"rounded-full",children:[e.jsx(D,{className:"size-4"}),"Settings"]})}),e.jsx(C,{children:e.jsxs("div",{className:"mx-auto w-full max-w-2xl pb-8",children:[e.jsxs(z,{children:[e.jsx(F,{children:"Ranging configuration"}),e.jsx(M,{children:"Applied immediately."})]}),e.jsx("div",{className:"px-4",children:e.jsx(u,{session:a,pro:s})})]})})]})]}),e.jsx("div",{className:"flex justify-center",children:e.jsx(j,{session:a,pro:s})})]})}export{Q as component};
@@ -0,0 +1 @@
1
+ import{ar as U,aq as at,at as k,as as it,ax as ot}from"./index-24Jof1S1.js";var T=(t=>(t[t.SensorReset=50]="SensorReset",t[t.SensorWakeUp=51]="SensorWakeUp",t[t.SendShtpPacket=52]="SendShtpPacket",t))(T||{}),Q=(t=>(t[t.Data=145]="Data",t))(Q||{});const ee=2,ne=64,ct=200;function ut(t){const e=new DataView(t.buffer,t.byteOffset,t.byteLength);return{cmd:e.getUint8(0),timestampUs:e.getBigUint64(1,!0),shtp:t.subarray(9)}}const X=7119,I=1155,Z=22236,lt=60536,ft=65535,V={60536:{name:"sr04",sensorType:"sr04"},60736:{name:"vl53l8ch",sensorType:"vl53l8"},60737:{name:"vl53l0x",sensorType:null},60738:{name:"vl53l1cb",sensorType:null},60739:{name:"vl53l1cx",sensorType:null},60740:{name:"vl53l3cx",sensorType:null},60741:{name:"vl53l4cd",sensorType:null},60742:{name:"vl53l4cx",sensorType:null},60743:{name:"vl53l4ed",sensorType:null},60744:{name:"vl53l5cx",sensorType:null},60745:{name:"vl53l7cx",sensorType:null},60746:{name:"vl53l7ch",sensorType:null},60747:{name:"vl53l8cx",sensorType:"vl53l8"},60936:{name:"bno086",sensorType:"bno086"},60937:{name:"bno085",sensorType:null},60938:{name:"bno055",sensorType:null}};function re(t,e){return t==null||e==null?!1:t===I&&e===Z?!0:t!==X?!1:e in V?!0:e>=lt&&e<=ft}function se(t){return t==null?null:V[t]??null}function ae(t,e){return t==null||e==null?null:t===I&&e===Z?"dev":t===X?V[e]?.name??null:null}var b=(t=>(t[t.Accelerometer=1]="Accelerometer",t[t.Gyroscope=2]="Gyroscope",t[t.Magnetometer=3]="Magnetometer",t[t.LinearAcceleration=4]="LinearAcceleration",t[t.RotationVector=5]="RotationVector",t[t.Gravity=6]="Gravity",t[t.UncalibratedGyroscope=7]="UncalibratedGyroscope",t[t.GameRotationVector=8]="GameRotationVector",t[t.GeomagneticRotationVector=9]="GeomagneticRotationVector",t[t.Pressure=10]="Pressure",t[t.AmbientLight=11]="AmbientLight",t[t.Humidity=12]="Humidity",t[t.Proximity=13]="Proximity",t[t.Temperature=14]="Temperature",t[t.UncalibratedMagnetometer=15]="UncalibratedMagnetometer",t[t.TapDetector=16]="TapDetector",t[t.StepCounter=17]="StepCounter",t[t.SignificantMotion=18]="SignificantMotion",t[t.StabilityClassifier=19]="StabilityClassifier",t[t.RawAccelerometer=20]="RawAccelerometer",t[t.RawGyroscope=21]="RawGyroscope",t[t.RawMagnetometer=22]="RawMagnetometer",t[t.StepDetector=24]="StepDetector",t[t.ShakeDetector=25]="ShakeDetector",t[t.FlipDetector=26]="FlipDetector",t[t.PickupDetector=27]="PickupDetector",t[t.StabilityDetector=28]="StabilityDetector",t[t.PersonalActivityClassifier=30]="PersonalActivityClassifier",t[t.SleepDetector=31]="SleepDetector",t[t.TiltDetector=32]="TiltDetector",t[t.PocketDetector=33]="PocketDetector",t[t.CircleDetector=34]="CircleDetector",t[t.HeartRateMonitor=35]="HeartRateMonitor",t[t.ArvrStabilizedRv=40]="ArvrStabilizedRv",t[t.ArvrStabilizedGameRv=41]="ArvrStabilizedGameRv",t[t.GyroIntegratedRv=42]="GyroIntegratedRv",t))(b||{});const j=251,ht=250,gt={1:8,4:8,6:8,2:9,7:9,3:4,15:4,5:14,8:14,9:14,40:14,41:14,42:14,10:20,11:8,12:8,13:4,14:7,20:0,21:0,22:0},mt=12,P=10,yt={1:10,2:10,3:10,4:10,5:14,6:10,7:16,8:12,9:14,10:8,11:8,12:6,13:6,14:6,15:16,16:5,17:12,18:6,19:6,20:16,21:16,22:16,24:8,25:6,26:6,27:8,28:6,30:16,31:6,32:6,33:6,34:6,35:6,40:14,41:12,42:14},wt={0:"unknown",1:"on_table",2:"stationary",3:"stable",4:"motion"},pt={0:"unknown",1:"in_vehicle",2:"on_bicycle",3:"on_foot",4:"still",5:"tilting",6:"walking",7:"running",8:"on_stairs"};function h(t,e){return t/(1<<e)}function M(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}function Rt(t,e){const n=[],r=M(t);let s=e,o=0;const a=t.length;for(;o<a;){const i=t[o];if(i===j&&o+5<=a){const q=r.getInt32(o+1,!0);s=e-BigInt(q)*100n,o+=5;continue}if(i===ht&&o+5<=a){const q=r.getInt32(o+1,!0);s+=BigInt(q)*100n,o+=5;continue}const u=yt[i];if(u===void 0||o+u>a){n.push({type:"UnknownReport",sensorId:i,timestampUs:s,data:t.slice(o)});break}const c=t.subarray(o,o+u),l=c[1],f=c[2],m=c[3],d=f&3,g=(f>>2<<8|m)*100,D=s+BigInt(g);n.push(dt(i,c,D,l,d,g)),o+=u}return n}function dt(t,e,n,r,s,o){const a=M(e),i={sensorId:t,timestampUs:n,seq:r,accuracy:s,delayUs:o},u=gt[t]??0;switch(t){case 1:case 4:case 6:{const[c,l,f]=[a.getInt16(4,!0),a.getInt16(6,!0),a.getInt16(8,!0)];return{type:"Acceleration",...i,xRaw:c,yRaw:l,zRaw:f,x:h(c,u),y:h(l,u),z:h(f,u)}}case 2:{const[c,l,f]=[a.getInt16(4,!0),a.getInt16(6,!0),a.getInt16(8,!0)];return{type:"Gyroscope",...i,xRaw:c,yRaw:l,zRaw:f,x:h(c,u),y:h(l,u),z:h(f,u)}}case 3:{const[c,l,f]=[a.getInt16(4,!0),a.getInt16(6,!0),a.getInt16(8,!0)];return{type:"Magnetometer",...i,xRaw:c,yRaw:l,zRaw:f,x:h(c,u),y:h(l,u),z:h(f,u)}}case 7:case 15:{const c=a.getInt16(4,!0),l=a.getInt16(6,!0),f=a.getInt16(8,!0),m=a.getInt16(10,!0),d=a.getInt16(12,!0),g=a.getInt16(14,!0),D={...i,xRaw:c,yRaw:l,zRaw:f,biasXRaw:m,biasYRaw:d,biasZRaw:g,x:h(c,u),y:h(l,u),z:h(f,u),bias:[h(m,u),h(d,u),h(g,u)]};return t===7?{type:"UncalibratedGyroscope",...D}:{type:"UncalibratedMagnetometer",...D}}case 5:case 9:case 40:case 8:case 41:{const c=a.getInt16(4,!0),l=a.getInt16(6,!0),f=a.getInt16(8,!0),m=a.getInt16(10,!0),g=t!==8&&t!==41?a.getInt16(12,!0):null;return{type:"RotationVector",...i,iRaw:c,jRaw:l,kRaw:f,realRaw:m,accuracyRaw:g,i:h(c,14),j:h(l,14),k:h(f,14),real:h(m,14),accuracyRad:g===null?null:h(g,mt)}}case 10:case 11:{const c=a.getUint32(4,!0);return{type:"ScalarReport",...i,valueRaw:c,value:h(c,u)}}case 12:case 13:{const c=a.getUint16(4,!0);return{type:"ScalarReport",...i,valueRaw:c,value:h(c,u)}}case 14:{const c=a.getInt16(4,!0);return{type:"ScalarReport",...i,valueRaw:c,value:h(c,u)}}case 16:{const c=e[4];return{type:"TapDetector",...i,flags:c,doubleTap:(c&64)!==0}}case 17:return{type:"StepCounter",...i,latencyUs:a.getUint32(4,!0),steps:a.getUint16(8,!0)};case 24:return{type:"StepDetector",...i,latencyUs:a.getUint32(4,!0)};case 18:return{type:"SignificantMotion",...i,motion:a.getUint16(4,!0)};case 19:{const c=e[4];return{type:"StabilityClassifier",...i,classification:c,name:wt[c]??String(c)}}case 25:return{type:"ShakeDetector",...i,flags:a.getUint16(4,!0)};case 30:{const c=e[5];return{type:"PersonalActivityClassifier",...i,pageNumber:e[4]&127,endOfSequence:(e[4]&128)!==0,mostLikelyState:c,confidences:Array.from(e.subarray(6,16)),mostLikelyName:pt[c]??String(c)}}case 20:case 22:return{type:"RawSensor",...i,xRaw:a.getInt16(4,!0),yRaw:a.getInt16(6,!0),zRaw:a.getInt16(8,!0),sensorTimestampUs:a.getUint32(12,!0),temperatureRaw:0};case 21:return{type:"RawSensor",...i,xRaw:a.getInt16(4,!0),yRaw:a.getInt16(6,!0),zRaw:a.getInt16(8,!0),sensorTimestampUs:a.getUint32(12,!0),temperatureRaw:a.getInt16(10,!0)};default:return{type:"GenericEvent",...i,valueRaw:a.getUint16(4,!0)}}}function vt(t,e){let n=e,r=t;if(t.length>=1&&t[0]===j){if(t.length<21)return null;const m=M(t),d=m.getInt32(1,!0),g=m.getUint16(5,!0);n=e-BigInt(d)*100n+BigInt(g)*100n,r=t.subarray(7)}if(r.length<14)return null;const s=M(r),o=s.getInt16(0,!0),a=s.getInt16(2,!0),i=s.getInt16(4,!0),u=s.getInt16(6,!0),c=s.getInt16(8,!0),l=s.getInt16(10,!0),f=s.getInt16(12,!0);return{type:"GyroIntegratedRV",sensorId:42,timestampUs:n,iRaw:o,jRaw:a,kRaw:i,realRaw:u,vxRaw:c,vyRaw:l,vzRaw:f,i:h(o,14),j:h(a,14),k:h(i,14),real:h(u,14),angularVelocity:[h(c,P),h(l,P),h(f,P)]}}class R extends U{}var A=(t=>(t[t.CommandResponse=241]="CommandResponse",t[t.CommandRequest=242]="CommandRequest",t[t.FrsReadResponse=243]="FrsReadResponse",t[t.FrsReadRequest=244]="FrsReadRequest",t[t.FrsWriteResponse=245]="FrsWriteResponse",t[t.FrsWriteData=246]="FrsWriteData",t[t.FrsWriteRequest=247]="FrsWriteRequest",t[t.ProductIdResponse=248]="ProductIdResponse",t[t.ProductIdRequest=249]="ProductIdRequest",t[t.GetFeatureResponse=252]="GetFeatureResponse",t[t.SetFeatureCommand=253]="SetFeatureCommand",t[t.GetFeatureRequest=254]="GetFeatureRequest",t))(A||{}),w=(t=>(t[t.Errors=1]="Errors",t[t.Counter=2]="Counter",t[t.Tare=3]="Tare",t[t.Initialize=4]="Initialize",t[t.SaveDcd=6]="SaveDcd",t[t.MeCalibrate=7]="MeCalibrate",t[t.PeriodicDcdConfig=9]="PeriodicDcdConfig",t[t.GetOscillatorType=10]="GetOscillatorType",t[t.ClearDcdAndReset=11]="ClearDcdAndReset",t))(w||{}),bt=(t=>(t[t.Internal=0]="Internal",t[t.ExtCrystal=1]="ExtCrystal",t[t.ExtClock=2]="ExtClock",t))(bt||{}),Y=(t=>(t[t.MotionEngine=1]="MotionEngine",t[t.MotionHub=2]="MotionHub",t[t.SensorHub=3]="SensorHub",t[t.Chip=4]="Chip",t[t.NoMoreErrors=255]="NoMoreErrors",t))(Y||{});const Ut=0,At=1;function Dt(t){return Uint8Array.of(Ut,t&255)}function Et(t){return Uint8Array.of(At,t&255)}function Tt(t=0){return Uint8Array.of(t&255)}function Ct(t){const e=t.r;return{severity:e[0],seq:e[1],source:e[2],error:e[3],module:e[4],code:e[5]}}var K=(t=>(t[t.RotationVector=0]="RotationVector",t[t.GameRotationVector=1]="GameRotationVector",t[t.GeomagneticRotationVector=2]="GeomagneticRotationVector",t[t.GyroIntegratedRv=3]="GyroIntegratedRv",t[t.ArvrStabilizedRv=4]="ArvrStabilizedRv",t[t.ArvrStabilizedGameRv=5]="ArvrStabilizedGameRv",t))(K||{}),F=(t=>(t[t.X=1]="X",t[t.Y=2]="Y",t[t.Z=4]="Z",t[t.All=7]="All",t))(F||{});function C(t){return t.toString(16).toUpperCase().padStart(2,"0")}function J(t){return t.toString(16).toUpperCase().padStart(4,"0")}function x(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}function O(t,e,n=0,r=0,s=0,o=0){const a=new Uint8Array(17),i=new DataView(a.buffer);return i.setUint8(0,253),i.setUint8(1,t),i.setUint8(2,s&255),i.setUint16(3,r&65535,!0),i.setUint32(5,e>>>0,!0),i.setUint32(9,n>>>0,!0),i.setUint32(13,o>>>0,!0),a}function Mt(t){return Uint8Array.of(254,t)}function N(t){const e=x(t),n=e.getUint8(0);if(n!==252)throw new R(`not a get-feature response: 0x${C(n)}`);return{sensorId:e.getUint8(1),flags:e.getUint8(2),sensitivity:e.getUint16(3,!0),intervalUs:e.getUint32(5,!0),batchUs:e.getUint32(9,!0),cfgWord:e.getUint32(13,!0)}}function xt(){return Uint8Array.of(249,0)}function qt(t){const e=x(t),n=e.getUint8(0);if(n!==248)throw new R(`not a product-id response: 0x${C(n)}`);const r=e.getUint8(2),s=e.getUint8(3),o=e.getUint16(12,!0);return{resetCause:e.getUint8(1),swVersionMajor:r,swVersionMinor:s,swPartNumber:e.getUint32(4,!0),swBuildNumber:e.getUint32(8,!0),swVersionPatch:o,version:`${r}.${s}.${o}`}}function z(t,e,n=new Uint8Array(0)){if(n.length>9)throw new Error("command request carries at most 9 parameter bytes");const r=new Uint8Array(12);return r[0]=242,r[1]=t&255,r[2]=e,r.set(n,3),r}function L(t){if(t[0]!==241)throw new R(`not a command response: 0x${C(t[0])}`);const e=Array.from(t.subarray(5,16));return{seq:t[1],command:t[2],commandSeq:t[3],responseSeq:t[4],r:e,status:e[0]}}function kt(t=7,e=0){return Uint8Array.of(0,t,e)}function Pt(){return Uint8Array.of(1)}function _t(t,e,n,r){const s=[t,e,n,r].map(i=>Math.round(i*16384));for(const i of s)if(i<-32768||i>32767)throw new Error("quaternion component out of Q14 int16 range");const o=new Uint8Array(9),a=new DataView(o.buffer);return a.setUint8(0,2),s.forEach((i,u)=>a.setInt16(1+u*2,i,!0)),o}function S(t,e,n,r=!1,s=0){return Uint8Array.of(Number(t),Number(e),Number(n),s,Number(r))}const Gt=1;function Vt(t){return Uint8Array.of(t?0:1)}var Ot=(t=>(t[t.StaticCalibrationAgm=31097]="StaticCalibrationAgm",t[t.NominalCalibration=19789]="NominalCalibration",t[t.DynamicCalibration=7967]="DynamicCalibration",t[t.MePowerMgmt=54242]="MePowerMgmt",t[t.SystemOrientation=11582]="SystemOrientation",t[t.AccelOrientation=11585]="AccelOrientation",t[t.GyroscopeOrientation=11590]="GyroscopeOrientation",t[t.MagnetometerOrientation=11596]="MagnetometerOrientation",t[t.ArvrStabilizationRv=15917]="ArvrStabilizationRv",t[t.ArvrStabilizationGrv=15918]="ArvrStabilizationGrv",t[t.SigMotionDetectConfig=49780]="SigMotionDetectConfig",t[t.ShakeDetectConfig=32125]="ShakeDetectConfig",t[t.StabilityDetectorConfig=60805]="StabilityDetectorConfig",t[t.ActivityTrackerConfig=60808]="ActivityTrackerConfig",t))(Ot||{});const Nt={20:58113,1:58114,4:58115,6:58116,21:58117,2:58118,7:58119,22:58120,3:58121,15:58122,5:58123,8:58124,9:58125,16:58131,24:58132,17:58133,18:58134,19:58135,25:58136,30:58140,40:58146,41:58147,42:58148};var tt=(t=>(t[t.NoError=0]="NoError",t[t.UnrecognizedFrsType=1]="UnrecognizedFrsType",t[t.Busy=2]="Busy",t[t.ReadCompleted=3]="ReadCompleted",t[t.OffsetOutOfRange=4]="OffsetOutOfRange",t[t.RecordEmpty=5]="RecordEmpty",t[t.BlockCompleted=6]="BlockCompleted",t[t.BlockAndReadCompleted=7]="BlockAndReadCompleted",t[t.DeviceError=8]="DeviceError",t))(tt||{}),et=(t=>(t[t.WordsReceived=0]="WordsReceived",t[t.UnrecognizedFrsType=1]="UnrecognizedFrsType",t[t.Busy=2]="Busy",t[t.WriteCompleted=3]="WriteCompleted",t[t.WriteModeReady=4]="WriteModeReady",t[t.WriteFailed=5]="WriteFailed",t[t.NotInWriteMode=6]="NotInWriteMode",t[t.InvalidLength=7]="InvalidLength",t[t.RecordValid=8]="RecordValid",t[t.RecordInvalid=9]="RecordInvalid",t))(et||{});function zt(t,e=0,n=0){const r=new Uint8Array(8),s=new DataView(r.buffer);return s.setUint8(0,244),s.setUint8(1,0),s.setUint16(2,e,!0),s.setUint16(4,t,!0),s.setUint16(6,n,!0),r}function Lt(t){const e=x(t),n=e.getUint8(0);if(n!==243)throw new R(`not an FRS read response: 0x${C(n)}`);const r=e.getUint8(1);return{status:r&15,dataLength:r>>4,offsetWords:e.getUint16(2,!0),data0:e.getUint32(4,!0),data1:e.getUint32(8,!0),frsType:e.getUint16(12,!0)}}function St(t,e){const n=new Uint8Array(6),r=new DataView(n.buffer);return r.setUint8(0,247),r.setUint8(1,0),r.setUint16(2,e,!0),r.setUint16(4,t,!0),n}function $t(t,e){if(e.length<1||e.length>2)throw new Error("FRS write data carries 1 or 2 words");const n=new Uint8Array(12),r=new DataView(n.buffer);return r.setUint8(0,246),r.setUint8(1,0),r.setUint16(2,t,!0),r.setUint32(4,e[0]>>>0,!0),r.setUint32(8,(e[1]??0)>>>0,!0),n}function Bt(t){const e=x(t),n=e.getUint8(0);if(n!==245)throw new R(`not an FRS write response: 0x${C(n)}`);return{status:e.getUint8(1),offsetWords:e.getUint16(2,!0)}}const Wt=new Set([1,2,4,5,8]);class Ht{frsType;words=[];done=!1;constructor(e){this.frsType=e}request(){return zt(this.frsType)}feed(e){if(e.frsType!==this.frsType)return this.done;if(Wt.has(e.status))throw new R(`FRS read 0x${J(this.frsType)} failed: ${tt[e.status]??e.status}`);for(const n of[e.data0,e.data1].slice(0,e.dataLength))this.words.push(n);return(e.status===3||e.status===7)&&(this.done=!0),this.done}}const Qt=new Set([1,2,5,6,7,9]);class Xt{frsType;words;offset=0;done=!1;constructor(e,n){this.frsType=e,this.words=n}request(){return St(this.frsType,this.words.length)}nextData(){if(this.offset>=this.words.length)return null;const e=this.words.slice(this.offset,this.offset+2),n=$t(this.offset,e);return this.offset+=e.length,n}feed(e){if(Qt.has(e.status))throw new R(`FRS write 0x${J(this.frsType)} failed: ${et[e.status]??e.status}`);return e.status===3?(this.done=!0,null):e.status===4||e.status===0?this.nextData():null}}function It(t){const e=[...t];for(;e.length<10;)e.push(0);const n=e[3]&65535;return{meVersion:e[0]&255,mhVersion:e[0]>>>8&255,shVersion:e[0]>>>16&255,rangeRaw:e[1],resolutionRaw:e[2],revision:n,powerMaQ10:e[3]>>>16&65535,minPeriodUs:e[4],fifoMax:e[5]&65535,fifoReserved:e[5]>>>16&65535,batchBufferBytes:e[6]&65535,qPoint1:e[7]&65535,qPoint2:e[7]>>>16&65535,qPoint3:n>=3?e[8]>>>16&65535:0,maxPeriodUs:n>=4?e[9]:0,rawWords:[...t]}}var y=(t=>(t[t.Command=0]="Command",t[t.Executable=1]="Executable",t[t.Control=2]="Control",t[t.InputNormal=3]="InputNormal",t[t.InputWake=4]="InputWake",t[t.GyroRv=5]="GyroRv",t))(y||{});const v=4,nt=32767,rt=32768,E=6,G=64;function st(t){const e=t.length&nt|(t.continuation?rt:0),n=new Uint8Array(v),r=new DataView(n.buffer);return r.setUint16(0,e,!0),r.setUint8(2,t.channel),r.setUint8(3,t.seq),n}function Zt(t){const e=new DataView(t.buffer,t.byteOffset,t.byteLength),n=e.getUint16(0,!0);return{length:n&nt,channel:e.getUint8(2),seq:e.getUint8(3),continuation:(n&rt)!==0}}function jt(t,e,n){const r=st({length:v+e.length,channel:t,seq:n&255,continuation:!1}),s=new Uint8Array(r.length+e.length);return s.set(r,0),s.set(e,r.length),s}function ie(t,e,n,r=G){if(r<=v)throw new Error("maxFrame must exceed the 4-byte SHTP header");const s=r-v,o=[];let a=0,i=n&255;const u=v+e.length;for(;;){const c=e.subarray(a,a+s),l=u-a,f=st({length:l,channel:t,seq:i,continuation:a>0}),m=new Uint8Array(f.length+c.length);if(m.set(f,0),m.set(c,f.length),o.push(m),a+=c.length,i=i+1&255,a>=e.length)return o}}function $(){return{chunks:[],received:0,expected:0,seq:0}}function Yt(t,e){const n=new Uint8Array(e);let r=0;for(const s of t)n.set(s,r),r+=s.length;return n}class Kt{discarded=0;txSeqs=new Array(E).fill(0);rx=Array.from({length:E},$);nextFrame(e,n){if(v+n.length>G)throw new Error(`TX cargo ${n.length}B exceeds the ${G}B MCU slot`);const r=this.txSeqs[e];return this.txSeqs[e]=r+1&255,jt(e,n,r)}txSeq(e){return this.txSeqs[e]}feed(e){if(e.length<v)return null;const n=Zt(e);if(n.channel>=E||n.length<v)return null;const r=e.subarray(v),s=this.rx[n.channel];if(!n.continuation)s.expected!==0&&s.received!==0&&(this.discarded+=1),s.chunks=[r.slice()],s.received=r.length,s.expected=n.length-v,s.seq=n.seq;else{if(s.expected===0)return this.discarded+=1,null;s.chunks.push(r.slice()),s.received+=r.length}if(s.received<s.expected)return null;if(s.received>s.expected)return this.discarded+=1,s.chunks=[],s.received=0,s.expected=0,null;const o={channel:n.channel,seq:s.seq,payload:Yt(s.chunks,s.received)};return s.chunks=[],s.received=0,s.expected=0,o}reset(){this.txSeqs=new Array(E).fill(0),this.rx=Array.from({length:E},$)}}const B=.9,W=2.1,Ft=1,p=1e3,_=2e3;function Jt(t){return new Promise(e=>setTimeout(e,t))}function H(t){return t==null?null:typeof t=="number"?new Set([t]):new Set(t)}class oe extends at{busyRetries=5;busyBackoffMs=ct;shtp=new Kt;txChain=Promise.resolve();reportCbs=[];reportQueues=[];controlWaiters=new Map;cmdSeq=0;resetResolvers=[];advertisementChunks=[];features=new Map;constructor(e,n){super(e,n),n?.busyRetries!==void 0&&(this.busyRetries=n.busyRetries),n?.busyBackoffMs!==void 0&&(this.busyBackoffMs=n.busyBackoffMs)}handleReport(e){if(e.cmd!==Q.Data||e.payload.length<9)return!1;const n=ut(e.payload),r=this.shtp.feed(n.shtp);return r!==null&&this.dispatchCargo(r,n.timestampUs),!0}dispatchCargo(e,n){switch(e.channel){case y.Command:this.advertisementChunks.push(e.payload);return;case y.Executable:if(e.payload[0]===Ft)for(const r of this.resetResolvers.splice(0))r();return;case y.Control:{if(e.payload.length===0)return;const r=e.payload[0];if(r===A.GetFeatureResponse&&e.payload.length>=17){const s=N(e.payload);this.features.set(s.sensorId,s)}for(const s of[...this.controlWaiters.get(r)??[]])s(e.payload.slice());return}case y.InputNormal:case y.InputWake:for(const r of Rt(e.payload,n))this.emitReport(r);return;case y.GyroRv:{const r=vt(e.payload,n);r!==null&&this.emitReport(r);return}}}emitReport(e){for(const{cb:n,filter:r}of[...this.reportCbs])(r===null||r.has(e.sensorId))&&n(e);for(const{queue:n,filter:r}of[...this.reportQueues])(r===null||r.has(e.sensorId))&&n.push(e)}sendShtp(e,n){const r=this.shtp.nextFrame(e,n),s=async()=>{for(let a=0;;a++)try{await this.request(T.SendShtpPacket,r,{okCompletes:!0});return}catch(i){if(!(i instanceof ot)||a>=this.busyRetries-1)throw i;await Jt(this.busyBackoffMs)}},o=this.txChain.then(s);return this.txChain=o.catch(()=>{}),o}controlExchange(e,n,r,s){return new Promise((o,a)=>{let i=!1;const u=()=>{clearTimeout(f);const g=this.controlWaiters.get(e);g!==void 0&&this.controlWaiters.set(e,g.filter(D=>D!==m))},c=g=>{i||(i=!0,u(),o(g))},l=g=>{i||(i=!0,u(),a(g))},f=setTimeout(()=>l(new k(e,n)),n),m=g=>r(g,c,l),d=this.controlWaiters.get(e)??[];d.push(m),this.controlWaiters.set(e,d),s().catch(g=>l(g instanceof Error?g:new U(String(g))))})}controlRequest(e,n,r,s,o=p){return this.controlExchange(n,o,(a,i,u)=>{let c;try{c=r(a)}catch(l){u(l instanceof Error?l:new U(String(l)));return}(s===void 0||s(c))&&i(c)},()=>this.sendShtp(y.Control,e))}nextCmdSeq(){const e=this.cmdSeq;return this.cmdSeq=e+1&255,e}async command(e,n,r,s=p){const o=this.nextCmdSeq(),a=z(o,e,n);return r?this.controlRequest(a,A.CommandResponse,L,i=>i.command===e&&i.commandSeq===o,s):(await this.sendShtp(y.Control,a),null)}commandCollect(e,n,r,s=p){const o=this.nextCmdSeq(),a=z(o,e,n),i=[];return this.controlExchange(A.CommandResponse,s,(u,c,l)=>{let f;try{f=L(u)}catch(m){l(m instanceof Error?m:new U(String(m)));return}f.command!==e||f.commandSeq!==o||r(f,i)&&c(i)},()=>this.sendShtp(y.Control,a))}async hardwareReset(e=2e3){this.shtp.reset(),this.advertisementChunks=[],this.features.clear();const n=new Promise(o=>this.resetResolvers.push(o));await this.request(T.SensorReset,void 0,{okCompletes:!0});let r;const s=new Promise((o,a)=>{r=setTimeout(()=>a(new k(T.SensorReset,e)),e)});try{await Promise.race([n,s])}finally{clearTimeout(r)}}async wake(){await this.request(T.SensorWakeUp,void 0,{okCompletes:!0})}get advertisement(){const e=this.advertisementChunks.reduce((s,o)=>s+o.length,0),n=new Uint8Array(e);let r=0;for(const s of this.advertisementChunks)n.set(s,r),r+=s.length;return n}productId(e=p){return this.controlRequest(xt(),A.ProductIdResponse,qt,void 0,e)}async enable(e,n,r={}){if(n===void 0==(r.intervalUs===void 0))throw new U("give exactly one of hz / intervalUs");let s;if(n!==void 0){if(n<=0)throw new U("hz must be positive; use disable()");s=Math.max(1,Math.round(1e6/n))}else s=r.intervalUs;if(await this.sendShtp(y.Control,O(e,s,r.batchUs??0,r.sensitivity??0,r.flags??0,r.cfgWord??0)),r.verify===!1)return null;const o=await this.getFeature(e,r.timeoutMs??p),a=1e6/s,i=o.intervalUs!==0?1e6/o.intervalUs:0;return B*a<=i&&i<=W*a||console.warn(`BNO086 sensor 0x${e.toString(16).toUpperCase().padStart(2,"0")}: requested ${a.toFixed(1)} Hz, granted ${i.toFixed(1)} Hz (outside ${B}–${W}× band)`),o}async disable(e){await this.sendShtp(y.Control,O(e,0)),this.features.delete(e)}getFeature(e,n=p){return this.controlRequest(Mt(e),A.GetFeatureResponse,N,r=>r.sensorId===e,n)}enableRotationVector(e=100,n){return this.enable(b.RotationVector,e,n)}enableGameRotationVector(e=100,n){return this.enable(b.GameRotationVector,e,n)}enableAccelerometer(e=100,n){return this.enable(b.Accelerometer,e,n)}enableGyroscope(e=100,n){return this.enable(b.Gyroscope,e,n)}enableMagnetometer(e=50,n){return this.enable(b.Magnetometer,e,n)}enableLinearAcceleration(e=100,n){return this.enable(b.LinearAcceleration,e,n)}enableGravity(e=100,n){return this.enable(b.Gravity,e,n)}enableGyroIntegratedRv(e=400,n){return this.enable(b.GyroIntegratedRv,e,n)}onReport(e,n){const r={cb:e,filter:H(n)};return this.reportCbs.push(r),()=>{this.reportCbs=this.reportCbs.filter(s=>s!==r)}}reports(e,n=1024){const r=new it(n,()=>{this.reportQueues=this.reportQueues.filter(o=>o.queue!==r),s()});this.reportQueues.push({queue:r,filter:H(e)});const s=this.registerStream(r);return r}async tareNow(e=F.All,n=K.RotationVector){await this.command(w.Tare,kt(e,n),!1)}async persistTare(){await this.command(w.Tare,Pt(),!1)}async setReorientation(e,n,r,s){await this.command(w.Tare,_t(e,n,r,s),!1)}async setCalibration(e={},n=p){const r=await this.command(w.MeCalibrate,S(e.accel??!0,e.gyro??!0,e.mag??!0,e.planar??!1),!0,n);if(r.status!==0)throw new R(`ME calibration configure failed: status ${r.status}`)}async getCalibration(e=p){const n=await this.command(w.MeCalibrate,S(!1,!1,!1,!1,Gt),!0,e);if(n.status!==0)throw new R(`ME calibration get failed: status ${n.status}`);const r=n.r;return{accel:!!r[1],gyro:!!r[2],mag:!!r[3],planar:!!r[4]}}async saveDcd(e=p){const n=await this.command(w.SaveDcd,new Uint8Array(0),!0,e);if(n.status!==0)throw new R(`DCD save failed: status ${n.status}`)}async configurePeriodicDcd(e){await this.command(w.PeriodicDcdConfig,Vt(e),!1)}frsRead(e,n=_){const r=new Ht(e);return this.controlExchange(A.FrsReadResponse,n,(s,o,a)=>{try{r.feed(Lt(s))&&o(r.words)}catch(i){a(i instanceof Error?i:new U(String(i)))}},()=>this.sendShtp(y.Control,r.request()))}frsWrite(e,n,r=_){const s=new Xt(e,[...n]);return this.controlExchange(A.FrsWriteResponse,r,(o,a,i)=>{try{const u=s.feed(Bt(o));s.done?a(void 0):u!==null&&this.sendShtp(y.Control,u).catch(i)}catch(u){i(u instanceof Error?u:new U(String(u)))}},()=>this.sendShtp(y.Control,s.request()))}async getMetadata(e,n=_){const r=Nt[e];if(r===void 0)throw new R(`no metadata FRS record known for sensor 0x${e.toString(16).toUpperCase().padStart(2,"0")}`);return It(await this.frsRead(r,n))}async getOscillatorType(e=p){return(await this.command(w.GetOscillatorType,new Uint8Array(0),!0,e)).r[0]}async clearDcdAndReset(e=2e3){this.shtp.reset(),this.advertisementChunks=[],this.features.clear();const n=new Promise(o=>this.resetResolvers.push(o));await this.command(w.ClearDcdAndReset,new Uint8Array(0),!1);let r;const s=new Promise((o,a)=>{r=setTimeout(()=>a(new k(w.ClearDcdAndReset,e)),e)});try{await Promise.race([n,s])}finally{clearTimeout(r)}this.shtp.reset()}async getErrors(e=0,n=p){return(await this.commandCollect(w.Errors,Tt(e),(s,o)=>s.r[2]===Y.NoMoreErrors?!0:(o.push(s),!1),n)).map(Ct)}async getCounts(e,n=p){const r=await this.commandCollect(w.Counter,Dt(e),(u,c)=>(c.push(u),c.some(l=>l.responseSeq===1)),n),s=new Map(r.map(u=>[u.responseSeq,u])),o=s.get(0).r,a=s.get(1).r,i=(u,c)=>(u[c]|u[c+1]<<8|u[c+2]<<16|u[c+3]<<24)>>>0;return{sensorId:e,offered:i(o,3),accepted:i(o,7),on:i(a,3),attempted:i(a,7)}}async clearCounts(e,n=p){const r=await this.command(w.Counter,Et(e),!0,n);if(r.status!==0)throw new R(`clear counts failed: status ${r.status}`)}}export{St as $,pt as A,oe as B,rt as C,ft as D,Y as E,Ht as F,P as G,w as H,R as I,y as J,Kt as K,nt as L,G as M,E as N,bt as O,ee as P,gt as Q,W as R,v as S,ht as T,ne as U,F as V,K as W,z as X,jt as Y,zt as Z,$t as _,j as a,Mt as a0,xt as a1,O as a2,Et as a3,Dt as a4,Ct as a5,Tt as a6,ie as a7,S as a8,st as a9,vt as aa,Rt as ab,Vt as ac,Pt as ad,It as ae,_t as af,kt as ag,ut as ah,L as ai,N as aj,Lt as ak,Bt as al,qt as am,Zt as an,ct as b,T as c,Q as d,At as e,Ut as f,A as g,lt as h,re as i,V as j,X as k,Z as l,I as m,Ot as n,tt as o,se as p,Xt as q,et as r,Nt as s,Gt as t,ae as u,B as v,yt as w,mt as x,wt as y,b as z};