lift_indicator_suite/tools/production
2026-07-01 16:54:10 +03:00
..
app # firmware_test: service-tui is ready for packing, docs updated 2026-07-01 16:54:10 +03:00
custom_binaries # firmware_test: service-tui is ready for packing, docs updated 2026-07-01 16:54:10 +03:00
docs # firmware_test: service-tui is ready for packing, docs updated 2026-07-01 16:54:10 +03:00
main.py # firmware_test: TUI app current state 2026-06-29 19:54:44 +03:00
pyproject.toml # firmware_test: service-tui is ready for packing, docs updated 2026-07-01 16:54:10 +03:00
README.md # firmware_test: service-tui is ready for packing, docs updated 2026-07-01 16:54:10 +03:00
uv.lock # firmware_test: service-tui is ready for packing, docs updated 2026-07-01 16:54:10 +03:00

service-tui — TUI сервисного инженера

TUI-приложение для диагностики и прошивки платы MIMXRT1052CVJ5B на сервисе. Написано на Python + Textual. Работает на Linux, macOS, Windows.

Внутреннее устройство, диаграммы архитектуры и заметки для разработчиков — в DEV_ARCH.md. Этот документ — только про то, как приложением пользоваться.


Экраны приложения

Ожидание подключения (WaitingScreen)

Стартовый экран. Автодетект USB — как только плата подключена, TUI сам определяет режим (прошивка или диагностика) и переключается.

┌────────────────────────────────────────────────────┐
│              service_tool  v0.3.0                   │
│                                                      │
│                 [LOGO_ART]                          │
│                                                      │
│   Подключите плату индикатора к USB...          ⠋   │
└────────────────────────────────────────────────────┘

При потере соединения на любом другом экране сессия разрывается полностью — TUI не пытается восстановить прежнее состояние, а возвращается сюда. Над подсказкой на 4 секунды появляется строка ⚠ <причина> (например, «⚠ Соединение с платой потеряно»), затем скрывается сама — обычный автодетект продолжается без вмешательства оператора.

Прошивка платы (FlashScreen)

Триггер: обнаружена плата в режиме BootROM SDP.

┌────────────────────────────────────────────────────┐
│  ⚡ Загрузка прошивки на плату индикатора            │
│     (режим BootROM)                                │
│                                                    │
│  Выбор загружаемой прошивки                        │
│  ◉ Диагностическая прошивка (firmware_test)        │
│  ○ Серийная прошивка (bootloader + tft_app)        │
│  ○ Другое                                          │
│    Файл (custom_binaries/)                         │
│    [ TFT_BOOTLOADER_NEW.bin              ▾ ]       │  ← только если «Другое»
│    Память платы                                    │
│    [ W25Q128 / W25Q64                    ▾ ]       │
│    ○ Использует SDRAM (DCD)                        │
│                                                    │
│  [ ▶ Загрузить ] [ ⚠ Очистить память ] [ ✕ Выйти из приложения ] │
│                                                    │
│  ████████████░░░░░░  ← без числового %             │
│  ┌────────────────────────────────────────────┐    │
│  │ ▶ Сборка HAB-образа (nxpimage)...          │    │
│  │ ▶ Прошивка: TFT_BOOTLOADER_NEW              │    │
│  │ ...                                         │    │
│  └────────────────────────────────────────────┘    │
└────────────────────────────────────────────────────┘

Лог виден постоянно (не только во время прошивки), прогресс-бар — только во время активной операции (скрыт в простое), без числового % — только полоса и построчный лог в реальном времени. Панель выбора прошивки ограничена по высоте и скроллится сама, если разрастается (варианты "Другое") — лог снизу гарантированно не сжимается меньше 6 строк.

"Другое" — для бинарников, собранных не в этом репозитории. В custom_binaries/ кладётся сырой образ (код + таблица векторов, без FCB/IVT/DCD — то же самое, что build/Debug/bootloader.bin до nxpimage). TUI сама собирает из него загружаемый образ на лету:

  1. nxpimage hab export — добавляет IVT (+DCD, если включён тумблер "Использует SDRAM")
  2. в Flash пишется явный FCB под выбранную память платы (не тот же auto-config, что для штатных firmware_test/bootloader/app — для W25Q256/512 он ненадёжен, см. DEV_ARCH.md)
  3. образ прошивается с 0x60001000, как обычно

