
# XGRIDS / LixelKity K1 как realtime CV-сенсор: pre-production Bible

Документ: инженерный аудит и ТЗ для пилота на macOS  
Версия: 1.0  
Дата: 2026-07-15  
Цель: использовать имеющийся официальный XGRIDS / LixelKity K1 как black-box сенсор для computer vision, realtime-кэша LiDAR/pose/camera данных и дальнейшей интеграции с робототехническим стеком.

## 0. Зачем этот документ существует

Предыдущий короткий документ был слишком верхнеуровневым. Этот документ фиксирует не итоговую выжимку, а полную pre-production карту: факты из мануалов, OSINT по железу, сетевую модель, гипотезы, эксперименты, план reverse engineering штатных интерфейсов, macOS-инструментарий и ТЗ на разработку `k1-mac-link`.

Фокус проекта:

- получить realtime point cloud / preview cloud;
- получить route / poses / trajectory / odometry-like stream, если он существует в live-сессии;
- получить realtime camera / panoramic preview / RGB stream, если он реально передается наружу;
- писать raw traffic и decoded данные на SSD;
- оставить штатную запись на K1 как fallback;
- не считать LAS/LCC/3DGS в runtime;
- не менять firmware на первом этапе;
- не вскрывать устройство на первом этапе.

Гражданские сценарии применения: инспекция, картография, навигационная осведомленность, локальное построение карты препятствий, запись исследовательских датасетов, офлайн-анализ собственных данных.

## 1. Главная концепция решения

### 1.1. Что хотим получить

Идеальный runtime:

```text
XGRIDS LixelKity K1
  -> Wi-Fi / local network
  -> собственный macOS-клиент
  -> realtime parser
  -> SSD raw cache
  -> decoded cache
  -> OpenCV / ML / ROS2-compatible bridge
```

Важный принцип: мы не пытаемся сразу заменить внутренний SLAM K1. Наоборот, мы хотим использовать то, что K1 уже умеет внутри: real-time mapping, realtime point cloud output, собственную локальную запись проекта и работу камер. Наша задача - стать внешним клиентом, который получает те же или близкие live-данные, которые получает LixelGO.

### 1.2. Минимально полезный результат

Минимальный полезный результат пилота:

```text
MacBook видит K1 по BLE
MacBook видит K1 в Wi-Fi сети
MacBook умеет снимать PCAP с K1-сессии
MacBook выделяет candidate live streams
MacBook пишет raw packets на SSD
```

Это уже полезно, потому что превращает неизвестную систему в измеряемую.

### 1.3. Практический результат уровня MVP

MVP:

```text
MacBook без LixelGO открывает data/control session
получает realtime point cloud или stream-кандидат
пишет raw stream на SSD
экспортирует decoded-кандидаты в PLY/NPZ/PCD
```

### 1.4. Максимальный результат

Максимальный результат первого производственного этапа:

```text
BLE provisioning без LixelGO
Wi-Fi data connection без LixelGO
realtime point cloud decoder
realtime pose/status decoder
camera/video/panoramic preview decoder, если поток доступен
session cache на SSD
OpenCV input / ROS2-compatible bridge
```

### 1.5. Что не входит в первый этап

Не входит:

- прошивка K1;
- root/jailbreak;
- стирание internal storage;
- изменение factory calibration;
- вскрытие LiDAR/camera узла;
- пересчет LAS, LCC, Gaussian splats;
- попытки обойти лицензии или облачные функции XGRIDS.

## 2. Опорные факты из официальной документации K1

### 2.1. Что K1 представляет собой физически

Официальный Product Overview описывает Lixel K1 как компактное handheld real-time 3D reconstruction устройство весом менее 1 кг. В нем указаны два ключевых сенсорных блока: `48 MP x2 panoramic vision` и `360 deg LiDAR`, которые используются для генерации цветных моделей в реальном времени. Источник: [S01].

Для нашего проекта это означает:

- камеры внутри действительно есть;
- LiDAR внутри действительно 360-градусный;
- устройство уже выполняет real-time reconstruction / mapping;
- телефон, скорее всего, не делает тяжелую реконструкцию, а отображает поток/результаты устройства.

### 2.2. Физическая кнопка: autonomous mode без телефона

Официальный Basic Operation фиксирует аппаратную кнопку и состояния:

| Действие | Операция | Состояние |
|---|---|---|
| Power On | удерживать 4 секунды | индикатор из slow-flashing blue переходит в solid green, standby |
| Power Off | удерживать 4 секунды в standby | система сохраняет данные и выключается |
| Start Scanning | double-click в standby | solid green -> fast-flashing green -> slow-flashing green, LiDAR начинает вращаться |
| Stop Scanning | double-click в scanning mode | slow-flashing green -> fast-flashing green -> solid green, LiDAR останавливается |
| Control Point | single-click во время скана | контрольная точка записана |
| USB Mode | single-click -> white LED -> single-click | переключение standby/USB mode |

Источник: [S02].

Ключевой вывод: K1 способен запускать и останавливать скан кнопкой. Для старта записи LixelGO не обязателен. Для проекта это критично: можно оставить физический запуск, а data-клиент делать отдельно.

### 2.3. LED state machine

| LED | Значение |
|---|---|
| Off | устройство выключено |
| Slow-flashing green | scanning mode |
| Solid green | standby |
| Solid blue | USB mode |
| Solid yellow | device not activated |
| Solid red | serious fault |
| Slow-flashing blue около 30 секунд | power on |
| Solid white | switching standby/USB |
| Fast-flashing green | starting/stopping scan |
| Alternating red/green | firmware upgrade |

Источник: [S02].

Для тестового стенда это внешний state machine. Даже без доступа к протоколу можно синхронизировать эксперименты по LED.

### 2.4. USB mode и локальная запись

В Basic Operation указано, что для передачи данных используется USB 3.1 cable; устройство нужно перевести в USB mode через LixelGO или shortcut key. После перезапуска USB mode отключается; если нужно снова сканировать, USB mode надо выключить вручную или перезапустить устройство. Источник: [S02].

Практический вывод:

- USB mode - канал для выгрузки проектов;
- во время USB mode сканировать нельзя или нужно выйти из режима;
- для realtime CV USB mode не является главным каналом;
- USB нужен как offline fallback для проверки того, что K1 записал внутри.

### 2.5. Thermal / mechanical ограничения

Basic Operation также говорит:

- устройство - precision surveying/mapping device;
- удары/падения могут повредить устройство или ухудшить точность;
- IP54;
- LiDAR и lens надо держать чистыми;
- нельзя закрывать heat dissipation area;
- при перегреве устройство может выключиться.

Источник: [S02].

Для БПЛА/робототехники: до любых полетов нужна стендовая проверка вибрации, вентиляции и тепла. На первом этапе не крепить так, чтобы перекрывать тепловые зоны.

## 3. Официальная модель подключения LixelGO

### 3.1. Роль LixelGO

Device Activation and Connection говорит, что K1 подключается, активируется и управляется через LixelGO. LixelGO поддерживает Wi-Fi и 5G/4G real-time transmission, true-color/elevation switching, viewing/managing projects. Источник: [S03].

Для нас это не просто описание приложения. Это указатель на архитектуру: приложение является внешним control/data client.

### 3.2. Direct Connect Mode

В Direct Connect Mode официальная последовательность такая:

1. включить Bluetooth телефона;
2. найти Bluetooth устройства;
3. подключиться к Bluetooth устройства;
4. включить hotspot телефона;
5. ввести hotspot name и password;
6. нажать Configure;
7. устройство само подключается к hotspot;
8. дождаться `network connection status` и `data connection status` = success;
9. нажать Done и смотреть basic device information.

Источник: [S03].

Выводы:

- Bluetooth используется как provisioning channel;
- SSID/password - это реквизиты Wi-Fi сети пользователя, а не магический заводской секрет;
- после Wi-Fi подключения есть отдельная `data connection`, то есть второй handshake / data session;
- заменить LixelGO значит воспроизвести минимум два слоя: BLE provisioning и Wi-Fi data session.

### 3.3. Bridge Mode

Bridge Mode в официальной документации описан как режим, где сначала выполняется поиск Bluetooth устройства, потом network configuration/verification, после правильного подключения приложение показывает basic device information. Источник: [S03].

Для нашей задачи Bridge Mode - основной режим:

```text
K1 -> подключается к нашей Wi-Fi сети
MacBook -> в той же Wi-Fi сети
MacBook -> data/control client
```

Это лучше, чем phone hotspot, потому что телефон не должен быть частью runtime.

### 3.4. Quick Connect Mode

Документация говорит:

- Android LixelGO с firmware V3.2.1 использует Quick Connect Mode по умолчанию;
- New Quick Connect Mode требует firmware >= 3.0;
- iOS Quick Connect Mode используется по умолчанию с firmware V3.2.1 и LixelGO V1.3.0;
- для iPhone имя устройства используется как hotspot SSID и должно быть без пробелов/спецсимволов.

Источник: [S03].

Вывод: Quick Connect может иметь device-specific логику, но для исследовательского pilot лучше начинать с Bridge Mode/Direct Connect, где SSID/password явно задаются пользователем.

### 3.5. Что такое SSID/password в этом проекте

SSID - имя нашей Wi-Fi сети. Password - пароль нашей Wi-Fi сети.

Пример лабораторной сети:

```text
SSID: K1_LAB
Password: K1lab123456
Band: 5 GHz сначала, 2.4 GHz как fallback
Client isolation: off
DHCP: on
```

Вероятность, что в Bridge/Direct Mode нужен огромный заводской список `serial -> password`, низкая, потому что официальная схема прямо говорит: пользователь вводит hotspot name/password, а приложение передает их устройству.

При этом нельзя исключать app-layer token/session token для `data connection`. Это другая сущность, не Wi-Fi пароль.

## 4. Scanning Workflow и важные детали для CV

