Dockerize build fixes: GCC 14 toolchain, clean build, flash helper
Bring the headless Docker build closer to the official OpenGD77 build and
add a flashing helper.
docker/Dockerfile
- Replace Ubuntu's stock gcc-arm-none-eabi (GCC 10.3.1) with the Arm GNU
Toolchain 14.2.rel1 (GCC 14). The official firmware is built with GCC 14
(gnu-tools-for-stm32 14.3); GCC 10 produced a firmware that hard-faults on
the DMR path. Guard the image build to fail if the compiler is not GCC 14.
- git config --system safe.directory '*' so the build stamps a real GitID
instead of #UNKNOWN.
docker/build.sh
- rm -rf build before compiling. obj/ lives on the host mount and was being
reused across toolchain changes, silently relinking stale .o files (an
earlier rebuild produced a byte-identical GCC-10 image because of this).
docker/firmware.mk
- Add -DNDEBUG to exactly mirror the STM32CubeIDE "MDUV380_FW" release config
(which defines both NDEBUG and DEBUG).
flash.sh
- Helper to flash via opengd77_stm32_firmware_loader.py with model, secondary
language (auto-builds the .gla files) and the DMR codec donor.
.gitignore
- Ignore generated *.gla files and the host-side languages_builder binary.
Note: the GCC 14 rebuild did NOT resolve the DMR-receive hang; that fault is in
the firmware source revision (this tree is a snapshot; the known-good build is
commit ebd7100, not present here) and is out of scope of these build changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6714da6e00
commit
0d8a293199
5 changed files with 144 additions and 5 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,3 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
build/
|
build/
|
||||||
codec_bin_section_1.bin
|
codec_bin_section_1.bin
|
||||||
|
|
||||||
|
# Generated language plugin files + host-side builder binary
|
||||||
|
*.gla
|
||||||
|
languages_builder
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,39 @@ FROM --platform=linux/amd64 ubuntu:22.04
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# IMPORTANT: use the same GCC major version as the official OpenGD77 builds.
|
||||||
|
# Ubuntu 22.04's stock gcc-arm-none-eabi is GCC 10.3.1, which miscompiles the
|
||||||
|
# timing-critical DMR / HR-C6000 path: the radio hard-faults (FreeRTOS
|
||||||
|
# configASSERT -> disable IRQs -> spin forever, needs a battery pull) the moment
|
||||||
|
# the AMBE codec runs on DMR TX. FM is unaffected. The official firmware is built
|
||||||
|
# with "gnu-tools-for-stm32 14.3.rel1" (GCC 14.3); we pin the equivalent vanilla
|
||||||
|
# Arm GNU Toolchain (GCC 14.2) so our build matches.
|
||||||
|
ARG ARM_TOOLCHAIN_VERSION=14.2.rel1
|
||||||
|
ARG ARM_TOOLCHAIN_TARBALL=arm-gnu-toolchain-${ARM_TOOLCHAIN_VERSION}-x86_64-arm-none-eabi.tar.xz
|
||||||
|
ARG ARM_TOOLCHAIN_URL=https://developer.arm.com/-/media/Files/downloads/gnu/${ARM_TOOLCHAIN_VERSION}/binrel/${ARM_TOOLCHAIN_TARBALL}
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
gcc-arm-none-eabi \
|
|
||||||
binutils-arm-none-eabi \
|
|
||||||
libnewlib-arm-none-eabi \
|
|
||||||
libstdc++-arm-none-eabi-newlib \
|
|
||||||
make \
|
make \
|
||||||
git \
|
git \
|
||||||
|
wget \
|
||||||
|
xz-utils \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Download and install the Arm GNU Toolchain (bare-metal, arm-none-eabi).
|
||||||
|
RUN wget -q -O /tmp/arm-toolchain.tar.xz "${ARM_TOOLCHAIN_URL}" \
|
||||||
|
&& mkdir -p /opt/arm-toolchain \
|
||||||
|
&& tar -xJf /tmp/arm-toolchain.tar.xz -C /opt/arm-toolchain --strip-components=1 \
|
||||||
|
&& rm /tmp/arm-toolchain.tar.xz
|
||||||
|
|
||||||
|
ENV PATH="/opt/arm-toolchain/bin:${PATH}"
|
||||||
|
|
||||||
|
# Fail the image build early if the toolchain is not the expected GCC major.
|
||||||
|
RUN arm-none-eabi-gcc --version | grep -q ' 14\.' \
|
||||||
|
&& echo "Toolchain OK: $(arm-none-eabi-gcc --version | head -1)"
|
||||||
|
|
||||||
|
# git refuses to report a version for a repo owned by another user (the mounted
|
||||||
|
# /work). Trust it so the build stamps a real GitID instead of #UNKNOWN.
|
||||||
|
RUN git config --system --add safe.directory '*'
|
||||||
|
|
||||||
WORKDIR /work
|
WORKDIR /work
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ chmod +x tools/codec_cleaner.Linux
|
||||||
( cd application/source/linkerdata && ../../../tools/codec_cleaner.Linux -C )
|
( cd application/source/linkerdata && ../../../tools/codec_cleaner.Linux -C )
|
||||||
|
|
||||||
echo "==> Building firmware"
|
echo "==> Building firmware"
|
||||||
|
# Clean build: obj/ lives on the host mount and would otherwise be reused across
|
||||||
|
# toolchain changes, silently relinking stale .o files (e.g. an old GCC build).
|
||||||
|
rm -rf build
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
make -f /work/docker/firmware.mk -j"$(nproc)"
|
make -f /work/docker/firmware.mk -j"$(nproc)"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ TARGET := OpenMDUV380
|
||||||
CPU := -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
|
CPU := -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb
|
||||||
|
|
||||||
# ---- Preprocessor defines -------------------------------------------------
|
# ---- Preprocessor defines -------------------------------------------------
|
||||||
DEFS := -DUSE_HAL_DRIVER -DSTM32F405xx -DPLATFORM_MDUV380 -DDEBUG
|
# NDEBUG + DEBUG mirrors the STM32CubeIDE "MDUV380_FW" release config exactly.
|
||||||
|
DEFS := -DUSE_HAL_DRIVER -DSTM32F405xx -DPLATFORM_MDUV380 -DNDEBUG -DDEBUG
|
||||||
|
|
||||||
# Short git hash if available, otherwise UNKNOWN (matches the .cproject rule).
|
# Short git hash if available, otherwise UNKNOWN (matches the .cproject rule).
|
||||||
GITVERSION := $(shell git -C .. rev-parse --short HEAD 2>/dev/null || echo UNKNOWN)
|
GITVERSION := $(shell git -C .. rev-parse --short HEAD 2>/dev/null || echo UNKNOWN)
|
||||||
|
|
|
||||||
106
flash.sh
Normal file
106
flash.sh
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# flash.sh — flash the OpenGD77 firmware to an MD-UV380 / DM-1701 in DFU mode,
|
||||||
|
# optionally merging a secondary language and the DMR (AMBE codec) donor firmware.
|
||||||
|
#
|
||||||
|
# The radio's language slot #1 is always English. This script injects ONE
|
||||||
|
# secondary language (slot #2) via the loader's -L option. Re-flash with a
|
||||||
|
# different language to change it.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./flash.sh # defaults: model MD-UV380, language German
|
||||||
|
# ./flash.sh -L French # flash with French as the secondary language
|
||||||
|
# ./flash.sh -m DM-1701 -L Italian
|
||||||
|
# ./flash.sh -L none # English only, no secondary language
|
||||||
|
# ./flash.sh -s /path/donor.bin # (re)register the DMR codec donor firmware
|
||||||
|
# ./flash.sh --list-languages # show available languages and exit
|
||||||
|
# ./flash.sh -l # list attached DFU devices and exit
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
FW_DIR="$REPO_DIR/MDUV380_firmware"
|
||||||
|
LOADER="$FW_DIR/tools/opengd77_stm32_firmware_loader.py"
|
||||||
|
FIRMWARE="$FW_DIR/build/OpenMDUV380.bin"
|
||||||
|
LANG_SRC="$FW_DIR/application/include/user_interface/languages/src"
|
||||||
|
|
||||||
|
# ---- defaults -------------------------------------------------------------
|
||||||
|
MODEL="MD-UV380" # or: DM-1701, MD-9600, MD-2017, MD-380
|
||||||
|
LANGUAGE="German" # a language name (see --list-languages), or "none"
|
||||||
|
DONOR="" # official V26.45 firmware; empty = use the saved one
|
||||||
|
|
||||||
|
usage() { sed -n '3,25p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit "${1:-0}"; }
|
||||||
|
lc() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; } # lowercase (bash 3.2 safe)
|
||||||
|
|
||||||
|
# ---- parse args -----------------------------------------------------------
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-m|--model) MODEL="$2"; shift 2 ;;
|
||||||
|
-L|--lang|--language) LANGUAGE="$2"; shift 2 ;;
|
||||||
|
-s|--source|--donor) DONOR="$2"; shift 2 ;;
|
||||||
|
-f|--firmware) FIRMWARE="$2"; shift 2 ;;
|
||||||
|
-l|--list) python3 "$LOADER" -l; exit $? ;;
|
||||||
|
--list-languages)
|
||||||
|
echo "Available languages (pass to -L):"
|
||||||
|
( cd "$LANG_SRC" && ls *.gla 2>/dev/null | sed 's/\.gla$//' ) \
|
||||||
|
|| ls "$LANG_SRC"/../*.h 2>/dev/null | xargs -n1 basename | sed 's/\.h$//'
|
||||||
|
echo " none (English only)"
|
||||||
|
exit 0 ;;
|
||||||
|
-h|--help) usage 0 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; usage 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ---- sanity checks --------------------------------------------------------
|
||||||
|
[[ -f "$LOADER" ]] || { echo "!! Loader not found: $LOADER" >&2; exit 1; }
|
||||||
|
[[ -f "$FIRMWARE" ]] || { echo "!! Firmware not found: $FIRMWARE (run ./build-firmware.sh first)" >&2; exit 1; }
|
||||||
|
|
||||||
|
# ---- resolve / build the language file ------------------------------------
|
||||||
|
LANG_ARGS=()
|
||||||
|
if [[ -n "$LANGUAGE" && "$(lc "$LANGUAGE")" != "none" ]]; then
|
||||||
|
# Build the .gla files once if they're missing.
|
||||||
|
if ! ls "$LANG_SRC"/*.gla >/dev/null 2>&1; then
|
||||||
|
echo "==> Building language (.gla) files..."
|
||||||
|
( cd "$LANG_SRC" && gcc -w -I../ -o languages_builder languages_builder.c && ./languages_builder >/dev/null )
|
||||||
|
fi
|
||||||
|
# Case-insensitive match of the requested name to an actual <Name>.gla file.
|
||||||
|
GLA=""
|
||||||
|
for f in "$LANG_SRC"/*.gla; do
|
||||||
|
base="$(basename "$f" .gla)"
|
||||||
|
if [[ "$(lc "$base")" == "$(lc "$LANGUAGE")" ]]; then GLA="$f"; break; fi
|
||||||
|
done
|
||||||
|
if [[ -z "$GLA" ]]; then
|
||||||
|
echo "!! Unknown language '$LANGUAGE'. Available:" >&2
|
||||||
|
( cd "$LANG_SRC" && ls *.gla | sed 's/\.gla$//' | sed 's/^/ /' ) >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "==> Secondary language: $(basename "$GLA" .gla)"
|
||||||
|
LANG_ARGS=(-L "$GLA")
|
||||||
|
else
|
||||||
|
echo "==> Secondary language: none (English only)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- donor firmware (DMR / AMBE codec) ------------------------------------
|
||||||
|
DONOR_ARGS=()
|
||||||
|
if [[ -n "$DONOR" ]]; then
|
||||||
|
[[ -f "$DONOR" ]] || { echo "!! Donor firmware not found: $DONOR" >&2; exit 1; }
|
||||||
|
echo "==> DMR donor (this run): $DONOR"
|
||||||
|
DONOR_ARGS=(-s "$DONOR")
|
||||||
|
elif grep -qi 'sourcestm32firmware *= *..*' "$HOME/.gd77firmwareloader.ini" 2>/dev/null; then
|
||||||
|
saved="$(grep -i 'sourcestm32firmware' "$HOME/.gd77firmwareloader.ini" | cut -d= -f2- | xargs)"
|
||||||
|
echo "==> DMR donor: using saved donor -> $saved"
|
||||||
|
else
|
||||||
|
echo "==> DMR donor: NONE registered — firmware will flash as FM-only."
|
||||||
|
echo " (pass -s /path/to/official_V26.45.bin once to enable DMR)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- flash ----------------------------------------------------------------
|
||||||
|
echo "==> Model: $MODEL"
|
||||||
|
echo "==> Firmware: $FIRMWARE"
|
||||||
|
echo "==> Make sure the radio is in DFU mode (power on holding PTT + SK1)."
|
||||||
|
echo
|
||||||
|
set -x
|
||||||
|
exec python3 "$LOADER" -m "$MODEL" \
|
||||||
|
"${DONOR_ARGS[@]+"${DONOR_ARGS[@]}"}" \
|
||||||
|
"${LANG_ARGS[@]+"${LANG_ARGS[@]}"}" \
|
||||||
|
-f "$FIRMWARE"
|
||||||
Loading…
Reference in a new issue