# 9
Переход на модульную архитектуру just скриптов (см. docs/DEV_ARCH.md)
This commit is contained in:
parent
e8a9826944
commit
6930479fdb
12 changed files with 673 additions and 566 deletions
0
.env.example
Normal file
0
.env.example
Normal file
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -67,4 +67,6 @@ compile_commands.json
|
|||
.venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.env
|
||||
|
||||
|
||||
|
|
|
|||
28
.vscode/tasks.json
vendored
28
.vscode/tasks.json
vendored
|
|
@ -13,9 +13,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"build-${input:project}-${input:buildType}"
|
||||
"build::build-${input:project}-${input:buildType}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
|
@ -41,9 +39,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"test-host"
|
||||
"build::test-host"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
|
@ -61,9 +57,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"test-host-release"
|
||||
"build::test-host-release"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
|
|
@ -79,9 +73,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"hab-${input:habProject}-${input:buildType}"
|
||||
"build::hab-${input:habProject}-${input:buildType}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
|
@ -99,9 +91,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"hab-all-debug"
|
||||
"build::hab-all-debug"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
|
|
@ -114,9 +104,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"hab-all-release"
|
||||
"build::hab-all-release"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
|
|
@ -132,9 +120,7 @@
|
|||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"clean"
|
||||
"build::clean"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
# Прошивка платы со стороны хоста
|
||||
|
||||
```bash
|
||||
# Прошить во Flash
|
||||
just flash firmware_test debug # разработка — итерации с отладчиком
|
||||
just flash firmware_test release # проверить как будет на сервере
|
||||
just flash bootloader debug
|
||||
just flash bootloader release
|
||||
just flash app debug
|
||||
just flash app release
|
||||
|
||||
|
||||
# TODO:Загрузить в RAM (без записи во Flash, плата стартует сразу)
|
||||
just flash-ram firmware_test # default: debug
|
||||
just flash-ram firmware_test debug
|
||||
just flash-ram app release
|
||||
|
||||
# TODO:Псевдонимы
|
||||
just flash-test-debug # = just flash firmware_test debug
|
||||
just flash-test-release # = just flash firmware_test release
|
||||
just flash-production # bootloader release + app release
|
||||
```
|
||||
370
Justfile
370
Justfile
|
|
@ -1,344 +1,64 @@
|
|||
# =============================================================================
|
||||
# Justfile — корень репозитория
|
||||
# Выполняется на ХОСТ-МАШИНЕ разработчика (вне devcontainer).
|
||||
#
|
||||
# Отвечает только за:
|
||||
# - инициализацию окружения (setup)
|
||||
# - прошивку платы через USB (flash)
|
||||
# - сквозные сценарии (pipeline)
|
||||
# - вспомогательные утилиты (util)
|
||||
#
|
||||
# Сборка, тесты и HAB-образы — в just/build.just (внутри devcontainer).
|
||||
# Корневой justfile — точка входа для всех команд
|
||||
# Может выполняться на хосте или внутри devcontainer
|
||||
#
|
||||
# Быстрый старт:
|
||||
# ./scripts/bootstrap.sh # первый запуск после git clone
|
||||
# just # показать все рецепты
|
||||
# just # показать все доступные команды
|
||||
# just bootstrap # первая настройка после git clone (на хосте)
|
||||
# just build ... # сборка (внутри devcontainer)
|
||||
# just host::flash # прошивка (на хосте)
|
||||
# =============================================================================
|
||||
|
||||
JUST_MIN := "1.27.0"
|
||||
UV_MIN := "0.4.0"
|
||||
DOCKER_MIN := "24.0.0"
|
||||
# === Глобальные настройки ===
|
||||
# Все модули наследуют эти настройки
|
||||
|
||||
TOOLS_DIR := "tools/host"
|
||||
set shell := ["bash", "-euo", "pipefail", "-c"]
|
||||
# экспортируем все just-переменные в окружение
|
||||
set export
|
||||
# автоматически загружать .env
|
||||
set dotenv-load
|
||||
|
||||
# === Общие переменные (доступны во всех модулях через export) ===
|
||||
BOARD := env('BOARD', 'MIMXRT1052')
|
||||
BUILD_DIR := env('BUILD_DIR', 'build')
|
||||
TOOLS_DIR := env('TOOLS_DIR', 'tools/host')
|
||||
CACHE_DIR := ".cache"
|
||||
|
||||
# По умолчанию — показать список рецептов
|
||||
_default:
|
||||
@just --list --unsorted
|
||||
# === Модули ===
|
||||
# Каждый модуль — это namespace с изолированными рецептами
|
||||
# host.just — операции на хост-машине
|
||||
mod host 'just/host.just'
|
||||
# build.just — сборка в DevContainer
|
||||
mod build 'just/build.just'
|
||||
# ci.just — CI/CD сценарии (опционально)
|
||||
mod ci 'just/ci.just'
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: setup — инициализация рабочего окружения
|
||||
# =============================================================================
|
||||
# === Default рецепт ===
|
||||
# Вызывается при `just` без аргументов
|
||||
# Показывает полное дерево команд из всех модулей
|
||||
|
||||
# [1/3] Проверить наличие и версии инструментов на хост-машине
|
||||
[group('setup')]
|
||||
check-deps:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
default:
|
||||
@just --list --list-submodules
|
||||
|
||||
BOLD="\033[1m"; GREEN="\033[0;32m"; RED="\033[0;31m"; YELLOW="\033[1;33m"; RESET="\033[0m"
|
||||
ERRORS=0; WARNINGS=0
|
||||
# === Популярные алиасы (для удобства команды) ===
|
||||
# Сокращают длинные вызовы модулей
|
||||
|
||||
ok() { echo -e " ${GREEN}✅ ${1}${RESET}"; }
|
||||
fail() { echo -e " ${RED}❌ ${1}${RESET}"; ERRORS=$((ERRORS+1)); }
|
||||
warn() { echo -e " ${YELLOW}⚠️ ${1}${RESET}"; WARNINGS=$((WARNINGS+1)); }
|
||||
# Инициализация окружения (эквивалент host::bootstrap)
|
||||
init:
|
||||
@just host::bootstrap
|
||||
|
||||
_uname="$(uname -s)"
|
||||
case "${_uname}" in
|
||||
Linux*) PLATFORM="linux" ;;
|
||||
Darwin*) PLATFORM="macos" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
|
||||
*) PLATFORM="unknown" ;;
|
||||
esac
|
||||
# Быстрая прошивка тестового образа в Debug
|
||||
flash:
|
||||
@just host::flash-test-debug
|
||||
|
||||
# Сравнение semver без sort -V (недоступен в Git Bash)
|
||||
semver_ge() {
|
||||
local a="$1" b="$2"
|
||||
local a1 a2 a3 b1 b2 b3
|
||||
IFS='.' read -r a1 a2 a3 <<< "${a}"
|
||||
IFS='.' read -r b1 b2 b3 <<< "${b}"
|
||||
a1="${a1//[^0-9]/}"; a2="${a2//[^0-9]/}"; a3="${a3//[^0-9]/}"
|
||||
b1="${b1//[^0-9]/}"; b2="${b2//[^0-9]/}"; b3="${b3//[^0-9]/}"
|
||||
[[ "${a1:-0}" -gt "${b1:-0}" ]] && return 0
|
||||
[[ "${a1:-0}" -lt "${b1:-0}" ]] && return 1
|
||||
[[ "${a2:-0}" -gt "${b2:-0}" ]] && return 0
|
||||
[[ "${a2:-0}" -lt "${b2:-0}" ]] && return 1
|
||||
[[ "${a3:-0}" -ge "${b3:-0}" ]] && return 0
|
||||
return 1
|
||||
}
|
||||
# Полная сборка всех проектов в Release (в контейнере)
|
||||
build-all:
|
||||
@just build::hab-all-release
|
||||
|
||||
install_hint() {
|
||||
local tool=$1
|
||||
case "${PLATFORM}" in
|
||||
linux)
|
||||
case "$tool" in
|
||||
just) echo "curl -sSf https://just.systems/install.sh | bash -s -- --to ~/.local/bin" ;;
|
||||
uv) echo "curl -LsSf https://astral.sh/uv/install.sh | sh" ;;
|
||||
docker) echo "https://docs.docker.com/engine/install/ubuntu/" ;;
|
||||
esac ;;
|
||||
macos)
|
||||
case "$tool" in
|
||||
just) echo "brew install just" ;;
|
||||
uv) echo "brew install uv" ;;
|
||||
docker) echo "brew install --cask docker" ;;
|
||||
esac ;;
|
||||
windows)
|
||||
case "$tool" in
|
||||
just) echo "winget install --id Casey.Just (в PowerShell)" ;;
|
||||
uv) echo 'powershell -c "irm https://astral.sh/uv/install.ps1 | iex"' ;;
|
||||
docker) echo "winget install --id Docker.DockerDesktop (в PowerShell)" ;;
|
||||
esac ;;
|
||||
esac
|
||||
}
|
||||
# CI пайплайн
|
||||
run-ci:
|
||||
@just ci::pipeline
|
||||
|
||||
check_tool() {
|
||||
local name=$1 cmd=$2 min_ver=$3
|
||||
shift 3
|
||||
local ver_args=("${@:---version}")
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
fail "$name not found -- $(install_hint "$name")"
|
||||
return
|
||||
fi
|
||||
local actual
|
||||
actual=$("$cmd" "${ver_args[@]}" 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
if [[ -z "$actual" ]]; then
|
||||
warn "$name found but version could not be detected"
|
||||
return
|
||||
fi
|
||||
if semver_ge "$actual" "$min_ver"; then
|
||||
ok "$name $actual (>= $min_ver)"
|
||||
else
|
||||
fail "$name $actual -- need >= $min_ver -- $(install_hint "$name")"
|
||||
fi
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD} Platform: ${PLATFORM}${RESET}"
|
||||
echo ""
|
||||
echo -e "${BOLD} Checking host dependencies...${RESET}"
|
||||
echo ""
|
||||
|
||||
check_tool "just" "just" "{{JUST_MIN}}"
|
||||
check_tool "uv" "uv" "{{UV_MIN}}"
|
||||
check_tool "docker" "docker" "{{DOCKER_MIN}}" version --format '{{{{.Client.Version}}}}'
|
||||
|
||||
if [[ "${PLATFORM}" == "linux" ]]; then
|
||||
echo ""
|
||||
echo -e "${BOLD} Checking udev rules (Linux only)...${RESET}"
|
||||
echo ""
|
||||
local rules_file="/etc/udev/rules.d/99-nxp-mimxrt.rules"
|
||||
local udev_ok=true
|
||||
grep -q "1fc9" "$rules_file" 2>/dev/null || { warn "udev: BootROM rule missing (VID 1fc9)"; udev_ok=false; }
|
||||
grep -q "15a2" "$rules_file" 2>/dev/null || { warn "udev: Flashloader rule missing (VID 15a2)"; udev_ok=false; }
|
||||
if ! groups 2>/dev/null | grep -q plugdev; then
|
||||
warn "User '$(whoami)' not in 'plugdev' group"
|
||||
udev_ok=false
|
||||
fi
|
||||
if [[ "$udev_ok" == "false" ]]; then
|
||||
warn "USB flashing requires root without udev rules -- run: just setup-udev"
|
||||
else
|
||||
ok "udev rules (NXP USB) + plugdev group"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [[ $ERRORS -gt 0 ]]; then
|
||||
echo -e " ${RED}${BOLD}$ERRORS error(s) found. Fix them before continuing.${RESET}"
|
||||
echo ""
|
||||
exit 1
|
||||
elif [[ $WARNINGS -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}${BOLD}$WARNINGS warning(s). Some features may not work.${RESET}"
|
||||
else
|
||||
echo -e " ${GREEN}${BOLD}All dependencies satisfied.${RESET}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# [2/3] Установить udev правила для USB-прошивки (только Linux, требует sudo)
|
||||
[group('setup')]
|
||||
setup-udev:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
case "$(uname -s)" in
|
||||
Linux*) ;;
|
||||
*)
|
||||
echo " ℹ️ udev rules are Linux-only, skipping on $(uname -s)."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
echo " Installing udev rules for NXP USB devices..."
|
||||
printf '%s\n%s\n%s\n%s\n' \
|
||||
'# NXP BootROM -- SDP mode (BOOT_MOD_1 = 3V3)' \
|
||||
'SUBSYSTEM=="usb", ATTR{idVendor}=="1fc9", ATTR{idProduct}=="0130", MODE="0666", GROUP="plugdev"' \
|
||||
'# NXP Flashloader -- after jump-address' \
|
||||
'SUBSYSTEM=="usb", ATTR{idVendor}=="15a2", ATTR{idProduct}=="0073", MODE="0666", GROUP="plugdev"' \
|
||||
| sudo tee /etc/udev/rules.d/99-nxp-mimxrt.rules > /dev/null
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
sudo usermod -a -G plugdev "$USER"
|
||||
echo " ✅ udev rules installed"
|
||||
echo " ⚠️ Re-login required for 'plugdev' group to take effect"
|
||||
|
||||
# [3/3] Синхронизировать зависимости tools/host (spsdk и др.)
|
||||
# Идемпотентен: пропускает sync если uv.lock не изменился
|
||||
[group('setup')]
|
||||
setup-tools:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
LOCK="{{TOOLS_DIR}}/uv.lock"
|
||||
STAMP="{{CACHE_DIR}}/uv_lock.sha256"
|
||||
mkdir -p "{{CACHE_DIR}}"
|
||||
current=$(sha256sum "$LOCK" 2>/dev/null | cut -d' ' -f1 || echo "missing")
|
||||
previous=$(cat "$STAMP" 2>/dev/null || echo "none")
|
||||
if [[ "$current" == "$previous" ]]; then
|
||||
echo " ✅ tools/host deps up to date (lockfile unchanged)"
|
||||
else
|
||||
echo " 📦 Syncing tools/host deps..."
|
||||
cd "{{TOOLS_DIR}}" && uv sync
|
||||
echo "$current" > "../../$STAMP"
|
||||
echo " ✅ tools/host deps installed"
|
||||
fi
|
||||
|
||||
# Полная инициализация — запустить один раз после git clone
|
||||
[group('setup')]
|
||||
bootstrap:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
_uname="$(uname -s)"
|
||||
case "${_uname}" in
|
||||
Linux*) PLATFORM="linux" ;;
|
||||
Darwin*) PLATFORM="macos" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
|
||||
*) PLATFORM="unknown" ;;
|
||||
esac
|
||||
echo ""
|
||||
echo " === Bootstrap: step 1/3 -- check-deps ==="
|
||||
just check-deps
|
||||
if [[ "${PLATFORM}" == "linux" ]]; then
|
||||
echo " === Bootstrap: step 2/3 -- setup-udev ==="
|
||||
just setup-udev
|
||||
else
|
||||
echo " ℹ️ step 2/3 -- setup-udev skipped (${PLATFORM})"
|
||||
fi
|
||||
echo " === Bootstrap: step 3/3 -- setup-tools ==="
|
||||
just setup-tools
|
||||
echo ""
|
||||
echo " ✅ Bootstrap complete."
|
||||
echo " Next: open project in VSCode -> 'Reopen in Container'"
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: flash — прошивка платы через USB
|
||||
# Требует: uv + spsdk (just setup-tools), плата в SDP-режиме
|
||||
# HAB-образы должны быть собраны заранее (just hab-* внутри devcontainer)
|
||||
#
|
||||
# Матрица прошивки:
|
||||
# just flash firmware_test debug
|
||||
# just flash firmware_test release
|
||||
# just flash bootloader debug
|
||||
# just flash bootloader release
|
||||
# just flash app debug
|
||||
# just flash app release
|
||||
# =============================================================================
|
||||
|
||||
# Прошить выбранный HAB-образ.
|
||||
# Использование: just flash <project> <type>
|
||||
# project: firmware_test | bootloader | app
|
||||
# type: debug | release (default: release)
|
||||
#
|
||||
# Образ должен быть собран заранее в devcontainer:
|
||||
# just --justfile just/build.just hab-<project>-<type>
|
||||
[group('flash')]
|
||||
flash project type="release":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
case "{{type}}" in
|
||||
debug) BUILD_TYPE="Debug" ;;
|
||||
release) BUILD_TYPE="Release" ;;
|
||||
*)
|
||||
echo " ❌ Unknown type: {{type}}"
|
||||
echo " Valid: debug, release"
|
||||
exit 1 ;;
|
||||
esac
|
||||
cd "{{TOOLS_DIR}}" && uv run python3 flash_usb.py \
|
||||
--firmware "{{project}}" --build-type "${BUILD_TYPE}"
|
||||
|
||||
# Загрузить образ в RAM без записи во Flash.
|
||||
# Полезно для быстрой проверки — не изнашивает Flash, плата стартует сразу.
|
||||
# Использование: just flash-ram <project> <type>
|
||||
[group('flash')]
|
||||
flash-ram project type="debug":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
case "{{type}}" in
|
||||
debug) BUILD_TYPE="Debug" ;;
|
||||
release) BUILD_TYPE="Release" ;;
|
||||
*)
|
||||
echo " ❌ Unknown type: {{type}}"
|
||||
echo " Valid: debug, release"
|
||||
exit 1 ;;
|
||||
esac
|
||||
cd "{{TOOLS_DIR}}" && uv run python3 flash_usb.py \
|
||||
--firmware "{{project}}" --build-type "${BUILD_TYPE}" --ram-only
|
||||
|
||||
# Псевдонимы для частых сценариев ────────────────────────────────────────────
|
||||
|
||||
# firmware_test Debug — самый частый при разработке
|
||||
[group('flash')]
|
||||
flash-test-debug:
|
||||
@just flash firmware_test debug
|
||||
|
||||
# firmware_test Release — как будет на производстве
|
||||
[group('flash')]
|
||||
flash-test-release:
|
||||
@just flash firmware_test release
|
||||
|
||||
# bootloader + app Release — финальная прошивка
|
||||
[group('flash')]
|
||||
flash-production:
|
||||
@just flash bootloader release
|
||||
@just flash app release
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: pipeline — производственные сценарии (для сервера)
|
||||
# =============================================================================
|
||||
|
||||
# Входной контроль платы: тестовая прошивка (Release) -> HIL-тесты
|
||||
[group('pipeline')]
|
||||
incoming: flash-test-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
echo " ▶ Running HIL tests (CAN, UART, SDRAM, SPI Flash)..."
|
||||
# cd tools/hil && uv run python3 run_hil.py <- раскомментить когда готово
|
||||
echo " ⚠️ HIL tests not yet implemented"
|
||||
|
||||
# Финальная прошивка: загрузчик + основная прошивка (Release)
|
||||
[group('pipeline')]
|
||||
production: flash-production
|
||||
@echo " ✅ Production firmware flashed (bootloader + app)"
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: util — вспомогательные инструменты
|
||||
# =============================================================================
|
||||
|
||||
# Найти подключённые NXP USB-устройства
|
||||
[group('util')]
|
||||
scan:
|
||||
cd "{{TOOLS_DIR}}" && uv run nxpdevscan
|
||||
|
||||
# Проверить связь с BootROM через SDP (плата в SDP-режиме)
|
||||
[group('util')]
|
||||
sdp-status:
|
||||
sdphost -u 0x1FC9,0x0130 -- error-status
|
||||
|
||||
# Проверить что Flashloader отвечает (после jump-address)
|
||||
[group('util')]
|
||||
flashloader-status:
|
||||
blhost -u 0x15A2,0x0073 -- get-property 1 0
|
||||
|
||||
# Обновить spsdk до новой версии
|
||||
# Использование: just upgrade-tools 3.8.0
|
||||
[group('util')]
|
||||
upgrade-tools version:
|
||||
cd "{{TOOLS_DIR}}" && uv add "spsdk=={{version}}" && uv sync
|
||||
@echo " ✅ spsdk upgraded to {{version}}"
|
||||
@echo " Run: git add tools/host/uv.lock tools/host/pyproject.toml"
|
||||
|
|
|
|||
70
README.md
70
README.md
|
|
@ -45,11 +45,13 @@
|
|||
│ └── host/ # Инструменты для работы с таргетом
|
||||
│ ├── flash_usb.py # Прошивка через USB ROM (nxp-spsdk / blhost)
|
||||
│ ├── hab/ # Утилиты и гайд по HAB (Secure Boot)
|
||||
│ ├── dcd/ # Device Configuration Data
|
||||
│ └── HOW_TO_FLASH.md → см. также /HOW_TO_FLASH.md
|
||||
│ └── dcd/ # Device Configuration Data
|
||||
├── just/ # Just-модули (автоматизация)
|
||||
│ ├── build.just # Сборка, тесты, HAB-образы (devcontainer)
|
||||
│ ├── host.just # Прошивка, bootstrap, HIL (хост)
|
||||
│ └── ci.just # CI/CD пайплайны
|
||||
├── scripts/
|
||||
│ ├── bootstrap.sh # Первичная настройка окружения
|
||||
│ └── build.just # Рецепты сборки (используется через Justfile)
|
||||
│ └── bootstrap.sh # Первичная настройка окружения (уровень 0)
|
||||
├── docs/ # Документация проекта
|
||||
│ ├── DEV_ARCH.md # Архитектура окружения разработки
|
||||
│ ├── CMAKE_HINTS.md # Шпаргалка по CMake в проекте
|
||||
|
|
@ -58,7 +60,7 @@
|
|||
│ └── manufacturing_user's_guide.pdf
|
||||
├── CMakeLists.txt # Корневой CMake
|
||||
├── CMakePresets.json # Пресеты сборки (Release/Debug/Host)
|
||||
├── Justfile # Точка входа для команд сборки/тестирования/прошивки
|
||||
├── Justfile # Точка входа для команд (модули: build, host, ci)
|
||||
└── README.md
|
||||
```
|
||||
|
||||
|
|
@ -88,10 +90,10 @@ Bare-metal прошивка для **входного контроля** пла
|
|||
|
||||
Стратегия тестирования двухуровневая:
|
||||
|
||||
| Уровень | Расположение | Инструменты | Запуск |
|
||||
|---|---|---|---|
|
||||
| **Host-тесты** (unit + интеграционные) | `tests/host/` | Unity + fff | `ctest` в devcontainer |
|
||||
| **Target-тесты** (аппаратные) | `tests/target/` | Unity на железе | Удалённый ПК-сервер через SSH |
|
||||
| Уровень | Расположение | Инструменты | Запуск |
|
||||
| -------------------------------------- | --------------- | --------------- | -------------------------------------- |
|
||||
| **Host-тесты** (unit + интеграционные) | `tests/host/` | Unity + fff | `just build::test-host` в devcontainer |
|
||||
| **Target-тесты** (аппаратные) | `tests/target/` | Unity на железе | Удалённый ПК-сервер через SSH |
|
||||
|
||||
Подробнее — [tests/HostTestingGuide.md](tests/HostTestingGuide.md) и [tests/README.md](tests/README.md).
|
||||
|
||||
|
|
@ -99,12 +101,12 @@ Bare-metal прошивка для **входного контроля** пла
|
|||
|
||||
## Управление зависимостями
|
||||
|
||||
| Зависимость | Подход | Причина |
|
||||
|---|---|---|
|
||||
| NXP MCUXpresso SDK | vendored | Стабильная версия, обновлений не планируется |
|
||||
| FreeRTOS, FatFS, LittleFS и др. | vendored (через SDK) | Стабильные версии |
|
||||
| Unity + fff | vendored | Маленькие, стабильные |
|
||||
| SEGGER RTT | vendored | Стабильный |
|
||||
| Зависимость | Подход | Причина |
|
||||
| ------------------------------- | -------------------- | -------------------------------------------- |
|
||||
| NXP MCUXpresso SDK | vendored | Стабильная версия, обновлений не планируется |
|
||||
| FreeRTOS, FatFS, LittleFS и др. | vendored (через SDK) | Стабильные версии |
|
||||
| Unity + fff | vendored | Маленькие, стабильные |
|
||||
| SEGGER RTT | vendored | Стабильный |
|
||||
|
||||
**Принцип:** всё что не меняется — vendored (закоммичено в репозиторий). Это обеспечивает полностью автономную сборку после `git clone` без доступа к интернету.
|
||||
|
||||
|
|
@ -112,18 +114,18 @@ Bare-metal прошивка для **входного контроля** пла
|
|||
|
||||
## Devcontainer — состав окружения
|
||||
|
||||
| Инструмент | Назначение |
|
||||
|---|---|
|
||||
| `arm-none-eabi-gcc` | Сборка firmware для таргета |
|
||||
| `arm-none-eabi-gdb` | Отладка через GDB server (удалённая) |
|
||||
| `gcc` (host) | Сборка и запуск host-тестов |
|
||||
| `CMake + Ninja` | Система сборки |
|
||||
| `CTest` | Запуск тестов (Unity + fff) |
|
||||
| `clangd` | Language server для VSCode |
|
||||
| `clang-format` | Форматирование кода |
|
||||
| `clang-tidy` | Статический анализ |
|
||||
| `Python 3 + nxp-spsdk` | Прошивка (blhost, nxpimage), HAB, провизия |
|
||||
| `just` | Запуск рецептов сборки/тестирования/прошивки |
|
||||
| Инструмент | Назначение |
|
||||
| ---------------------- | -------------------------------------- |
|
||||
| `arm-none-eabi-gcc` | Сборка firmware для таргета |
|
||||
| `arm-none-eabi-gdb` | Отладка через GDB server (удалённая) |
|
||||
| `gcc` (host) | Сборка и запуск host-тестов |
|
||||
| `CMake + Ninja` | Система сборки |
|
||||
| `CTest` | Запуск тестов (Unity + fff) |
|
||||
| `clangd` | Language server для VSCode |
|
||||
| `clang-format` | Форматирование кода |
|
||||
| `clang-tidy` | Статический анализ |
|
||||
| `Python 3 + nxp-spsdk` | HAB-образы (nxpimage) |
|
||||
| `just` | Запуск рецептов через модули `build::` |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -139,13 +141,19 @@ Bare-metal прошивка для **входного контроля** пла
|
|||
git clone <repo-url>
|
||||
cd tft_manufacture_test
|
||||
|
||||
# Инициализация хоста (один раз)
|
||||
sudo chmod +x bootstrap.sh
|
||||
./bootstrap.sh
|
||||
|
||||
# Открыть в VSCode → Reopen in Container
|
||||
# Затем внутри devcontainer:
|
||||
|
||||
just build-host # сборка host-тестов
|
||||
just test # запуск host-тестов через CTest
|
||||
just build-firmware # сборка firmware для таргета
|
||||
just flash # прошивка через USB ROM
|
||||
just build::test-host # сборка и запуск host-тестов
|
||||
just build::build-firmware-test-debug # сборка firmware для таргета
|
||||
just build::hab-firmware-test-debug # подготовка HAB-образа
|
||||
|
||||
# На хосте (вне контейнера):
|
||||
just flash # прошивка через USB ROM
|
||||
```
|
||||
|
||||
> Подробнее о прошивке — [HOW_TO_FLASH.md](HOW_TO_FLASH.md)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# scripts/bootstrap.sh
|
||||
# bootstrap.sh
|
||||
# Уровень 0: устанавливает just (если отсутствует), затем передаёт управление
|
||||
# just bootstrap для полной инициализации окружения.
|
||||
# just host::bootstrap для полной инициализации окружения.
|
||||
#
|
||||
# Поддерживаемые платформы:
|
||||
# Linux — bash (native)
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
# Windows — Git Bash (поставляется вместе с git)
|
||||
#
|
||||
# Требования: bash >= 4, curl (Linux/macOS) или winget (Windows)
|
||||
# Запуск: ./scripts/bootstrap.sh
|
||||
# Запуск: ./bootstrap.sh
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
|
|
@ -23,18 +23,17 @@ YELLOW="\033[1;33m"
|
|||
GREEN="\033[0;32m"
|
||||
RESET="\033[0m"
|
||||
|
||||
info() { echo -e " ${BOLD}${*}${RESET}"; }
|
||||
success() { echo -e " ${GREEN}✅ ${*}${RESET}"; }
|
||||
warn() { echo -e " ${YELLOW}⚠️ ${*}${RESET}"; }
|
||||
error() { echo -e " ${RED}❌ ${*}${RESET}"; }
|
||||
info() { echo -e " ${BOLD}${*}${RESET}"; }
|
||||
success() { echo -e " ${GREEN}✅ ${*}${RESET}"; }
|
||||
warn() { echo -e " ${YELLOW}⚠️ ${*}${RESET}"; }
|
||||
error() { echo -e " ${RED}❌ ${*}${RESET}"; }
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}=== TFT Firmware — Bootstrap ===${RESET}"
|
||||
echo -e "${BOLD}=== Project Bootstrap ===${RESET}"
|
||||
echo ""
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 1. Определить платформу
|
||||
# uname на Git Bash: MINGW64_NT-10.0-19045, MSYS_NT-..., CYGWIN_NT-...
|
||||
# -----------------------------------------------------------------------------
|
||||
_uname="$(uname -s)"
|
||||
case "${_uname}" in
|
||||
|
|
@ -52,17 +51,15 @@ echo ""
|
|||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2. Сравнение semver без sort -V (недоступен в Git Bash)
|
||||
# Возвращает 0 если $1 >= $2
|
||||
# -----------------------------------------------------------------------------
|
||||
semver_ge() {
|
||||
local a="$1" b="$2"
|
||||
local a1 a2 a3 b1 b2 b3
|
||||
IFS='.' read -r a1 a2 a3 <<< "${a}"
|
||||
IFS='.' read -r b1 b2 b3 <<< "${b}"
|
||||
# Убрать нечисловые суффиксы (1.36.0-beta -> обнулить суффикс)
|
||||
a1="${a1//[^0-9]/}"; a2="${a2//[^0-9]/}"; a3="${a3//[^0-9]/}"
|
||||
b1="${b1//[^0-9]/}"; b2="${b2//[^0-9]/}"; b3="${b3//[^0-9]/}"
|
||||
|
||||
|
||||
[[ "${a1:-0}" -gt "${b1:-0}" ]] && return 0
|
||||
[[ "${a1:-0}" -lt "${b1:-0}" ]] && return 1
|
||||
[[ "${a2:-0}" -gt "${b2:-0}" ]] && return 0
|
||||
|
|
@ -79,7 +76,7 @@ install_just_linux() {
|
|||
mkdir -p "${LINUX_INSTALL_DIR}"
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh \
|
||||
| bash -s -- --tag "${JUST_VERSION}" --to "${LINUX_INSTALL_DIR}"
|
||||
|
||||
|
||||
if ! echo "${PATH}" | grep -q "${LINUX_INSTALL_DIR}"; then
|
||||
warn "${LINUX_INSTALL_DIR} not in PATH -- adding for this session"
|
||||
warn "Add to ~/.bashrc to make permanent:"
|
||||
|
|
@ -98,18 +95,18 @@ install_just_macos() {
|
|||
}
|
||||
|
||||
install_just_windows() {
|
||||
# Предпочитаем winget -- кладёт just.exe в системный PATH автоматически
|
||||
if command -v winget &>/dev/null; then
|
||||
info "Installing just via winget..."
|
||||
winget install --id Casey.Just \
|
||||
--accept-package-agreements --accept-source-agreements || {
|
||||
error "winget install failed."
|
||||
echo " Run manually in PowerShell: winget install --id Casey.Just"
|
||||
echo " Then restart Git Bash and re-run: ./scripts/bootstrap.sh"
|
||||
echo " Then restart Git Bash and re-run: ./bootstrap.sh"
|
||||
exit 1
|
||||
}
|
||||
|
||||
warn "Restart Git Bash so the new PATH from winget takes effect,"
|
||||
warn "then re-run: ./scripts/bootstrap.sh"
|
||||
warn "then re-run: ./bootstrap.sh"
|
||||
exit 0
|
||||
else
|
||||
error "winget not found."
|
||||
|
|
@ -143,15 +140,15 @@ if [[ "${JUST_OK}" == "false" ]]; then
|
|||
macos) install_just_macos ;;
|
||||
windows) install_just_windows ;;
|
||||
esac
|
||||
|
||||
|
||||
JUST_CURRENT="$(just --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')"
|
||||
success "just ${JUST_CURRENT} installed"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 5. Передать управление just bootstrap
|
||||
# 5. Передать управление just host::bootstrap для дальнейшей настройки рабочего окружения
|
||||
# -----------------------------------------------------------------------------
|
||||
info "Delegating to: just bootstrap"
|
||||
info "Delegating to: just host::bootstrap"
|
||||
echo ""
|
||||
exec just bootstrap "$@"
|
||||
exec just host::bootstrap "$@"
|
||||
259
docs/DEV_ARCH.md
259
docs/DEV_ARCH.md
|
|
@ -13,10 +13,10 @@
|
|||
|
||||
**Devcontainer** — всё что касается кода: сборка, статический анализ,
|
||||
форматирование, host-тесты, подготовка HAB-образов. Разработчик проводит
|
||||
здесь большую часть времени. Управляется через VSCode tasks и `scripts/build.just`.
|
||||
здесь большую часть времени. Управляется через VSCode tasks и модуль `just build::`.
|
||||
|
||||
**Хост** — всё что касается железа: прошивка платы через USB, отладка
|
||||
через JLink/probe-rs. Управляется через корневой `Justfile`.
|
||||
через JLink/probe-rs. Управляется через модуль `just host::`.
|
||||
|
||||
Такое разделение решает несколько проблем: USB-устройства не требуют
|
||||
проброса в контейнер; оба разработчика работают в идентичных условиях;
|
||||
|
|
@ -30,10 +30,11 @@ CI использует те же команды что и локальная р
|
|||
ПК разработчика
|
||||
│
|
||||
├── Хост (Linux / macOS / Windows + Git Bash)
|
||||
│ ├── just ← запуск задач хостового уровня
|
||||
│ ├── just ← запуск задач хостового уровня (just host::*)
|
||||
│ ├── docker ← управление devcontainer
|
||||
│ ├── git ← работа с репозиторием
|
||||
│ ├── uv + spsdk ← прошивка платы (flash_usb.py, sdphost, blhost)
|
||||
│ │ venv: tools/host/.venv-host
|
||||
│ ├── JLinkGDBServer / probe-rs ← сервер отладки (USB → TCP :2331)
|
||||
│ └── VSCode ← IDE (Dev Containers extension)
|
||||
│
|
||||
|
|
@ -45,8 +46,9 @@ CI использует те же команды что и локальная р
|
|||
│ ├── clang-tidy-17 ← статический анализ
|
||||
│ ├── clang-format-17 ← форматирование кода
|
||||
│ ├── cmake-format ← форматирование CMakeLists
|
||||
│ ├── just ← запуск задач внутри контейнера
|
||||
│ ├── just ← запуск задач внутри контейнера (just build::*)
|
||||
│ ├── uv + spsdk ← сборка HAB-образов (только nxpimage)
|
||||
│ │ venv: tools/host/.venv-container
|
||||
│ └── Unity + fff ← фреймворки host-тестов
|
||||
│
|
||||
└── Плата TFT (IMXRT1052) — на столе у разработчика
|
||||
|
|
@ -59,18 +61,18 @@ CI использует те же команды что и локальная р
|
|||
|
||||
## 3. Что устанавливается и где
|
||||
|
||||
| Инструмент | Хост | Devcontainer | Сервер |
|
||||
|---|---|---|---|
|
||||
| `just` | ✅ | ✅ Dockerfile | ✅ |
|
||||
| `docker` | ✅ | — | — |
|
||||
| `git` | ✅ | ✅ | ✅ |
|
||||
| `uv` | ✅ | ✅ Dockerfile | ✅ |
|
||||
| `spsdk` | ✅ uv sync | ✅ uv sync | ✅ uv sync |
|
||||
| ARM GCC toolchain | — | ✅ | — |
|
||||
| `cmake` / `ninja` | — | ✅ | — |
|
||||
| `clang` / `clangd` | — | ✅ | — |
|
||||
| Unity / fff | — | ✅ | — |
|
||||
| JLink / probe-rs | ✅ | — | — |
|
||||
| Инструмент | Хост | Devcontainer | Сервер |
|
||||
| ------------------ | --------- | ------------ | --------- |
|
||||
| `just` | ✅ | ✅ Dockerfile | ✅ |
|
||||
| `docker` | ✅ | — | — |
|
||||
| `git` | ✅ | ✅ | ✅ |
|
||||
| `uv` | ✅ | ✅ Dockerfile | ✅ |
|
||||
| `spsdk` | ✅ uv sync | ✅ uv sync | ✅ uv sync |
|
||||
| ARM GCC toolchain | — | ✅ | — |
|
||||
| `cmake` / `ninja` | — | ✅ | — |
|
||||
| `clang` / `clangd` | — | ✅ | — |
|
||||
| Unity / fff | — | ✅ | — |
|
||||
| JLink / probe-rs | ✅ | — | — |
|
||||
|
||||
`spsdk` присутствует везде, но с разными ролями:
|
||||
|
||||
|
|
@ -81,16 +83,21 @@ CI использует те же команды что и локальная р
|
|||
Версия `spsdk` зафиксирована в `tools/host/uv.lock` — все три места
|
||||
используют одну и ту же версию.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 4. Структура репозитория (automation-часть)
|
||||
|
||||
```bash
|
||||
/
|
||||
├── Justfile ← хост: прошивка, setup, pipeline
|
||||
├── Justfile ← корневой оркестратор; модули: build, host, ci
|
||||
├── just/
|
||||
│ ├── build.just ← devcontainer: сборка, тесты, HAB
|
||||
│ ├── host.just ← хост: прошивка, bootstrap, HIL
|
||||
│ └── ci.just ← CI/CD пайплайны
|
||||
├── scripts/
|
||||
│ └── bootstrap.sh ← уровень 0: just → just bootstrap
|
||||
│ └── build.just ← devcontainer: сборка, тесты, HAB
|
||||
│ └── bootstrap.sh ← уровень 0: just → just host::bootstrap
|
||||
├── .devcontainer/
|
||||
│ ├── Dockerfile
|
||||
│ └── devcontainer.json
|
||||
|
|
@ -110,7 +117,7 @@ CI использует те же команды что и локальная р
|
|||
│ ├── pyproject.toml
|
||||
│ └── uv.lock
|
||||
├── .vscode/
|
||||
│ └── tasks.json ← UI для build.just (внутри devcontainer)
|
||||
│ └── tasks.json ← UI для just build::* (внутри devcontainer)
|
||||
├── CMakePresets.json
|
||||
├── cmake/
|
||||
├── sdk/
|
||||
|
|
@ -119,7 +126,7 @@ CI использует те же команды что и локальная р
|
|||
├── firmware/
|
||||
│ ├── test/
|
||||
│ ├── bootloader/
|
||||
│ └── app/
|
||||
│ └── tft_app/
|
||||
└── tests/ ← host-тесты (Unity + fff)
|
||||
```
|
||||
|
||||
|
|
@ -129,17 +136,17 @@ CI использует те же команды что и локальная р
|
|||
|
||||
### 5.1 Предварительные требования
|
||||
|
||||
| Платформа | Что нужно до bootstrap |
|
||||
|---|---|
|
||||
| Linux | `docker`, `git`, `curl` |
|
||||
| macOS | Docker Desktop, `git` (Xcode CLT) |
|
||||
| Windows | Docker Desktop, Git for Windows → **использовать Git Bash** |
|
||||
| Платформа | Что нужно до bootstrap |
|
||||
| --------- | ----------------------------------------------------------- |
|
||||
| Linux | `docker`, `git`, `curl` |
|
||||
| macOS | Docker Desktop, `git` (Xcode CLT) |
|
||||
| Windows | Docker Desktop, Git for Windows → **использовать Git Bash** |
|
||||
|
||||
### 5.2 Единственная команда для нового разработчика
|
||||
|
||||
```bash
|
||||
git clone <repo-url> && cd <repo>
|
||||
./scripts/bootstrap.sh
|
||||
./bootstrap.sh
|
||||
```
|
||||
|
||||
### 5.3 Что делает bootstrap
|
||||
|
|
@ -151,15 +158,15 @@ bootstrap.sh (уровень 0)
|
|||
│ uname: MINGW64_NT-... → windows, Linux → linux, Darwin → macos
|
||||
│
|
||||
├── проверить just (semver без sort -V — работает в Git Bash)
|
||||
│ < 1.27.0 или отсутствует:
|
||||
│ < 1.36.0 или отсутствует:
|
||||
│ Linux/macOS → curl | bash → ~/.local/bin/just
|
||||
│ Windows → winget install --id Casey.Just
|
||||
│ (перезапустить Git Bash после установки)
|
||||
│
|
||||
└── exec just bootstrap
|
||||
└── exec just host::bootstrap
|
||||
│
|
||||
├── [1/3] check-deps
|
||||
│ just >= 1.27.0 · uv >= 0.4.0 · docker >= 24.0.0
|
||||
│ just >= 1.36.0 · uv >= 0.4.0 · docker >= 24.0.0
|
||||
│ платформо-зависимые подсказки при ошибках
|
||||
│
|
||||
├── [2/3] setup-udev (только Linux)
|
||||
|
|
@ -170,7 +177,7 @@ bootstrap.sh (уровень 0)
|
|||
│ требует re-login · на macOS/Windows пропускается
|
||||
│
|
||||
└── [3/3] setup-tools
|
||||
uv sync в tools/host/
|
||||
uv sync в tools/host/ (venv: .venv-host на хосте)
|
||||
SHA-256 uv.lock кэшируется в .cache/
|
||||
повторный вызов мгновенный если lockfile не изменился
|
||||
```
|
||||
|
|
@ -184,7 +191,7 @@ bootstrap.sh (уровень 0)
|
|||
`postCreateCommand` выполняется автоматически при поднятии контейнера:
|
||||
|
||||
```bash
|
||||
cd tools/host && uv sync &&
|
||||
cd tools/host && uv sync && # venv: .venv-container
|
||||
cd ../.. &&
|
||||
cmake --preset host-debug &&
|
||||
cmake --preset Debug
|
||||
|
|
@ -199,21 +206,21 @@ cmake --preset Debug
|
|||
|
||||
### 6.1 Три подпроекта
|
||||
|
||||
| Прошивка | Boot-стратегия | DCD | Назначение |
|
||||
|---|---|---|---|
|
||||
| `firmware_test` | XIP из Flash | ✅ | Входной контроль, тестирование периферии |
|
||||
| `bootloader` | Копирование в ITCM | ❌ | Загрузчик, не использует SDRAM |
|
||||
| `app` | XIP + буферы в SDRAM | ✅ | Основное приложение (FreeRTOS, LCDIF) |
|
||||
| Прошивка | Boot-стратегия | DCD | Назначение |
|
||||
| --------------- | -------------------- | ---- | ---------------------------------------- |
|
||||
| `firmware_test` | XIP из Flash | ✅ | Входной контроль, тестирование периферии |
|
||||
| `bootloader` | Копирование в ITCM | ❌ | Загрузчик, не использует SDRAM |
|
||||
| `tft_app` | XIP + буферы в SDRAM | ✅ | Основное приложение (FreeRTOS, LCDIF) |
|
||||
|
||||
### 6.2 Матрица сборки
|
||||
|
||||
Каждый проект собирается в двух режимах:
|
||||
|
||||
| | Debug | Release |
|
||||
|---|---|---|
|
||||
| `firmware_test` | разработка, отладка | HAB для сервера |
|
||||
| `bootloader` | отладка загрузчика | финальная прошивка |
|
||||
| `app` | отладка приложения | финальная прошивка |
|
||||
| | Debug | Release |
|
||||
| --------------- | ------------------- | ------------------ |
|
||||
| `firmware_test` | разработка, отладка | HAB для сервера |
|
||||
| `bootloader` | отладка загрузчика | финальная прошивка |
|
||||
| `tft_app` | отладка приложения | финальная прошивка |
|
||||
|
||||
### 6.3 CMake пресеты
|
||||
|
||||
|
|
@ -235,7 +242,7 @@ buildPresets (host):
|
|||
```bash
|
||||
0x60000000 FCB — Flash Config Block 512 байт (пишет Flashloader)
|
||||
0x60001000 IVT + BDT ← начало HAB-образа
|
||||
0x60001040 DCD — инициализация SDRAM ~1088 байт (firmware_test, app)
|
||||
0x60001040 DCD — инициализация SDRAM ~1088 байт (firmware_test, tft_app)
|
||||
0x60003000 Код прошивки (.text, .data…)
|
||||
```
|
||||
|
||||
|
|
@ -245,17 +252,17 @@ buildPresets (host):
|
|||
|
||||
### 7.1 Карта задач по контекстам
|
||||
|
||||
| Задача | Где |
|
||||
|---|---|
|
||||
| Написание кода, clangd, форматирование | devcontainer |
|
||||
| Статический анализ (clang-tidy) | devcontainer |
|
||||
| Host-тесты (Unity + fff) | devcontainer |
|
||||
| Сборка ARM firmware (ELF) | devcontainer |
|
||||
| Подготовка HAB-образов (nxpimage) | devcontainer |
|
||||
| Прошивка платы через USB | **хост** |
|
||||
| Отладка — GDB-сервер (JLink/probe-rs) | **хост** |
|
||||
| Отладка — GDB-клиент | devcontainer → хост по TCP |
|
||||
| Target-тесты (управление стендом) | **хост** |
|
||||
| Задача | Где |
|
||||
| -------------------------------------- | -------------------------- |
|
||||
| Написание кода, clangd, форматирование | devcontainer |
|
||||
| Статический анализ (clang-tidy) | devcontainer |
|
||||
| Host-тесты (Unity + fff) | devcontainer |
|
||||
| Сборка ARM firmware (ELF) | devcontainer |
|
||||
| Подготовка HAB-образов (nxpimage) | devcontainer |
|
||||
| Прошивка платы через USB | **хост** |
|
||||
| Отладка — GDB-сервер (JLink/probe-rs) | **хост** |
|
||||
| Отладка — GDB-клиент | devcontainer → хост по TCP |
|
||||
| Target-тесты (управление стендом) | **хост** |
|
||||
|
||||
### 7.2 Типичная сессия разработки
|
||||
|
||||
|
|
@ -265,7 +272,7 @@ buildPresets (host):
|
|||
├── писать код
|
||||
│
|
||||
├── Ctrl+Shift+P → "Run Task" → 🧪 Host Tests (Debug)
|
||||
│ или в терминале: just --justfile just/build.just test-host
|
||||
│ или в терминале: just build::test-host
|
||||
│
|
||||
├── Ctrl+Shift+P → "Run Task" → 🔨 Build → firmware-test · debug
|
||||
│ → build/Debug/firmware/test/firmware_test.elf
|
||||
|
|
@ -277,22 +284,22 @@ buildPresets (host):
|
|||
│
|
||||
├── just flash firmware_test debug ← прошить отладочный образ
|
||||
│ или
|
||||
├── just flash-ram firmware_test debug ← загрузить в RAM (быстро, без износа Flash)
|
||||
├── just host::flash-ram firmware_test debug ← загрузить в RAM (быстро, без износа Flash)
|
||||
│
|
||||
└── F5 в VSCode → отладка через JLink
|
||||
```
|
||||
|
||||
### 7.3 VSCode Tasks (внутри devcontainer)
|
||||
|
||||
| Таск | Input 1 | Input 2 | Команда |
|
||||
|---|---|---|---|
|
||||
| 🔨 Build | project | debug/release | `just build-<project>-<type>` |
|
||||
| 🧪 Host Tests (Debug) | — | — | `just test-host` |
|
||||
| 🧪 Host Tests (Release) | — | — | `just test-host-release` |
|
||||
| 📦 HAB Image | project | debug/release | `just hab-<project>-<type>` |
|
||||
| 📦 HAB All (Debug) | — | — | `just hab-all-debug` |
|
||||
| 📦 HAB All (Release) | — | — | `just hab-all-release` |
|
||||
| 🗑️ Clean | — | — | `just clean` |
|
||||
| Таск | Input 1 | Input 2 | Команда |
|
||||
| ---------------------- | ------- | ------------- | ------------------------------------ |
|
||||
| 🔨 Build | project | debug/release | `just build::build-<project>-<type>` |
|
||||
| 🧪 Host Tests (Debug) | — | — | `just build::test-host` |
|
||||
| 🧪 Host Tests (Release) | — | — | `just build::test-host-release` |
|
||||
| 📦 HAB Image | project | debug/release | `just build::hab-<project>-<type>` |
|
||||
| 📦 HAB All (Debug) | — | — | `just build::hab-all-debug` |
|
||||
| 📦 HAB All (Release) | — | — | `just build::hab-all-release` |
|
||||
| 🗑️ Clean | — | — | `just build::clean` |
|
||||
|
||||
Таски «Build» и «HAB Image» запрашивают два input последовательно:
|
||||
сначала проект (`firmware-test / bootloader / app / all`),
|
||||
|
|
@ -309,7 +316,7 @@ buildPresets (host):
|
|||
2. Reset
|
||||
3. Подключить USB к хосту
|
||||
→ плата определяется как VID:PID = 1FC9:0130
|
||||
4. Выполнить нужный just flash-* рецепт
|
||||
4. Выполнить нужный just host::flash-* рецепт
|
||||
5. После прошивки: BOOT_MOD_1 → GND, Reset
|
||||
→ плата стартует из Flash
|
||||
```
|
||||
|
|
@ -318,23 +325,24 @@ buildPresets (host):
|
|||
|
||||
```bash
|
||||
# Основной рецепт (project × type)
|
||||
just flash firmware_test debug # разработка — итерации с отладчиком
|
||||
just flash firmware_test release # проверить как будет на сервере
|
||||
just flash bootloader debug
|
||||
just flash bootloader release
|
||||
just flash app debug
|
||||
just flash app release
|
||||
just host::flash firmware_test debug # разработка — итерации с отладчиком
|
||||
just host::flash firmware_test release # проверить как будет на сервере
|
||||
just host::flash bootloader debug
|
||||
just host::flash bootloader release
|
||||
just host::flash tft_app debug
|
||||
just host::flash tft_app release
|
||||
|
||||
# TODO: Загрузка в RAM — без записи во Flash, мгновенный старт
|
||||
# Удобно для частых итераций: не изнашивает Flash, не нужен BOOT_MOD переключатель
|
||||
just flash-ram firmware_test # default: debug
|
||||
just flash-ram firmware_test debug
|
||||
just flash-ram app release
|
||||
# Загрузка в RAM — без записи во Flash, мгновенный старт
|
||||
# Удобно для частых итераций: не изнашивает Flash
|
||||
just host::flash-ram firmware_test # default: debug
|
||||
just host::flash-ram firmware_test debug
|
||||
just host::flash-ram tft_app release
|
||||
|
||||
# TODO: Быстрые псевдонимы
|
||||
just flash-test-debug # = just flash firmware_test debug
|
||||
just flash-test-release # = just flash firmware_test release
|
||||
just flash-production # bootloader release + app release
|
||||
# Быстрые псевдонимы (из корневого Justfile)
|
||||
just flash # = just host::flash-test-debug
|
||||
just host::flash-test-debug
|
||||
just host::flash-test-release
|
||||
just host::flash-production # bootloader release + tft_app release
|
||||
```
|
||||
|
||||
### 8.3 Что происходит внутри flash_usb.py
|
||||
|
|
@ -403,7 +411,7 @@ Devcontainer
|
|||
Фреймворк: Unity + fff
|
||||
Пресеты: host-debug / host-release
|
||||
Компилятор: системный clang-17 (не ARM GCC)
|
||||
Запуск: just --justfile just/build.just test-host
|
||||
Запуск: just build::test-host
|
||||
Результат: JUnit XML → VSCode CTest Lab + GitLab CI
|
||||
```
|
||||
|
||||
|
|
@ -439,17 +447,17 @@ Devcontainer
|
|||
feature-ветка
|
||||
│
|
||||
├── код в devcontainer
|
||||
│ 🧪 Host Tests ← зелёные?
|
||||
│ 🔨 Build firmware-test debug ← компилируется?
|
||||
│ just build::test-host ← зелёные?
|
||||
│ just build::build-firmware-test-debug ← компилируется?
|
||||
│
|
||||
├── проверка на железе
|
||||
│ 📦 HAB Image → firmware-test · debug
|
||||
│ just flash-test-debug ← прошить
|
||||
│ target-тесты со стендом ← периферия работает?
|
||||
│ just build::hab-firmware-test-debug
|
||||
│ just flash ← прошить (алиас flash-test-debug)
|
||||
│ target-тесты со стендом ← периферия работает?
|
||||
│
|
||||
├── подготовка к MR
|
||||
│ 📦 HAB All (Release) ← финальные образы
|
||||
│ just flash firmware_test release ← убедиться что release работает
|
||||
│ just build::hab-all-release ← финальные образы
|
||||
│ just host::flash firmware_test release ← убедиться что release работает
|
||||
│
|
||||
└── Merge Request → GitLab
|
||||
[CI pipeline — отдельная тема]
|
||||
|
|
@ -457,29 +465,29 @@ feature-ветка
|
|||
│
|
||||
▼
|
||||
Производственный сервер
|
||||
just incoming → firmware_test release → HIL
|
||||
just production → bootloader + app release
|
||||
just host::incoming → firmware_test release → HIL
|
||||
just host::production → bootloader + tft_app release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Обновление зависимостей
|
||||
|
||||
### spsdk (на хосте разработчика)
|
||||
### spsdk
|
||||
|
||||
```bash
|
||||
just upgrade-tools 3.8.0
|
||||
just host::upgrade-tools 3.8.0
|
||||
git add tools/host/uv.lock tools/host/pyproject.toml
|
||||
git commit -m "chore: upgrade spsdk to 3.8.0"
|
||||
```
|
||||
|
||||
После этого у всех разработчиков и в контейнере обновится автоматически
|
||||
при следующем `just setup-tools` / `uv sync`.
|
||||
при следующем `just host::setup-tools` / `uv sync`.
|
||||
|
||||
### just в Dockerfile
|
||||
|
||||
```dockerfile
|
||||
ARG JUST_VERSION=1.40.0 # .devcontainer/Dockerfile — единственное место
|
||||
ARG JUST_VERSION=1.36.0 # .devcontainer/Dockerfile — единственное место
|
||||
```
|
||||
|
||||
### ARM toolchain
|
||||
|
|
@ -494,7 +502,7 @@ ARG TOOLCHAIN_VERSION=14.2.rel1 # .devcontainer/Dockerfile
|
|||
### После git pull если изменился uv.lock
|
||||
|
||||
```bash
|
||||
just setup-tools # автоматически обнаружит изменение и выполнит uv sync
|
||||
just host::setup-tools # автоматически обнаружит изменение и выполнит uv sync
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -509,12 +517,12 @@ just setup-tools # автоматически обнаружит измене
|
|||
— только теггированные релизы, прошедшие CI
|
||||
|
||||
Сценарий входного контроля новой платы:
|
||||
1. just incoming
|
||||
1. just host::incoming
|
||||
└── flash firmware_test release → HIL-тесты периферии
|
||||
2. Тесты пройдены:
|
||||
just production
|
||||
just host::production
|
||||
├── flash bootloader release
|
||||
└── flash app release
|
||||
└── flash tft_app release
|
||||
|
||||
Установлено: just · uv + spsdk · git
|
||||
НЕ установлено: docker · cmake · компилятор · ARM toolchain
|
||||
|
|
@ -526,41 +534,42 @@ just setup-tools # автоматически обнаружит измене
|
|||
|
||||
## Приложение А: минимальные версии
|
||||
|
||||
| Инструмент | Версия | Причина |
|
||||
|---|---|---|
|
||||
| `just` | 1.27.0 | поддержка `[group()]` |
|
||||
| `uv` | 0.4.0 | стабильный lockfile формат |
|
||||
| `docker` | 24.0.0 | Compose v2, `--build-arg` |
|
||||
| `spsdk` | 3.7.x | совместимость с HAB yaml-форматом |
|
||||
| ARM GCC | 13.3.rel1 | C11, LTO, текущий SDK |
|
||||
| clang/clangd | 17 | поддержка `If:` в `.clangd` |
|
||||
| Инструмент | Версия | Причина |
|
||||
| ------------ | --------- | ------------------------------------------------------------ |
|
||||
| `just` | 1.36.0 | поддержка `mod` с кастомным путём (`mod host 'just/host.just'`) |
|
||||
| `uv` | 0.4.0 | стабильный lockfile формат |
|
||||
| `docker` | 24.0.0 | Compose v2, `--build-arg` |
|
||||
| `spsdk` | 3.7.x | совместимость с HAB yaml-форматом |
|
||||
| ARM GCC | 13.3.rel1 | C11, LTO, текущий SDK |
|
||||
| clang/clangd | 17 | поддержка `If:` в `.clangd` |
|
||||
|
||||
## Приложение Б: быстрая шпаргалка
|
||||
|
||||
```bash
|
||||
# ── Первый запуск ──────────────────────────────────────────────
|
||||
./scripts/bootstrap.sh # инициализация хоста
|
||||
./bootstrap.sh # инициализация хоста
|
||||
# VSCode → Reopen in Container
|
||||
|
||||
# ── Внутри devcontainer (терминал VSCode) ──────────────────────
|
||||
just --justfile just/build.just test-host
|
||||
just --justfile just/build.just build-firmware-test-debug
|
||||
just --justfile just/build.just build-app-release
|
||||
just --justfile just/build.just hab-firmware-test-debug
|
||||
just --justfile just/build.just hab-all-release
|
||||
just --justfile just/build.just clean
|
||||
just build::test-host
|
||||
just build::build-firmware-test-debug
|
||||
just build::build-tft-app-release
|
||||
just build::hab-firmware-test-debug
|
||||
just build::hab-all-release
|
||||
just build::clean
|
||||
|
||||
# ── Хостовый терминал — прошивка ───────────────────────────────
|
||||
just flash firmware_test debug # во Flash
|
||||
just flash firmware_test release
|
||||
just flash bootloader release
|
||||
just flash app release
|
||||
just flash-ram firmware_test # в RAM (быстро, без износа Flash)
|
||||
just flash-production # bootloader + app release
|
||||
just flash # алиас: firmware_test debug
|
||||
just host::flash firmware_test debug # во Flash
|
||||
just host::flash firmware_test release
|
||||
just host::flash bootloader release
|
||||
just host::flash tft_app release
|
||||
just host::flash-ram firmware_test # в RAM (быстро, без износа Flash)
|
||||
just host::flash-production # bootloader + tft_app release
|
||||
|
||||
# ── Хостовый терминал — обслуживание ───────────────────────────
|
||||
just scan # найти NXP USB-устройства
|
||||
just sdp-status # проверить BootROM
|
||||
just setup-tools # обновить spsdk после git pull
|
||||
just check-deps # проверить версии инструментов
|
||||
```
|
||||
just host::scan # найти NXP USB-устройства
|
||||
just host::sdp-status # проверить BootROM
|
||||
just host::setup-tools # обновить spsdk после git pull
|
||||
just host::check-deps # проверить версии инструментов
|
||||
```
|
||||
|
|
@ -30,7 +30,7 @@ int main(void)
|
|||
{
|
||||
BOARD_Init();
|
||||
GPIO_PinWrite(BOARD_INITPINS_UserLed1_PORT, BOARD_INITPINS_UserLed1_PIN, 0);
|
||||
//GPIO_PinWrite(BOARD_INITPINS_UserLed2_PORT, BOARD_INITPINS_UserLed2_PIN, 0);
|
||||
GPIO_PinWrite(BOARD_INITPINS_UserLed2_PORT, BOARD_INITPINS_UserLed2_PIN, 0);
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
# Рабочая директория — корень репозитория (не scripts/).
|
||||
# =============================================================================
|
||||
|
||||
set working-directory := ".."
|
||||
# === Импорт общих переменных ===
|
||||
TOOLS_DIR := env('TOOLS_DIR', justfile_directory() / 'tools/host')
|
||||
BUILD_DIR := env('BUILD_DIR', justfile_directory() / 'build')
|
||||
|
||||
TOOLS_DIR := "tools/host"
|
||||
BUILD_DIR := "build"
|
||||
set working-directory := '..'
|
||||
|
||||
_default:
|
||||
@just --list --justfile scripts/build.just --unsorted
|
||||
|
|
@ -22,7 +23,7 @@ _default:
|
|||
# app × debug / release
|
||||
# all × debug / release (все проекты сразу, для CI)
|
||||
# =============================================================================
|
||||
|
||||
# Приватные рецепты для configure (не показываются в --list)
|
||||
[private]
|
||||
_configure-debug:
|
||||
cmake --preset Debug
|
||||
|
|
@ -68,7 +69,7 @@ build-all-release: _configure-release
|
|||
cmake --build --preset all-release
|
||||
|
||||
# ── утилиты ───────────────────────────────────────────────────────────────────
|
||||
[group('build')]
|
||||
[group('build'), confirm("Delete build/ directory?")]
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ test-host-release: _configure-host-release
|
|||
# =============================================================================
|
||||
|
||||
# ── firmware_test ─────────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-firmware-test-debug: build-firmware-test-debug
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
|
@ -122,7 +123,7 @@ hab-firmware-test-debug: build-firmware-test-debug
|
|||
-o "../../../{{BUILD_DIR}}/Debug/firmware_test_hab.bin"
|
||||
echo " ✅ firmware_test_hab.bin (Debug)"
|
||||
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-firmware-test-release: build-firmware-test-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
|
@ -133,7 +134,7 @@ hab-firmware-test-release: build-firmware-test-release
|
|||
echo " ✅ firmware_test_hab.bin (Release)"
|
||||
|
||||
# ── bootloader ───────────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-bootloader-debug: build-bootloader-debug
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
|
@ -143,7 +144,7 @@ hab-bootloader-debug: build-bootloader-debug
|
|||
-o "../../../{{BUILD_DIR}}/Debug/bootloader_hab.bin"
|
||||
echo " ✅ bootloader_hab.bin (Debug)"
|
||||
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-bootloader-release: build-bootloader-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
|
@ -154,7 +155,7 @@ hab-bootloader-release: build-bootloader-release
|
|||
echo " ✅ bootloader_hab.bin (Release)"
|
||||
|
||||
# ── app ───────────────────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-app-debug: build-app-debug
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
|
@ -164,7 +165,7 @@ hab-app-debug: build-app-debug
|
|||
-o "../../../{{BUILD_DIR}}/Debug/app_hab.bin"
|
||||
echo " ✅ app_hab.bin (Debug)"
|
||||
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-app-release: build-app-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
|
@ -175,27 +176,28 @@ hab-app-release: build-app-release
|
|||
echo " ✅ app_hab.bin (Release)"
|
||||
|
||||
# ── все образы сразу ─────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-all-debug: hab-firmware-test-debug hab-bootloader-debug hab-app-debug
|
||||
@echo " ✅ All HAB images (Debug) ready"
|
||||
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-all-release: hab-firmware-test-release hab-bootloader-release hab-app-release
|
||||
@echo " ✅ All HAB images (Release) ready"
|
||||
|
||||
# ── верификация образа (для отладки) ─────────────────────────────────────────
|
||||
# Использование: just --justfile just/build.just hab-verify firmware_test debug
|
||||
[group('flash')]
|
||||
[group('hab_image_gen')]
|
||||
hab-verify project="firmware_test" type="release":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ROOT="$(pwd)"
|
||||
case "{{project}}-{{type}}" in
|
||||
firmware_test-debug) BIN="{{BUILD_DIR}}/Debug/firmware_test_hab.bin" ;;
|
||||
firmware_test-release) BIN="{{BUILD_DIR}}/Release/firmware_test_hab.bin" ;;
|
||||
bootloader-debug) BIN="{{BUILD_DIR}}/Debug/bootloader_hab.bin" ;;
|
||||
bootloader-release) BIN="{{BUILD_DIR}}/Release/bootloader_hab.bin" ;;
|
||||
app-debug) BIN="{{BUILD_DIR}}/Debug/app_hab.bin" ;;
|
||||
app-release) BIN="{{BUILD_DIR}}/Release/app_hab.bin" ;;
|
||||
firmware_test-debug) BIN="${ROOT}/{{BUILD_DIR}}/Debug/firmware_test_hab.bin" ;;
|
||||
firmware_test-release) BIN="${ROOT}/{{BUILD_DIR}}/Release/firmware_test_hab.bin" ;;
|
||||
bootloader-debug) BIN="${ROOT}/{{BUILD_DIR}}/Debug/bootloader_hab.bin" ;;
|
||||
bootloader-release) BIN="${ROOT}/{{BUILD_DIR}}/Release/bootloader_hab.bin" ;;
|
||||
app-debug) BIN="${ROOT}/{{BUILD_DIR}}/Debug/app_hab.bin" ;;
|
||||
app-release) BIN="${ROOT}/{{BUILD_DIR}}/Release/app_hab.bin" ;;
|
||||
*)
|
||||
echo " ❌ Unknown: {{project}}-{{type}}"
|
||||
echo " Projects: firmware_test, bootloader, app"
|
||||
|
|
@ -203,6 +205,20 @@ hab-verify project="firmware_test" type="release":
|
|||
exit 1 ;;
|
||||
esac
|
||||
OUT="/tmp/hab_parse_{{project}}_{{type}}.yaml"
|
||||
uv run nxpimage hab parse -b "${BIN}" -o "${OUT}"
|
||||
cd "{{TOOLS_DIR}}" && uv run nxpimage hab parse -b "${BIN}" -o "${OUT}"
|
||||
echo " ✅ ${OUT}"
|
||||
grep -E "(entry|csf|tag)" "${OUT}" || true
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: quality — линтеры, форматтеры
|
||||
# =============================================================================
|
||||
# TODO: проверять bsp,firmware, modules
|
||||
[group('quality')]
|
||||
lint:
|
||||
echo "TODO!"
|
||||
# clang-tidy -p {{BUILD_DIR}}/Debug src/**/*.c
|
||||
|
||||
[group('quality')]
|
||||
format:
|
||||
echo "TODO!"
|
||||
# clang-format -i src/**/*.{c,h}
|
||||
53
just/ci.just
Normal file
53
just/ci.just
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# =============================================================================
|
||||
# ci.just — CI/CD пайплайны
|
||||
# Выполняется в CI-окружении (GitHub Actions, GitLab CI, Jenkins)
|
||||
#
|
||||
# Предполагается что CI работает внутри devcontainer.
|
||||
# =============================================================================
|
||||
|
||||
# === Импорт общих переменных ===
|
||||
BUILD_DIR := env('BUILD_DIR', justfile_directory() / 'build')
|
||||
set working-directory := '..'
|
||||
# =============================================================================
|
||||
# ГРУППА: ci — полные пайплайны
|
||||
# =============================================================================
|
||||
|
||||
# Полный CI pipeline: сборка + тесты + линтеры
|
||||
[group('ci')]
|
||||
pipeline: build test lint
|
||||
@echo " ✅ CI pipeline complete"
|
||||
|
||||
# Сборка всех проектов в Release
|
||||
[group('ci')]
|
||||
build:
|
||||
just build::build-all-release
|
||||
|
||||
# Unit-тесты
|
||||
[group('ci')]
|
||||
test:
|
||||
just build::test-host-release
|
||||
|
||||
# TODO: Линтеры + статический анализ
|
||||
[group('ci')]
|
||||
lint:
|
||||
echo "TODO"
|
||||
#just build::lint
|
||||
#just build::check
|
||||
|
||||
# Генерация HAB-образов для релиза
|
||||
[group('ci')]
|
||||
release: build
|
||||
just build::hab-all-release
|
||||
@echo " ✅ Release artifacts ready in {{BUILD_DIR}}/Release/"
|
||||
|
||||
# Генерация coverage отчёта (если gcov настроен)
|
||||
[group('ci'), private]
|
||||
_coverage:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
if command -v gcovr &>/dev/null; then
|
||||
echo " 📊 Generating coverage report..."
|
||||
gcovr --xml -o {{BUILD_DIR}}/coverage.xml
|
||||
else
|
||||
echo " ⚠️ gcovr not found, skipping coverage"
|
||||
fi
|
||||
338
just/host.just
Normal file
338
just/host.just
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
# =============================================================================
|
||||
# host.just — операции на хост-машине (вне devcontainer)
|
||||
#
|
||||
# Ответственность:
|
||||
# - bootstrap окружения (just, uv, docker, udev)
|
||||
# - USB-прошивка через spsdk
|
||||
# - HIL-тесты на реальном железе
|
||||
# - производственные сценарии (incoming, production)
|
||||
#
|
||||
# Все рецепты должны работать БЕЗ devcontainer.
|
||||
# =============================================================================
|
||||
|
||||
# === Импорт общих переменных из корневого justfile ===
|
||||
# Благодаря `set export` в корне, эти переменные доступны
|
||||
TOOLS_DIR := env('TOOLS_DIR', justfile_directory() / 'tools/host')
|
||||
CACHE_DIR := env('CACHE_DIR', justfile_directory() / '.cache')
|
||||
|
||||
# === Минимальные версии зависимостей ===
|
||||
JUST_MIN := "1.36.0"
|
||||
UV_MIN := "0.4.0"
|
||||
DOCKER_MIN := "24.0.0"
|
||||
set working-directory := '..'
|
||||
# =============================================================================
|
||||
# ГРУППА: setup — инициализация рабочего окружения
|
||||
# =============================================================================
|
||||
|
||||
# [1/3] Проверить наличие и версии инструментов на хост-машине
|
||||
[group('setup')]
|
||||
check-deps:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BOLD="\033[1m"; GREEN="\033[0;32m"; RED="\033[0;31m"; YELLOW="\033[1;33m"; RESET="\033[0m"
|
||||
ERRORS=0; WARNINGS=0
|
||||
|
||||
ok() { echo -e " ${GREEN}✅ ${1}${RESET}"; }
|
||||
fail() { echo -e " ${RED}❌ ${1}${RESET}"; ERRORS=$((ERRORS+1)); }
|
||||
warn() { echo -e " ${YELLOW}⚠️ ${1}${RESET}"; WARNINGS=$((WARNINGS+1)); }
|
||||
|
||||
_uname="$(uname -s)"
|
||||
case "${_uname}" in
|
||||
Linux*) PLATFORM="linux" ;;
|
||||
Darwin*) PLATFORM="macos" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
|
||||
*) PLATFORM="unknown" ;;
|
||||
esac
|
||||
|
||||
# Сравнение semver без sort -V (недоступен в Git Bash)
|
||||
semver_ge() {
|
||||
local a="$1" b="$2"
|
||||
local a1 a2 a3 b1 b2 b3
|
||||
IFS='.' read -r a1 a2 a3 <<< "${a}"
|
||||
IFS='.' read -r b1 b2 b3 <<< "${b}"
|
||||
a1="${a1//[^0-9]/}"; a2="${a2//[^0-9]/}"; a3="${a3//[^0-9]/}"
|
||||
b1="${b1//[^0-9]/}"; b2="${b2//[^0-9]/}"; b3="${b3//[^0-9]/}"
|
||||
[[ "${a1:-0}" -gt "${b1:-0}" ]] && return 0
|
||||
[[ "${a1:-0}" -lt "${b1:-0}" ]] && return 1
|
||||
[[ "${a2:-0}" -gt "${b2:-0}" ]] && return 0
|
||||
[[ "${a2:-0}" -lt "${b2:-0}" ]] && return 1
|
||||
[[ "${a3:-0}" -ge "${b3:-0}" ]] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
install_hint() {
|
||||
local tool=$1
|
||||
case "${PLATFORM}" in
|
||||
linux)
|
||||
case "$tool" in
|
||||
just) echo "curl -sSf https://just.systems/install.sh | bash -s -- --to ~/.local/bin" ;;
|
||||
uv) echo "curl -LsSf https://astral.sh/uv/install.sh | sh" ;;
|
||||
docker) echo "https://docs.docker.com/engine/install/ubuntu/" ;;
|
||||
esac ;;
|
||||
macos)
|
||||
case "$tool" in
|
||||
just) echo "brew install just" ;;
|
||||
uv) echo "brew install uv" ;;
|
||||
docker) echo "brew install --cask docker" ;;
|
||||
esac ;;
|
||||
windows)
|
||||
case "$tool" in
|
||||
just) echo "winget install --id Casey.Just (в PowerShell)" ;;
|
||||
uv) echo 'powershell -c "irm https://astral.sh/uv/install.ps1 | iex"' ;;
|
||||
docker) echo "winget install --id Docker.DockerDesktop (в PowerShell)" ;;
|
||||
esac ;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_tool() {
|
||||
local name=$1 cmd=$2 min_ver=$3
|
||||
shift 3
|
||||
local ver_args=("${@:---version}")
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
fail "$name not found -- $(install_hint "$name")"
|
||||
return
|
||||
fi
|
||||
local actual
|
||||
actual=$("$cmd" "${ver_args[@]}" 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
if [[ -z "$actual" ]]; then
|
||||
warn "$name found but version could not be detected"
|
||||
return
|
||||
fi
|
||||
if semver_ge "$actual" "$min_ver"; then
|
||||
ok "$name $actual (>= $min_ver)"
|
||||
else
|
||||
fail "$name $actual -- need >= $min_ver -- $(install_hint "$name")"
|
||||
fi
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD} Platform: ${PLATFORM}${RESET}"
|
||||
echo ""
|
||||
echo -e "${BOLD} Checking host dependencies...${RESET}"
|
||||
echo ""
|
||||
|
||||
check_tool "just" "just" "{{JUST_MIN}}"
|
||||
check_tool "uv" "uv" "{{UV_MIN}}"
|
||||
check_tool "docker" "docker" "{{DOCKER_MIN}}" version --format '{{{{.Client.Version}}}}'
|
||||
|
||||
if [[ "${PLATFORM}" == "linux" ]]; then
|
||||
echo ""
|
||||
echo -e "${BOLD} Checking udev rules (Linux only)...${RESET}"
|
||||
echo ""
|
||||
rules_file="/etc/udev/rules.d/99-nxp-mimxrt.rules"
|
||||
udev_ok=true
|
||||
grep -q "1fc9" "$rules_file" 2>/dev/null || { warn "udev: BootROM rule missing (VID 1fc9)"; udev_ok=false; }
|
||||
grep -q "15a2" "$rules_file" 2>/dev/null || { warn "udev: Flashloader rule missing (VID 15a2)"; udev_ok=false; }
|
||||
if ! groups 2>/dev/null | grep -q plugdev; then
|
||||
warn "User '$(whoami)' not in 'plugdev' group"
|
||||
udev_ok=false
|
||||
fi
|
||||
if [[ "$udev_ok" == "false" ]]; then
|
||||
warn "USB flashing requires root without udev rules -- run: just setup-udev"
|
||||
else
|
||||
ok "udev rules (NXP USB) + plugdev group"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [[ $ERRORS -gt 0 ]]; then
|
||||
echo -e " ${RED}${BOLD}$ERRORS error(s) found. Fix them before continuing.${RESET}"
|
||||
echo ""
|
||||
exit 1
|
||||
elif [[ $WARNINGS -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}${BOLD}$WARNINGS warning(s). Some features may not work.${RESET}"
|
||||
else
|
||||
echo -e " ${GREEN}${BOLD}All dependencies satisfied.${RESET}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# [2/3] Установить udev правила для USB-прошивки (только Linux, требует sudo)
|
||||
[group('setup')]
|
||||
setup-udev:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
case "$(uname -s)" in
|
||||
Linux*) ;;
|
||||
*)
|
||||
echo " ℹ️ udev rules are Linux-only, skipping on $(uname -s)."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
echo " Installing udev rules for NXP USB devices..."
|
||||
printf '%s\n%s\n%s\n%s\n' \
|
||||
'# NXP BootROM -- SDP mode (BOOT_MOD_1 = 3V3)' \
|
||||
'SUBSYSTEM=="usb", ATTR{idVendor}=="1fc9", ATTR{idProduct}=="0130", MODE="0666", GROUP="plugdev"' \
|
||||
'# NXP Flashloader -- after jump-address' \
|
||||
'SUBSYSTEM=="usb", ATTR{idVendor}=="15a2", ATTR{idProduct}=="0073", MODE="0666", GROUP="plugdev"' \
|
||||
| sudo tee /etc/udev/rules.d/99-nxp-mimxrt.rules > /dev/null
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
sudo usermod -a -G plugdev "$USER"
|
||||
echo " ✅ udev rules installed"
|
||||
echo " ⚠️ Re-login required for 'plugdev' group to take effect"
|
||||
|
||||
# [3/3] Синхронизировать зависимости tools/host (spsdk и др.)
|
||||
# Идемпотентен: пропускает sync если uv.lock не изменился
|
||||
[group('setup')]
|
||||
setup-tools:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
LOCK="{{TOOLS_DIR}}/uv.lock"
|
||||
STAMP="{{CACHE_DIR}}/uv_lock.sha256"
|
||||
mkdir -p "{{CACHE_DIR}}"
|
||||
current=$(sha256sum "$LOCK" 2>/dev/null | cut -d' ' -f1 || echo "missing")
|
||||
previous=$(cat "$STAMP" 2>/dev/null || echo "none")
|
||||
if [[ "$current" == "$previous" ]]; then
|
||||
echo " ✅ tools/host deps up to date (lockfile unchanged)"
|
||||
else
|
||||
echo " 📦 Syncing tools/host deps..."
|
||||
cd "{{TOOLS_DIR}}" && uv sync
|
||||
echo "$current" > "$STAMP"
|
||||
echo " ✅ tools/host deps installed"
|
||||
fi
|
||||
|
||||
# Полная инициализация — запустить один раз после git clone
|
||||
[group('setup')]
|
||||
bootstrap:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
_uname="$(uname -s)"
|
||||
case "${_uname}" in
|
||||
Linux*) PLATFORM="linux" ;;
|
||||
Darwin*) PLATFORM="macos" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
|
||||
*) PLATFORM="unknown" ;;
|
||||
esac
|
||||
echo ""
|
||||
echo " === Bootstrap: step 1/3 -- check-deps ==="
|
||||
just host::check-deps
|
||||
if [[ "${PLATFORM}" == "linux" ]]; then
|
||||
echo " === Bootstrap: step 2/3 -- setup-udev ==="
|
||||
just host::setup-udev
|
||||
else
|
||||
echo " ℹ️ step 2/3 -- setup-udev skipped (${PLATFORM})"
|
||||
fi
|
||||
echo " === Bootstrap: step 3/3 -- setup-tools ==="
|
||||
just host::setup-tools
|
||||
echo ""
|
||||
echo " ✅ Bootstrap complete."
|
||||
echo " Next: open project in VSCode -> 'Reopen in Container'"
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: flash — прошивка платы через USB
|
||||
# Требует: uv + spsdk (just setup-tools), плата в SDP-режиме
|
||||
# HAB-образы должны быть собраны заранее (just hab-* внутри devcontainer)
|
||||
#
|
||||
# Матрица прошивки:
|
||||
# just flash firmware_test debug
|
||||
# just flash firmware_test release
|
||||
# just flash bootloader debug
|
||||
# just flash bootloader release
|
||||
# just flash app debug
|
||||
# just flash app release
|
||||
# =============================================================================
|
||||
|
||||
# Прошить выбранный HAB-образ.
|
||||
# Использование: just flash <project> <type>
|
||||
# project: firmware_test | bootloader | app
|
||||
# type: debug | release (default: release)
|
||||
#
|
||||
# Образ должен быть собран заранее в devcontainer:
|
||||
# just --justfile just/build.just hab-<project>-<type>
|
||||
[group('flash')]
|
||||
flash project type="release":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
case "{{type}}" in
|
||||
debug) BUILD_TYPE="Debug" ;;
|
||||
release) BUILD_TYPE="Release" ;;
|
||||
*)
|
||||
echo " ❌ Unknown type: {{type}}"
|
||||
echo " Valid: debug, release"
|
||||
exit 1 ;;
|
||||
esac
|
||||
cd "{{TOOLS_DIR}}" && uv run python3 flash_usb.py \
|
||||
--firmware "{{project}}" --build-type "${BUILD_TYPE}"
|
||||
|
||||
# Загрузить образ в RAM без записи во Flash.
|
||||
# Полезно для быстрой проверки — не изнашивает Flash, плата стартует сразу.
|
||||
# Использование: just flash-ram <project> <type>
|
||||
[group('flash')]
|
||||
flash-ram project type="debug":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
case "{{type}}" in
|
||||
debug) BUILD_TYPE="Debug" ;;
|
||||
release) BUILD_TYPE="Release" ;;
|
||||
*)
|
||||
echo " ❌ Unknown type: {{type}}"
|
||||
echo " Valid: debug, release"
|
||||
exit 1 ;;
|
||||
esac
|
||||
cd "{{TOOLS_DIR}}" && uv run python3 flash_usb.py \
|
||||
--firmware "{{project}}" --build-type "${BUILD_TYPE}" --ram-only
|
||||
|
||||
# Псевдонимы для частых сценариев ────────────────────────────────────────────
|
||||
|
||||
# firmware_test Debug — самый частый при разработке
|
||||
[group('flash')]
|
||||
flash-test-debug:
|
||||
@just host::flash firmware_test debug
|
||||
|
||||
# firmware_test Release — как будет на производстве
|
||||
[group('flash')]
|
||||
flash-test-release:
|
||||
@just host::flash firmware_test release
|
||||
|
||||
# TODO: bootloader + app Release — финальная прошивка
|
||||
[group('flash'), confirm("Flash bootloader + app (Release)?")]
|
||||
flash-production:
|
||||
@just host::flash bootloader release
|
||||
@just host::flash app release
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: pipeline — производственные сценарии (для сервера)
|
||||
# =============================================================================
|
||||
|
||||
# Входной контроль платы: тестовая прошивка (Release) -> HIL-тесты
|
||||
[group('pipeline')]
|
||||
incoming: flash-test-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
echo " ▶ Running HIL tests (CAN, UART, SDRAM, SPI Flash)..."
|
||||
# cd tools/hil && uv run python3 run_hil.py <- раскомментить когда готово
|
||||
echo " ⚠️ HIL tests not yet implemented"
|
||||
|
||||
# Финальная прошивка: загрузчик + основная прошивка (Release)
|
||||
[group('pipeline')]
|
||||
production: flash-production
|
||||
@echo " ✅ Production firmware flashed (bootloader + app)"
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: util — вспомогательные инструменты
|
||||
# =============================================================================
|
||||
|
||||
# Найти подключённые NXP USB-устройства
|
||||
[group('util')]
|
||||
scan:
|
||||
cd "{{TOOLS_DIR}}" && uv run nxpdevscan
|
||||
|
||||
# Проверить связь с BootROM через SDP (плата в SDP-режиме)
|
||||
[group('util'), no-cd]
|
||||
sdp-status:
|
||||
cd "{{TOOLS_DIR}}" && uv run sdphost -u 0x1FC9,0x0130 -- error-status
|
||||
|
||||
# Проверить что Flashloader отвечает (после jump-address)
|
||||
[group('util')]
|
||||
flashloader-status:
|
||||
cd "{{TOOLS_DIR}}" && uv run blhost -u 0x15A2,0x0073 -- get-property 1 0
|
||||
|
||||
# Обновить spsdk до новой версии
|
||||
# Использование: just upgrade-tools 3.8.0
|
||||
[group('util')]
|
||||
upgrade-tools version:
|
||||
cd "{{TOOLS_DIR}}" && uv add "spsdk=={{version}}" && uv sync
|
||||
@echo " ✅ spsdk upgraded to {{version}}"
|
||||
@echo " Run: git add tools/host/uv.lock tools/host/pyproject.toml"
|
||||
Loading…
Reference in a new issue