### 4.1. Time sync

Scanning Workflow говорит, что device time откалиброван на заводе, но после долгого хранения может дрейфовать; LixelGO по умолчанию синхронизирует время телефона с устройством, а также позволяет задавать время вручную. Источник: [S04].

Для realtime CV это важно:

- timestamps в project files могут зависеть от device time;
- custom клиент должен либо уметь sync time, либо записывать offset между Mac monotonic time и K1 device time;
- все captures должны иметь `session_start_wall_time`, `mac_monotonic_start`, `k1_reported_time`, если его удастся прочитать.

### 4.2. Mount Type включает Drone

Официальный Scanning Workflow перечисляет Mount Type: Handheld, Vehicle-Mounted, Drone, Backpack. LixelStudio читает mount type автоматически. Источник: [S04].

Для нашего проекта это две подсказки:

1. XGRIDS уже предусматривает drone-like сценарий.
2. Если стартовать скан кнопкой, надо проверить, какой mount type реально попадает в `project.json`.

Вопрос для эксперимента: автономный кнопочный старт использует last-used settings или default settings?

### 4.3. Static initialization 15 секунд

Официально: после старта скана LiDAR начинает работать, LED становится fast-flashing green, начинается static initialization countdown на 15 секунд; в это время устройство нельзя двигать. Источник: [S04].

Для стенда:

- все эксперименты делаются так: нажали Start, ждем 20 секунд неподвижно, только потом двигаем;
- для БПЛА: старт/инициализация на земле, потом движение;
- любые пакеты первых 15-20 секунд помечать как initialization phase.

### 4.4. Project file structure и значение каждого файла

Официальная структура проекта K1:

| Файл/папка | Официальное описание | Значение для нас |
|---|---|---|
| `xxx.xbin` | raw sensor data recorded by the device | offline raw fallback; не runtime target |
| `map.las` | point cloud output by the device in real time | главное доказательство, что realtime cloud pipeline есть внутри K1 |
| `control_points.csv` | control point info | проверка single-click events |
| `gnss.csv` | GNSS info when using RTK | потенциальный route/geo fallback |
| `poses.csv` | trajectory file recorded during scanning | offline pose ground truth для поиска live pose stream |
| `project.json` | device attributes and related information | настройки scan mode, firmware, mount, metadata |
| `model` | in-app model preview file | возможно связано с live preview/data chunks |
| `photo` | camera image at moment a control point is added | доказательство доступа к камере, но не continuous video |
| `preview_photo.jpg` | project preview image | preview fallback |
| `log` | scanning logs | источник протоколов, ошибок, IP/ports, daemon names |
| `external_data` | files for LixelStudio post-processing | не runtime target |

Источник: [S04].

Критическое замечание из официального мануала: direct point cloud data is downsampled; полный point cloud делается через LixelStudio. Источник: [S04].

Для CV на борту downsampled cloud может быть даже полезнее полного: меньше трафика, меньше latency, меньше CPU.

## 5. Что подтверждают LixelGO App Store / Google Play

### 5.1. Real-time point cloud data существует

App Store описание говорит, что LixelGO позволяет подключаться к XGRIDS LiDAR scanners, управлять устройствами, менять настройки и просматривать real-time point cloud data. Источник: [S05].

Google Play описание говорит про real-time scanner control, live data preview и device monitoring. Источник: [S06].

Это подтверждает, что live data path существует как продуктовая функция.

### 5.2. RGB point cloud rendering и camera hints

В App Store version history есть пункты:

- RGB point cloud rendering;
- scanning guidance & range indicator;
- real-time quality feedback;
- fixed issue where real-time point clouds were not displayed on some Samsung Exynos phones;
- fixed occasional camera loading failures;
- support for mount mode AIR Drone;
- external power status display for vehicle-mounted or airborne power supply.

Источник: [S05].

Интерпретация:

- приложение не просто получает final LAS;
- есть live render layer;
- есть RGB point cloud, возможно цвет уже интегрирован в cloud preview;
- `camera loading failures` может означать отдельный camera/preview component, но это не доказательство raw 360 video stream;
- AIR Drone и airborne power status полезны для нашей постановки, но не доказывают open API.

### 5.3. Риск шифрования

Google Play data safety указывает `Data is encrypted in transit`. Источник: [S06].

Это может означать:

- HTTPS/TLS для облака/аккаунта;
- TLS/QUIC для локального device data;
- app-layer encryption;
- общую декларацию магазина.

Вывод: в плане обязательно считать шифрование реальным риском. PCAP может показать endpoints, bitrate и session structure, но не payload.

## 6. Сторонний полевой гайд: связь теряется, запись продолжается

Гайд Alpine Reality Capture по LixelGO сообщает важную практическую деталь: если связь телефона со сканером потеряна, сканер продолжит recording, но real-time preview и app-контроль будут потеряны. Там же Bridge Mode описан как режим, где телефон и сканер находятся в одной Wi-Fi сети, а приложение общается со сканером по этой shared network. Источник: [S07].

Это не официальный K1 manual, но очень хорошо согласуется с официальной архитектурой:

```text
запись проекта идет на K1
телефон - control/preview client
при потере клиента recording остается
preview/control теряются
```

Для runtime без LixelGO это значит:

- нельзя рассчитывать на reconnect LixelGO в качестве надежной архитектуры;
- нужен собственный постоянно работающий client на борту;
- кнопочный старт + локальная запись остаются fallback даже если live stream упал.

## 7. Железо K1 по FCC / OSINT

### 7.1. FCC ID и радиодиапазоны

FCC ID: `2A9PI-K1`. FCC page идентифицирует устройство как SHENZHEN XGRIDS-INNOVATION CO., LTD - K1 и показывает одобренные частотные диапазоны: 5 GHz Wi-Fi, 2.4 GHz Wi-Fi, Bluetooth/BLE диапазоны. Источник: [S08].

### 7.2. Wi-Fi возможности

FCC 5 GHz Wi-Fi report для LixelKity K1 указывает:

- U-NII-1: 5180-5240 MHz;
- U-NII-3: 5745-5825 MHz;
- 802.11a/n/ac;
- 256QAM для 802.11ac;
- 20/40/80 MHz каналы.

Источник: [S09].

2.4 GHz Wi-Fi report указывает 802.11b/g/n, HT20/HT40 и bit rate up to 150 Mbps для 802.11n. Источник: [S10].

Вывод: Wi-Fi - единственный реалистичный внешний канал для live cloud/video. Bluetooth для этого узкий.

### 7.3. Bluetooth/BLE возможности

BT report указывает Bluetooth 5.0 BR+EDR, 79 channels, 1/2/3 Mbps modulation rates. Источник: [S11].

BLE report указывает Bluetooth 5.0 BLE, 40 channels, 1/2 Mbps transmitter bit rate. Источник: [S12].

Вывод: Bluetooth/BLE подходит для discovery/provisioning/status, но не для тяжелого point cloud/camera stream.

### 7.4. Батарея и питание

FCC Wi-Fi/BT/BLE reports указывают батарею `DC 14.4V 1900mAh 27.36Wh` и charger output `16.8V 1.2A`. Источники: [S09], [S11], [S12].

Для пилота:

- не проектировать внешнее питание без отдельного power-аудита;
- в стенде использовать штатную батарею;
- записывать battery status, если он доступен через data/status connection.

### 7.5. Внутренние фото: compute и radio

FCC internal photos показывают:

- несколько отдельных PCB;
- модуль/плату с маркировкой Rockchip RK3588S;
- Wi-Fi/BT модуль Realtek RTL8822CE;
- отдельные антенны WLAN/RLAN и WLAN/RLAN/BT;
- коннекторы/шлейфы, что говорит о модульной внутренней архитектуре.

Источник: [S13].

Инженерный вывод:

- внутри есть Linux-class compute, а не только MCU;
- realtime mapping, вероятно, считается внутри устройства;
- телефон, скорее всего, получает уже готовый preview/data, а не сам считает SLAM;
- при провале black-box подхода потенциальный fallback - доступ к внутреннему Linux/RK3588S, но это вне первого этапа.

## 8. Главное архитектурное предположение

На основе мануалов, приложений и FCC складывается такая модель:

```text
BLE layer:
  - advertise / discovery
  - connect
  - network provisioning
  - possibly status notifications
  - possibly activation/pair token

Wi-Fi layer:
  - network connection
  - data connection handshake
  - status/control
  - realtime preview / point cloud / maybe pose
  - maybe camera/preview data

Local storage:
  - .xbin raw sensor data
  - map.las realtime output, downsampled
  - poses.csv trajectory
  - project.json metadata
  - model preview
  - photo/control-point images
  - logs
```

Это не доказанная структура протокола. Это рабочая модель, которую надо подтвердить экспериментами.

## 9. Где именно скрывается ценность для нашего решения

### 9.1. Не в LAS и не в Gaussian splats

LAS/LCC/3DGS - это важный offline/post-processing мир, но для realtime CV он вторичен. Нас интересуют не файлы после обработки, а live data path.

### 9.2. Внутренний realtime point cloud pipeline

`map.las` описан как point cloud output by the device in real time. Это означает, что внутри K1 уже формируется realtime cloud. Даже если он downsampled, он может быть идеален для onboard CV.

### 9.3. Trajectory / poses

`poses.csv` после скана - trajectory file recorded during scanning. Это почти точно производная внутреннего SLAM/odometry. Нам нужно проверить, идет ли pose live в data session. Если live pose не идет, `poses.csv` использовать как offline ground truth при reverse engineering.

### 9.4. Камеры

Камеры подтверждены официально как `48 MP x2 panoramic vision`. Но доступность live raw/preview frames наружу не подтверждена. В документации есть `photo` как camera image at the moment a control point is added, а не continuous stream. LixelGO version history упоминает RGB point cloud rendering и camera loading fixes, что дает надежду на camera/preview component, но это гипотеза.