Выбор запоминается на весь запуск TUI — файл, память платы и DCD не нужно выставлять заново на каждой следующей плате: прошили одну, вынули USB, вставили следующую такую же — TUI уже подставила прошлый выбор, остаётся нажать "Загрузить". Сбрасывается только при перезапуске TUI.

Переход в рабочий режим (PostFlashScreen)

Показывается только после успешной прошивки firmware_test (для Production/Custom этот шаг не нужен).

┌────────────────────────────────────────────────────┐
│  ✅ firmware_test успешно записан                  │
│                                                    │
│  Переведите плату в нормальный режим:              │
│  BOOT_MOD_1 → GND → Reset                         │
│                                                    │
│  [ ✓ Готово ]   [ ✕ Выйти из приложения ]         │
│  Автопереход через: 40с                            │
└────────────────────────────────────────────────────┘

Диагностика (DiagScreen)

Триггер: плата видна как CDC-устройство и отвечает на связь.

┌────────────────────────────────────────────────────────────────┐
│  fw: 0.2.0     MCU ID: A1B2C3D4E5F60011     M5 Bench: ✓ подключён │
├───────────────────────────┬──────────────────────────────────────┤
│  Доступные тесты           │  Тест        M5 Bench Статус  Время  │
│  [Выбрать все][Снять все]  │  microSD     [-]      ✗ FAIL  0.1с   │
│  ☐ SDRAM 32 MB             │    no card detected (без обрезки)    │
│  ☐ QSPI Flash              │  SDRAM 32 MB [-]      ✓ PASS  1.8с   │
│  ☐ microSD                 │  QSPI Flash  [-]      ✓ PASS  0.6с   │
│  ☐ TFT Display             │  TFT Display [-]      …              │
│  ☐ CAN loopback  [HIL]     │  Кнопки      [-]                     │
│  ☐ Оптовходы     [HIL]     │                                      │
├──────────────────────────────────────────────────────────────────┤
│  ████████░░░░  Тест: usd — mount: ok         ← только во время прогона │
├──────────────────────────────────────────────────────────────────┤
│  [▶ Запустить выбранные тесты] [▶▶ Запустить все тесты] [✕ Выйти из приложения] │
├──────────────────────────────────────────────────────────────────┤
│  ⚠  Экран залит красным цветом?                          28с      │
│  [ ✓ Да ]   [ ✗ Нет ]                    ← только во время confirm │
└────────────────────────────────────────────────────────────────┘

Что важно знать:

  • Тесты изначально не выбраны — выбирайте вручную либо кнопками "Выбрать все"/"Снять все".
  • Результаты — таблица с сортировкой FAIL-наверх, FAIL-строка подсвечена целиком, длинные сообщения переносятся на несколько строк без обрезания. Колонка M5 Bench отмечает [*]/[-] — требует ли тест HIL-стенд.
  • HIL-тесты (CAN, оптовходы) без подключённого M5StampPLC — серые, недоступны для выбора.
  • Интерактивные проверки во время прогона теста бывают трёх видов:
    • HIL-тесты (CAN, оптовходы) при наличии M5 — отвечает стенд автоматически, без участия оператора;
    • тесты кнопок — экран показывает подсказку ⌨ <инструкция>, ответ не требуется, нужно физически нажать кнопку на плате;
    • остальное (дисплей, аудио) — форма "Да/Нет" с таймером ⚠ <вопрос> на экране.
  • До завершения загрузки списка тестов правая колонка показывает подсказку «Выберите тесты и нажмите «Запустить выбранные»» вместо таблицы.

Рабочие процессы сервисника

Диагностика (firmware_test уже прошит)

