# 8 - IMPORTANT
- Переход на task-runner Just (Justfile - для хоста, build.just - для контейнера) - настройки clang-format - небольшие изменения в структуре проекта
This commit is contained in:
parent
6eaca0c183
commit
e8a9826944
37 changed files with 1957 additions and 286 deletions
55
.clang-format
Normal file
55
.clang-format
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# --- Отступы ---
|
||||
IndentWidth: 4 # 4 пробела — стандарт для embedded
|
||||
TabWidth: 4
|
||||
UseTab: Never # Только пробелы, чтобы не было войны в git
|
||||
|
||||
# --- Скобки ---
|
||||
BreakBeforeBraces: Allman # Открывающая скобка на новой строке
|
||||
# Альтернатива: Linux (скобка после if/for, но
|
||||
# Allman нагляднее при отладке железа)
|
||||
|
||||
# --- Длина строки ---
|
||||
ColumnLimit: 100 # 80 — слишком мало для современных мониторов
|
||||
|
||||
# --- Выравнивание ---
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true # Выравнивает = в блоках присваиваний
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true # Очень удобно для регистровых масок
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false # Спорно — может ломать читаемость
|
||||
|
||||
# --- Пробелы ---
|
||||
SpaceBeforeParens: ControlStatements # if (...) но func(...)
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpaceAfterCStyleCast: true # (uint8_t) value
|
||||
|
||||
# --- Указатели ---
|
||||
PointerAlignment: Right # uint8_t *ptr (или Left — uint8_t* ptr)
|
||||
# Right — традиционный C стиль
|
||||
|
||||
# --- Переносы ---
|
||||
AllowShortFunctionsOnASingleLine: None # Запрет коротких функций в одну строку
|
||||
AllowShortIfStatementsOnASingleLine: Never # if всегда с телом на новой строке
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
|
||||
# --- Include-сортировка ---
|
||||
SortIncludes: CaseSensitive
|
||||
IncludeBlocks: Regroup # Группирует и сортирует #include блоки
|
||||
|
||||
# --- Комментарии ---
|
||||
ReflowComments: false # НЕ переформатировать комментарии автоматически
|
||||
# Важно для ASCII-art схем и таблиц регистров!
|
||||
|
||||
# --- Прочее ---
|
||||
InsertTrailingCommas: None
|
||||
Cpp11BracedListStyle: false
|
||||
|
|
@ -58,12 +58,23 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
&& update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 100 \
|
||||
&& update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-17 100 \
|
||||
&& update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-17 100 \
|
||||
&& pip3 install --no-cache-dir spsdk cmake-format==0.6.13 \
|
||||
&& pip3 install --no-cache-dir cmake-format==0.6.13 \
|
||||
&& ln -s /usr/bin/clangd /usr/local/bin/clangd \
|
||||
&& ln -s /usr/bin/clang /usr/local/bin/clang \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# uv — менеджер Python-окружений для spsdk и других host-инструментов.
|
||||
# spsdk НЕ ставится через pip напрямую — версия фиксируется в tools/host/uv.lock.
|
||||
# uv sync в postCreateCommand подтянет нужную версию автоматически.
|
||||
ARG UV_VERSION=0.5.0
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh
|
||||
|
||||
ARG JUST_VERSION=1.36.0
|
||||
|
||||
RUN curl -sSf https://just.systems/install.sh \
|
||||
| bash -s -- --tag ${JUST_VERSION} --to /usr/local/bin
|
||||
|
||||
ARG USER_ID=1000
|
||||
ARG GROUP_ID=1000
|
||||
ARG WORKSPACE_PATH="/workspace"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
|
||||
"workspaceFolder": "/workspace",
|
||||
"postCreateCommand": "cmake --preset host-debug && cmake --preset Debug",
|
||||
"postCreateCommand": "cd tools/host && uv sync && cd ../.. && cmake --preset host-debug && cmake --preset Debug",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
|
|
@ -43,7 +43,6 @@
|
|||
"*.h": "c",
|
||||
"*.c": "c"
|
||||
},
|
||||
// clangd
|
||||
"clangd.path": "clangd",
|
||||
"clangd.arguments": [
|
||||
"--query-driver=/opt/arm-toolchain/bin/arm-none-eabi-*",
|
||||
|
|
@ -52,20 +51,26 @@
|
|||
"--header-insertion=iwyu",
|
||||
"--log=error"
|
||||
],
|
||||
// Отключаем встроенный IntelliSense от ms-vscode.cpptools, чтобы не конфликтовал с clangd
|
||||
"C_Cpp.intelliSenseEngine": "disabled",
|
||||
"C_Cpp.formatting": "disabled",
|
||||
// clang-format
|
||||
"clang-format.executable": "clang-format",
|
||||
"clang-format.style": "file",
|
||||
"clang-format.fallbackStyle": "LLVM",
|
||||
"[c]": {
|
||||
"editor.defaultFormatter": "xaver.clang-format"
|
||||
"editor.defaultFormatter": "xaver.clang-format",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[h]": {
|
||||
"editor.defaultFormatter": "xaver.clang-format",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
// cmake-format
|
||||
"cmakeFormat.exePath": "cmake-format",
|
||||
"[cmake]": {
|
||||
"editor.defaultFormatter": "cheshirekow.cmake-format"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runArgs": [
|
||||
"--name",
|
||||
"tft-devcontainer"
|
||||
]
|
||||
}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -57,6 +57,7 @@ Debug/
|
|||
Release/
|
||||
build*
|
||||
Testing/
|
||||
!build.just
|
||||
|
||||
# Файлы настройки среды разработки
|
||||
.project
|
||||
|
|
|
|||
310
.vscode/tasks.json
vendored
310
.vscode/tasks.json
vendored
|
|
@ -1,213 +1,185 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
// Очистка директории с артефактами сборки
|
||||
// =============================================================
|
||||
// СБОРКА
|
||||
// =============================================================
|
||||
{
|
||||
"label": "Clean",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "rm -rf build*",
|
||||
"windows": {
|
||||
"command": "rm build* -Recurse -Force"
|
||||
"label": "🔨 Build",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"options": {
|
||||
"statusbar": {
|
||||
"color": "#ff8b8b",
|
||||
"label": "$(clear-all) CleanBuildDir",
|
||||
"detail": "Clean ALL"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Сборка и запуск тестов на хосте в режиме Debug
|
||||
{
|
||||
"label": "Configure Host Debug tests",
|
||||
"group": "build",
|
||||
"hide": true,
|
||||
"type": "shell",
|
||||
"command": "cmake",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--preset",
|
||||
"host-debug"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build Host Debug tests",
|
||||
"group": "build",
|
||||
"hide": true,
|
||||
"type": "shell",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"--preset",
|
||||
"host-debug-build"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"dependsOn": "Configure Host Debug tests"
|
||||
},
|
||||
{
|
||||
"label": "🧪 Host Build & Test All",
|
||||
"type": "shell",
|
||||
"command": "ctest",
|
||||
"args": [
|
||||
"--preset",
|
||||
"host-debug-test"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"statusbar": {
|
||||
"color": "#c800ff",
|
||||
"label": "$(test-view-icon) Host Test Debug",
|
||||
"detail": "Perform all the host tests"
|
||||
}
|
||||
},
|
||||
"group": "test",
|
||||
"dependsOrder": "sequence",
|
||||
"dependsOn": [
|
||||
"Build Host Debug tests"
|
||||
]
|
||||
},
|
||||
// Сборка и запуск тестов на хосте в режиме Release
|
||||
{
|
||||
"label": "Configure Host Release tests",
|
||||
"group": "build",
|
||||
"hide": true,
|
||||
"type": "shell",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--preset",
|
||||
"host-release"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build Host Release tests",
|
||||
"group": "build",
|
||||
"hide": true,
|
||||
"type": "shell",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"--preset",
|
||||
"host-release-build"
|
||||
],
|
||||
"dependsOn": "Configure Host Release tests"
|
||||
},
|
||||
{
|
||||
"label": "🧪 Host Release Tests",
|
||||
"type": "shell",
|
||||
"command": "ctest",
|
||||
"args": [
|
||||
"--preset",
|
||||
"host-release-test"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"statusbar": {
|
||||
"color": "#c800ff",
|
||||
"label": "$(test-view-icon) Host Test Release",
|
||||
"detail": "Perform all the host tests"
|
||||
}
|
||||
},
|
||||
"group": "test",
|
||||
"dependsOrder": "sequence",
|
||||
"dependsOn": [
|
||||
"Build Host Release tests"
|
||||
],
|
||||
},
|
||||
// Подготовка сборки в контейнере с пресетом Debug
|
||||
{
|
||||
"label": "Docker: Configure (Debug)",
|
||||
"type": "shell",
|
||||
"hide": true,
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--preset",
|
||||
"Debug"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
// Сборка проекта в контейнере Debug
|
||||
{
|
||||
"label": "Docker: Build (Debug)",
|
||||
"type": "shell",
|
||||
"hide": false,
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"--preset",
|
||||
"Debug"
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"build-${input:project}-${input:buildType}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"statusbar": {
|
||||
"color": "#ff8bd4",
|
||||
"label": "$(debug-console-view-icon) Target: Build (Debug)",
|
||||
"detail": "do Debug build"
|
||||
"label": "$(debug-console-view-icon) Build",
|
||||
"detail": "Build selected firmware"
|
||||
}
|
||||
},
|
||||
"group": "build",
|
||||
"dependsOn": "Docker: Configure (Debug)",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
// Подготовка сборки в контейнере с пресетом Release
|
||||
// =============================================================
|
||||
// HOST-ТЕСТЫ
|
||||
// =============================================================
|
||||
{
|
||||
"label": "Docker: Configure (Release)",
|
||||
"label": "🧪 Host Tests (Debug)",
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"type": "shell",
|
||||
"hide": true,
|
||||
"command": "cmake",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--preset",
|
||||
"Release"
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"test-host"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"statusbar": {
|
||||
"color": "#c800ff",
|
||||
"label": "$(test-view-icon) Host Tests",
|
||||
"detail": "Run host unit tests"
|
||||
}
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "🧪 Host Tests (Release)",
|
||||
"group": "test",
|
||||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"test-host-release"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
// Сборка проекта в контейнере Release
|
||||
// =============================================================
|
||||
// HAB-ОБРАЗЫ
|
||||
// =============================================================
|
||||
{
|
||||
"label": "Docker: Build (Release)",
|
||||
"label": "📦 HAB Image",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"hide": false,
|
||||
"command": "cmake",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--build",
|
||||
"--preset",
|
||||
"Release"
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"hab-${input:habProject}-${input:buildType}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"statusbar": {
|
||||
"color": "#03b3ff",
|
||||
"label": "$(pass-filled) Target: Build (Release)",
|
||||
"detail": "do Release build"
|
||||
"label": "$(package) HAB",
|
||||
"detail": "Build HAB image"
|
||||
}
|
||||
},
|
||||
"group": "build",
|
||||
"dependsOn": "Docker: Configure (Release)",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "📦 HAB All (Debug)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"hab-all-debug"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "📦 HAB All (Release)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"hab-all-release"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
// =============================================================
|
||||
// УТИЛИТЫ
|
||||
// =============================================================
|
||||
{
|
||||
"label": "🗑️ Clean",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "just",
|
||||
"args": [
|
||||
"--justfile",
|
||||
"scripts/build.just",
|
||||
"clean"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"statusbar": {
|
||||
"color": "#ff8b8b",
|
||||
"label": "$(clear-all) Clean",
|
||||
"detail": "Remove build artifacts"
|
||||
}
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "project",
|
||||
"type": "pickString",
|
||||
"description": "Project",
|
||||
"options": [
|
||||
"firmware-test",
|
||||
"bootloader",
|
||||
"app",
|
||||
"all"
|
||||
],
|
||||
"default": "firmware-test"
|
||||
},
|
||||
{
|
||||
"id": "buildType",
|
||||
"type": "pickString",
|
||||
"description": "Тип сборки",
|
||||
"description": "Build type",
|
||||
"options": [
|
||||
"Debug",
|
||||
"Release",
|
||||
"debug",
|
||||
"release"
|
||||
],
|
||||
"default": "Debug"
|
||||
"default": "debug"
|
||||
},
|
||||
{
|
||||
"id": "habProject",
|
||||
"type": "pickString",
|
||||
"description": "HAB project",
|
||||
"options": [
|
||||
"firmware-test",
|
||||
"bootloader",
|
||||
"app"
|
||||
],
|
||||
"default": "firmware-test"
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
|
|
@ -66,17 +66,67 @@
|
|||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "Debug",
|
||||
"name": "all-debug",
|
||||
"displayName": "All — Debug",
|
||||
"configurePreset": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "Release",
|
||||
"name": "all-release",
|
||||
"displayName": "All — Release",
|
||||
"configurePreset": "Release"
|
||||
},
|
||||
{
|
||||
"name": "firmware-test-debug",
|
||||
"displayName": "firmware_test — Debug",
|
||||
"configurePreset": "Debug",
|
||||
"targets": [
|
||||
"firmware_test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "firmware-test-release",
|
||||
"displayName": "firmware_test — Release",
|
||||
"configurePreset": "Release",
|
||||
"targets": [
|
||||
"firmware_test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bootloader-debug",
|
||||
"displayName": "bootloader — Debug",
|
||||
"configurePreset": "Debug",
|
||||
"targets": [
|
||||
"bootloader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bootloader-release",
|
||||
"displayName": "bootloader — Release",
|
||||
"configurePreset": "Release",
|
||||
"targets": [
|
||||
"bootloader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "app-debug",
|
||||
"displayName": "app — Debug",
|
||||
"configurePreset": "Debug",
|
||||
"targets": [
|
||||
"app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "app-release",
|
||||
"displayName": "app — Release",
|
||||
"configurePreset": "Release",
|
||||
"targets": [
|
||||
"app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "host-debug-build",
|
||||
"displayName": "Host Tests — Debug",
|
||||
"configurePreset": "host-debug",
|
||||
"displayName": "Build Host Debug Tests",
|
||||
"targets": [
|
||||
"test_host_simple",
|
||||
"test_host_second"
|
||||
|
|
@ -84,8 +134,8 @@
|
|||
},
|
||||
{
|
||||
"name": "host-release-build",
|
||||
"displayName": "Host Tests — Release",
|
||||
"configurePreset": "host-release",
|
||||
"displayName": "Build Host Release Tests",
|
||||
"targets": [
|
||||
"test_host_simple",
|
||||
"test_host_second"
|
||||
|
|
|
|||
22
HOW_TO_FLASH.md
Normal file
22
HOW_TO_FLASH.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Прошивка платы со стороны хоста
|
||||
|
||||
```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
|
||||
```
|
||||
344
Justfile
Normal file
344
Justfile
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
# =============================================================================
|
||||
# Justfile — корень репозитория
|
||||
# Выполняется на ХОСТ-МАШИНЕ разработчика (вне devcontainer).
|
||||
#
|
||||
# Отвечает только за:
|
||||
# - инициализацию окружения (setup)
|
||||
# - прошивку платы через USB (flash)
|
||||
# - сквозные сценарии (pipeline)
|
||||
# - вспомогательные утилиты (util)
|
||||
#
|
||||
# Сборка, тесты и HAB-образы — в just/build.just (внутри devcontainer).
|
||||
#
|
||||
# Быстрый старт:
|
||||
# ./scripts/bootstrap.sh # первый запуск после git clone
|
||||
# just # показать все рецепты
|
||||
# =============================================================================
|
||||
|
||||
JUST_MIN := "1.27.0"
|
||||
UV_MIN := "0.4.0"
|
||||
DOCKER_MIN := "24.0.0"
|
||||
|
||||
TOOLS_DIR := "tools/host"
|
||||
CACHE_DIR := ".cache"
|
||||
|
||||
# По умолчанию — показать список рецептов
|
||||
_default:
|
||||
@just --list --unsorted
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: 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 ""
|
||||
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"
|
||||
148
README.md
148
README.md
|
|
@ -1,8 +1,8 @@
|
|||
# tft_manufacture_test
|
||||
|
||||
## Структура проекта
|
||||
Монорепозиторий для **MIMXRT1052CVJ5B**. Содержит три независимых firmware-проекта с общей инфраструктурой сборки, тестирования и инструментарием.
|
||||
|
||||
Монорепозиторий для MIMXRT1052CVJ5B. Три независимых firmware-проекта с общей инфраструктурой сборки, тестирования и инструментарием.
|
||||
> Архитектура рабочего окружения разработчика — [docs/DEV_ARCH.md](docs/DEV_ARCH.md)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -11,44 +11,55 @@
|
|||
```bash
|
||||
/
|
||||
├── .devcontainer/ # VSCode Devcontainer — единое окружение для всех разработчиков
|
||||
├── bsp/ # Board Support Package
|
||||
│ └── generated/ # Сгенерировано NXP Config Tools (Pins + Clocks Tool)
|
||||
│ ├── TFT_Board.mex # Источник истины конфигурации пинов и тактирования
|
||||
│ ├── pin_mux.c/h # Сгенерировано из .mex (Pins Tool)
|
||||
│ ├── clock_config.c/h # Сгенерировано из .mex (Clocks Tool)
|
||||
│ ├── board.c/h # Ручная инициализация специфики платы
|
||||
│ └── BOOT_FLAGS.md # Описание флагов загрузчика
|
||||
├── cmake/ # Общие CMake модули и toolchain files
|
||||
│ ├── linker/ # Линкер-скрипты под разные схемы размещения
|
||||
│ ├── toolchain_arm.cmake # ARM cross-compilation toolchain
|
||||
│ └── toolchain_host.cmake # Host GCC для unit-тестов
|
||||
├── sdk/ # NXP MCUXpresso SDK — vendored, только нужные компоненты
|
||||
│ ├── CMakeLists.txt # CMake-таргеты для каждого драйвера
|
||||
├── sdk/ # NXP MCUXpresso SDK — vendored
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── CMSIS/
|
||||
│ ├── devices/
|
||||
│ │ └── MIMXRT1052/
|
||||
│ │ ├── drivers/ # fsl_flexcan, fsl_lpuart, fsl_usdhc и др.
|
||||
│ │ ├── startup/
|
||||
│ │ └── utilities/
|
||||
│ └── components/
|
||||
├── bsp/ # Board Support Package
|
||||
│ └── board/
|
||||
│ ├── board.mex # Исходник конфигурации для NXP Config Tools
|
||||
│ ├── pin_mux.c/h # Сгенерировано из board.mex (Pins Tool)
|
||||
│ ├── clock_config.c/h # Сгенерировано из board.mex (Clocks Tool)
|
||||
│ └── board.c/h # Ручная инициализация специфики платы
|
||||
├── lib/ # Библиотеки и зависимости
|
||||
│ ├── CMakeLists.txt # Агрегатор — подключает нужные модули через опции
|
||||
│ ├── freertos/ # vendored
|
||||
│ ├── fatfs/ # vendored
|
||||
│ ├── mbedtls/ # vendored (если используется)
|
||||
│ ├── unity/ # vendored (test framework)
|
||||
│ ├── fff/ # vendored (fake functions для тестов)
|
||||
│ └── hal/ # submodule — аппаратно-независимые библиотеки
|
||||
│ # (второй разработчик, активно развивается)
|
||||
│ ├── devices/MIMXRT1052/ # Драйверы, startup, утилиты
|
||||
│ ├── components/ # fsl_button, fsl_led, serial_manager и др.
|
||||
│ ├── middleware/ # FatFS, FreeRTOS, LittleFS, USB, mcuboot и др.
|
||||
│ └── rtos/freertos/ # FreeRTOS (vendored через SDK)
|
||||
├── lib/ # Внешние библиотеки
|
||||
│ ├── Unity/ # Фреймворк для unit-тестов (vendored)
|
||||
│ ├── fff/ # Fake Function Framework для моков (vendored)
|
||||
│ └── SEGGER/ # SEGGER RTT — вывод логов через отладчик
|
||||
├── firmware/
|
||||
│ ├── test/ # [Проект 1] Тестовая прошивка — входной контроль
|
||||
│ ├── test/ # [Проект 1] Тестовая прошивка — входной контроль платы
|
||||
│ ├── bootloader/ # [Проект 2] Загрузчик с поддержкой A/B обновления
|
||||
│ └── app/ # [Проект 3] Основная боевая прошивка (FreeRTOS)
|
||||
├── tests/ # Host-тесты (unit + integration)
|
||||
│ ├── host/
|
||||
│ └── target/
|
||||
└── tools/ # Скрипты для прошивки, провизии, HIL-тестов
|
||||
├── flash_usb.py # Прошивка через USB ROM (blhost / nxp-spsdk)
|
||||
├── flash_remote.sh # Прошивка на удалённый сервер через SSH
|
||||
└── provision.py # Производственная провизия (SPT / nxpimage)
|
||||
│ └── tft_app/ # [Проект 3] Основная боевая прошивка (FreeRTOS)
|
||||
├── tests/ # Тесты (host + target)
|
||||
│ ├── host/ # Unit/интеграционные тесты, запускаемые на хосте
|
||||
│ ├── target/ # Тесты периферии, запускаемые на таргете
|
||||
│ └── HostTestingGuide.md
|
||||
├── tools/
|
||||
│ └── 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
|
||||
├── scripts/
|
||||
│ ├── bootstrap.sh # Первичная настройка окружения
|
||||
│ └── build.just # Рецепты сборки (используется через Justfile)
|
||||
├── docs/ # Документация проекта
|
||||
│ ├── DEV_ARCH.md # Архитектура окружения разработки
|
||||
│ ├── CMAKE_HINTS.md # Шпаргалка по CMake в проекте
|
||||
│ ├── schematic.pdf # Схема платы
|
||||
│ ├── mcu_rm.pdf # Reference Manual IMXRT1052
|
||||
│ └── manufacturing_user's_guide.pdf
|
||||
├── CMakeLists.txt # Корневой CMake
|
||||
├── CMakePresets.json # Пресеты сборки (Release/Debug/Host)
|
||||
├── Justfile # Точка входа для команд сборки/тестирования/прошивки
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -57,15 +68,32 @@
|
|||
|
||||
### 1. Тестовая прошивка (`firmware/test/`)
|
||||
|
||||
Bare-metal прошивка для входного контроля на производстве. Проверяет базовую работоспособность всех интерфейсов и периферии: CAN, UART, SDRAM, QSPI Flash, uSD, RGB-интерфейс, гальванически развязанные входы, светодиоды, кнопки. Загружается через USB ROM (Serial Download Mode). **Рекомендуется начать разработку с этого проекта** — он наиболее прост и позволяет полностью отладить окружение сборки.
|
||||
Bare-metal прошивка для **входного контроля** платы. Проверяет базовую работоспособность всех интерфейсов: CAN, UART, SDRAM, QSPI Flash, uSD (SDIO), RGB-интерфейс, гальванически развязанные входы, светодиоды, кнопки, IR-приёмник, MQS.
|
||||
|
||||
Загружается через USB ROM (Serial Download Mode) — подробнее в [HOW_TO_FLASH.md](HOW_TO_FLASH.md).
|
||||
|
||||
> **Рекомендуется начать разработку с этого проекта** — он наиболее прост и позволяет полностью отладить окружение сборки и прошивки.
|
||||
|
||||
### 2. Загрузчик (`firmware/bootloader/`)
|
||||
|
||||
Отвечает за обновление боевой прошивки в полевых условиях. Поддерживает схему A/B с шифрованием (обновление через uSD). Обновление самого загрузчика — только через внешний инструмент (USB ROM + blhost), не через себя. Загружается на производстве вместе с первой версией боевой прошивки единым blob-ом.
|
||||
Отвечает за обновление боевой прошивки в полевых условиях. Поддерживает схему **A/B** с обновлением через uSD. Обновление самого загрузчика — только через внешний инструмент (USB ROM + blhost), не через себя. На производстве загружается единым blob-ом вместе с первой версией боевой прошивки.
|
||||
|
||||
### 3. Боевая прошивка (`firmware/app/`)
|
||||
### 3. Боевая прошивка (`firmware/tft_app/`)
|
||||
|
||||
Основная прошивка на базе FreeRTOS. Включает FatFS, бизнес-логику, модули. Обновляется через загрузчик по схеме A/B.
|
||||
Основная прошивка на базе **FreeRTOS**. Включает FatFS, бизнес-логику, модули. Обновляется через загрузчик по схеме A/B.
|
||||
|
||||
---
|
||||
|
||||
## Тестирование
|
||||
|
||||
Стратегия тестирования двухуровневая:
|
||||
|
||||
| Уровень | Расположение | Инструменты | Запуск |
|
||||
|---|---|---|---|
|
||||
| **Host-тесты** (unit + интеграционные) | `tests/host/` | Unity + fff | `ctest` в devcontainer |
|
||||
| **Target-тесты** (аппаратные) | `tests/target/` | Unity на железе | Удалённый ПК-сервер через SSH |
|
||||
|
||||
Подробнее — [tests/HostTestingGuide.md](tests/HostTestingGuide.md) и [tests/README.md](tests/README.md).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -73,44 +101,52 @@ Bare-metal прошивка для входного контроля на про
|
|||
|
||||
| Зависимость | Подход | Причина |
|
||||
|---|---|---|
|
||||
| NXP SDK | vendored | Стабильная версия, обновлений не планируется |
|
||||
| FreeRTOS | vendored | Стабильная версия |
|
||||
| FatFS, mbedTLS и др. | vendored | Стабильные версии |
|
||||
| NXP MCUXpresso SDK | vendored | Стабильная версия, обновлений не планируется |
|
||||
| FreeRTOS, FatFS, LittleFS и др. | vendored (через SDK) | Стабильные версии |
|
||||
| Unity + fff | vendored | Маленькие, стабильные |
|
||||
| lib/hal (второй разработчик) | **submodule** | Активно развивается параллельно |
|
||||
| SEGGER RTT | vendored | Стабильный |
|
||||
|
||||
**Принцип:** всё что не меняется — vendored (скачано и закоммичено). Submodule только для активно развивающихся зависимостей. Это обеспечивает полностью автономную сборку после `git clone` без доступа к интернету.
|
||||
**Принцип:** всё что не меняется — vendored (закоммичено в репозиторий). Это обеспечивает полностью автономную сборку после `git clone` без доступа к интернету.
|
||||
|
||||
---
|
||||
|
||||
## Devcontainer — состав окружения
|
||||
|
||||
| Инструмент | Назначение |
|
||||
|---|---|
|
||||
| `arm-none-eabi-gcc` | Сборка firmware для таргета |
|
||||
| `arm-none-eabi-gdb` | Отладка через GDB server |
|
||||
| `host-gcc` | Сборка и запуск host-тестов |
|
||||
| `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), производственная провизия |
|
||||
|
||||
| `Python 3 + nxp-spsdk` | Прошивка (blhost, nxpimage), HAB, провизия |
|
||||
| `just` | Запуск рецептов сборки/тестирования/прошивки |
|
||||
|
||||
---
|
||||
|
||||
## Конфигурация платы (NXP Config Tools)
|
||||
|
||||
Файл `bsp/board/board.mex` — источник истины для конфигурации пинов и тактирования. Открывается в NXP Config Tools (Pins Tool + Clocks Tool) для генерации `pin_mux.c/h` и `clock_config.c/h`. Используется **один раз** при старте проекта или при изменении аппаратной схемы. Коммитится в репозиторий вместе со сгенерированным кодом.
|
||||
Файл `bsp/generated/TFT_Board.mex` — **источник истины** для конфигурации пинов и тактирования. Открывается в NXP Config Tools (Pins Tool + Clocks Tool) для регенерации `pin_mux.c/h` и `clock_config.c/h`. Используется при старте проекта или при изменении аппаратной схемы. Коммитится вместе со сгенерированным кодом.
|
||||
|
||||
---
|
||||
|
||||
## Доставка прошивки
|
||||
## Быстрый старт
|
||||
|
||||
| Сценарий | Способ |
|
||||
|---|---|
|
||||
| Разработка (с ПК разработчика) | `rsync` / `scp` → SSH на ПК-сервер → OpenOCD/blhost |
|
||||
| Производство | `nxp-spsdk` (blhost + nxpimage) через USB ROM |
|
||||
| Готовое ПО на сервер | GitLab CI/CD → GitLab Package Registry → сервер подтягивает |
|
||||
| Обновление загрузчика | USB ROM + blhost (только так, не через сам загрузчик) |
|
||||
| Обновление боевой прошивки в поле | Через загрузчик, схема A/B, uSD |
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd tft_manufacture_test
|
||||
|
||||
# Открыть в VSCode → Reopen in Container
|
||||
# Затем внутри devcontainer:
|
||||
|
||||
just build-host # сборка host-тестов
|
||||
just test # запуск host-тестов через CTest
|
||||
just build-firmware # сборка firmware для таргета
|
||||
just flash # прошивка через USB ROM
|
||||
```
|
||||
|
||||
> Подробнее о прошивке — [HOW_TO_FLASH.md](HOW_TO_FLASH.md)
|
||||
> Подробнее об окружении разработки — [docs/DEV_ARCH.md](docs/DEV_ARCH.md)
|
||||
|
|
|
|||
|
|
@ -6,14 +6,17 @@ endif()
|
|||
# bsp_board — стартап, сгенерированные файлы Config Tools, инициализация платы
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
add_library(bsp_board STATIC board/board.c board/pin_mux.c board/clock_config.c
|
||||
board/startup/startup_MIMXRT1052.S)
|
||||
add_library(
|
||||
bsp_board STATIC
|
||||
generated/board.c generated/pin_mux.c generated/clock_config.c
|
||||
generated/startup/startup_MIMXRT1052.S)
|
||||
|
||||
target_include_directories(bsp_board PUBLIC board)
|
||||
# Подавляем предупреждения при компиляции собственных .c файлов библиотеки
|
||||
target_compile_options(bsp_board PRIVATE -w)
|
||||
|
||||
# SYSTEM подавляет предупреждения для всех внешних потребителей
|
||||
target_include_directories(bsp_board SYSTEM PUBLIC generated)
|
||||
|
||||
# Подавляем предупреждения о macro redefined
|
||||
set_source_files_properties(board/board.c board/pin_mux.c
|
||||
PROPERTIES COMPILE_OPTIONS "-w")
|
||||
# Дефайны PUBLIC — транзитивно подтянутся во все firmware таргеты TODO: для
|
||||
# каждого приложения свои дефайны
|
||||
target_compile_definitions(
|
||||
|
|
|
|||
219
docs/CMAKE_HINTS.md
Normal file
219
docs/CMAKE_HINTS.md
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
# PRIVATE, PUBLIC и INTERFACE в CMake
|
||||
|
||||
## Основная идея
|
||||
|
||||
Каждый таргет в CMake — это «чёрный ящик» с двумя границами:
|
||||
|
||||
- **внутренняя** — то, что нужно только для компиляции самого таргета
|
||||
- **внешняя** — то, что таргет «экспортирует» своим потребителям
|
||||
|
||||
Ключевые слова `PRIVATE`, `PUBLIC` и `INTERFACE` управляют тем, в какую из этих границ попадает свойство.
|
||||
|
||||
``````bash
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ lib_a │
|
||||
│ │
|
||||
│ PRIVATE │ INTERFACE │
|
||||
│ (только внутри) │ (только снаружи) │
|
||||
│ │ │
|
||||
│ PUBLIC = PRIVATE + INTERFACE │
|
||||
└─────────────────────────────────────────────────┘
|
||||
│ target_link_libraries(app PRIVATE lib_a)
|
||||
▼
|
||||
[ app ] ← получает только INTERFACE-свойства lib_a
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Определения
|
||||
|
||||
| Ключевое слово | Применяется к самому таргету | Передаётся потребителям |
|
||||
|----------------|:----------------------------:|:-----------------------:|
|
||||
| `PRIVATE` | ✅ | ❌ |
|
||||
| `PUBLIC` | ✅ | ✅ |
|
||||
| `INTERFACE` | ❌ | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Разбор на примерах
|
||||
|
||||
### Пример 1 — `target_include_directories`
|
||||
|
||||
``````bash
|
||||
src/
|
||||
├── lib_math/
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── include/ ← публичные заголовки (нужны потребителям)
|
||||
│ │ └── math.h
|
||||
│ ├── internal/ ← внутренние заголовки (только для lib_math)
|
||||
│ │ └── impl.h
|
||||
│ └── math.c
|
||||
└── app/
|
||||
├── CMakeLists.txt
|
||||
└── main.c ← #include "math.h"
|
||||
```
|
||||
|
||||
```cmake
|
||||
# lib_math/CMakeLists.txt
|
||||
add_library(lib_math STATIC math.c)
|
||||
|
||||
target_include_directories(lib_math
|
||||
PRIVATE internal/ # impl.h нужен только при компиляции math.c
|
||||
PUBLIC include/ # math.h нужен и lib_math, и всем её потребителям
|
||||
)
|
||||
```
|
||||
|
||||
```cmake
|
||||
# app/CMakeLists.txt
|
||||
add_library(app main.c)
|
||||
target_link_libraries(app PRIVATE lib_math)
|
||||
# app автоматически получает include/ через PUBLIC-свойство lib_math
|
||||
# app НЕ получает internal/ — оно PRIVATE
|
||||
```
|
||||
|
||||
**Итог:** `main.c` может писать `#include "math.h"`, но не видит `impl.h`.
|
||||
|
||||
---
|
||||
|
||||
### Пример 2 — `target_compile_definitions`
|
||||
|
||||
``````bash
|
||||
lib_json ──→ lib_http ──→ app
|
||||
```
|
||||
|
||||
```cmake
|
||||
# lib_json
|
||||
add_library(lib_json STATIC json.c)
|
||||
target_compile_definitions(lib_json
|
||||
PRIVATE JSON_INTERNAL_DEBUG # дефайн только для json.c
|
||||
PUBLIC JSON_VERSION=2 # нужен и json.c, и потребителям
|
||||
)
|
||||
```
|
||||
|
||||
```cmake
|
||||
# lib_http линкуется с lib_json
|
||||
add_library(lib_http STATIC http.c)
|
||||
target_link_libraries(lib_http PUBLIC lib_json)
|
||||
# lib_http транзитивно передаёт JSON_VERSION=2 дальше в app
|
||||
```
|
||||
|
||||
```cmake
|
||||
# app
|
||||
add_executable(app main.c)
|
||||
target_link_libraries(app PRIVATE lib_http)
|
||||
# app видит JSON_VERSION=2 (транзитивно через lib_http → lib_json)
|
||||
# app НЕ видит JSON_INTERNAL_DEBUG (PRIVATE)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Пример 3 — `INTERFACE` (header-only библиотека)
|
||||
|
||||
`INTERFACE` используется тогда, когда таргет сам **не компилируется** — например, header-only библиотека или набор флагов.
|
||||
|
||||
```cmake
|
||||
# Набор флагов для встроенных таргетов — сам не компилируется
|
||||
add_library(flags_embedded INTERFACE)
|
||||
|
||||
target_compile_options(flags_embedded INTERFACE
|
||||
-mcpu=cortex-m7
|
||||
-mfpu=fpv5-d16
|
||||
-mfloat-abi=hard
|
||||
-mthumb
|
||||
)
|
||||
|
||||
target_compile_definitions(flags_embedded INTERFACE
|
||||
ARM_MATH_CM7
|
||||
__FPU_PRESENT=1
|
||||
)
|
||||
```
|
||||
|
||||
```cmake
|
||||
# Любой firmware-таргет подключает флаги одной строкой
|
||||
target_link_libraries(firmware_app PRIVATE flags_embedded)
|
||||
# firmware_app получает все -mcpu, -mfpu и дефайны
|
||||
```
|
||||
|
||||
Такой паттерн часто используется для:
|
||||
|
||||
- HAL/SDK флагов конкретного МК
|
||||
- Флагов линкера (`-T linker.ld`)
|
||||
- Опций оптимизации для конкретного сценария сборки
|
||||
|
||||
---
|
||||
|
||||
### Пример 4 — транзитивность
|
||||
|
||||
Понять транзитивность важно: свойства распространяются по цепочке зависимостей.
|
||||
|
||||
```
|
||||
lib_base ──→ lib_mid ──→ app
|
||||
```
|
||||
|
||||
```cmake
|
||||
add_library(lib_base STATIC base.c)
|
||||
target_compile_definitions(lib_base
|
||||
PUBLIC BASE_FEATURE_ENABLED # пойдёт вглубь цепочки
|
||||
PRIVATE BASE_INTERNAL # остановится здесь
|
||||
)
|
||||
|
||||
add_library(lib_mid STATIC mid.c)
|
||||
target_link_libraries(lib_mid PUBLIC lib_base)
|
||||
# ^^^^^^
|
||||
# PUBLIC здесь означает: "lib_mid использует lib_base,
|
||||
# и мои потребители тоже должны о ней знать"
|
||||
|
||||
add_executable(app main.c)
|
||||
target_link_libraries(app PRIVATE lib_mid)
|
||||
```
|
||||
|
||||
**Что видит `app`:**
|
||||
|
||||
| Дефайн | Виден в app? | Причина |
|
||||
|-----------------------|:------------:|--------------------------------------------------|
|
||||
| `BASE_FEATURE_ENABLED`| ✅ | PUBLIC в lib_base → PUBLIC в lib_mid → app |
|
||||
| `BASE_INTERNAL` | ❌ | PRIVATE в lib_base, цепочка обрывается |
|
||||
|
||||
Если бы `lib_mid` слинковался с `lib_base` через `PRIVATE`:
|
||||
|
||||
```cmake
|
||||
target_link_libraries(lib_mid PRIVATE lib_base)
|
||||
# тогда app НЕ увидел бы BASE_FEATURE_ENABLED — цепочка оборвалась бы на lib_mid
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Применимость к командам
|
||||
|
||||
Ключевые слова работают одинаково во всех `target_*` командах:
|
||||
|
||||
| Команда | Типичное использование |
|
||||
|--------------------------------|----------------------------------------------------------|
|
||||
| `target_include_directories` | PRIVATE — внутренние папки; PUBLIC — публичные заголовки |
|
||||
| `target_compile_definitions` | PRIVATE — отладочные дефайны; PUBLIC — версии API |
|
||||
| `target_compile_options` | PRIVATE — флаги оптимизации; INTERFACE — флаги МК |
|
||||
| `target_link_libraries` | PRIVATE — внутр. зависимость; PUBLIC — транзитивная |
|
||||
| `target_link_options` | INTERFACE — скрипт линкера для всей цепочки |
|
||||
| `target_sources` | Всегда PRIVATE — исходники не передаются потребителям |
|
||||
|
||||
---
|
||||
|
||||
## Правило выбора
|
||||
|
||||
```bash
|
||||
Нужно ли это свойство самому таргету?
|
||||
│
|
||||
ДА ──→ Нужно ли оно потребителям?
|
||||
│ │
|
||||
│ ДА ──→ PUBLIC
|
||||
│ │
|
||||
│ НЕТ ──→ PRIVATE
|
||||
│
|
||||
НЕТ ──→ Нужно ли оно потребителям?
|
||||
│
|
||||
ДА ──→ INTERFACE
|
||||
│
|
||||
НЕТ ──→ (не добавляйте это свойство вообще)
|
||||
```
|
||||
|
||||
---
|
||||
566
docs/DEV_ARCH.md
Normal file
566
docs/DEV_ARCH.md
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
# Архитектура рабочего окружения разработчика
|
||||
|
||||
> Проект: TFT Firmware (MIMXRT1052CVJ5B)
|
||||
> Документ описывает итоговый рабочий процесс разработчиков: от разворачивания
|
||||
> окружения до сборки, тестирования, отладки и прошивки платы.
|
||||
> Производственный сервер описан кратко — подробно в отдельном документе.
|
||||
|
||||
---
|
||||
|
||||
## 1. Концепция
|
||||
|
||||
Рабочее окружение разделено на два контекста с чёткой границей:
|
||||
|
||||
**Devcontainer** — всё что касается кода: сборка, статический анализ,
|
||||
форматирование, host-тесты, подготовка HAB-образов. Разработчик проводит
|
||||
здесь большую часть времени. Управляется через VSCode tasks и `scripts/build.just`.
|
||||
|
||||
**Хост** — всё что касается железа: прошивка платы через USB, отладка
|
||||
через JLink/probe-rs. Управляется через корневой `Justfile`.
|
||||
|
||||
Такое разделение решает несколько проблем: USB-устройства не требуют
|
||||
проброса в контейнер; оба разработчика работают в идентичных условиях;
|
||||
CI использует те же команды что и локальная разработка.
|
||||
|
||||
---
|
||||
|
||||
## 2. Компоненты окружения
|
||||
|
||||
```bash
|
||||
ПК разработчика
|
||||
│
|
||||
├── Хост (Linux / macOS / Windows + Git Bash)
|
||||
│ ├── just ← запуск задач хостового уровня
|
||||
│ ├── docker ← управление devcontainer
|
||||
│ ├── git ← работа с репозиторием
|
||||
│ ├── uv + spsdk ← прошивка платы (flash_usb.py, sdphost, blhost)
|
||||
│ ├── JLinkGDBServer / probe-rs ← сервер отладки (USB → TCP :2331)
|
||||
│ └── VSCode ← IDE (Dev Containers extension)
|
||||
│
|
||||
├── Devcontainer (Docker)
|
||||
│ ├── ARM GCC 13.3 ← кросс-компилятор
|
||||
│ ├── cmake + ninja ← система сборки
|
||||
│ ├── clang-17 ← компилятор для host-тестов
|
||||
│ ├── clangd-17 ← LSP (автодополнение, диагностика)
|
||||
│ ├── clang-tidy-17 ← статический анализ
|
||||
│ ├── clang-format-17 ← форматирование кода
|
||||
│ ├── cmake-format ← форматирование CMakeLists
|
||||
│ ├── just ← запуск задач внутри контейнера
|
||||
│ ├── uv + spsdk ← сборка HAB-образов (только nxpimage)
|
||||
│ └── Unity + fff ← фреймворки host-тестов
|
||||
│
|
||||
└── Плата TFT (IMXRT1052) — на столе у разработчика
|
||||
├── USB ──────────────▶ хост (SDP-режим, прошивка)
|
||||
├── SWD ──────────────▶ JLink/probe-rs на хосте (отладка)
|
||||
└── CAN / UART / IO ──▶ локальный стенд (target-тесты)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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 | ✅ | — | — |
|
||||
|
||||
`spsdk` присутствует везде, но с разными ролями:
|
||||
|
||||
- **devcontainer** — только `nxpimage` для сборки HAB-образов
|
||||
- **хост** — полный стек: `nxpimage` + `sdphost` + `blhost` для прошивки
|
||||
- **сервер** — то же что на хосте, но для производственного сценария
|
||||
|
||||
Версия `spsdk` зафиксирована в `tools/host/uv.lock` — все три места
|
||||
используют одну и ту же версию.
|
||||
|
||||
---
|
||||
|
||||
## 4. Структура репозитория (automation-часть)
|
||||
|
||||
```bash
|
||||
/
|
||||
├── Justfile ← хост: прошивка, setup, pipeline
|
||||
├── scripts/
|
||||
│ └── bootstrap.sh ← уровень 0: just → just bootstrap
|
||||
│ └── build.just ← devcontainer: сборка, тесты, HAB
|
||||
├── .devcontainer/
|
||||
│ ├── Dockerfile
|
||||
│ └── devcontainer.json
|
||||
├── tools/
|
||||
│ └── host/
|
||||
│ ├── hab/
|
||||
│ │ ├── hab_firmware_test_debug.yaml
|
||||
│ │ ├── hab_firmware_test_release.yaml
|
||||
│ │ ├── hab_bootloader_debug.yaml
|
||||
│ │ ├── hab_bootloader_release.yaml
|
||||
│ │ ├── hab_app_debug.yaml
|
||||
│ │ └── hab_app_release.yaml
|
||||
│ ├── dcd/
|
||||
│ │ ├── dcd.bin
|
||||
│ │ └── ivt_flashloader.bin
|
||||
│ ├── flash_usb.py
|
||||
│ ├── pyproject.toml
|
||||
│ └── uv.lock
|
||||
├── .vscode/
|
||||
│ └── tasks.json ← UI для build.just (внутри devcontainer)
|
||||
├── CMakePresets.json
|
||||
├── cmake/
|
||||
├── sdk/
|
||||
├── bsp/
|
||||
├── lib/
|
||||
├── firmware/
|
||||
│ ├── test/
|
||||
│ ├── bootloader/
|
||||
│ └── app/
|
||||
└── tests/ ← host-тесты (Unity + fff)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Первый запуск: разворачивание окружения
|
||||
|
||||
### 5.1 Предварительные требования
|
||||
|
||||
| Платформа | Что нужно до 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
|
||||
```
|
||||
|
||||
### 5.3 Что делает bootstrap
|
||||
|
||||
```bash
|
||||
bootstrap.sh (уровень 0)
|
||||
│
|
||||
├── определить платформу (Linux / macOS / Windows Git Bash)
|
||||
│ uname: MINGW64_NT-... → windows, Linux → linux, Darwin → macos
|
||||
│
|
||||
├── проверить just (semver без sort -V — работает в Git Bash)
|
||||
│ < 1.27.0 или отсутствует:
|
||||
│ Linux/macOS → curl | bash → ~/.local/bin/just
|
||||
│ Windows → winget install --id Casey.Just
|
||||
│ (перезапустить Git Bash после установки)
|
||||
│
|
||||
└── exec just bootstrap
|
||||
│
|
||||
├── [1/3] check-deps
|
||||
│ just >= 1.27.0 · uv >= 0.4.0 · docker >= 24.0.0
|
||||
│ платформо-зависимые подсказки при ошибках
|
||||
│
|
||||
├── [2/3] setup-udev (только Linux)
|
||||
│ /etc/udev/rules.d/99-nxp-mimxrt.rules:
|
||||
│ 1FC9:0130 ← NXP BootROM (SDP-режим)
|
||||
│ 15A2:0073 ← NXP Flashloader
|
||||
│ usermod -a -G plugdev $USER
|
||||
│ требует re-login · на macOS/Windows пропускается
|
||||
│
|
||||
└── [3/3] setup-tools
|
||||
uv sync в tools/host/
|
||||
SHA-256 uv.lock кэшируется в .cache/
|
||||
повторный вызов мгновенный если lockfile не изменился
|
||||
```
|
||||
|
||||
### 5.4 После bootstrap
|
||||
|
||||
```bash
|
||||
Открыть VSCode → "Reopen in Container"
|
||||
```
|
||||
|
||||
`postCreateCommand` выполняется автоматически при поднятии контейнера:
|
||||
|
||||
```bash
|
||||
cd tools/host && uv sync &&
|
||||
cd ../.. &&
|
||||
cmake --preset host-debug &&
|
||||
cmake --preset Debug
|
||||
```
|
||||
|
||||
Прогрев CMake-кэша нужен чтобы clangd и IntelliSense заработали сразу,
|
||||
без первой ручной сборки.
|
||||
|
||||
---
|
||||
|
||||
## 6. Прошивки, boot-стратегии и матрица сборки
|
||||
|
||||
### 6.1 Три подпроекта
|
||||
|
||||
| Прошивка | Boot-стратегия | DCD | Назначение |
|
||||
|---|---|---|---|
|
||||
| `firmware_test` | XIP из Flash | ✅ | Входной контроль, тестирование периферии |
|
||||
| `bootloader` | Копирование в ITCM | ❌ | Загрузчик, не использует SDRAM |
|
||||
| `app` | XIP + буферы в SDRAM | ✅ | Основное приложение (FreeRTOS, LCDIF) |
|
||||
|
||||
### 6.2 Матрица сборки
|
||||
|
||||
Каждый проект собирается в двух режимах:
|
||||
|
||||
| | Debug | Release |
|
||||
|---|---|---|
|
||||
| `firmware_test` | разработка, отладка | HAB для сервера |
|
||||
| `bootloader` | отладка загрузчика | финальная прошивка |
|
||||
| `app` | отладка приложения | финальная прошивка |
|
||||
|
||||
### 6.3 CMake пресеты
|
||||
|
||||
```bash
|
||||
configurePresets: Debug · Release · host-debug · host-release
|
||||
|
||||
buildPresets (ARM):
|
||||
all-debug / all-release ← все проекты (для CI)
|
||||
firmware-test-debug / release
|
||||
bootloader-debug / release
|
||||
app-debug / release
|
||||
|
||||
buildPresets (host):
|
||||
host-debug-build / host-release-build
|
||||
```
|
||||
|
||||
### 6.4 Карта Flash (W25Q128, 16 MB)
|
||||
|
||||
```bash
|
||||
0x60000000 FCB — Flash Config Block 512 байт (пишет Flashloader)
|
||||
0x60001000 IVT + BDT ← начало HAB-образа
|
||||
0x60001040 DCD — инициализация SDRAM ~1088 байт (firmware_test, app)
|
||||
0x60003000 Код прошивки (.text, .data…)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Рабочий процесс разработчика
|
||||
|
||||
### 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-тесты (управление стендом) | **хост** |
|
||||
|
||||
### 7.2 Типичная сессия разработки
|
||||
|
||||
```
|
||||
Открыть VSCode → работать в devcontainer весь день
|
||||
│
|
||||
├── писать код
|
||||
│
|
||||
├── Ctrl+Shift+P → "Run Task" → 🧪 Host Tests (Debug)
|
||||
│ или в терминале: just --justfile just/build.just test-host
|
||||
│
|
||||
├── Ctrl+Shift+P → "Run Task" → 🔨 Build → firmware-test · debug
|
||||
│ → build/Debug/firmware/test/firmware_test.elf
|
||||
│
|
||||
├── Ctrl+Shift+P → "Run Task" → 📦 HAB Image → firmware-test · debug
|
||||
│ → build/Debug/firmware_test_hab.bin
|
||||
│
|
||||
│ Переключиться в хостовый терминал
|
||||
│
|
||||
├── just flash firmware_test debug ← прошить отладочный образ
|
||||
│ или
|
||||
├── just 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` |
|
||||
|
||||
Таски «Build» и «HAB Image» запрашивают два input последовательно:
|
||||
сначала проект (`firmware-test / bootloader / app / all`),
|
||||
затем тип (`debug / release`).
|
||||
|
||||
---
|
||||
|
||||
## 8. Прошивка платы (хост)
|
||||
|
||||
### 8.1 Перевод платы в SDP-режим
|
||||
|
||||
```
|
||||
1. BOOT_MOD_1 → 3V3
|
||||
2. Reset
|
||||
3. Подключить USB к хосту
|
||||
→ плата определяется как VID:PID = 1FC9:0130
|
||||
4. Выполнить нужный just flash-* рецепт
|
||||
5. После прошивки: BOOT_MOD_1 → GND, Reset
|
||||
→ плата стартует из Flash
|
||||
```
|
||||
|
||||
### 8.2 Команды прошивки
|
||||
|
||||
```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
|
||||
|
||||
# TODO: Загрузка в RAM — без записи во Flash, мгновенный старт
|
||||
# Удобно для частых итераций: не изнашивает Flash, не нужен BOOT_MOD переключатель
|
||||
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
|
||||
```
|
||||
|
||||
### 8.3 Что происходит внутри flash_usb.py
|
||||
|
||||
```
|
||||
Плата в SDP-режиме (1FC9:0130)
|
||||
│
|
||||
├── sdphost: загрузить ivt_flashloader.bin в RAM (0x20001C00)
|
||||
└── sdphost: jump-address 0x20001C00
|
||||
│
|
||||
│ ожидание до 10с — Flashloader поднимается как 15A2:0073
|
||||
│
|
||||
Flashloader (15A2:0073)
|
||||
├── fill-memory + configure-memory (0xC0000007) — инициализация FlexSPI
|
||||
├── flash-erase-region 0x60000000
|
||||
├── fill-memory + configure-memory (0xF000000F) — запись FCB
|
||||
├── write-memory 0x60001000 ← HAB-образ
|
||||
└── reset
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Отладка
|
||||
|
||||
JLink/probe-rs работает на хосте напрямую через USB/SWD.
|
||||
GDB-клиент в devcontainer подключается к серверу по TCP.
|
||||
|
||||
```bash
|
||||
Хост
|
||||
├── JLinkGDBServer -device MIMXRT1052 -if SWD -port 2331
|
||||
│ USB/SWD → плата
|
||||
└── host.docker.internal:2331 ← доступен из devcontainer
|
||||
|
||||
Devcontainer
|
||||
└── arm-none-eabi-gdb / probe-rs
|
||||
target remote host.docker.internal:2331
|
||||
```
|
||||
|
||||
`.vscode/launch.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "cortex-debug",
|
||||
"servertype": "external",
|
||||
"gdbTarget": "host.docker.internal:2331",
|
||||
"executable": "${workspaceFolder}/build/Debug/firmware/test/firmware_test.elf"
|
||||
}
|
||||
```
|
||||
|
||||
`host.docker.internal` — стандартный DNS-алиас Docker для хоста.
|
||||
Работает на macOS, Windows и Linux (Docker Desktop).
|
||||
|
||||
> USB-passthrough программатора в Docker на macOS невозможен, на других
|
||||
> платформах нестабилен. TCP-мост — единственное надёжное решение для
|
||||
> всех платформ.
|
||||
|
||||
---
|
||||
|
||||
## 10. Тесты
|
||||
|
||||
### 10.1 Host-тесты
|
||||
|
||||
Выполняются в devcontainer на хостовом компиляторе (x86/arm64). Железо не нужно.
|
||||
|
||||
```bash
|
||||
Фреймворк: Unity + fff
|
||||
Пресеты: host-debug / host-release
|
||||
Компилятор: системный clang-17 (не ARM GCC)
|
||||
Запуск: just --justfile just/build.just test-host
|
||||
Результат: JUnit XML → VSCode CTest Lab + GitLab CI
|
||||
```
|
||||
|
||||
`BUILD_TESTS_HOST=ON` отключает ARM-специфику (BSP, SDK) — компилируются
|
||||
только тестируемые модули и fff-заглушки.
|
||||
|
||||
### 10.2 Target-тесты
|
||||
|
||||
Выполняются на физической плате. Прошивается `firmware_test`,
|
||||
стенд подаёт сигналы и проверяет ответы.
|
||||
|
||||
```bash
|
||||
Стенд (M5StampPLC или аналог) ←→ Плата TFT
|
||||
|
||||
Тестируемые подсистемы:
|
||||
SDRAM 32 MB — чтение/запись паттернов
|
||||
QSPI Flash — erase / write / verify
|
||||
CAN — loopback + внешний фрейм от стенда
|
||||
UART TTL — echo-тест
|
||||
UART +24V изол. — echo-тест
|
||||
Гальв. входы +24V — состояния при подаче напряжения от стенда
|
||||
RTC BM8563 — установка / чтение времени
|
||||
SD-карта (SDIO) — монтирование, R/W файл
|
||||
MQS (аудио) — воспроизведение тестового сигнала
|
||||
IR-приёмник — приём тестового кода от стенда
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Жизненный цикл изменений
|
||||
|
||||
```bash
|
||||
feature-ветка
|
||||
│
|
||||
├── код в devcontainer
|
||||
│ 🧪 Host Tests ← зелёные?
|
||||
│ 🔨 Build firmware-test debug ← компилируется?
|
||||
│
|
||||
├── проверка на железе
|
||||
│ 📦 HAB Image → firmware-test · debug
|
||||
│ just flash-test-debug ← прошить
|
||||
│ target-тесты со стендом ← периферия работает?
|
||||
│
|
||||
├── подготовка к MR
|
||||
│ 📦 HAB All (Release) ← финальные образы
|
||||
│ just flash firmware_test release ← убедиться что release работает
|
||||
│
|
||||
└── Merge Request → GitLab
|
||||
[CI pipeline — отдельная тема]
|
||||
host-тесты, сборка, публикация артефактов
|
||||
│
|
||||
▼
|
||||
Производственный сервер
|
||||
just incoming → firmware_test release → HIL
|
||||
just production → bootloader + app release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Обновление зависимостей
|
||||
|
||||
### spsdk (на хосте разработчика)
|
||||
|
||||
```bash
|
||||
just 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 в Dockerfile
|
||||
|
||||
```dockerfile
|
||||
ARG JUST_VERSION=1.40.0 # .devcontainer/Dockerfile — единственное место
|
||||
```
|
||||
|
||||
### ARM toolchain
|
||||
|
||||
```dockerfile
|
||||
ARG TOOLCHAIN_VERSION=14.2.rel1 # .devcontainer/Dockerfile
|
||||
```
|
||||
|
||||
Пересборка инвалидирует только Stage 1 (toolchain). Stage 2
|
||||
(clang, cmake и др.) берётся из кэша — пересборка быстрая.
|
||||
|
||||
### После git pull если изменился uv.lock
|
||||
|
||||
```bash
|
||||
just setup-tools # автоматически обнаружит изменение и выполнит uv sync
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Производственный сервер (к сведению)
|
||||
|
||||
Сервер работает **только с готовыми проверенными артефактами**.
|
||||
Никакой сборки, никакого компилятора.
|
||||
|
||||
```bash
|
||||
Источник: GitLab Releases или FTP
|
||||
— только теггированные релизы, прошедшие CI
|
||||
|
||||
Сценарий входного контроля новой платы:
|
||||
1. just incoming
|
||||
└── flash firmware_test release → HIL-тесты периферии
|
||||
2. Тесты пройдены:
|
||||
just production
|
||||
├── flash bootloader release
|
||||
└── flash app release
|
||||
|
||||
Установлено: just · uv + spsdk · git
|
||||
НЕ установлено: docker · cmake · компилятор · ARM toolchain
|
||||
```
|
||||
|
||||
Детальный `server.just` и пайплайн сервера — отдельная задача.
|
||||
|
||||
---
|
||||
|
||||
## Приложение А: минимальные версии
|
||||
|
||||
| Инструмент | Версия | Причина |
|
||||
|---|---|---|
|
||||
| `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` |
|
||||
|
||||
## Приложение Б: быстрая шпаргалка
|
||||
|
||||
```bash
|
||||
# ── Первый запуск ──────────────────────────────────────────────
|
||||
./scripts/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 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 scan # найти NXP USB-устройства
|
||||
just sdp-status # проверить BootROM
|
||||
just setup-tools # обновить spsdk после git pull
|
||||
just check-deps # проверить версии инструментов
|
||||
```
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
# Программные компоненты ThirdParty
|
||||
|
||||
## Библиотеки сторонних разработчиков, загруженные в виде субмодулей
|
||||
|
||||
* [SEGGER_RTT](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/)
|
||||
* [Unity](https://www.throwtheswitch.org/unity)
|
||||
* [FFF](https://github.com/meekrosoft/fff)
|
||||
|
||||
## Работа с Git-Submodules
|
||||
|
||||
```bash
|
||||
# 1. Добавление субмодулей (например SEGGER_RTT)
|
||||
git submodule add https://github.com/SEGGERMicro/RTT ThirdParty/RTT
|
||||
# 2. Синхронизация состояния субмодулей, загруженных локально с remote
|
||||
git submodule update --init --recursive
|
||||
|
||||
# Полная переинициализация субмодулей (На примере SEGGER_RTT)
|
||||
# 1. Удалить submodule полностью
|
||||
git submodule deinit -f ThirdParty/RTT
|
||||
rm -rf .git/modules/ThirdParty/RTT
|
||||
git rm -rf ThirdParty/RTT
|
||||
|
||||
# 2. Удалить .gitmodules запись
|
||||
vim .gitmodules # удалить секцию [submodule "ThirdParty/RTT"]
|
||||
|
||||
# 3. Добавить заново
|
||||
git submodule add https://github.com/SEGGERMicro/RTT ThirdParty/RTT
|
||||
git submodule update --init --recursive
|
||||
|
||||
```
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
add_executable(firmware_test)
|
||||
|
||||
target_sources(firmware_test PRIVATE main.c
|
||||
${PROJECT_SOURCE_DIR}/bsp/board/syscalls.c)
|
||||
target_sources(firmware_test
|
||||
PRIVATE main.c ${PROJECT_SOURCE_DIR}/bsp/generated/syscalls.c)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Зависимости — только то что нужно для входного контроля bsp_board транзитивно
|
||||
|
|
@ -36,6 +36,7 @@ target_link_options(
|
|||
-Wl,-Map=${CMAKE_BINARY_DIR}/firmware_test.map
|
||||
-T${PROJECT_SOURCE_DIR}/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld)
|
||||
|
||||
# TODO: дефайны BOOT
|
||||
# -----------------------------------------------------------------------------
|
||||
# Post-build: генерация .bin для прошивки через blhost
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include "fsl_gpio.h"
|
||||
#include "pin_mux.h"
|
||||
|
||||
|
|
@ -27,12 +26,12 @@
|
|||
* Code
|
||||
******************************************************************************/
|
||||
|
||||
int main(void) {
|
||||
const uint32_t USER_DELAY_US = 1000000;
|
||||
BOARD_Init();
|
||||
// GPIO_PinWrite(BOARD_INITPINS_UserLed1_PORT, BOARD_INITPINS_UserLed1_PIN,
|
||||
// 0);
|
||||
GPIO_PinWrite(BOARD_INITPINS_UserLed2_PORT, BOARD_INITPINS_UserLed2_PIN, 0);
|
||||
while (1) {
|
||||
}
|
||||
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);
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
157
scripts/bootstrap.sh
Executable file
157
scripts/bootstrap.sh
Executable file
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# scripts/bootstrap.sh
|
||||
# Уровень 0: устанавливает just (если отсутствует), затем передаёт управление
|
||||
# just bootstrap для полной инициализации окружения.
|
||||
#
|
||||
# Поддерживаемые платформы:
|
||||
# Linux — bash (native)
|
||||
# macOS — bash (native)
|
||||
# Windows — Git Bash (поставляется вместе с git)
|
||||
#
|
||||
# Требования: bash >= 4, curl (Linux/macOS) или winget (Windows)
|
||||
# Запуск: ./scripts/bootstrap.sh
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
JUST_VERSION="1.36.0"
|
||||
LINUX_INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
BOLD="\033[1m"
|
||||
RED="\033[0;31m"
|
||||
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}"; }
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}=== TFT Firmware — Bootstrap ===${RESET}"
|
||||
echo ""
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 1. Определить платформу
|
||||
# uname на Git Bash: MINGW64_NT-10.0-19045, MSYS_NT-..., CYGWIN_NT-...
|
||||
# -----------------------------------------------------------------------------
|
||||
_uname="$(uname -s)"
|
||||
case "${_uname}" in
|
||||
Linux*) PLATFORM="linux" ;;
|
||||
Darwin*) PLATFORM="macos" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
|
||||
*)
|
||||
error "Unsupported platform: ${_uname}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
info "Platform detected: ${PLATFORM}"
|
||||
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
|
||||
[[ "${a2:-0}" -lt "${b2:-0}" ]] && return 1
|
||||
[[ "${a3:-0}" -ge "${b3:-0}" ]] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 3. Платформо-зависимая установка just
|
||||
# -----------------------------------------------------------------------------
|
||||
install_just_linux() {
|
||||
info "Installing just ${JUST_VERSION} -> ${LINUX_INSTALL_DIR}"
|
||||
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:"
|
||||
warn " export PATH=\"${LINUX_INSTALL_DIR}:\$PATH\""
|
||||
export PATH="${LINUX_INSTALL_DIR}:${PATH}"
|
||||
fi
|
||||
}
|
||||
|
||||
install_just_macos() {
|
||||
if command -v brew &>/dev/null; then
|
||||
info "Installing just via Homebrew..."
|
||||
brew install just
|
||||
else
|
||||
install_just_linux
|
||||
fi
|
||||
}
|
||||
|
||||
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"
|
||||
exit 1
|
||||
}
|
||||
warn "Restart Git Bash so the new PATH from winget takes effect,"
|
||||
warn "then re-run: ./scripts/bootstrap.sh"
|
||||
exit 0
|
||||
else
|
||||
error "winget not found."
|
||||
echo ""
|
||||
echo " Options to install just on Windows:"
|
||||
echo " 1. Install 'App Installer' from Microsoft Store (brings winget)"
|
||||
echo " 2. Download just.exe manually: https://github.com/casey/just/releases"
|
||||
echo " Place it in a directory that is in your Git Bash PATH"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 4. Проверить / установить just
|
||||
# -----------------------------------------------------------------------------
|
||||
JUST_OK=false
|
||||
|
||||
if command -v just &>/dev/null; then
|
||||
JUST_CURRENT="$(just --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')"
|
||||
if semver_ge "${JUST_CURRENT}" "${JUST_VERSION}"; then
|
||||
success "just ${JUST_CURRENT} (>= ${JUST_VERSION} required)"
|
||||
JUST_OK=true
|
||||
else
|
||||
warn "just ${JUST_CURRENT} is outdated (need >= ${JUST_VERSION}), reinstalling..."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${JUST_OK}" == "false" ]]; then
|
||||
case "${PLATFORM}" in
|
||||
linux) install_just_linux ;;
|
||||
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
|
||||
# -----------------------------------------------------------------------------
|
||||
info "Delegating to: just bootstrap"
|
||||
echo ""
|
||||
exec just bootstrap "$@"
|
||||
208
scripts/build.just
Normal file
208
scripts/build.just
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# =============================================================================
|
||||
# scripts/build.just — сборка, тесты, HAB-образы
|
||||
# Выполняется ТОЛЬКО внутри devcontainer (из терминала VSCode или tasks).
|
||||
#
|
||||
# Рабочая директория — корень репозитория (не scripts/).
|
||||
# =============================================================================
|
||||
|
||||
set working-directory := ".."
|
||||
|
||||
TOOLS_DIR := "tools/host"
|
||||
BUILD_DIR := "build"
|
||||
|
||||
_default:
|
||||
@just --list --justfile scripts/build.just --unsorted
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: build
|
||||
#
|
||||
# Матрица сборки:
|
||||
# firmware-test × debug / release
|
||||
# bootloader × debug / release
|
||||
# app × debug / release
|
||||
# all × debug / release (все проекты сразу, для CI)
|
||||
# =============================================================================
|
||||
|
||||
[private]
|
||||
_configure-debug:
|
||||
cmake --preset Debug
|
||||
|
||||
[private]
|
||||
_configure-release:
|
||||
cmake --preset Release
|
||||
|
||||
# ── firmware_test ─────────────────────────────────────────────────────────────
|
||||
[group('build')]
|
||||
build-firmware-test-debug: _configure-debug
|
||||
cmake --build --preset firmware-test-debug
|
||||
|
||||
[group('build')]
|
||||
build-firmware-test-release: _configure-release
|
||||
cmake --build --preset firmware-test-release
|
||||
|
||||
# ── bootloader ───────────────────────────────────────────────────────────────
|
||||
[group('build')]
|
||||
build-bootloader-debug: _configure-debug
|
||||
cmake --build --preset bootloader-debug
|
||||
|
||||
[group('build')]
|
||||
build-bootloader-release: _configure-release
|
||||
cmake --build --preset bootloader-release
|
||||
|
||||
# ── app ───────────────────────────────────────────────────────────────────────
|
||||
[group('build')]
|
||||
build-app-debug: _configure-debug
|
||||
cmake --build --preset app-debug
|
||||
|
||||
[group('build')]
|
||||
build-app-release: _configure-release
|
||||
cmake --build --preset app-release
|
||||
|
||||
# ── все проекты сразу ─────────────────────────────────────────────────────────
|
||||
[group('build')]
|
||||
build-all-debug: _configure-debug
|
||||
cmake --build --preset all-debug
|
||||
|
||||
[group('build')]
|
||||
build-all-release: _configure-release
|
||||
cmake --build --preset all-release
|
||||
|
||||
# ── утилиты ───────────────────────────────────────────────────────────────────
|
||||
[group('build')]
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: test
|
||||
# =============================================================================
|
||||
|
||||
[private]
|
||||
_configure-host-debug:
|
||||
cmake --preset host-debug
|
||||
|
||||
[private]
|
||||
_configure-host-release:
|
||||
cmake --preset host-release
|
||||
|
||||
[group('test')]
|
||||
test-host: _configure-host-debug
|
||||
cmake --build --preset host-debug-build
|
||||
ctest --preset host-debug-test
|
||||
|
||||
[group('test')]
|
||||
test-host-release: _configure-host-release
|
||||
cmake --build --preset host-release-build
|
||||
ctest --preset host-release-test
|
||||
|
||||
# =============================================================================
|
||||
# ГРУППА: flash — подготовка HAB-образов
|
||||
#
|
||||
# Матрица HAB:
|
||||
# firmware-test × debug / release
|
||||
# bootloader × debug / release
|
||||
# app × debug / release
|
||||
# all × debug / release
|
||||
#
|
||||
# Debug HAB — для прошивки своей платы и отладки.
|
||||
# Release HAB — для производственного сервера.
|
||||
#
|
||||
# HAB yaml конфиги:
|
||||
# tools/host/hab/hab_<project>_debug.yaml — путь к Debug ELF
|
||||
# tools/host/hab/hab_<project>_release.yaml — путь к Release ELF
|
||||
# =============================================================================
|
||||
|
||||
# ── firmware_test ─────────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
hab-firmware-test-debug: build-firmware-test-debug
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "{{TOOLS_DIR}}/hab"
|
||||
uv run nxpimage hab export --force \
|
||||
-c hab_firmware_test_debug.yaml \
|
||||
-o "../../../{{BUILD_DIR}}/Debug/firmware_test_hab.bin"
|
||||
echo " ✅ firmware_test_hab.bin (Debug)"
|
||||
|
||||
[group('flash')]
|
||||
hab-firmware-test-release: build-firmware-test-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "{{TOOLS_DIR}}/hab"
|
||||
uv run nxpimage hab export --force \
|
||||
-c hab_firmware_test_release.yaml \
|
||||
-o "../../../{{BUILD_DIR}}/Release/firmware_test_hab.bin"
|
||||
echo " ✅ firmware_test_hab.bin (Release)"
|
||||
|
||||
# ── bootloader ───────────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
hab-bootloader-debug: build-bootloader-debug
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "{{TOOLS_DIR}}/hab"
|
||||
uv run nxpimage hab export --force \
|
||||
-c hab_bootloader_debug.yaml \
|
||||
-o "../../../{{BUILD_DIR}}/Debug/bootloader_hab.bin"
|
||||
echo " ✅ bootloader_hab.bin (Debug)"
|
||||
|
||||
[group('flash')]
|
||||
hab-bootloader-release: build-bootloader-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "{{TOOLS_DIR}}/hab"
|
||||
uv run nxpimage hab export --force \
|
||||
-c hab_bootloader_release.yaml \
|
||||
-o "../../../{{BUILD_DIR}}/Release/bootloader_hab.bin"
|
||||
echo " ✅ bootloader_hab.bin (Release)"
|
||||
|
||||
# ── app ───────────────────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
hab-app-debug: build-app-debug
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "{{TOOLS_DIR}}/hab"
|
||||
uv run nxpimage hab export --force \
|
||||
-c hab_app_debug.yaml \
|
||||
-o "../../../{{BUILD_DIR}}/Debug/app_hab.bin"
|
||||
echo " ✅ app_hab.bin (Debug)"
|
||||
|
||||
[group('flash')]
|
||||
hab-app-release: build-app-release
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "{{TOOLS_DIR}}/hab"
|
||||
uv run nxpimage hab export --force \
|
||||
-c hab_app_release.yaml \
|
||||
-o "../../../{{BUILD_DIR}}/Release/app_hab.bin"
|
||||
echo " ✅ app_hab.bin (Release)"
|
||||
|
||||
# ── все образы сразу ─────────────────────────────────────────────────────────
|
||||
[group('flash')]
|
||||
hab-all-debug: hab-firmware-test-debug hab-bootloader-debug hab-app-debug
|
||||
@echo " ✅ All HAB images (Debug) ready"
|
||||
|
||||
[group('flash')]
|
||||
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')]
|
||||
hab-verify project="firmware_test" type="release":
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
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" ;;
|
||||
*)
|
||||
echo " ❌ Unknown: {{project}}-{{type}}"
|
||||
echo " Projects: firmware_test, bootloader, app"
|
||||
echo " Types: debug, release"
|
||||
exit 1 ;;
|
||||
esac
|
||||
OUT="/tmp/hab_parse_{{project}}_{{type}}.yaml"
|
||||
uv run nxpimage hab parse -b "${BIN}" -o "${OUT}"
|
||||
echo " ✅ ${OUT}"
|
||||
grep -E "(entry|csf|tag)" "${OUT}" || true
|
||||
17
tools/host/hab/hab_app_debug.yaml
Normal file
17
tools/host/hab/hab_app_debug.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# =============================================================================
|
||||
# HAB Container — firmware/app (боевая прошивка)
|
||||
# Расположение: tools/host/hab/hab_app.yaml
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
options:
|
||||
flags: 0x00
|
||||
startAddress: 0x60000000
|
||||
ivtOffset: 0x1000
|
||||
initialLoadSize: 0x2000
|
||||
family: mimxrt1050
|
||||
DCDFilePath: ../dcd/dcd.bin # обязателен — heap FreeRTOS и LCDIF в SDRAM
|
||||
|
||||
inputImageFile: "../../../build/Debug/app.bin"
|
||||
|
||||
sections: []
|
||||
17
tools/host/hab/hab_bootloader_debug.yaml
Normal file
17
tools/host/hab/hab_bootloader_debug.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# =============================================================================
|
||||
# HAB Container — firmware/bootloader
|
||||
# Расположение: tools/host/hab/hab_bootloader.yaml
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
options:
|
||||
flags: 0x00
|
||||
startAddress: 0x60000000
|
||||
ivtOffset: 0x1000
|
||||
initialLoadSize: 0x2000
|
||||
family: mimxrt1050
|
||||
# DCD намеренно отсутствует — загрузчик не использует SDRAM
|
||||
|
||||
inputImageFile: "../../../build/Debug/bootloader.bin"
|
||||
|
||||
sections: []
|
||||
18
tools/host/hab/hab_firmware_test_release.yaml
Normal file
18
tools/host/hab/hab_firmware_test_release.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# =============================================================================
|
||||
# HAB Container — firmware/test (входной контроль производства)
|
||||
# Расположение: tools/host/hab/hab_firmware_test.yaml
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
options:
|
||||
flags: 0x00 # unsigned — без подписи
|
||||
startAddress: 0x60000000 # FlexSPI NOR base (XIP)
|
||||
ivtOffset: 0x1000 # IVT offset for FlexSPI NOR boot
|
||||
initialLoadSize: 0x2000 # размер области IVT+BDT+DCD до кода
|
||||
family: mimxrt1050
|
||||
DCDFilePath: ../dcd/dcd.bin # инициализация SDRAM
|
||||
|
||||
# .bin или .srec — оба принимаются
|
||||
inputImageFile: "../../../build/Release/firmware_test.bin"
|
||||
|
||||
sections: []
|
||||
Loading…
Reference in a new issue