Поэтому камера - главный риск проекта.

## 10. Вероятностная матрица доступности данных

| Данные | Вероятность live-доступа снаружи | Уверенность | Почему |
|---|---:|---:|---|
| Device status: battery/storage/firmware/scan state | высокая | высокая | LixelGO показывает device info/status; есть data connection status |
| Realtime point cloud preview | высокая | высокая | App Store прямо говорит real-time point cloud; `map.las` - realtime output |
| Realtime RGB/colorized point cloud | средняя/высокая | средняя | App Store говорит RGB point cloud rendering; но формат неизвестен |
| Live pose/trajectory | средняя | средняя | `poses.csv` существует; app может иметь route/status, но live export не доказан |
| Live raw 360 camera frames | низкая/средняя | низкая | камеры есть; camera loading fixes есть; но docs не обещают video stream наружу |
| Live rendered preview/model chunks | средняя | средняя | `model` in-app preview file; LixelGO live preview; может быть не raw frames |
| Full raw LiDAR stream | низкая/средняя | низкая | наружу вероятнее идет processed/downsampled cloud, raw в `.xbin` |
| Full raw sensor `.xbin` live stream | низкая | низкая | docs говорят `.xbin` recorded by device, не live external stream |

## 11. Почему Bluetooth - не канал облака

Bluetooth Classic BR/EDR у K1 по FCC - максимум 1/2/3 Mbps; BLE - 1/2 Mbps. Даже сильно downsampled облако и тем более камеры требуют больше. Wi-Fi у K1 поддерживает 802.11ac 5 GHz и 802.11n 2.4 GHz.

Следовательно:

```text
Bluetooth = pairing/provisioning/control/status
Wi-Fi = data/control/live preview
```

Именно поэтому первым слоем разработки должен быть BLE discovery/GATT/provisioning, а главным слоем reverse engineering - Wi-Fi data session.

## 12. Лабораторный стенд на MacBook без Linux

### 12.1. Доступное железо

Есть:

- K1;
- MacBook;
- Wi-Fi роутер;
- любая Wi-Fi сеть;
- Bluetooth на Mac.

Нет:

- Linux как отдельный стенд;
- OpenWrt/tcpdump на роутере, если текущий роутер обычный.

### 12.2. Рекомендуемая лабораторная сеть

```text
SSID: K1_LAB
Password: K1lab123456
Wi-Fi band: 5 GHz first, 2.4 GHz fallback
Security: WPA2-Personal or WPA2/WPA3 mixed
Client isolation: OFF
DHCP: ON
Multicast/mDNS: allowed
Internet: optional for local tests
```

Пароль и SSID специально простые: официальная документация рекомендует keep hotspot name/password as simple as possible.

### 12.3. Важное ограничение обычного роутера

Если K1 и телефон с LixelGO общаются через обычный роутер, Mac как третий Wi-Fi клиент обычно не увидит unicast-трафик между телефоном и K1. Он увидит broadcast/multicast, ARP, DNS/mDNS, но не полный TCP/UDP payload чужой сессии.

Для baseline-захвата LixelGO сессии нужны варианты:

| Вариант | Сложность | Надежность | Комментарий |
|---|---:|---:|---|
| Mac как AP через Internet Sharing | средняя | средняя | можно пробовать tcpdump на bridge/interface |
| Роутер с packet capture | низкая/средняя | высокая | если роутер умеет capture/port mirror |
| OpenWrt/travel router | средняя | высокая | лучший вариант, но это Linux/router |
| Wi-Fi monitor mode | высокая | низкая/средняя | WPA расшифровка и modern Wi-Fi нюансы |
| Android HCI log для BLE + Mac direct session для Wi-Fi | средняя | высокая для BLE, средняя для Wi-Fi | pragmatic route |

Для первого этапа можно начинать без полного phone<->K1 sniffing: сначала снять BLE/GATT с Mac, затем пробовать Mac как собственный data client.

### 12.4. macOS ограничения BLE

Bleak на macOS работает через CoreBluetooth/pyobjc. Важно:

- macOS не использует обычный BLE MAC address как Linux; CoreBluetooth дает UUID, уникальный для пары Mac<->device;
- explicit pairing в Bleak на macOS не реализован; macOS сама покажет prompt при доступе к защищенной characteristic;
- нужны Bluetooth permissions;
- passive scanning не поддерживается.

Источник: [S14].

Это означает: в документации и логах нашего инструмента нельзя полагаться на привычный MAC как стабильный ID. Нужно сохранять both: `macos_uuid`, advertised name, manufacturer data, service UUIDs.

## 13. macOS инструменты

### 13.1. Установка базового инструментария

```bash
xcode-select --install

brew install python@3.12
brew install wireshark
brew install nmap
brew install arp-scan
brew install jq
brew install ffmpeg
brew install socat
brew install cmake pkg-config
```

Wireshark на macOS требует ChmodBPF launch daemon для packet capture. Источник: [S15].

Apple указывает PacketLogger в Additional Tools for Xcode как инструмент для Bluetooth debugging. Источник: [S16].

Nmap официально поддерживает macOS. Источник: [S17].

### 13.2. Python зависимости

```bash
python3.12 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip

pip install bleak typer rich pydantic pydantic-settings loguru
pip install pyshark scapy construct kaitaistruct bitstruct
pip install numpy pandas opencv-python pillow open3d
pip install zeroconf ifaddr psutil
pip install pytest pytest-asyncio ruff mypy
```

Зачем:

| Пакет | Роль |
|---|---|
| `bleak` | BLE scan/connect/GATT/read/notify/write |
| `typer`, `rich` | CLI и удобный вывод |
| `pydantic` | схемы конфигураций/артефактов |
| `pyshark` | анализ PCAP через tshark/Wireshark dissectors |
| `scapy` | низкоуровневый PCAP/payload анализ |
| `construct` | бинарные структуры |
| `numpy` | numeric/probe point cloud |
| `opencv-python` | video/frame probe |
| `open3d` | point cloud visualization/export |
| `zeroconf` | mDNS/Bonjour discovery |

## 14. Устройство как state machine

### 14.1. Физический state machine

```text
POWER_OFF
  hold 4s
  -> BOOTING / slow blue ~30s
  -> STANDBY / solid green

STANDBY
  double-click
  -> STARTING_SCAN / fast green
  -> STATIC_INIT / 15 sec
  -> SCANNING / slow green

SCANNING
  single-click
  -> CONTROL_POINT_MARK

SCANNING
  double-click
  -> STOPPING / fast green
  -> STANDBY / solid green

STANDBY
  single-click + white + single-click
  -> USB_MODE / solid blue
```

### 14.2. Communication state machine

```text
BLE_ADVERTISING
  -> BLE_CONNECTED
  -> WIFI_CONFIG_SENT
  -> WIFI_ASSOCIATED
  -> IP_ASSIGNED
  -> NETWORK_CONNECTION_SUCCESS
  -> DATA_CONNECTION_HANDSHAKE
  -> DATA_CONNECTION_SUCCESS
  -> STREAM_SUBSCRIBED
```

Официальный manual разделяет `network connection` и `data connection`, поэтому их надо считать разными состояниями.

## 15. BLE provisioning: что именно надо восстановить

### 15.1. Термины

| Термин | Значение |
|---|---|
| SSID | имя Wi-Fi сети, например `K1_LAB` |
| Wi-Fi password / PSK | пароль Wi-Fi сети |
| BLE address / macOS UUID | идентификатор BLE device на Mac |
| Service UUID | идентификатор GATT-сервиса |
| Characteristic UUID | идентификатор поля read/write/notify |
| CCCD / 0x2902 | descriptor для включения notifications/indications |
| ATT handle | низкоуровневый номер атрибута |

### 15.2. Что ищем

Нужно найти:

```text
K1 BLE advertised name
manufacturer data
service UUIDs
GATT services
writable characteristic для Wi-Fi config
notify characteristic для status/progress
format provisioning payload
```

### 15.3. Нельзя делать

Нельзя слать случайные write payloads в неизвестные характеристики. Любой write только после того, как:

- мы сняли эталонную LixelGO сессию;
- знаем UUID/handle;
- знаем payload format;
- команда явно включена флагом `--i-understand-this-writes-to-device`.

### 15.4. Как восстановить BLE provisioning без гаданий

Сценарий:

```text
1. Настроить сеть A:
   SSID = K1_LAB_A
   PASS = AAAAAAAA11
   пройти Bridge/Direct Connect через LixelGO
   сохранить BLE log

2. Настроить сеть B:
   SSID = K1_LAB_B
   PASS = BBBBBBBB22
   пройти Bridge/Direct Connect через LixelGO
   сохранить BLE log

3. Сравнить ATT Write payloads.

4. Найти байты, где меняются SSID/password.

5. Определить формат:
   - ASCII/JSON
   - TLV
   - protobuf-like
   - encrypted blob
```

Если SSID/password видны в plain text, provisioning можно сделать быстро. Если это encrypted blob, provisioning может требовать app-layer key/token.

### 15.5. Сценарий, где BLE provisioning вообще не нужен в runtime

Если K1 запоминает Wi-Fi profile, то можно один раз настроить его через LixelGO на `K1_LAB`, а потом в runtime:

```text
Mac/router поднимает K1_LAB
K1 включается
K1 сам подключается к знакомой сети
Mac находит IP
Mac открывает data session
```

Это важный shortcut: BLE provisioning нужен для полного replacement, но не обязательно для первого runtime-пилота.

## 16. Wi-Fi data session: где живут нужные данные

### 16.1. Что должен сделать Wi-Fi клиент

После появления K1 в сети:

```text
1. Discover IP.
2. Enumerate services/ports.
3. Observe idle traffic.
4. Establish or imitate data connection.
5. Subscribe to streams.
6. Cache raw traffic.
7. Decode candidate streams.
```