1. BOOT_MOD_1 → GND, сбросить плату
2. Подключить USB → DiagScreen
3. Выбрать тесты (по умолчанию ничего не выбрано) или "Выбрать все"
4. Запустить → ответить на интерактивные запросы
5. Получить итог; FAIL-тесты — наверху таблицы, detail виден полностью

Перепрошивка firmware_test

1. BOOT_MOD_1 → 3V3, сбросить плату → FlashScreen
2. Выбрать «Диагностическая прошивка (firmware_test)» → Загрузить
3. PostFlashScreen: BOOT_MOD_1 → GND, сбросить плату
4. Нажать "Готово" (или дождаться авто-перехода через 40с)
5. TUI автоматически попадает в DiagScreen при следующем подключении

Прошивка стороннего бинарника (custom_binaries/)

Для плат старых ревизий и любых образов, собранных не в этом репозитории.

1. Положить сырой бинарник (без FCB/IVT/DCD) в custom_binaries/
   (или в директорию из SERVICE_CUSTOM_BINARIES_DIR)
2. BOOT_MOD_1 → 3V3, сбросить плату → FlashScreen
3. Выбрать «Другое» → выбрать файл → выбрать память платы → DCD при необходимости
4. Загрузить — TUI сама соберёт HAB-образ и запишет правильный FCB
5. Партия одинаковых плат: вынуть USB, вставить следующую — выбор уже
   подставлен, останется нажать «Загрузить»

Chip Erase

1. Плата в SDP-режиме (BOOT_MOD_1 → 3V3)
2. FlashScreen → Очистить память (~30 с для W25Q128, дольше для W25Q512)
3. После erase BootROM не загрузит прошивку — требуется перепрошить

Конфигурация (.env)

# USB VID:PID — BootROM SDP (константы NXP, не менять)
BOOTROM_VID=1fc9
BOOTROM_PID=0130

# USB VID:PID — Flashloader (константы NXP, не менять)
FLASHLOADER_VID=15a2
FLASHLOADER_PID=0073

# USB VID:PID — firmware_test CDC (наше устройство)
SERVICE_CDC_VID=1996
SERVICE_CDC_PID=00ad

# USB VID:PID — M5StampPLC (детект HIL-стенда)
SERVICE_M5_VID=303a
SERVICE_M5_PID=4001

# Директория с сырыми кастомными бинарниками для FlashScreen → "Другое".
# По умолчанию — custom_binaries/ рядом с исполняемым файлом (или рядом
# с main.py в dev-режиме); создаётся автоматически при старте.
# SERVICE_CUSTOM_BINARIES_DIR=/path/to/custom_binaries

# Тип сборки firmware_test для прошивки (Debug | Release).
# Release временно нестабилен — по умолчанию Debug.
FIRMWARE_BUILD_TYPE=Debug

# Опционально: путь к директории лога TUI
# SERVICE_LOG_DIR=/tmp

Запуск

Из монорепозитория (разработчик)

just host::service-setup   # установить зависимости tools/production/
just host::service-tui     # запустить TUI

Standalone-бинарь (сервисник)

just host::service-build
# → tools/production/dist/service_tui

Standalone-бинарь не включает tools/host/ — для прошивки рядом нужен инициализированный tools/host/ (just host::setup-tools), либо абсолютный путь в _FLASH_USB_SCRIPT (flasher.py).


Зависимости

Пакет Версия Назначение
textual ≥ 0.80 TUI фреймворк
pyserial ≥ 3.5 USB CDC ACM + M5 Serial
pyusb ≥ 1.0 детект BootROM SDP (не виден через pyserial на macOS)
python-dotenv ≥ 1.0 загрузка .env
pyinstaller ≥ 6.0 сборка standalone-бинаря

Runtime-зависимость (не в pyproject.toml): flasher.py вызывает tools/host/flash_usb.py через uv runtools/host/ должен быть инициализирован (just host::setup-tools).


Логирование

tools/production/service_tui.log   ← по умолчанию
$SERVICE_LOG_DIR/service_tui.log   ← если задан в .env

Уровень: DEBUG для модулей приложения, WARNING для самого textual. TUI не пишет в stdout — Textual захватывает терминал.