diff --git a/.gitignore b/.gitignore index f16dafc1..3772f9dd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ compile_commands.json k5_eeprom.raw /build +/serialtool/__pycache__ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 81e336e2..23bf8fcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,9 @@ target_link_options(${EXE_NAME} PRIVATE "-Wl,-Map=${EXE_NAME}.map") # Add the map file to the list of files to be removed with 'clean' target set_target_properties(${EXE_NAME} PROPERTIES ADDITIONAL_CLEAN_FILES ${EXE_NAME}.map) +# Force linker to ignore RWX segment warning even if cache exists +target_link_options(${EXE_NAME} PRIVATE -Wl,--no-warn-rwx-segment) + # ----------------------------------- # Post build processing # diff --git a/CMakePresets.json b/CMakePresets.json index e3ee6736..b913c5f2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -77,7 +77,9 @@ "cacheVariables": { "ENABLE_VOICE": false, "ENABLE_SWD": true, - "ENABLE_AIRCOPY": false + "ENABLE_AIRCOPY": false, + "EDITION_STRING": "Custom", + "TARGET": "f4hwn.custom" } }, { diff --git a/Dockerfile b/Dockerfile index 0c67b544..dbe663a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,36 @@ -ARG BUILDPLATFORM -FROM --platform=${BUILDPLATFORM} archlinux:latest -RUN pacman -Syyu base-devel --noconfirm -RUN pacman -Syyu arm-none-eabi-gcc --noconfirm -RUN pacman -Syyu arm-none-eabi-newlib --noconfirm -RUN pacman -Syyu git --noconfirm -RUN pacman -Syyu python-pip --noconfirm -RUN pacman -Syyu python-crcmod --noconfirm -WORKDIR /app -COPY . . -RUN git submodule update --init --recursive \ No newline at end of file +FROM debian:bookworm-slim + +# --------------------------------------------- +# Install required packages +# --------------------------------------------- +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential cmake ninja-build python3 curl xz-utils ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# --------------------------------------------- +# Download and install ARM GCC toolchain +# Supports both Apple Silicon (arm64) and Intel (amd64) +# --------------------------------------------- +ARG TARGETARCH +ARG ARM_GCC_VERSION=13.3.rel1 + +RUN set -eux; \ + if [ "${TARGETARCH}" = "arm64" ]; then HOSTARCH="aarch64"; else HOSTARCH="x86_64"; fi; \ + TARBALL="arm-gnu-toolchain-${ARM_GCC_VERSION}-${HOSTARCH}-arm-none-eabi.tar.xz"; \ + URL="https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/${ARM_GCC_VERSION}/binrel/${TARBALL}"; \ + echo "Downloading ${URL}"; \ + curl -fL -O "${URL}"; \ + tar -xf "${TARBALL}"; \ + rm "${TARBALL}"; \ + DIR="$(ls -d arm-gnu-toolchain-${ARM_GCC_VERSION}-*-arm-none-eabi)"; \ + mv "${DIR}" /opt/toolchain + +# --------------------------------------------- +# Add toolchain to PATH +# --------------------------------------------- +ENV PATH="/opt/toolchain/bin:${PATH}" + +# --------------------------------------------- +# Set working directory +# --------------------------------------------- +WORKDIR /src diff --git a/cmake/gcc-arm-none-eabi.cmake b/cmake/gcc-arm-none-eabi.cmake index 1803fa54..10971efb 100644 --- a/cmake/gcc-arm-none-eabi.cmake +++ b/cmake/gcc-arm-none-eabi.cmake @@ -40,3 +40,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --specs=nano.specs") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--print-memory-usage") set(TOOLCHAIN_LINK_LIBRARIES "m") + +# Suppress harmless "RWX segment" warning +set(CMAKE_EXE_LINKER_FLAGS_INIT + "--specs=nosys.specs -Wl,--gc-sections -Wl,--no-warn-rwx-segment") diff --git a/compile-with-docker.sh b/compile-with-docker.sh index 8a52a821..ca1c9ccc 100755 --- a/compile-with-docker.sh +++ b/compile-with-docker.sh @@ -1,180 +1,46 @@ -#!/bin/sh +#!/usr/bin/env bash +set -euo pipefail -IMAGE_NAME="uvk5" -FIRMWARE_DIR="${PWD}/compiled-firmware" +# --------------------------------------------- +# Usage: +# ./compile-with-docker.sh [Preset] +# Example: +# ./compile-with-docker.sh Custom +# ./compile-with-docker.sh Bandscope +# ./compile-with-docker.sh Broadcast +# ./compile-with-docker.sh Basic +# ./compile-with-docker.sh RescueOps +# ./compile-with-docker.sh Game +# Default preset: "Custom" +# --------------------------------------------- -# Create firmware output directory if it doesn't exist -mkdir -p "$FIRMWARE_DIR" +IMAGE=uvk1-uvk5v3 +PRESET=${1:-Custom} -# Clean previously compiled firmware files -rm -f "$FIRMWARE_DIR"/* - -# Clean up old Docker artifacts -echo "🧽 Cleaning up old Docker artifacts..." -docker system prune -f --volumes >/dev/null 2>&1 || true - -# Always rebuild the Docker image to ensure latest code changes -echo "⚙️ Rebuilding Docker image '$IMAGE_NAME'..." -docker rmi "$IMAGE_NAME" 2>/dev/null || true -if ! docker build --build-arg BUILDPLATFORM=linux/amd64 -t "$IMAGE_NAME" .; then - echo "❌ Failed to build docker image" - exit 1 +# --------------------------------------------- +# Validate preset name +# --------------------------------------------- +if [[ ! "$PRESET" =~ ^(Custom|Bandscope|Broadcast|Basic|RescueOps|Game)$ ]]; then + echo "❌ Unknown preset: '$PRESET'" + echo "Valid presets are: Custom, Bandscope, Broadcast, Basic, RescueOps, Game" + exit 1 fi -# -------------------- CLEAN ALL --------------------- +# --------------------------------------------- +# Build the Docker image (only needed once) +# --------------------------------------------- +docker build -t "$IMAGE" . -clean() { - echo "🧽 Cleaning all" - docker rmi uvk5 - docker buildx prune -f - docker buildx history ls | awk 'NR>1 {print $1}' | xargs docker buildx history rm - make clean -} +# --------------------------------------------- +# Clean existing CMake cache to ensure toolchain reload +# --------------------------------------------- +rm -rf build -# ------------------ BUILD VARIANTS ------------------ - -custom() { - echo "🔧 Custom compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - rm -f ./compiled-firmware/* && cd /app && make -s \ - EDITION_STRING=Custom \ - TARGET=f4hwn.custom \ - && cp f4hwn.custom* compiled-firmware/" -} - -standard() { - echo "📦 Standard compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - rm -f ./compiled-firmware/* && cd /app && make -s \ - ENABLE_SPECTRUM=0 \ - ENABLE_FMRADIO=0 \ - ENABLE_AIRCOPY=0 \ - ENABLE_NOAA=0 \ - EDITION_STRING=Standard \ - TARGET=f4hwn.standard \ - && cp f4hwn.standard* compiled-firmware/" -} - -bandscope() { - echo "📺 Bandscope compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - rm -f ./compiled-firmware/* && cd /app && make -s \ - ENABLE_SPECTRUM=1 \ - ENABLE_FMRADIO=0 \ - ENABLE_VOX=0 \ - ENABLE_AIRCOPY=1 \ - ENABLE_FEAT_F4HWN_SCREENSHOT=1 \ - ENABLE_FEAT_F4HWN_GAME=0 \ - ENABLE_FEAT_F4HWN_PMR=1 \ - ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \ - ENABLE_NOAA=0 \ - ENABLE_FEAT_F4HWN_RESCUE_OPS=0 \ - EDITION_STRING=Bandscope \ - TARGET=f4hwn.bandscope \ - && cp f4hwn.bandscope* compiled-firmware/" -} - -broadcast() { - echo "📻 Broadcast compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - cd /app && make -s \ - ENABLE_SPECTRUM=0 \ - ENABLE_FMRADIO=1 \ - ENABLE_VOX=1 \ - ENABLE_AIRCOPY=1 \ - ENABLE_FEAT_F4HWN_SCREENSHOT=1 \ - ENABLE_FEAT_F4HWN_GAME=0 \ - ENABLE_FEAT_F4HWN_PMR=1 \ - ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \ - ENABLE_NOAA=0 \ - ENABLE_FEAT_F4HWN_RESCUE_OPS=0 \ - EDITION_STRING=Broadcast \ - TARGET=f4hwn.broadcast \ - && cp f4hwn.broadcast* compiled-firmware/" -} - -basic() { - echo "☘️ Basic compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - cd /app && make -s \ - ENABLE_SPECTRUM=1 \ - ENABLE_FMRADIO=1 \ - ENABLE_VOX=0 \ - ENABLE_AIRCOPY=0 \ - ENABLE_FEAT_F4HWN_GAME=0 \ - ENABLE_FEAT_F4HWN_SPECTRUM=0 \ - ENABLE_FEAT_F4HWN_PMR=1 \ - ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \ - ENABLE_NOAA=0 \ - ENABLE_AUDIO_BAR=0 \ - ENABLE_FEAT_F4HWN_RESUME_STATE=0 \ - ENABLE_FEAT_F4HWN_CHARGING_C=0 \ - ENABLE_FEAT_F4HWN_INV=1 \ - ENABLE_FEAT_F4HWN_CTR=0 \ - ENABLE_FEAT_F4HWN_NARROWER=1 \ - ENABLE_FEAT_F4HWN_RESCUE_OPS=0 \ - EDITION_STRING=Basic \ - TARGET=f4hwn.basic \ - && cp f4hwn.basic* compiled-firmware/" -} - -rescueops() { - echo "🚨 RescueOps compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - cd /app && make -s \ - ENABLE_SPECTRUM=0 \ - ENABLE_FMRADIO=0 \ - ENABLE_VOX=1 \ - ENABLE_AIRCOPY=1 \ - ENABLE_FEAT_F4HWN_SCREENSHOT=1 \ - ENABLE_FEAT_F4HWN_GAME=0 \ - ENABLE_FEAT_F4HWN_PMR=1 \ - ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \ - ENABLE_NOAA=1 \ - ENABLE_FEAT_F4HWN_RESCUE_OPS=1 \ - EDITION_STRING=RescueOps \ - TARGET=f4hwn.rescueops \ - && cp f4hwn.rescueops* compiled-firmware/" -} - -game() { - echo "🎮 Game compilation..." - docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\ - cd /app && make -s \ - ENABLE_SPECTRUM=0 \ - ENABLE_FMRADIO=1 \ - ENABLE_VOX=0 \ - ENABLE_AIRCOPY=1 \ - ENABLE_FEAT_F4HWN_GAME=1 \ - ENABLE_FEAT_F4HWN_PMR=1 \ - ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \ - ENABLE_NOAA=0 \ - ENABLE_FEAT_F4HWN_RESCUE_OPS=0 \ - EDITION_STRING=Game \ - TARGET=f4hwn.game \ - && cp f4hwn.game* compiled-firmware/" -} - -# ------------------ MENU ------------------ - -case "$1" in - clean) clean ;; - custom) custom ;; - standard) standard ;; - bandscope) bandscope ;; - broadcast) broadcast ;; - basic) basic ;; - rescueops) rescueops ;; - game) game ;; - all) - bandscope - broadcast - basic - rescueops - game - ;; - *) - echo "Usage: $0 {clean|custom|standard|bandscope|broadcast|basic|rescueops|game|all}" - exit 1 - ;; -esac +# --------------------------------------------- +# Run CMake inside the container with the selected preset +# --------------------------------------------- +docker run --rm -it -v "$PWD":/src -w /src "$IMAGE" \ + bash -c "which arm-none-eabi-gcc && arm-none-eabi-gcc --version && \ + echo '=== Building preset: ${PRESET} ===' && \ + cmake --preset ${PRESET} && \ + cmake --build --preset ${PRESET} -j"