### 16.2. Что искать по портам

```text
80 / 8080 / 8000 / 8888   HTTP/WebSocket/API
443 / 8443                HTTPS/TLS
50051                     gRPC
554 / 8554                RTSP
1883 / 8883               MQTT/MQTTS
5353                      mDNS
1900                      SSDP
22                        SSH, только если открыт, без bruteforce
5555                      ADB/Android debug, только если открыт, без abuse
custom UDP high ports     likely realtime stream
```

### 16.3. Фингерпринт протоколов

| Наблюдение | Возможное значение |
|---|---|
| Большой UDP поток K1 -> client | realtime point cloud/video chunks |
| TCP/WebSocket binary frames | app-level stream, часто удобно парсить |
| HTTP/2/gRPC | protobuf/streaming API |
| TLS | payload скрыт, но видны endpoints/bitrates/certs |
| QUIC/UDP encrypted | сложнее, но fingerprint возможен |
| RTSP/RTP | video/camera/preview stream |
| Малый heartbeat | status/control только |

### 16.4. Что искать для point cloud

Признаки point cloud:

- поток появляется/растет только во время scanning mode;
- packet rate стабильный;
- payload binary;
- stride похож на 12/16/20/24/32 bytes per point;
- есть координаты float32 little-endian или scaled integers;
- диапазоны координат похожи на метры;
- при движении сцена меняется в decoded candidate;
- при закрытии LiDAR/стене перед сканером меняется распределение.

### 16.5. Что искать для camera/video

Признаки видео/камер:

```text
JPEG: FF D8 FF
PNG: 89 50 4E 47
H264 Annex B: 00 00 00 01
H265/HEVC NAL
MP4 boxes: ftyp / moof / mdat
MJPEG over HTTP
RTSP DESCRIBE / SETUP / PLAY
RTP packet streams
WebSocket binary frames
protobuf chunks with large compressed images
```

Специальный эксперимент для камер:

```text
1. Запустить capture.
2. K1 стоит неподвижно.
3. Закрыть одну камеру черной тканью на 10 секунд.
4. Открыть.
5. Закрыть вторую камеру.
6. Направить яркий источник/цветной паттерн.
7. Поставить control point single-click.
8. Сравнить payload bitrate/signature/frame candidates.
```

Если никакой stream не реагирует на визуальную сцену, возможно наружу идет только already-colorized point cloud или rendered preview, а не camera frames.

## 17. Полная программа экспериментов

### 17.1. E0 - инвентаризация устройства

Цель: зафиксировать baseline до любых действий.

Действия:

```text
1. Модель: LixelKity K1.
2. Серийник / last 4 digits.
3. Firmware version в LixelGO.
4. LixelGO version.
5. Активирован / не активирован.
6. Состояние батареи.
7. Storage free/used.
8. Последний способ подключения: Quick/Direct/Bridge.
```

Через USB mode после короткого тестового скана:

```bash
find /Volumes -maxdepth 3 -type d | sort
find /Volumes/<K1_VOLUME>/<PROJECT> -maxdepth 4 -type f | sort > project_tree.txt
find /Volumes/<K1_VOLUME>/<PROJECT> -maxdepth 4 -type f -exec ls -lh {} \; > project_files.txt
```

Скопировать:

```text
project.json
poses.csv
map.las
log/*
preview_photo.jpg
photo/*
model/*
```

Критерий успеха: есть baseline-папка проекта и файл `project_tree.txt`.

### 17.2. E1 - кнопочный автономный скан без телефона

Цель: доказать автономный runtime без LixelGO.

Шаги:

```text
1. Выключить LixelGO.
2. Включить K1.
3. Дождаться solid green.
4. Double-click.
5. Ждать 20 секунд.
6. 60 секунд двигать по простой сцене.
7. Double-click stop.
8. Дождаться solid green.
9. Перейти в USB mode.
10. Проверить проект.
```

Фиксировать:

- LED timings;
- появление проекта;
- наличие `map.las`, `poses.csv`, `project.json`, `log`;
- settings в `project.json`.

### 17.3. E2 - Bridge Mode через LixelGO на нашу сеть

Цель: настроить K1 на `K1_LAB` и понять, запоминает ли он сеть.

Шаги:

```text
1. Поднять SSID K1_LAB.
2. Телефон/Mac подключить к K1_LAB.
3. В LixelGO выбрать Bridge Mode.
4. Через Bluetooth найти K1.
5. Ввести SSID/password.
6. Дождаться network connection success.
7. Дождаться data connection success.
8. Перезапустить K1.
9. Проверить, подключается ли K1 к K1_LAB автоматически.
```

Критерий успеха: K1 появляется в DHCP/ARP без повторного LixelGO provisioning.

### 17.4. E3 - BLE scan/GATT dump на Mac

Цель: получить карту BLE.

Команды будущего инструмента:

```bash
k1link ble scan --duration 30 --out captures/e3_ble_scan.json
k1link ble gatt-dump --device <MACOS_UUID> --out captures/e3_gatt.json
k1link ble listen --device <MACOS_UUID> --out captures/e3_notifications.jsonl
```

Сохранять:

- advertised name;
- UUIDs;
- manufacturer data;
- services/chars/properties/descriptors;
- read results для read-only chars;
- notifications.

### 17.5. E4 - BLE provisioning diff

Цель: определить characteristic/payload для Wi-Fi config.

Нужно две или больше LixelGO-сессии с разными SSID/PASS. Captures сравниваются.

Артефакты:

```text
ble_session_A.snoop
ble_session_B.snoop
att_writes_A.jsonl
att_writes_B.jsonl
provisioning_diff.md
```

Критерий успеха: найден UUID/handle и payload pattern.

### 17.6. E5 - Wi-Fi discovery

Команды:

```bash
arp -a
sudo arp-scan --localnet
nmap -Pn -sV -p- <K1_IP>
sudo nmap -Pn -sU --top-ports 200 <K1_IP>
dns-sd -B _services._dns-sd._udp local
```

Артефакты:

```text
net_discover.json
ports_tcp.txt
ports_udp.txt
mdns.txt
```

### 17.7. E6 - idle capture

```bash
sudo tcpdump -i en0 -s 0 -B 524288 -w captures/e6_idle.pcap 'host <K1_IP>'
```

Сценарий: K1 включен, standby, не сканирует.

Цель: baseline heartbeat/status.

### 17.8. E7 - scan by button capture

```bash
sudo tcpdump -i en0 -s 0 -B 524288 -w captures/e7_scan_button.pcap 'host <K1_IP>'
```

Шаги:

```text
1. K1 standby.
2. Start capture.
3. Double-click start.
4. 20 sec static init.
5. 60 sec slow movement.
6. 20 sec fast movement.
7. 20 sec stationary.
8. Double-click stop.
9. Stop capture.
```

Критерий: потоки, появляющиеся/увеличивающиеся в scanning mode.

### 17.9. E8 - scan by app capture

Цель: сравнить app-start и button-start.

Шаги:

```text
1. Start scan via LixelGO.
2. Capture network.
3. Stop via LixelGO.
4. Compare with E7.
```

Если app-start включает дополнительные streams, а button-start нет, значит data subscription зависит от LixelGO.

### 17.10. E9 - reconnect behavior

Цель: проверить, можно ли подключиться к уже идущему скану.

Шаги:

```text
1. Start scan button/app.
2. Убить LixelGO / выключить phone Wi-Fi.
3. K1 продолжает scanning.
4. Попробовать reconnect.
5. Смотреть: возвращается ли preview/data connection.
```

Артефакт: `reconnect_notes.md`.

### 17.11. E10 - camera perturbation test

Цель: доказать или опровергнуть наличие live camera stream.

Шаги:

```text
1. Capture во время scan.
2. Неподвижная сцена 10 сек.
3. Закрыть camera A 10 сек.
4. Открыть.
5. Закрыть camera B 10 сек.
6. Цветной паттерн перед камерой.
7. Single-click control point.
8. Сравнить traffic и decoded video candidates.
```

Критерий: video/image stream должен реагировать на визуальные изменения.

### 17.12. E11 - point cloud perturbation test

Цель: найти point cloud stream.

Шаги:

```text
1. Сцена: плоская стена на 2-5 м.
2. Захват 30 сек.
3. Быстро повернуть K1 на другой объект.
4. Пройти мимо угла/коридора.
5. Поставить крупный объект перед LiDAR.
6. Сравнить candidate decoded points.
```

Критерий: candidate point decoder показывает изменяющуюся геометрию.

### 17.13. E12 - после скана сопоставить live capture с файлами

Цель: понять, что было в live stream.

После E7/E8 скачать проект и сравнить:

```text
map.las size / point count
poses.csv count / timestamps
project.json settings
log messages
model preview timestamps
photo/control point timestamps
```

Идея: timestamps/packet counts в PCAP сопоставить с `poses.csv` и `map.las`.

## 18. Анализ PCAP: методика

### 18.1. Первичная сводка

```bash
tshark -r captures/session.pcap -q -z conv,tcp -z conv,udp
```

Что смотреть:

- biggest flows;
- flow start/stop relative to scan start;
- packets per second;
- average payload size;
- direction: K1 -> client или client -> K1.

### 18.2. Протокольные фильтры

```bash
tshark -r captures/session.pcap -Y "dns || mdns || ssdp || http || websocket || http2 || grpc || rtsp || rtp || tls || quic"

tshark -r captures/session.pcap -Y "udp && frame.len > 600"

tshark -r captures/session.pcap -Y "tcp.len > 1000"
```

### 18.3. Payload extraction

Для каждого крупного flow:

```text
flow_id = proto + src_ip + src_port + dst_ip + dst_port
raw_payloads/flow_<id>.bin
raw_payloads/flow_<id>.jsonl  # packet metadata
```

Metadata per packet:

