lift_indicator_suite/tools/production
2026-07-07 12:07:15 +03:00
..
app # Refactoring: source code docstrings 2026-07-07 12:07:15 +03:00
custom_binaries # Phase 4: Windows tested 2026-07-06 11:14:17 +03:00
dist # Phase 5 - alpha-pyinstaller packed version of service-tui (Win tested) 2026-07-06 14:31:59 +03:00
docs # Refactoring: all the documents 2026-07-07 11:25:06 +03:00
spike # Phase 4: connection loss handling with spsdk 2026-07-03 17:19:16 +03:00
tests # Refactoring: source code docstrings 2026-07-07 12:07:15 +03:00
main.py # Phase 5 - alpha-pyinstaller packed version of service-tui (MacOS tested) 2026-07-06 13:04:59 +03:00
pyproject.toml # Phase 5 - alpha-pyinstaller packed version of service-tui (MacOS tested) 2026-07-06 13:04:59 +03:00
README.md # Refactoring: source code docstrings 2026-07-07 12:07:15 +03:00
service_tui.spec # Fixes: unit test mocks + small fixes 2026-07-06 18:10:56 +03:00
uv.lock # Fixes: unit test mocks + small fixes 2026-07-06 18:10:56 +03:00

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

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

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


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

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

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

┌────────────────────────────────────────────────────┐
│              service_tool  v0.2.0                   │
│                                                      │
│                 [LOGO_ART]                          │
│                                                      │
│   Подключите плату индикатора к USB...          ⠋   │
│                                                      │
│              [ ✕ Выйти из приложения ]              │
└────────────────────────────────────────────────────┘

Версия читается из pyproject.toml — при бампе версии мокап выше не нужно обновлять руками, TUI подставит актуальную сама.

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

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

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

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

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

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

  1. HabImage (spsdk) — добавляет 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 не загрузит прошивку — требуется перепрошить

Известные ограничения

  • Одна плата на столе одновременно. В SDP/Flashloader-режиме плату нельзя идентифицировать по UID — авто-прошивка по факту детекта без подтверждения оператора убрала бы последний шанс заметить, что в руках не та плата. Массового программирования (несколько плат параллельно) нет и не планируется в этом виде — см. docs/DEV_ARCH.md, §8.
  • Циклический прогон тестов (повторный автозапуск набора без ручного нажатия на каждую итерацию) — отложен на пост-релиз, не входит в текущую версию.

Конфигурация (.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

# Уровень логирования. По умолчанию — INFO, при этом spsdk/libusbsio
# принудительно приглушены до WARNING. DEBUG включает полный дамп,
# включая сырые HID-пакеты spsdk (много строк на одну прошивку).
# SERVICE_LOG_LEVEL=DEBUG

Запуск

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

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

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

just host::package-tui
# → tools/production/dist/service-tui-vX.Y.Z-<os>/

Бандл (PyInstaller, onedir) самодостаточен — прошивка идёт напрямую через spsdk Python API (app/flash_backend.py), без вызова tools/host/ ни субпроцессом, ни как-либо иначе. Не нужны ни Zadig, ни установленный Python/uv на машине сервисника. Структура бандла и резолв путей во frozen — см. DEV_ARCH.md, §14.


Зависимости

Пакет Версия Назначение
textual ≥ 0.80 TUI фреймворк
pyserial ≥ 3.5 USB CDC ACM + M5 Serial
pyusb ≥ 1.0 не используется в коде (детект SDP/CDC идёт через spsdk) — исторический остаток, кандидат на удаление из pyproject.toml
spsdk 3.7.0 прошивка: SDP/McuBoot (Flash, chip erase) + HabImage (сборка кастомных HAB), нативный HID (libusbsio) — без Zadig
python-dotenv ≥ 1.0 загрузка .env
pyinstaller ≥ 6.0 сборка standalone-бандла (just host::package-tui)

Никакой рантайм-зависимости на tools/host/ в смысле subprocess-вызовов нет. Прошивка выполняется in-process через spsdk (app/flash_backend.py). Из tools/host/dcd/ читаются только статичные data-блобы (dcd.bin, *_fdcb.bin, ivt_flashloader.bin) — они отслеживаются в git, just host::setup-tools для запуска TUI из исходников не требуется. tools/host/ flash_usb.py — независимый dev-CLI для just host::flash*, TUI его не вызывает (см. DEV_ARCH.md, §1/§8).


Логирование

tools/production/service_tui.log   ← по умолчанию (dev) / рядом с exe (frozen)
$SERVICE_LOG_DIR/service_tui.log   ← если задан в .env

Уровень по умолчанию — INFO; textual, spsdk и libusbsio понижены до WARNING независимо от root (иначе прошивка даёт ~135 строк сырых HID-пакетов на одну операцию). SERVICE_LOG_LEVEL=DEBUG включает полный DEBUG везде, включая эти модули — используется при разборе проблем на железе. TUI не пишет в stdout — Textual захватывает терминал.