feat: prove and decode K1 realtime MQTT streams
This commit is contained in:
+34
-24
@@ -1,14 +1,19 @@
|
||||
# Technical audit
|
||||
|
||||
Status: pre-production planning, 2026-07-15.
|
||||
Status: live feasibility validated, 2026-07-15.
|
||||
|
||||
## Executive finding
|
||||
|
||||
The project is feasible as a disciplined black-box investigation, but the
|
||||
existence of a complete K1-to-Mac realtime link is not yet established. The
|
||||
first hard problem is not decoding points or images. It is bootstrapping the K1
|
||||
from BLE availability into Wi-Fi association and then opening the proprietary
|
||||
application data session without LixelGO.
|
||||
The K1-to-Mac realtime link is feasible and has been demonstrated without
|
||||
LixelGO. The tested Mac provisioned firmware 3.0.2 over BLE, confirmed K1 LAN
|
||||
association, opened the device's MQTT 3.1.1 service on TCP 1883, captured a
|
||||
physical-button scan and decoded both point-cloud and pose reports.
|
||||
|
||||
All 1,140 captured `lio_pcl` frames decoded as raw-LZ4 protobuf blocks, yielding
|
||||
4,165,862 points. All 1,215 `lio_pose` messages decoded, and the resulting
|
||||
approximately 1.566 m displacement matched the controlled movement. The
|
||||
remaining feasibility question is the panoramic camera branch, not the core
|
||||
realtime LiDAR/pose path.
|
||||
|
||||
The supplied Bible is useful as an OSINT dossier. It is not an executable plan
|
||||
for the actual stand because many experiments assume a phone and LixelGO. The
|
||||
@@ -31,16 +36,16 @@ writes.
|
||||
Each of these remains scoped to the actual firmware/hardware state observed in
|
||||
the lab. The physical unit is authoritative.
|
||||
|
||||
### Strong hypotheses
|
||||
### Resolved hypotheses
|
||||
|
||||
- BLE is the bootstrap/control plane and Wi-Fi is the likely high-rate data
|
||||
plane.
|
||||
- The user-provided SSID and PSK are transported inside a vendor-defined GATT
|
||||
protocol.
|
||||
- The application may need a second token, certificate, handshake, or stream
|
||||
subscription after ordinary Wi-Fi association.
|
||||
- The externally exposed point cloud is more likely a processed/downsampled
|
||||
preview than raw LiDAR packets.
|
||||
- BLE is the bootstrap/provisioning plane and Wi-Fi/MQTT is the high-rate data
|
||||
plane on the tested firmware.
|
||||
- SSID and PSK use a verified fixed 99-byte GATT frame; the hidden credential
|
||||
path never persists the password.
|
||||
- The report subscriptions require no second MQTT credential, certificate or
|
||||
application publish handshake on the direct LAN path.
|
||||
- The external `lio_pcl` stream is a processed point cloud rather than raw
|
||||
LiDAR packets.
|
||||
|
||||
XGRIDS provides stronger product evidence for an external point-cloud path than
|
||||
the local LAS alone: current LixelStudio materials describe K1 remote control
|
||||
@@ -49,18 +54,18 @@ and this does not disclose or guarantee access to the protocol from macOS. It
|
||||
does, however, justify keeping realtime point cloud as the primary stream target.
|
||||
No comparable official evidence proves an exportable raw panorama/camera stream.
|
||||
|
||||
### Unsupported until measured
|
||||
### Still unsupported until measured
|
||||
|
||||
- K1 remembers an existing Wi-Fi profile.
|
||||
- K1 exposes its own access point.
|
||||
- Provisioning fields are plain UTF-8, JSON, TLV, CBOR, or protobuf.
|
||||
- A writable GATT characteristic can be used without bonding or an app token.
|
||||
- Local `map.las` layout resembles the network stream.
|
||||
- Live pose or camera frames leave the device.
|
||||
- A point stream contains simple float32 XYZ tuples.
|
||||
- Network payloads are unencrypted.
|
||||
- Raw or stitched panoramic camera frames leave the device.
|
||||
- The upper 24 bits of point `rgbi` are usable packed RGB.
|
||||
- MQTT application commands can be published safely without first reproducing
|
||||
device/session header state and response handling.
|
||||
|
||||
## Major corrections to the source plan
|
||||
## Initial corrections to the source plan
|
||||
|
||||
These corrections governed the safe experiment. The resolved outcomes above
|
||||
and the verified profiles now supersede their pre-lab uncertainty.
|
||||
|
||||
1. Experiments requiring LixelGO are removed from the active critical path.
|
||||
There will be no app-session capture, provisioning diff, app-start comparison,
|
||||
@@ -142,6 +147,11 @@ device baseline
|
||||
-> point cloud / pose / status / optional camera decoders
|
||||
```
|
||||
|
||||
The chain through point-cloud/pose decoding is now complete. See the
|
||||
[MQTT stream profile](05_K1_MQTT_STREAM_PROFILE.md) and
|
||||
[redacted lab report](lab/001_K1_LIVE_MQTT_20260715.redacted.md) for measured
|
||||
formats, counts and artifact hashes.
|
||||
|
||||
## Verified primary references
|
||||
|
||||
- [XGRIDS K1 firmware and release notes](https://www.xgrids.com/intl/support/download?page=K1)
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
This plan supersedes the app-dependent experiment order in the reference Bible.
|
||||
Each gate produces evidence and an explicit GO, PAUSE or BLOCKED result.
|
||||
|
||||
## Live checkpoint — 2026-07-15
|
||||
|
||||
| Stage | Result |
|
||||
| --- | --- |
|
||||
| Stage 0 host/repository | GO — isolated Python 3.12 environment and private Git |
|
||||
| Gate 1 physical operation | GO — autonomous double-click start/stop verified |
|
||||
| Stage 1 BLE discovery | GO — repeatable advertisement and GATT profile |
|
||||
| Stage 2 BLE provisioning | GO — reviewed 99-byte profile, LAN association confirmed |
|
||||
| Stage 3 application session | GO — MQTT 3.1.1 on confirmed K1 TCP 1883 |
|
||||
| Stage 4 artifacts/flows | GO — bounded capture, hashes and negative control |
|
||||
| Stage 5 point cloud | GO — raw-LZ4 protobuf, 1,140 live frames decoded |
|
||||
| Stage 5 pose | GO — 1,215 live frames decoded and motion-correlated |
|
||||
| Stage 5 camera | PAUSE — no independent frame/video stream observed |
|
||||
|
||||
USB project copying remains optional ground truth rather than a blocker for the
|
||||
now-verified network path. MQTT control publishing remains deliberately deferred
|
||||
because the physical button is a known-safe start/stop mechanism.
|
||||
|
||||
## Stage 0 — repository and host baseline
|
||||
|
||||
Deliverables:
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
# Reviewed K1 Wi-Fi provisioning profile
|
||||
|
||||
Profile ID: `xgrids-k1-fw3-wifi-v1`
|
||||
|
||||
Status: reviewed for one controlled write against the owner-controlled K1. This
|
||||
profile is not a generic XGRIDS protocol claim and must not be used for fuzzing.
|
||||
|
||||
## Evidence and target
|
||||
|
||||
- Observed device firmware: 3.0.2.
|
||||
- Live metadata-only GATT discovery exposes service `7f00`, read/write
|
||||
characteristic `7f01`, and read characteristic `7f02`.
|
||||
- Static analysis of the official Android application's production path maps
|
||||
its service field to `7f00`, discovered write field to `7f01`, and status/read
|
||||
field to `7f02`.
|
||||
- The application sends operator-supplied router credentials; it does not derive
|
||||
them from the K1 and it does not require the password of the K1's own AP.
|
||||
|
||||
Full UUIDs:
|
||||
|
||||
- service: `00007f00-0000-1000-8000-00805f9b34fb`;
|
||||
- write: `00007f01-0000-1000-8000-00805f9b34fb`;
|
||||
- status/read: `00007f02-0000-1000-8000-00805f9b34fb`.
|
||||
|
||||
## Request frame
|
||||
|
||||
The application writes exactly 99 bytes:
|
||||
|
||||
| Offset | Length | Meaning |
|
||||
| --- | ---: | --- |
|
||||
| 0 | 1 | SSID UTF-8 byte length, 1 through 32 |
|
||||
| 1 | 32 | SSID UTF-8 bytes followed by zero padding |
|
||||
| 33 | 1 | password UTF-8 byte length, 1 through 64 |
|
||||
| 34 | 64 | password UTF-8 bytes followed by zero padding |
|
||||
| 98 | 1 | zero |
|
||||
|
||||
There is no checksum, nonce, token, certificate, signature, or separate commit
|
||||
command in this production call path. The implementation must never print,
|
||||
persist, or accept the password as a command-line argument.
|
||||
|
||||
The Android application unequivocally requests a write without response and
|
||||
negotiates MTU 120, making the 99-byte frame one ATT command. A live read-only
|
||||
CoreBluetooth check reports MTU 256 and a maximum write-without-response size of
|
||||
253, so the same frame also fits one command on this Mac.
|
||||
|
||||
CoreBluetooth metadata advertises `write`, not `write-without-response`, despite
|
||||
the official application forcing the latter. The macOS tool exposes that
|
||||
discrepancy: `auto` follows advertised properties, while the explicit
|
||||
`without_response` mode mirrors the application only after checking the live
|
||||
maximum is at least 99. The first controlled experiment uses that explicit
|
||||
mode. It never fragments or retries the payload automatically.
|
||||
|
||||
## Expected transition and evidence of acceptance
|
||||
|
||||
A completed GATT write only proves transport completion. It does not prove that
|
||||
the K1 joined Wi-Fi. The application polls `7f02`; the observed response frame
|
||||
contains a fixed-width mode slot, an address slot, and a status byte at offset
|
||||
50. The current AP baseline reports mode `WIFI_AP` and address `192.168.56.1`.
|
||||
|
||||
For the controlled experiment, acceptance required at least one of:
|
||||
|
||||
1. `7f02` reports a non-AP IPv4 address;
|
||||
2. the same address appears as a new router/ARP client after the write;
|
||||
3. a statically evidenced K1 application endpoint is reached at that confirmed
|
||||
address.
|
||||
|
||||
Do not infer success from a write callback alone.
|
||||
|
||||
## Safety, recovery and stop conditions
|
||||
|
||||
- Perform one write per explicitly named attempt, using credentials for the LAN
|
||||
already used by the Mac. Never retry automatically.
|
||||
- Do not alter Deco settings, scan the subnet, or guess any credential.
|
||||
- If the status does not change, do not retry automatically.
|
||||
- If the supplied credentials are wrong, reconnect over BLE and overwrite them
|
||||
with corrected credentials using the same reviewed profile.
|
||||
- A single normal power cycle is allowed as a recovery check. It is not claimed
|
||||
to erase stored credentials. Factory reset and firmware actions are prohibited.
|
||||
- Stop on repeated disconnects, an unexpected GATT layout, overheating, an
|
||||
activation prompt, or any device fault indication.
|
||||
|
||||
The exact factory-return command is not known. That limitation is accepted for
|
||||
the first write because BLE remains the documented configuration transport and
|
||||
the operator controls the intended LAN credentials.
|
||||
|
||||
## Live transport attempts
|
||||
|
||||
Attempt 01 mirrored the Android application: one 99-byte write without response,
|
||||
with a live CoreBluetooth maximum of 253 bytes. For 60 seconds afterward, `7f02`
|
||||
remained at the AP baseline and the existing LAN neighbor table did not change.
|
||||
There was no automatic retry.
|
||||
|
||||
Attempt 02 was separately reviewed because `7f01` explicitly advertises ordinary
|
||||
write-with-response to CoreBluetooth. The identical 99-byte payload was sent
|
||||
once using that advertised transport. This tested the transport mismatch only;
|
||||
it did not change credential values or application framing.
|
||||
|
||||
Attempt 02 succeeded immediately. `7f02` reported the operator-selected LAN,
|
||||
status code 1 and a non-AP private IPv4 address. The existing neighbor table then
|
||||
confirmed the same new address on the Mac's Wi-Fi interface. No third
|
||||
provisioning write was made.
|
||||
|
||||
Offline analysis of the owned application and a targeted check against only that
|
||||
confirmed address identified plain MQTT on TCP 1883 as the production
|
||||
application endpoint. Port 8008 belongs to a separate QuickLink/AP WebSocket
|
||||
branch and was correctly refused in the bridge/LAN topology. The successful
|
||||
MQTT result is documented in `05_K1_MQTT_STREAM_PROFILE.md`.
|
||||
@@ -0,0 +1,164 @@
|
||||
# Verified K1 MQTT stream profile
|
||||
|
||||
Status: verified against one owner-controlled LixelKity K1 running firmware
|
||||
3.0.2. This is a capture and decoder profile, not a claim of vendor support or a
|
||||
stable public API.
|
||||
|
||||
## Transport
|
||||
|
||||
After BLE provisioning, the K1 joins the operator's LAN and exposes:
|
||||
|
||||
| Property | Verified value |
|
||||
| --- | --- |
|
||||
| Transport | TCP |
|
||||
| Port | 1883 |
|
||||
| Application protocol | MQTT 3.1.1 |
|
||||
| TLS | not used by this direct-LAN path |
|
||||
| Username/password | not used by the observed client setup |
|
||||
| K1 address | DHCP/private IPv4, retained only in the ignored session |
|
||||
|
||||
The direct route for the confirmed K1 address used the Mac Wi-Fi interface even
|
||||
while the Mac's default route was a VPN tunnel. Commands must resolve the route
|
||||
for the confirmed K1 address and must not scan the surrounding subnet.
|
||||
|
||||
The repository's capture client is subscribe-only. It sends the minimum MQTT
|
||||
CONNECT, SUBSCRIBE, keepalive and DISCONNECT protocol packets; it has no reason
|
||||
to publish an application command.
|
||||
|
||||
## Verified report topics
|
||||
|
||||
The firmware-3 stream set is:
|
||||
|
||||
```text
|
||||
lixel/application/report/heartbeat
|
||||
lixel/application/report/device_status
|
||||
lixel/application/report/lio_pcl
|
||||
lixel/application/report/lio_pose
|
||||
lixel/application/report/modeling
|
||||
```
|
||||
|
||||
Additional report topics exist for system errors, modeling status, PGO,
|
||||
control points and upgrades. The safe discovery subscription is restricted to
|
||||
`lixel/application/report/#`. It does not subscribe to request topics.
|
||||
|
||||
The application also retains compatibility subscribers for:
|
||||
|
||||
```text
|
||||
RealtimePointcloud
|
||||
RealtimePath
|
||||
DeviceStatus
|
||||
```
|
||||
|
||||
No legacy stream was emitted by the tested firmware during the live run.
|
||||
|
||||
## Firmware-3 point cloud
|
||||
|
||||
`lixel/application/report/lio_pcl` contains a protobuf compression envelope:
|
||||
|
||||
```proto
|
||||
message MqttCompressMsg {
|
||||
Header header = 1;
|
||||
CompressionType compression = 2; // 0=LZ4, 1=Zstd
|
||||
uint32 compressed_size = 3; // expected decoded byte count
|
||||
bytes compressed_data = 4;
|
||||
}
|
||||
```
|
||||
|
||||
The verified value is compression enum 0. `compressed_data` is a raw LZ4 block,
|
||||
not an LZ4 frame. The decoder must supply `compressed_size`, enforce the exact
|
||||
decoded length and reject enum 1 until a bounded Zstd path is reviewed.
|
||||
|
||||
The decoded protobuf is:
|
||||
|
||||
```proto
|
||||
message LioPclReport {
|
||||
Header header = 1;
|
||||
repeated Point points = 2;
|
||||
}
|
||||
|
||||
message Point {
|
||||
sint64 x = 1;
|
||||
sint64 y = 2;
|
||||
sint64 z = 3;
|
||||
uint32 rgbi = 4;
|
||||
}
|
||||
```
|
||||
|
||||
Coordinates are ZigZag `sint64` values. Sensor-native metric coordinates are
|
||||
`(x/header.scaler, y/header.scaler, z/header.scaler)`; a zero scaler is invalid.
|
||||
The tested frames consistently used scaler 1000.
|
||||
|
||||
The application uses only `rgbi & 0xff` as intensity/alpha. The connector keeps
|
||||
the complete `uint32`; interpreting the upper 24 bits as RGB remains unverified.
|
||||
Raw coordinates are preserved. Any Y/Z swap belongs in a derived visualization,
|
||||
not in capture storage.
|
||||
|
||||
## Firmware-3 pose
|
||||
|
||||
`lixel/application/report/lio_pose` is an uncompressed protobuf:
|
||||
|
||||
```proto
|
||||
message LioPoseReport {
|
||||
Header header = 1;
|
||||
PoseStamped pose = 2;
|
||||
float distance = 3;
|
||||
float pose_accuracy = 4;
|
||||
}
|
||||
|
||||
message PoseStamped { sint64 stamp = 1; Pose pose = 2; }
|
||||
message Pose { Point position = 1; Quaternion orientation = 2; }
|
||||
message Point { double x = 1; double y = 2; double z = 3; }
|
||||
message Quaternion { double x = 1; double y = 2; double z = 3; double w = 4; }
|
||||
```
|
||||
|
||||
Storage keeps position `(x,y,z)` and quaternion `(x,y,z,w)` exactly as received.
|
||||
Non-finite values are rejected. Quaternion normalization, coordinate transforms
|
||||
and sensor-to-vehicle extrinsics are derived operations and must not overwrite
|
||||
raw values.
|
||||
|
||||
## Legacy formats
|
||||
|
||||
`RealtimePointcloud` starts with a 12-byte envelope. Little-endian uint32 at
|
||||
offset 0 is the point stride. Records contain float32 `x,y,z` at offsets 0,4,8,
|
||||
RGB bytes at 12,13,14 and, when stride is at least 16, intensity at 15. Envelope
|
||||
bytes 4 through 11 remain uninterpreted and are retained.
|
||||
|
||||
`RealtimePath` contains float32 position `x,y,z` at offsets 0,4,8; offset 12 is
|
||||
unknown; quaternion wire order is `w,x,y,z` at offsets 16,20,24,28. The decoded
|
||||
orientation is exposed as `(x,y,z,w)`. Unknown tail fields are retained.
|
||||
|
||||
`PrePathArray` is exactly 16 little-endian float64 values.
|
||||
|
||||
## Application control boundary
|
||||
|
||||
Static analysis identified the application start/stop topic as
|
||||
`lixel/application/request/modeling`, QoS 2, with a protobuf
|
||||
`ModelingRequest`. Start action is 1 and stop action is 2. A valid request also
|
||||
contains a device/session/OpenAPI header and, for start, project/record/scan/mount
|
||||
settings.
|
||||
|
||||
Publishing is deliberately not implemented. The physical double-click provides
|
||||
a verified autonomous start/stop path and avoids inventing session headers or
|
||||
changing scan settings. A future publisher requires a separate reviewed profile,
|
||||
explicit confirmation, response handling and rollback.
|
||||
|
||||
## Decoder and capture bounds
|
||||
|
||||
Default defensive limits are applied before allocation or iteration:
|
||||
|
||||
- 2 MiB maximum MQTT payload;
|
||||
- 1 MiB maximum compressed block;
|
||||
- 8 MiB maximum decoded block;
|
||||
- 64:1 maximum claimed expansion ratio;
|
||||
- 250,000 points per frame;
|
||||
- bounded protobuf field counts and exact LZ4 decoded length.
|
||||
|
||||
Per-frame failures do not justify firmware writes or speculative recovery.
|
||||
Always preserve the raw MQTT record and report the decoder error separately.
|
||||
|
||||
## Current camera result
|
||||
|
||||
No independent camera, panorama, JPEG, H.264 or RTSP topic was observed in this
|
||||
run. `lio_pcl` may carry intensity or packed color information, but that does not
|
||||
prove access to the two raw panoramic camera streams. Camera discovery remains a
|
||||
separate evidence gate.
|
||||
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"session_id": "20260715T122850Z_live_power_cycle",
|
||||
"experiment": "BLE provisioning and physical-button MQTT stream capture",
|
||||
"tool": {
|
||||
"version": "0.1.0",
|
||||
"git_commit": "faa442e+working-tree-lab-tooling"
|
||||
},
|
||||
"host": {
|
||||
"macos_version": "26.5.1",
|
||||
"machine": "arm64",
|
||||
"python_version": "3.12.13",
|
||||
"wifi_interface": "en0",
|
||||
"vpn_active": true
|
||||
},
|
||||
"device": {
|
||||
"model": "XGRIDS/LixelKity K1",
|
||||
"serial_suffix": null,
|
||||
"activation_state": "active",
|
||||
"firmware": "3.0.2"
|
||||
},
|
||||
"network": {
|
||||
"topology": "current_lan",
|
||||
"k1_address_redacted": "RFC1918 private IPv4"
|
||||
},
|
||||
"timeline": [
|
||||
{
|
||||
"event": "MQTT standby baseline begins",
|
||||
"monotonic_seconds": 0.0,
|
||||
"utc": "2026-07-15T14:05:15.186Z",
|
||||
"note": "heartbeat and device_status only"
|
||||
},
|
||||
{
|
||||
"event": "first live pose report",
|
||||
"monotonic_seconds": 57.778,
|
||||
"utc": "2026-07-15T14:06:12.964Z",
|
||||
"note": "physical double-click scan start"
|
||||
},
|
||||
{
|
||||
"event": "first live point-cloud report",
|
||||
"monotonic_seconds": 57.795,
|
||||
"utc": "2026-07-15T14:06:12.981Z",
|
||||
"note": "firmware-3 lio_pcl topic"
|
||||
},
|
||||
{
|
||||
"event": "full-payload capture window ends",
|
||||
"monotonic_seconds": 179.166,
|
||||
"utc": "2026-07-15T14:08:14.352Z",
|
||||
"note": "180-second subscriber timeout"
|
||||
},
|
||||
{
|
||||
"event": "post-stop negative control begins",
|
||||
"monotonic_seconds": 369.254,
|
||||
"utc": "2026-07-15T14:11:24.440Z",
|
||||
"note": "solid-green standby; no lio_pcl/lio_pose/modeling reports"
|
||||
},
|
||||
{
|
||||
"event": "repository-native standby smoke capture",
|
||||
"monotonic_seconds": 2443.564,
|
||||
"utc": "2026-07-15T14:45:58.750Z",
|
||||
"note": "5-second fixed-topic subscriber; 11 heartbeat/status frames"
|
||||
}
|
||||
],
|
||||
"artifacts": [
|
||||
{
|
||||
"path": "reference/LG_i18n_125_20250820.apk",
|
||||
"size_bytes": 118234630,
|
||||
"sha256": "c83736f782981282b933cd4737c4f9fa46cbd7f651660c1a9057580f7312361f",
|
||||
"classification": "sensitive"
|
||||
},
|
||||
{
|
||||
"path": "captures/wifi_provisioning_attempt_01.json",
|
||||
"size_bytes": 1258,
|
||||
"sha256": "cc73705c185315286f4009b6619f82a7953b38528a919f7fd2b18ecd788c7637",
|
||||
"classification": "sensitive"
|
||||
},
|
||||
{
|
||||
"path": "captures/wifi_provisioning_attempt_02.json",
|
||||
"size_bytes": 1247,
|
||||
"sha256": "4acf432dd8797802a0033efb7c89f3c11827f681bbf152249c02cccb41d9f873",
|
||||
"classification": "sensitive"
|
||||
},
|
||||
{
|
||||
"path": "captures/mqtt_scan_full_payloads_03.tsv",
|
||||
"size_bytes": 79937918,
|
||||
"sha256": "6b2a4a66d24a89ac048a2be11c5ab45923ee60d4ef07ad3ed3fa3cc508bf8500",
|
||||
"classification": "sensitive"
|
||||
},
|
||||
{
|
||||
"path": "captures/mqtt_post_stop_metadata_04.tsv",
|
||||
"size_bytes": 1488,
|
||||
"sha256": "677835db8175ab6001bec6ecc703413c07795062bb9b4e86c187c77c3e6c73eb",
|
||||
"classification": "sensitive"
|
||||
},
|
||||
{
|
||||
"path": "captures/native_mqtt_standby_05/mqtt.raw.k1mqtt",
|
||||
"size_bytes": 1924,
|
||||
"sha256": "1ff2984d7f305e41f80c13b820405b9b18c8c79c15efe698d51a02fffa22ca82",
|
||||
"classification": "sensitive"
|
||||
},
|
||||
{
|
||||
"path": "analysis/native_mqtt_standby_05.summary.json",
|
||||
"size_bytes": 1481,
|
||||
"sha256": "da72847c9454bd69915c65d49101cb93261d034ec1c1db329ead0b20a6dcbb0e",
|
||||
"classification": "sensitive"
|
||||
}
|
||||
],
|
||||
"decision": {
|
||||
"status": "GO",
|
||||
"gate": "Stage 5 point-cloud and pose decoding",
|
||||
"reason": "All captured firmware-3 point-cloud and pose frames decoded and correlated with controlled physical motion.",
|
||||
"next_smallest_experiment": "Longer repository-native capture on verified power bank; keep camera discovery separate."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
# K1 Lab Report 001 — redacted
|
||||
|
||||
Date: 2026-07-15
|
||||
|
||||
Decision: **GO** for BLE provisioning, LAN association, MQTT capture, firmware-3
|
||||
point-cloud decoding and live pose decoding. Camera stream remains unproven.
|
||||
|
||||
## Stand
|
||||
|
||||
- owner-controlled XGRIDS/LixelKity K1;
|
||||
- observed firmware 3.0.2;
|
||||
- Apple Silicon MacBook;
|
||||
- existing TP-Link mesh LAN;
|
||||
- no LixelGO, phone, SDK, router reconfiguration or firmware change;
|
||||
- device identity, SSID, password, IP and MAC retained only in ignored artifacts.
|
||||
|
||||
## Physical result
|
||||
|
||||
- power-on: slow blue to solid green standby;
|
||||
- autonomous scan start: physical double-click from standby;
|
||||
- start transition: fast green, LiDAR rotation, then scanning green;
|
||||
- initialization: device held still for at least 20 seconds;
|
||||
- controlled movement: approximately one metre plus a turn;
|
||||
- stop: physical double-click, fast green while saving, LiDAR stopped, solid green;
|
||||
- single-click is not the scan-start action;
|
||||
- a depleted battery caused one clean power loss; the battery was replaced before
|
||||
the successful run;
|
||||
- later transfer from battery/USB connection to a verified power bank did not
|
||||
reset the device or change the standby LED.
|
||||
|
||||
## BLE and Wi-Fi result
|
||||
|
||||
The reviewed 99-byte firmware-3 provisioning frame was tested twice:
|
||||
|
||||
1. write without response, mirroring the Android application: transport
|
||||
completed but K1 remained in AP mode;
|
||||
2. write with response, matching the live CoreBluetooth property: immediate
|
||||
success, status code 1 and a LAN IPv4 address.
|
||||
|
||||
There was no automatic retry and no third provisioning write. The password was
|
||||
entered in a hidden local macOS dialog and never appeared in arguments, logs,
|
||||
artifacts or Git.
|
||||
|
||||
## MQTT result
|
||||
|
||||
Targeted connection to the confirmed K1 address accepted plain MQTT 3.1.1 on
|
||||
TCP 1883 with no username/password. A subscribe-only client received standby
|
||||
heartbeat and status at approximately 1 Hz.
|
||||
|
||||
The 180-second scan capture contained 2,836 valid records and no framing/declared
|
||||
length errors:
|
||||
|
||||
| Topic | Messages | MQTT payload bytes |
|
||||
| --- | ---: | ---: |
|
||||
| `device_status` | 180 | 31,830 |
|
||||
| `heartbeat` | 180 | 17,997 |
|
||||
| `lio_pcl` | 1,140 | 39,617,777 |
|
||||
| `lio_pose` | 1,215 | 204,370 |
|
||||
| `modeling` | 121 | 10,867 |
|
||||
|
||||
After physical stop, a separate 12-second negative-control subscription received
|
||||
only 12 heartbeat and 12 status messages. It received no `lio_pcl`, `lio_pose` or
|
||||
`modeling` reports.
|
||||
|
||||
After implementation, the repository-native `k1link net mqtt-capture` command
|
||||
was smoke-tested for 5 seconds in standby. It completed a fixed allowlisted
|
||||
subscription, saved 11 messages in the length-framed `.k1mqtt` format and exited
|
||||
on duration. `k1link analyze mqtt-streams` then verified the raw capture hash and
|
||||
all frame boundaries; as expected for standby, it found no PCL or pose frames.
|
||||
|
||||
## Decoder result
|
||||
|
||||
All 1,140 point-cloud MQTT payloads decoded successfully:
|
||||
|
||||
- compression: raw LZ4 block, enum 0 in every frame;
|
||||
- decoded protobuf size: 37,083 through 55,111 bytes per frame;
|
||||
- scaler: 1000 in every frame;
|
||||
- 2,703 through 4,065 points per frame;
|
||||
- total decoded points: 4,165,862;
|
||||
- decode failures: 0.
|
||||
|
||||
All 1,215 pose payloads decoded successfully:
|
||||
|
||||
- protobuf position and quaternion values were finite;
|
||||
- first-to-last pose displacement was approximately 1.566 m, consistent with
|
||||
the operator's controlled movement;
|
||||
- reported pose accuracy was approximately 0.001 throughout;
|
||||
- decode failures: 0.
|
||||
|
||||
Scene bounds, trajectory coordinates and raw payloads remain private and ignored.
|
||||
|
||||
## Artifact integrity
|
||||
|
||||
The raw files are under the ignored session
|
||||
`20260715T122850Z_live_power_cycle`. Only redacted facts and hashes are committed.
|
||||
|
||||
| Artifact | SHA-256 |
|
||||
| --- | --- |
|
||||
| owned reference APK | `c83736f782981282b933cd4737c4f9fa46cbd7f651660c1a9057580f7312361f` |
|
||||
| provisioning attempt 01 | `cc73705c185315286f4009b6619f82a7953b38528a919f7fd2b18ecd788c7637` |
|
||||
| provisioning attempt 02 | `4acf432dd8797802a0033efb7c89f3c11827f681bbf152249c02cccb41d9f873` |
|
||||
| full MQTT scan capture | `6b2a4a66d24a89ac048a2be11c5ab45923ee60d4ef07ad3ed3fa3cc508bf8500` |
|
||||
| post-stop metadata control | `677835db8175ab6001bec6ecc703413c07795062bb9b4e86c187c77c3e6c73eb` |
|
||||
| native standby `.k1mqtt` smoke capture | `1ff2984d7f305e41f80c13b820405b9b18c8c79c15efe698d51a02fffa22ca82` |
|
||||
| native aggregate analysis | `da72847c9454bd69915c65d49101cb93261d034ec1c1db329ead0b20a6dcbb0e` |
|
||||
|
||||
## Remaining gates
|
||||
|
||||
1. Integrate the bounded stream decoder with the repository-native binary MQTT
|
||||
capture format.
|
||||
2. Run a longer power-bank capture and measure packet loss, CPU, disk and thermal
|
||||
behavior.
|
||||
3. Establish K1-to-vehicle/airframe extrinsics and time synchronization before
|
||||
using pose on a robot or UAV.
|
||||
4. Determine whether usable RGB is packed into `rgbi` or delivered elsewhere.
|
||||
5. Treat raw panoramic camera access as unproven until a scan-correlated stream
|
||||
or endpoint is observed.
|
||||
Reference in New Issue
Block a user