```json
{
  "ts_epoch": 0.0,
  "relative_ts": 0.0,
  "proto": "udp",
  "src": "192.168.1.10:50000",
  "dst": "192.168.1.20:60000",
  "payload_len": 1024,
  "sha1_16": "...",
  "first16_hex": "..."
}
```

## 19. Point cloud reverse-probe

### 19.1. Float32 little-endian probe

Алгоритм:

```text
for each flow:
  concatenate payloads or process packet-wise
  for offset in 0..128:
    for stride in [12, 16, 20, 24, 28, 32, 40, 48]:
      parse x,y,z as float32 little-endian
      score:
        valid finite ratio
        coordinate range ratio [-200,200]
        spatial variance
        non-zero points
        temporal continuity
      save top candidates
```

### 19.2. Scaled integer probe

Если float не сработал:

```text
try int16/int32 little-endian
scale candidates: 0.001, 0.005, 0.01, 0.1
look for coordinate bounds and structure
```

### 19.3. Packet header detection

Искать:

- monotonic sequence numbers;
- timestamps;
- packet type;
- chunk length;
- CRC/checksum;
- frame ID.

Метод:

```text
compare first 64 bytes across packets
bytes with monotonic increments -> seq/time
bytes constant -> magic/version/type
bytes equal payload len -> length field
```

### 19.4. Validation через физический эксперимент

Кандидат считается реальным point cloud, если:

- decoded точки визуализируются как облако;
- движение/стена/угол влияют на геометрию;
- packet rate совпадает с scanning phase;
- количество точек/сек логически похоже на downsampled preview;
- после скана `map.las` похож по масштабу/координатам.

## 20. Camera/video reverse-probe

### 20.1. Сигнатуры

```text
JPEG start: FF D8 FF
JPEG end: FF D9
PNG: 89 50 4E 47 0D 0A 1A 0A
H264 Annex B: 00 00 00 01 or 00 00 01
H265: similar NAL patterns
MP4/fragmented: ftyp, moof, mdat
RTSP: OPTIONS/DESCRIBE/SETUP/PLAY
RTP: sequence/timestamp/SSRC fields
MJPEG HTTP: multipart/x-mixed-replace
```

### 20.2. Сжатый custom frame

Если нет сигнатур:

- payload может быть protobuf with compressed image bytes;
- может быть raw YUV/RGB chunks;
- может быть rendered preview tiles;
- может быть RGB point cloud, а не image frames.

Нужны perturbation tests: закрытие камер, яркий цветной паттерн, single-click control point.

### 20.3. Условия признания camera stream найденным

Camera stream найден, если:

- есть декодируемые frames;
- или есть устойчивые frame boundaries и payload меняется при визуальной сцене;
- или есть protocol names/endpoints в app/traffic: `camera`, `preview`, `image`, `panorama`, `rgb`, `isp`;
- можно извлечь хотя бы 1 кадр в PNG/JPEG/NPY.

## 21. Проект `k1-mac-link`: полное ТЗ

### 21.1. Назначение

`k1-mac-link` - macOS CLI tool для исследования и постепенной замены LixelGO в части локального подключения к K1.

Он должен:

- сканировать BLE;
- дампить GATT;
- безопасно слушать BLE notifications;
- воспроизводить BLE provisioning только после определения payload;
- обнаруживать K1 в Wi-Fi сети;
- запускать tcpdump/tshark captures;
- суммировать flows;
- извлекать raw payloads;
- искать point cloud candidates;
- искать camera/video candidates;
- писать все raw данные на SSD;
- не терять raw captures при failure decode.

### 21.2. Структура репозитория

```text
k1-mac-link/
  README.md
  pyproject.toml
  docs/
    00_scope.md
    01_k1_manual_facts.md
    02_lab_setup_macos.md
    03_experiments.md
    04_protocol_notes.md
    05_risks.md
  src/k1link/
    __init__.py
    cli.py
    config.py
    logging.py
    artifacts.py
    ble/
      scanner.py
      gatt_dump.py
      listener.py
      provisioner.py
      protocol_guess.py
      macos_notes.py
    net/
      discover.py
      ports.py
      capture.py
      tshark.py
      session.py
      mdns.py
    analysis/
      pcap_summary.py
      flow_classifier.py
      payload_extract.py
      payload_fingerprint.py
      protocol_diff.py
      pointcloud_probe.py
      video_probe.py
      timeline.py
    decode/
      pointcloud.py
      pose.py
      video.py
      status.py
      unknown.py
    cache/
      writer.py
      manifest.py
      raw_stream.py
      metadata.py
    export/
      ply.py
      pcd.py
      npz.py
      frames.py
  tests/
    test_payload_fingerprint.py
    test_pointcloud_probe.py
    test_video_signatures.py
  scripts/
    setup_macos.sh
    collect_session.sh
```

### 21.3. CLI команды

```bash
k1link doctor

k1link ble scan \
  --duration 30 \
  --out captures/ble_scan.json

k1link ble gatt-dump \
  --device <macos_uuid> \
  --out captures/gatt_dump.json

k1link ble listen \
  --device <macos_uuid> \
  --duration 120 \
  --out captures/ble_notifications.jsonl

k1link ble write-known \
  --device <macos_uuid> \
  --profile wifi-provision-v1 \
  --ssid K1_LAB \
  --password K1lab123456 \
  --i-understand-this-writes-to-device

k1link net discover \
  --subnet 192.168.1.0/24 \
  --out captures/net_discover.json

k1link net ports \
  --ip <K1_IP> \
  --out captures/ports.json

k1link net capture \
  --iface en0 \
  --host <K1_IP> \
  --out captures/session.pcap

k1link analyze summarize \
  --pcap captures/session.pcap \
  --out captures/session_summary.json

k1link analyze extract-flows \
  --pcap captures/session.pcap \
  --out-dir captures/flows

k1link analyze fingerprint \
  --flows captures/flows \
  --out captures/fingerprint.json

k1link analyze pointcloud-probe \
  --flows captures/flows \
  --out-dir captures/pointcloud_candidates

k1link analyze video-probe \
  --flows captures/flows \
  --out-dir captures/video_candidates

k1link run-pilot \
  --ssid K1_LAB \
  --password K1lab123456 \
  --cache /Volumes/K1SSD/k1-cache
```

### 21.4. `doctor`

Проверяет:

```text
macOS version
Python version
Bluetooth permission / bleak scan works
Wireshark/tshark installed
tcpdump available
ChmodBPF installed or capture permission available
nmap installed
ffmpeg installed
write permission to cache path
```

### 21.5. BLE scanner output schema

```json
{
  "session_id": "20260715-120000",
  "adapter": "CoreBluetooth",
  "devices": [
    {
      "macos_uuid": "...",
      "name": "Lixel-1234",
      "rssi": -55,
      "service_uuids": [],
      "manufacturer_data_hex": {},
      "service_data_hex": {},
      "timestamp": "..."
    }
  ]
}
```

### 21.6. GATT dump output schema

```json
{
  "device": {
    "macos_uuid": "...",
    "name": "..."
  },
  "services": [
    {
      "uuid": "...",
      "description": "...",
      "characteristics": [
        {
          "uuid": "...",
          "handle": 1,
          "properties": ["read", "write", "notify"],
          "descriptors": [
            {"uuid": "00002902-0000-1000-8000-00805f9b34fb", "handle": 2}
          ],
          "read_result_hex": "...",
          "read_error": null
        }
      ]
    }
  ]
}
```

### 21.7. Flow summary schema

```json
{
  "flow_id": "udp_192.168.1.10_50000_192.168.1.20_60000",
  "proto": "udp",
  "src": "192.168.1.10:50000",
  "dst": "192.168.1.20:60000",
  "packets": 12345,
  "bytes": 987654321,
  "first_ts": 0.0,
  "last_ts": 120.0,
  "duration": 120.0,
  "pps": 102.8,
  "bps": 65800000,
  "avg_payload_len": 980,
  "direction_guess": "k1_to_client",
  "protocol_guess": ["custom_binary", "pointcloud_candidate"]
}
```

### 21.8. Session manifest

Каждый эксперимент должен создавать `session_manifest.json`:

```json
{
  "session_id": "E7_20260715_120000",
  "experiment": "scan_button_capture",
  "k1_model": "LixelKity K1",
  "k1_firmware": "unknown",
  "lixelgo_version": "not_used",
  "network": {
    "ssid": "K1_LAB",
    "mac_iface": "en0",
    "k1_ip": "192.168.1.50"
  },
  "timeline": [
    {"t": 0, "event": "capture_start"},
    {"t": 5, "event": "button_double_click_start"},
    {"t": 25, "event": "static_init_expected_done"},
    {"t": 90, "event": "button_double_click_stop"},
    {"t": 110, "event": "capture_stop"}
  ],
  "artifacts": [
    "session.pcap",
    "flows.json",
    "pointcloud_candidates/candidate_001.ply"
  ]
}
```

## 22. Safety policy для софта

### 22.1. Безопасные операции по умолчанию

Разрешены по умолчанию:

- BLE scan;
- GATT service discovery;
- read readable characteristics;
- subscribe notifications;
- network scan собственному IP/subnet;
- tcpdump capture;
- packet analysis;
- raw cache.

### 22.2. Ограниченные операции

BLE writes, TCP/UDP packet sending, provisioning commands - только с явным флагом:

```bash
--i-understand-this-writes-to-device
```

### 22.3. Запрещено в v1

- random write fuzzing;
- brute force passwords/tokens;
- firmware upload;
- deletion/modification of K1 files;
- SSH/ADB login guessing;
- exploit attempts.

## 23. Реализация BLE модуля

### 23.1. `ble scan`

Требования:

- async scan через Bleak;
- показывать все devices;
- выделять candidates by name: `Lixel`, `K1`, `XGRIDS`, `Lixel-XXXX`;
- сохранять advertisements;
- учитывать macOS UUID вместо MAC.

### 23.2. `ble gatt-dump`

