mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
253 lines
7.6 KiB
Bash
Executable File
253 lines
7.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# ---------------------------------------------
|
|
# Usage:
|
|
# ./compile-with-docker.sh [Preset] [CMake options...]
|
|
# Examples:
|
|
# ./compile-with-docker.sh Fusion
|
|
# ./compile-with-docker.sh Transfer
|
|
# ./compile-with-docker.sh FieldOps
|
|
# ./compile-with-docker.sh Max
|
|
# ./compile-with-docker.sh Fusion -DDEV=ON
|
|
# ./compile-with-docker.sh FieldOps -DENABLE_VOX=OFF
|
|
# ./compile-with-docker.sh All
|
|
# Default preset: "Fusion"
|
|
# ---------------------------------------------
|
|
|
|
IMAGE=uvk1-uvk5v3
|
|
RELEASE_PRESETS=(Fusion Transfer FieldOps Max)
|
|
FLASH_LIMIT=$((118 * 1024))
|
|
RAM_LIMIT=$((16 * 1024))
|
|
|
|
PRESET=${1:-Fusion}
|
|
shift || true # remove preset from arguments if present
|
|
|
|
# Any remaining args will be treated as CMake cache variables
|
|
EXTRA_ARGS=("$@")
|
|
|
|
# ---------------------------------------------
|
|
# Validate preset name
|
|
# ---------------------------------------------
|
|
if [[ ! "$PRESET" =~ ^(Custom|Fusion|Transfer|FieldOps|Max|All)$ ]]; then
|
|
echo "❌ Unknown preset: '$PRESET'"
|
|
echo "Valid presets are: Custom, Fusion, Transfer, FieldOps, Max, All"
|
|
exit 1
|
|
fi
|
|
|
|
QUIET=0
|
|
if [[ "$PRESET" == "All" ]]; then
|
|
QUIET=1
|
|
fi
|
|
|
|
# Remember whether the script itself was started from an interactive terminal.
|
|
# The build output is piped through tee below, so checking stdout later from
|
|
# run_preset_build() would always report a non-terminal.
|
|
INTERACTIVE=0
|
|
if [[ -t 1 ]]; then
|
|
INTERACTIVE=1
|
|
fi
|
|
|
|
# ---------------------------------------------
|
|
# Build the Docker image (only needed once)
|
|
# ---------------------------------------------
|
|
if [[ "$(docker images -q "$IMAGE")" == "" ]]; then
|
|
echo "Building Docker image..."
|
|
docker build -q -t "$IMAGE" . >/dev/null
|
|
fi
|
|
export MSYS_NO_PATHCONV=1
|
|
|
|
RESULT_PRESETS=()
|
|
RESULT_FLASH_SIZES=()
|
|
RESULT_RAM_SIZES=()
|
|
|
|
run_preset_build() {
|
|
local preset="$1"
|
|
local -a docker_tty_args=()
|
|
|
|
# Give Ninja a pseudo-terminal for an interactive single-preset build. This
|
|
# lets it refresh its [current/total] progress on one line. Batch/redirected
|
|
# builds keep plain line-oriented output suitable for logs and CI.
|
|
if (( INTERACTIVE && ! QUIET )); then
|
|
docker_tty_args=(-t)
|
|
fi
|
|
|
|
docker run --rm "${docker_tty_args[@]}" \
|
|
-u "$(id -u):$(id -g)" \
|
|
-v "$PWD":/src -w /src "$IMAGE" \
|
|
bash -c 'which arm-none-eabi-gcc && arm-none-eabi-gcc --version &&
|
|
cmake --fresh --preset "$1" "${@:2}" &&
|
|
cmake --build --preset "$1" -j' \
|
|
bash "$preset" "${EXTRA_ARGS[@]}"
|
|
}
|
|
|
|
build_preset() {
|
|
local preset="$1"
|
|
local preset_slug log_file bin_file flash_size ram_size status
|
|
|
|
preset_slug="${preset,,}"
|
|
log_file="$(mktemp)"
|
|
bin_file=""
|
|
|
|
find "build/${preset}" -maxdepth 1 -type f -name 'f4hwn.*' -delete 2>/dev/null || true
|
|
|
|
if (( QUIET )); then
|
|
printf "Building %-10s ... " "$preset"
|
|
if run_preset_build "$preset" >"$log_file" 2>&1; then
|
|
status=0
|
|
else
|
|
status=$?
|
|
fi
|
|
else
|
|
echo ""
|
|
echo "=== 🚀 Building preset: ${preset} ==="
|
|
echo "---------------------------------------------"
|
|
if (( INTERACTIVE )); then
|
|
# Do not put a line-oriented filter after tee here: it would buffer
|
|
# Ninja's carriage-return progress updates and defeat the TTY display.
|
|
if run_preset_build "$preset" 2>&1 | tee "$log_file"; then
|
|
status=0
|
|
else
|
|
status=$?
|
|
fi
|
|
else
|
|
if run_preset_build "$preset" 2>&1 | tee "$log_file" | awk '
|
|
/^Memory region[[:space:]]+Used Size[[:space:]]+Region Size/ { next }
|
|
/^[[:space:]]+RAM:[[:space:]]/ { next }
|
|
/^[[:space:]]+FLASH:[[:space:]]/ { next }
|
|
{ print; fflush() }
|
|
'; then
|
|
status=0
|
|
else
|
|
status=$?
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if (( status != 0 )); then
|
|
if (( QUIET )); then
|
|
printf "FAILED\n\n"
|
|
cat "$log_file"
|
|
else
|
|
echo "Failed: ${preset}"
|
|
fi
|
|
rm -f -- "$log_file"
|
|
return "$status"
|
|
fi
|
|
|
|
bin_file="build/${preset}/f4hwn.${preset_slug}.bin"
|
|
if [[ -z "$bin_file" || ! -f "$bin_file" ]]; then
|
|
if (( QUIET )); then
|
|
printf "FAILED\n"
|
|
fi
|
|
echo "Expected binary not found: $bin_file"
|
|
if (( QUIET )); then
|
|
cat "$log_file"
|
|
fi
|
|
rm -f -- "$log_file"
|
|
return 1
|
|
fi
|
|
|
|
flash_size="$(wc -c < "$bin_file")"
|
|
ram_size="$(awk '$1 == "RAM:" {
|
|
value = $2
|
|
if ($3 == "KB") value *= 1024
|
|
else if ($3 == "MB") value *= 1024 * 1024
|
|
printf "%.0f\n", value
|
|
}' "$log_file" | tail -n 1)"
|
|
|
|
if [[ ! "$ram_size" =~ ^[0-9]+$ ]]; then
|
|
if (( QUIET )); then
|
|
printf "FAILED\n"
|
|
fi
|
|
echo "Could not read RAM usage from linker output"
|
|
if (( QUIET )); then
|
|
cat "$log_file"
|
|
fi
|
|
rm -f -- "$log_file"
|
|
return 1
|
|
fi
|
|
|
|
RESULT_PRESETS+=("$preset")
|
|
RESULT_FLASH_SIZES+=("$flash_size")
|
|
RESULT_RAM_SIZES+=("$ram_size")
|
|
|
|
if (( QUIET )); then
|
|
printf "OK\n"
|
|
else
|
|
echo "✅ Done: ${preset}"
|
|
fi
|
|
rm -f -- "$log_file"
|
|
}
|
|
|
|
print_summary() {
|
|
local i
|
|
local flash_used flash_free flash_bp flash_pct
|
|
local flash_used_kib100 flash_free_kib100 flash_used_kib flash_free_kib
|
|
local ram_used ram_free ram_bp ram_pct
|
|
local ram_used_kib100 ram_free_kib100 ram_used_kib ram_free_kib
|
|
|
|
echo ""
|
|
printf "Flash (limit: %d B / %d.00 KiB)\n" "$FLASH_LIMIT" "$((FLASH_LIMIT / 1024))"
|
|
printf "%-10s | %10s | %10s | %10s | %10s | %7s\n" \
|
|
"Preset" "Used (B)" "Used (KiB)" "Free (B)" "Free (KiB)" "Usage"
|
|
printf "%-10s-+-%10s-+-%10s-+-%10s-+-%10s-+-%7s\n" \
|
|
"----------" "----------" "----------" "----------" "----------" "-------"
|
|
|
|
for i in "${!RESULT_PRESETS[@]}"; do
|
|
flash_used="${RESULT_FLASH_SIZES[$i]}"
|
|
flash_free=$((FLASH_LIMIT - flash_used))
|
|
flash_bp=$(((flash_used * 10000 + FLASH_LIMIT / 2) / FLASH_LIMIT))
|
|
flash_used_kib100=$(((flash_used * 100 + 512) / 1024))
|
|
flash_free_kib100=$(((flash_free * 100 + 512) / 1024))
|
|
printf -v flash_pct "%d.%02d%%" "$((flash_bp / 100))" "$((flash_bp % 100))"
|
|
printf -v flash_used_kib "%d.%02d" "$((flash_used_kib100 / 100))" "$((flash_used_kib100 % 100))"
|
|
printf -v flash_free_kib "%d.%02d" "$((flash_free_kib100 / 100))" "$((flash_free_kib100 % 100))"
|
|
|
|
printf "%-10s | %10d | %10s | %10d | %10s | %7s\n" \
|
|
"${RESULT_PRESETS[$i]}" "$flash_used" "$flash_used_kib" \
|
|
"$flash_free" "$flash_free_kib" "$flash_pct"
|
|
done
|
|
|
|
echo ""
|
|
printf "RAM (limit: %d B / %d.00 KiB)\n" "$RAM_LIMIT" "$((RAM_LIMIT / 1024))"
|
|
printf "%-10s | %10s | %10s | %10s | %10s | %7s\n" \
|
|
"Preset" "Used (B)" "Used (KiB)" "Free (B)" "Free (KiB)" "Usage"
|
|
printf "%-10s-+-%10s-+-%10s-+-%10s-+-%10s-+-%7s\n" \
|
|
"----------" "----------" "----------" "----------" "----------" "-------"
|
|
|
|
for i in "${!RESULT_PRESETS[@]}"; do
|
|
ram_used="${RESULT_RAM_SIZES[$i]}"
|
|
ram_free=$((RAM_LIMIT - ram_used))
|
|
ram_bp=$(((ram_used * 10000 + RAM_LIMIT / 2) / RAM_LIMIT))
|
|
ram_used_kib100=$(((ram_used * 100 + 512) / 1024))
|
|
ram_free_kib100=$(((ram_free * 100 + 512) / 1024))
|
|
printf -v ram_pct "%d.%02d%%" "$((ram_bp / 100))" "$((ram_bp % 100))"
|
|
printf -v ram_used_kib "%d.%02d" "$((ram_used_kib100 / 100))" "$((ram_used_kib100 % 100))"
|
|
printf -v ram_free_kib "%d.%02d" "$((ram_free_kib100 / 100))" "$((ram_free_kib100 % 100))"
|
|
|
|
printf "%-10s | %10d | %10s | %10d | %10s | %7s\n" \
|
|
"${RESULT_PRESETS[$i]}" "$ram_used" "$ram_used_kib" \
|
|
"$ram_free" "$ram_free_kib" "$ram_pct"
|
|
done
|
|
|
|
echo ""
|
|
if (( ${#RESULT_PRESETS[@]} == 1 )); then
|
|
echo "🎉 Preset ${RESULT_PRESETS[0]} built successfully!"
|
|
else
|
|
echo "🎉 All presets built successfully!"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------
|
|
# Handle 'All' preset
|
|
# ---------------------------------------------
|
|
if [[ "$PRESET" == "All" ]]; then
|
|
for p in "${RELEASE_PRESETS[@]}"; do
|
|
build_preset "$p"
|
|
done
|
|
else
|
|
build_preset "$PRESET"
|
|
fi
|
|
print_summary
|