Требования:

- connect;
- enumerate services;
- enumerate characteristics/properties/descriptors;
- читать only read characteristics;
- не писать;
- timeout минимум 30-60 секунд, потому что macOS может показывать permission/auth prompts;
- JSON export.

### 23.3. `ble listen`

Требования:

- включить notifications на всех notify/indicate characteristics по очереди или выбранных;
- писать JSONL:

```json
{"ts": 0.0, "char_uuid": "...", "data_hex": "...", "len": 20}
```

### 23.4. `ble write-known`

Требования:

- не реализовывать до появления documented encoder;
- поддержать profiles:
  - `wifi-provision-v1-json`;
  - `wifi-provision-v1-tlv`;
  - `wifi-provision-v1-protobuf`;
- profile активируется только после ручного внесения UUID/format в config.

## 24. Реализация Wi-Fi discovery/capture

### 24.1. `net discover`

Методы:

- ARP table;
- arp-scan;
- mDNS/zeroconf;
- optional ping sweep;
- DHCP lease file если доступен.

Кандидаты K1:

- vendor OUI if visible;
- hostname containing `lixel`, `xgrids`, `k1`;
- device that appears when K1 is powered and disappears when off;
- IP involved in LixelGO traffic.

### 24.2. `net ports`

Использовать nmap wrapper:

```bash
nmap -Pn -sV -p- <K1_IP>
sudo nmap -Pn -sU --top-ports 200 <K1_IP>
```

Результат парсить в JSON.

### 24.3. `net capture`

Wrapper над tcpdump:

```bash
sudo tcpdump -i <iface> -s 0 -B 524288 -w <out.pcap> 'host <K1_IP>'
```

Требования:

- правильная обработка Ctrl+C;
- писать manifest;
- опционально писать timeline events вручную через клавиатуру:
  - `s` start scan;
  - `i` init done;
  - `m` moving;
  - `c` camera cover;
  - `p` control point;
  - `x` stop scan.

## 25. Реализация анализатора потоков

### 25.1. Flow classifier

Признаки:

- protocol;
- src/dst;
- port;
- packet count;
- byte count;
- pps/bps;
- payload length histogram;
- entropy;
- first bytes histogram;
- scanning phase correlation.

### 25.2. Protocol fingerprint

Ищет:

- ASCII strings;
- JSON;
- HTTP headers;
- protobuf-like fields;
- TLS handshake;
- QUIC long header;
- RTSP;
- RTP;
- image/video signatures;
- float/int point patterns.

### 25.3. Timeline correlation

Для каждого flow:

```text
bytes/sec over time
packets/sec over time
payload_len over time
correlation with events:
  capture_start
  scan_start
  static_init_done
  movement
  camera_cover
  control_point
  scan_stop
```

Flow, который живет только во время scan, получает высокий priority.

## 26. Реализация decoders/probes

### 26.1. PointCloudProbe

Выход:

```text
pointcloud_candidates/
  candidate_001.json
  candidate_001.ply
  candidate_001.npz
  candidate_001_preview.png
```

Скоринг:

```text
finite_ratio
range_score
variance_score
temporal_score
packet_alignment_score
visual_score_manual
```

### 26.2. VideoProbe

Выход:

```text
video_candidates/
  candidate_001.json
  candidate_001.raw
  frames/
    frame_0001.jpg
```

Пробовать:

- ffmpeg decode;
- OpenCV VideoCapture;
- JPEG extraction;
- H264 Annex B extraction;
- RTP depayload if ports/protocol match.

### 26.3. PoseProbe

Искать:

- 3 floats position + 4 floats quaternion;
- 4x4 transform matrices;
- euler angles;
- timestamps;
- repeated packets with smooth temporal evolution;
- values comparable to `poses.csv` after scan.

## 27. Файловая структура кеша

На SSD каждая сессия:

```text
/Volumes/K1SSD/k1-cache/
  2026-07-15_E7_scan_button/
    session_manifest.json
    notes.md
    captures/
      ble_scan.json
      gatt_dump.json
      session.pcap
    flows/
      flows.json
      flow_001.bin
      flow_001.jsonl
    analysis/
      pcap_summary.json
      fingerprints.json
      timeline.csv
    decoded/
      pointcloud/
      video/
      pose/
    k1_project_copy/
      project_tree.txt
      project.json
      poses.csv
      map.las
      log/
```

Правило: raw всегда сохраняется; decoded failure не должен терять capture.

## 28. Интеграция с OpenCV / ML / ROS-like pipeline

### 28.1. На Mac pilot

Первый pilot на Mac может не поднимать ROS2. Достаточно:

- raw capture;
- decoded frames to directory;
- decoded point clouds to PLY/NPZ;
- optional ZeroMQ/WebSocket local publish.

### 28.2. Далее на бортовом компьютере

Потом можно сделать:

```text
/k1/points_preview   PointCloud2-like
/k1/image_left       Image-like
/k1/image_right      Image-like
/k1/panorama         Image-like
/k1/pose             Odometry-like
/k1/status           diagnostics
```

Если ROS2 будет не на Mac, exporter должен быть независимым:

- MCAP;
- NPZ;
- PCD/PLY;
- PNG/JPEG frames;
- JSONL metadata.

## 29. Аппаратный запуск scan без LixelGO

### 29.1. Первый стенд

На первом стенде кнопка нажимается вручную.

### 29.2. Бортовая версия

Не ставить сервопривод, если можно не ставить. Лучше:

```text
MCU GPIO -> optocoupler / PhotoMOS -> parallel to K1 button
```

Логика:

```text
click 80 ms
pause 180 ms
click 80 ms
wait 20 sec static init
```

### 29.3. Чтение состояния

Лучше:

- через Wi-Fi status stream.

Fallback:

- фотодиод/цветовой датчик на LED;
- камера на LED в стенде;
- ручная запись таймлайна.

## 30. Decision tree: что делать в зависимости от результата

### 30.1. K1 сам подключается к сохраненной Wi-Fi сети

Тогда BLE provisioning в runtime не нужен. Фокус на Wi-Fi data session.

### 30.2. K1 требует provisioning каждый раз

Надо реализовать BLE provisioning или оставить LixelGO/phone только как temporary provisioning tool.

### 30.3. Wi-Fi data session открытая/простая

Пишем client/parser.

### 30.4. Wi-Fi data session TLS/encrypted

Варианты:

- понимать endpoints/flow timings;
- смотреть app logs/APK/IPA metadata;
- использовать LixelGO как session broker на пилоте;
- искать официальный/local SDK;
- переходить к internal Linux fallback только после исчерпания black-box пути.

### 30.5. Point cloud найден, camera нет

Для первого CV использовать point cloud/pose. Камеры искать дальше через perturbation/app analysis или внутренний доступ.

### 30.6. Camera найден, point cloud нет

Использовать K1 как panoramic camera source + локальная запись K1 как LiDAR fallback. Но это менее вероятный сценарий.

### 30.7. Ничего live не отдается без LixelGO

Имитировать LixelGO handshake. Если невозможно - temporary broker:

```text
LixelGO starts session
Mac captures/receives via same network if possible
```

Если и это невозможно - рассматривать аппаратный fallback.

## 31. Главные риски и блокеры

| Риск | Вероятность | Урон | Митигирование |
|---|---:|---:|---|
| BLE provisioning payload encrypted | средняя | средний | LixelGO baseline, diff sessions, configure once |
| Wi-Fi data session requires token | высокая/средняя | высокий | app traffic analysis, logs, APK/IPA research |
| Local data encrypted/TLS | средняя | высокий | traffic metadata, official APIs, broker mode |
| Camera stream not exported | средняя/высокая | высокий для CV | perturbation tests, app analysis, internal fallback |
| Live point cloud only downsampled | высокая | низкий/средний | acceptable for obstacle mapping; offline .xbin fallback |
| Ordinary router cannot sniff unicast | высокая | средний | Mac as AP, router capture, OpenWrt later |
| macOS BLE limitations | высокая | средний | Bleak/CoreBluetooth workflow, PacketLogger, Android HCI if needed |
| Firmware versions change behavior | высокая | средний | record firmware/app version, avoid updates during experiment |
| K1 overheats/vibration issues | средняя | высокий | bench thermal/vibration tests before flight |

## 32. Что сделать первым: 48-часовой план

### 32.1. День 1: инвентаризация и автономная запись

```text
1. Записать firmware version и LixelGO version.
2. Сделать 1 кнопочный скан без app.
3. Скопировать проект через USB mode.
4. Сохранить tree/project.json/poses.csv/map.las/log.
5. Сделать K1_LAB Wi-Fi.
6. Настроить Bridge Mode через LixelGO на K1_LAB.
7. Перезагрузить K1 и проверить, подключается ли сам.
```

### 32.2. День 2: Mac capture framework

```text
1. Установить toolchain.
2. BLE scan через Bleak.
3. GATT dump.
4. Network discover K1 IP.
5. Idle capture.
6. Button scan capture.
7. App scan capture, если можно.
8. Flow summary.
9. Выделить top candidate streams.
```

Результат второго дня: не decoder, а карта потоков.

## 33. ТЗ для Codex: stage-by-stage

### 33.1. Общая задача для Codex

Создать Python 3.12 CLI проект `k1-mac-link` для macOS. Проект должен быть исследовательским framework, а не финальным декодером. Все операции, которые пишут в K1, по умолчанию запрещены.

### 33.2. Stage 0 - project skeleton

Deliverables:

- `pyproject.toml`;
- Typer CLI;
- Rich logging;
- config loader;
- artifact/session manifest helpers;
- tests.

### 33.3. Stage 1 - BLE tools

Deliverables:

- `k1link ble scan`;
- `k1link ble gatt-dump`;
- `k1link ble listen`;
- JSON/JSONL outputs;
- no writes.

### 33.4. Stage 2 - Network tools

Deliverables:

- `k1link net discover`;
- `k1link net ports` wrapper;
- `k1link net capture` wrapper;
- PCAP session manifests.

### 33.5. Stage 3 - PCAP analysis

Deliverables:

- flow summary;
- payload extraction;
- protocol fingerprint;
- timeline correlation.

### 33.6. Stage 4 - Point cloud probe

Deliverables:

- float32/strided probe;
- int scaled probe;
- candidate scoring;
- PLY/NPZ export.

### 33.7. Stage 5 - Video probe

Deliverables:

- JPEG/PNG/H264/H265/RTSP/RTP/MJPEG detectors;
- ffmpeg/OpenCV attempts;
- frames extraction.

### 33.8. Stage 6 - Known provisioning profile

Only after manual reverse:

- add safe provisioner;
- profile-based encoder;
- explicit flag required.

## 34. Кодовые наброски для Codex

### 34.1. BLE scan skeleton

```python
import asyncio
import json
from bleak import BleakScanner

async def scan(duration: float = 30.0):
    devices = await BleakScanner.discover(timeout=duration, return_adv=True)
    rows = []
    for dev, adv in devices.values():
        rows.append({
            "address_or_uuid": dev.address,
            "name": dev.name or adv.local_name,
            "rssi": adv.rssi,
            "service_uuids": adv.service_uuids,
            "manufacturer_data_hex": {
                str(k): v.hex() for k, v in adv.manufacturer_data.items()
            },
            "service_data_hex": {
                str(k): v.hex() for k, v in adv.service_data.items()
            },
        })
    return rows

if __name__ == "__main__":
    print(json.dumps(asyncio.run(scan()), ensure_ascii=False, indent=2))
```

### 34.2. Payload signature probe skeleton

```python
SIGNATURES = {
    "jpeg_start": bytes.fromhex("ff d8 ff"),
    "png": bytes.fromhex("89 50 4e 47 0d 0a 1a 0a"),
    "h264_annexb_4": bytes.fromhex("00 00 00 01"),
    "h264_annexb_3": bytes.fromhex("00 00 01"),
    "mp4_ftyp": b"ftyp",
    "mp4_moof": b"moof",
    "mp4_mdat": b"mdat",
}

def find_signatures(blob: bytes):
    hits = []
    for name, sig in SIGNATURES.items():
        pos = blob.find(sig)
        while pos != -1:
            hits.append({"signature": name, "offset": pos})
            pos = blob.find(sig, pos + 1)
    return hits
```

### 34.3. Float cloud probe skeleton

```python
import numpy as np

def score_xyz(blob: bytes, offset: int, stride: int):
    usable = len(blob) - offset
    n = usable // stride
    if n < 100:
        return None
    arr = np.frombuffer(blob[offset:offset + n * stride], dtype=np.uint8).reshape(n, stride)
    xyz = arr[:, :12].copy().view("<f4").reshape(n, 3)
    finite = np.isfinite(xyz).all(axis=1)
    if finite.mean() < 0.8:
        return None
    good = finite & (np.abs(xyz) < 200).all(axis=1)
    if good.mean() < 0.5:
        return None
    pts = xyz[good]
    variance = float(np.var(pts, axis=0).sum())
    return {
        "offset": offset,
        "stride": stride,
        "n": int(n),
        "finite_ratio": float(finite.mean()),
        "range_ratio": float(good.mean()),
        "variance": variance,
    }
```

## 35. Какие данные надо просить у оператора после каждого запуска

Оператор должен складывать в одну папку:

```text
photo/video of LED behavior
screen recording of LixelGO, если используется
ble_scan.json
gatt_dump.json
session.pcap
session_summary.json
flows.json
notes.md
project_tree.txt
project.json
poses.csv
map.las metadata
log folder
```

`notes.md` шаблон:

```markdown
# Session notes

## Device
Firmware:
Battery:
Storage:

## Network
SSID:
K1 IP:
Mac interface:

## Timeline
00:00 capture start
00:05 button double-click start
00:25 static init expected done
00:45 camera A covered
00:55 camera A uncovered
01:10 control point click
01:30 stop scan

## Observations
LED:
LixelGO preview:
Mac output:
```

## 36. Как использовать файлы на диске K1 для reverse engineering, не считая LAS/гауссы

Мы не считаем LAS/LCC/3DGS в runtime, но локальные файлы нужны для анализа протокола.

### 36.1. `poses.csv`

Использование:

- понять frequency trajectory recording;
- сопоставить timestamp диапазон с PCAP;
- понять coordinate system;
- искать аналогичные pose packets в live traffic.

### 36.2. `map.las`

Использование:

- не как целевой output, а как ground truth для downsampled realtime cloud;
- сравнить density/scale/bounds с candidate decoded live stream;
- проверить, появилась ли геометрия тестовой сцены.

### 36.3. `project.json`

Использование:

- firmware/hardware/settings;
- mount type;
- scan mode;
- time zone/time;
- device attributes;
- possible internal sensor names.

### 36.4. `log`

Использование:

- искать IP/ports;
- искать daemon names;
- искать warnings/errors;
- искать camera/imu/lidar module names;
- искать protocol keywords: `grpc`, `mqtt`, `websocket`, `rtsp`, `udp`, `preview`, `point`, `pose`, `camera`.

Команда:

```bash
grep -RniE "grpc|mqtt|websocket|socket|udp|tcp|rtsp|camera|preview|point|pose|imu|lidar|xbin|las|wifi|ble|bt|data connection|network" <PROJECT>/log <PROJECT>/project.json
```

## 37. Что уже не нашли / что не является решением

### 37.1. Не найдены публичные custom firmware

По ранее пройденным OSINT-маршрутам публичных кастомных прошивок, root-thread, jailbreak-инструкций или firmware dumps для K1 не найдено.

### 37.2. Публичный GitHub XGRIDS - не про live K1

XGRIDS публично выкладывает LCC/SDK/whitepaper/viewer-инструменты, но это про LCC/3DGS/rendering ecosystem, а не про live connection protocol K1. Источник: [S18].

### 37.3. Open-source аналоги полезны как fallback, не как K1 decoder

FAST-LIVO2, LIV_handhold, livo-handheld, mandeye_controller, HDMapping полезны, если придется строить собственный open sensor stack на Livox/camera/IMU. Но они не расшифровывают K1 live protocol. Источники: [S19]-[S23].

## 38. Аппаратный fallback, если black-box route провалится

Не делать на первом этапе, но держать в голове:

1. FCC photos показывают RK3588S compute и RTL8822CE radio.
2. Теоретически устройство может иметь Linux userspace.
3. Если внешние протоколы закрыты, можно исследовать внутренний storage/logs/debug ports.
4. Это рискованный route: можно потерять калибровки, гарантию, работоспособность.

Fallback routes:

| Route | Что сохраняет | Риск |
|---|---|---:|
| Black-box Wi-Fi client | все штатное железо/калибровки | низкий |
| LixelGO broker + Mac passive/capture | штатный workflow | низкий/средний |
| Internal Linux access | сенсоры/калибровки, если read-only | высокий |
| Brain transplant | корпус/часть сенсоров | очень высокий |

## 39. Проверка гипотезы о “заводских SSID/password”

Гипотеза: китайцы могли зашить SSID/password по серийнику.

Оценка:

- Для Bridge/Direct Mode: маловероятно. Мануал говорит, что пользователь вводит hotspot name/password. Это обычный Wi-Fi profile.
- Для Quick Connect: возможно есть device-specific workflow, где приложение читает BLE advertisement/serial/config и подключается автоматически.
- Для data connection: возможно есть токен/сертификат/сессионный ключ, но это не Wi-Fi SSID/password.

Практический тест:

```text
1. Настроить K1 на K1_LAB через LixelGO.
2. Изменить пароль K1_LAB на роутере.
3. Проверить, перестал ли K1 подключаться.
4. Вернуть пароль.
5. Проверить, подключился ли снова.
```

Если behavior зависит от нашего пароля - это обычный Wi-Fi profile.

## 40. Почему `data connection status` важнее `network connection status`

Официальная документация говорит, что после настройки должны быть успешны оба статуса: network connection status и data connection status.

Значит:

```text
network connection = K1 получил Wi-Fi/IP

data connection = LixelGO открыл application-layer session
```

Проект может застрять на втором слое. Поэтому `k1-mac-link` должен разделять:

- Wi-Fi reachability;
- service discovery;
- session handshake;
- stream subscription.

## 41. Режим “сначала без BLE”

Самый быстрый route:

```text
1. Через LixelGO один раз настроить K1 на K1_LAB.
2. Закрыть LixelGO.
3. Перезагрузить K1.
4. Проверить, появляется ли K1 в K1_LAB.
5. Если появляется, BLE provisioning временно отложить.
6. Делать Wi-Fi discovery/capture/client.
```

Это может сэкономить дни.

## 42. Режим “LixelGO как временный session broker”

Если K1 не отдает live streams без app handshake:

```text
LixelGO starts/opens session
K1 begins streaming to app
Mac captures traffic if AP can mirror/sniff
or Mac probes endpoints discovered from app session
```

Это не финальное решение, но полезный bridge для reverse engineering.

## 43. Отдельная проблема камер

### 43.1. Что знаем

Знаем:

- K1 имеет 2 panoramic cameras по official overview;
- LixelGO имеет true-color/elevation modes;
- App Store говорит про RGB point cloud rendering;
- version history упоминает camera loading failures;
- project structure содержит `photo` at control point.

### 43.2. Чего не знаем

Не знаем:

- идут ли raw frames наружу;
- есть ли stitched panorama live;
- есть ли compressed camera stream;
- получает ли LixelGO картинку, или только цветной point cloud/rendered preview;
- можно ли подписаться на камеры отдельно.

### 43.3. Практическая стратегия

Параллельно искать:

1. RTSP/RTP/video signatures.
2. JPEG/H264 payloads.
3. Endpoints with names `camera`, `photo`, `preview`, `rgb`.
4. Traffic reaction to covering cameras.
5. App binary strings, если понадобится.

## 44. Отдельная проблема pose/route

`poses.csv` после скана - сильная зацепка. Для live pose искать:

- small high-frequency status packets;
- packets with 7 floats: x,y,z,qx,qy,qz,qw;
- packets with 16 floats: 4x4 matrix;
- timestamp + pose fields;
- smooth trajectory over time;
- correlation with movement.

Эксперимент:

```text
1. Стоять 20 сек.
2. Переместить K1 на 1 метр вперед.
3. Повернуть на 90 градусов.
4. Стоять.
5. Сравнить candidate pose values.
```

## 45. Что делать с firmware versions

Не обновлять firmware во время исследования без необходимости.

Причины:

- Quick Connect/default behavior зависит от версии;
- `.xbin` format менялся в новых firmware;
- app compatibility меняется;
- firmware update может форматировать internal storage или менять project structure.

Перед любым update:

```text
1. Скопировать все проекты.
2. Сохранить firmware package checksum.
3. Сохранить текущую версию firmware/app.
4. Сделать полный capture старого поведения.
```

## 46. Формат pre-production отчета после первой лаборатории

После 2-3 дней работы должен быть отчет:

```markdown
# K1 Lab Report 001

## Device
Model:
Serial:
Firmware:
LixelGO:

## Network
SSID:
Router:
K1 IP:

## BLE
Advertised name:
Services:
Writable chars:
Notify chars:
Provisioning status:

## Wi-Fi
Open TCP ports:
Open UDP candidates:
Data connection behavior:

## Streams
Point cloud candidate:
Camera candidate:
Pose candidate:
Status candidate:

## Evidence
PCAP:
Screenshots:
Project files:
Logs:

## Blockers
...

## Next steps
...
```

## 47. Готовый prompt для Codex

```text
Ты работаешь над проектом k1-mac-link.

Цель: создать macOS Python 3.12 CLI framework для исследования XGRIDS/LixelKity K1 как black-box realtime sensor. Нельзя прошивать устройство, нельзя делать random BLE writes, нельзя brute force. Все write-действия должны быть выключены по умолчанию и требовать явного флага.

Создай проект с Typer CLI и модулями:
- ble scan/gatt-dump/listen
- net discover/ports/capture
- pcap flow summary
- payload extraction
- protocol fingerprint
- pointcloud probe
- video probe
- raw cache/session manifest

Сделай команды:
- k1link doctor
- k1link ble scan
- k1link ble gatt-dump
- k1link ble listen
- k1link net discover
- k1link net ports
- k1link net capture
- k1link analyze summarize
- k1link analyze extract-flows
- k1link analyze fingerprint
- k1link analyze pointcloud-probe
- k1link analyze video-probe

Сначала реализуй только safe read/capture tools. BLE write/provisioner оставь skeleton, который завершает работу с ошибкой NotImplemented, пока не будет добавлен known protocol profile.

Все результаты сохраняй в JSON/JSONL/PCAP/RAW. Raw captures никогда не удалять. Добавь README с macOS setup, Bluetooth permissions, Wireshark ChmodBPF, tcpdump notes.
```

## 48. Source map

### 48.1. Основные официальные источники

| ID | Источник | Что подтверждает |
|---|---|---|
| S01 | XGRIDS K1 Product Overview, `https://docs.xgrids.cn/en-us/02-lingguang-k/01-lingguang-k1/v2.4.0/01-product-overview.html` | K1: <1 кг, 48MP x2 panoramic vision, 360 deg LiDAR, real-time colorized models |
| S02 | XGRIDS K1 Basic Operation, `https://docs.xgrids.cn/en-us/02-lingguang-k/01-lingguang-k1/v2.4.0/02-basic-operation.html` | кнопки, LED, autonomous start/stop, USB mode, thermal/IP54 notes |
| S03 | XGRIDS K1 Device Activation and Connection, `https://docs.xgrids.cn/en-us/02-lingguang-k/01-lingguang-k1/v2.4.0/03-device-activation-and-connection.html` | LixelGO, Bluetooth provisioning, Direct/Bridge/Quick Connect, network/data statuses |
| S04 | XGRIDS K1 Scanning Workflow, `https://docs.xgrids.cn/en-us/02-lingguang-k/01-lingguang-k1/v2.4.0/04-scanning-workflow.html` | time sync, Drone mount type, 15 sec static init, project structure, map.las realtime, poses.csv, downsampled note |
| S05 | Apple App Store LixelGO, `https://apps.apple.com/gr/app/lixelgo/id6476125173` | real-time point cloud data, RGB point cloud rendering, camera loading fixes, airborne/mount hints |
| S06 | Google Play LixelGO, `https://play.google.com/store/apps/details?hl=en&id=com.XGrids.LixelGo.os` | real-time scanner control, live data preview, monitoring, encrypted in transit |

### 48.2. OSINT / FCC

| ID | Источник | Что подтверждает |
|---|---|---|
| S08 | FCC ID 2A9PI-K1, `https://fcc.report/FCC-ID/2A9PI-K1` | FCC ID, радиодиапазоны, документы K1 |
| S09 | FCC 5 GHz Wi-Fi report, `https://fcc.report/FCC-ID/2A9PI-K1/7248480.pdf` | 802.11a/n/ac, 5 GHz channels, battery/version |
| S10 | FCC 2.4 GHz Wi-Fi report, `https://fcc.report/FCC-ID/2A9PI-K1/7248312.pdf` | 802.11b/g/n, 2.4 GHz, up to 150 Mbps |
| S11 | FCC BT report, `https://fcc.report/FCC-ID/2A9PI-K1/7248224.pdf` | Bluetooth 5.0 BR+EDR 1/2/3 Mbps, battery/version |
| S12 | FCC BLE report, `https://fcc.report/FCC-ID/2A9PI-K1/7248310.pdf` | BLE 1/2 Mbps, 40 channels, battery/version |
| S13 | FCC internal photos, `https://fcc.report/FCC-ID/2A9PI-K1/7248458.pdf` | RK3588S, RTL8822CE, antennas, modular PCBs |

### 48.3. Инструменты

| ID | Источник | Что подтверждает |
|---|---|---|
| S14 | Bleak macOS backend, `https://bleak.readthedocs.io/en/latest/backends/macos.html` | CoreBluetooth UUID behavior, pairing limitation, permissions |
| S15 | Wireshark macOS install, `https://www.wireshark.org/docs/wsug_html_chunked/ChBuildInstallOSXInstall.html` | `.dmg`, ChmodBPF required for capture |
| S16 | Apple Developer Bluetooth, `https://developer.apple.com/bluetooth/` | Core Bluetooth and PacketLogger in Additional Tools for Xcode |
| S17 | Nmap macOS install, `https://nmap.org/book/inst-macosx.html` | Nmap support for macOS |

### 48.4. Secondary / context

| ID | Источник | Что использовать осторожно |
|---|---|---|
| S07 | Alpine Reality Capture LixelGO setup guide, `https://www.alpinerealitycapture.com/guide/lixelgo-setup` | phone loss -> recording continues but preview/control lost; Bridge Mode shared network |
| S18 | XGRIDS GitHub, `https://github.com/xgrids` | LCC/SDK ecosystem, not live K1 protocol |
| S19 | FAST-LIVO2, `https://github.com/hku-mars/FAST-LIVO2` | open LiDAR-inertial-visual architecture fallback |
| S20 | LIV_handhold, `https://github.com/xuankuzcr/LIV_handhold` | hardware sync/CAD/UAV-mounted reference |
| S21 | livo-handheld, `https://github.com/RomanStadlhuber/livo-handheld` | Livox + Raspberry Pi + camera reference |
| S22 | mandeye_controller, `https://github.com/JanuszBedkowski/mandeye_controller` | open handheld scanner controller reference |
| S23 | HDMapping, `https://github.com/MapsHD/HDMapping` | mobile mapping open stack reference |

## 49. Итоговая карта решения

```text
Phase 0: no-code inventory
  -> firmware/app versions
  -> USB project structure
  -> autonomous button scan confirmed

Phase 1: Mac lab tooling
  -> BLE scan/GATT dump
  -> Wi-Fi discover/ports/capture
  -> PCAP flow summary

Phase 2: LixelGO behavior capture
  -> Direct/Bridge provisioning baseline
  -> app scan vs button scan
  -> reconnect behavior

Phase 3: Stream identification
  -> point cloud candidate
  -> pose candidate
  -> camera/video candidate
  -> status candidate

Phase 4: Decoding
  -> point cloud probe/export
  -> camera frame extraction, if available
  -> pose/status decoder

Phase 5: Runtime connector
  -> K1 connects to lab/onboard Wi-Fi
  -> Mac/client opens data session
  -> raw cache + decoded streams
  -> OpenCV/ML/ROS-compatible outputs

Phase 6: fallback only if needed
  -> LixelGO broker
  -> Android HCI/APK analysis
  -> internal Linux/RK3588S route
```

## 50. Ключевые takeaways

1. SSID/password - это обычная сеть пользователя; проблема не в них, а в data connection.
2. Bluetooth почти точно нужен для provisioning, а не для live cloud/video.
3. Wi-Fi - главный канал live data.
4. K1 умеет автономно стартовать scan кнопкой.
5. K1 пишет `map.las` как realtime point cloud output, но downsampled.
6. `poses.csv` - offline trajectory ground truth.
7. Камеры подтверждены аппаратно, но live camera stream наружу не доказан.
8. Внутри есть RK3588S и RTL8822CE; это подтверждает мощный onboard compute.
9. Первый этап должен быть black-box, read-only, с полным raw cache.
10. `k1-mac-link` должен быть не “финальным драйвером”, а framework для экспериментов и декодеров.
