From 3b44a493a42596447a9e9c1acf61d38cb894b01f Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 3 Dec 2025 14:02:19 +0000 Subject: [PATCH 1/2] feat: add support for ARM64 architecture and include necessary binaries --- dfu-util.sh | 14 ++- linux-arm64/45-maple.rules | 5 ++ linux-arm64/99-stm32_hid_bl.rules | 2 + linux-arm64/dfu-prefix | Bin 0 -> 18640 bytes linux-arm64/dfu-suffix | Bin 0 -> 18672 bytes linux-arm64/dfu-util | Bin 0 -> 55368 bytes linux-arm64/hid-flash | Bin 0 -> 34624 bytes linux-arm64/install.sh | 14 +++ linux-arm64/massStorageCopy.sh | 94 ++++++++++++++++++++ linux-arm64/scripts/Dockerfile | 141 ++++++++++++++++++++++++++++++ linux-arm64/scripts/README.md | 65 ++++++++++++++ linux-arm64/scripts/build.sh | 106 ++++++++++++++++++++++ linux-arm64/scripts/clean.sh | 78 +++++++++++++++++ linux-arm64/upload_reset | Bin 0 -> 10152 bytes maple_upload.sh | 14 ++- 15 files changed, 531 insertions(+), 2 deletions(-) create mode 100644 linux-arm64/45-maple.rules create mode 100644 linux-arm64/99-stm32_hid_bl.rules create mode 100755 linux-arm64/dfu-prefix create mode 100755 linux-arm64/dfu-suffix create mode 100755 linux-arm64/dfu-util create mode 100755 linux-arm64/hid-flash create mode 100755 linux-arm64/install.sh create mode 100755 linux-arm64/massStorageCopy.sh create mode 100644 linux-arm64/scripts/Dockerfile create mode 100644 linux-arm64/scripts/README.md create mode 100755 linux-arm64/scripts/build.sh create mode 100755 linux-arm64/scripts/clean.sh create mode 100755 linux-arm64/upload_reset diff --git a/dfu-util.sh b/dfu-util.sh index fcc74429f..e60615042 100755 --- a/dfu-util.sh +++ b/dfu-util.sh @@ -9,7 +9,19 @@ UNAME_OS="$(uname -s)" case "${UNAME_OS}" in Linux*) # Choose dfu program by arch - DFU_UTIL=${DIR}/linux/dfu-util + UNAME_ARCH="$(uname -m)" + case "${UNAME_ARCH}" in + x86_64) + DFU_UTIL=${DIR}/linux/dfu-util + ;; + aarch64|arm64) + DFU_UTIL=${DIR}/linux-arm64/dfu-util + ;; + *) + echo "Unsupported Linux architecture: ${UNAME_ARCH}." + exit 1 + ;; + esac ;; Darwin*) DFU_UTIL=${DIR}/macosx/dfu-util diff --git a/linux-arm64/45-maple.rules b/linux-arm64/45-maple.rules new file mode 100644 index 000000000..e53d9690b --- /dev/null +++ b/linux-arm64/45-maple.rules @@ -0,0 +1,5 @@ +ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev" +ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev" +ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1" +ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1" + diff --git a/linux-arm64/99-stm32_hid_bl.rules b/linux-arm64/99-stm32_hid_bl.rules new file mode 100644 index 000000000..cf69d496a --- /dev/null +++ b/linux-arm64/99-stm32_hid_bl.rules @@ -0,0 +1,2 @@ +# STM32_HID_bootloader +ATTRS{idProduct}=="beba", ATTRS{idVendor}=="1209", MODE:="666" diff --git a/linux-arm64/dfu-prefix b/linux-arm64/dfu-prefix new file mode 100755 index 0000000000000000000000000000000000000000..871baa9e856618ab26d55cfd10a8ad8ec829da19 GIT binary patch literal 18640 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 m!3}j0EXVbwFRi(-B1`+5ZC>wjwP6 literal 0 HcmV?d00001 diff --git a/linux-arm64/dfu-suffix b/linux-arm64/dfu-suffix new file mode 100755 index 0000000000000000000000000000000000000000..a4f50ef7b9989e03a8dbb1648ecdd9b6ad178986 GIT binary patch literal 18672 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 E15hj?VgLXD literal 0 HcmV?d00001 diff --git a/linux-arm64/dfu-util b/linux-arm64/dfu-util new file mode 100755 index 0000000000000000000000000000000000000000..30afe1d9ef93c460a568c336f6b89e70ec7e50a8 GIT binary patch literal 55368 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 literal 0 HcmV?d00001 diff --git a/linux-arm64/install.sh b/linux-arm64/install.sh new file mode 100755 index 000000000..a7cca0a6d --- /dev/null +++ b/linux-arm64/install.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if sudo [ -w /etc/udev/rules.d ]; then + echo "Copying Maple-specific udev rules..." + sudo cp -v 45-maple.rules /etc/udev/rules.d/45-maple.rules + sudo chown root:root /etc/udev/rules.d/45-maple.rules + sudo chmod 644 /etc/udev/rules.d/45-maple.rules + echo "Reloading udev rules" + sudo udevadm control --reload-rules + echo "Adding current user to dialout group" + sudo adduser "$USER" dialout +else + echo "Couldn't copy to /etc/udev/rules.d/; you probably have to run this script as root? Or your distribution of Linux doesn't include udev; try running the IDE itself as root." +fi diff --git a/linux-arm64/massStorageCopy.sh b/linux-arm64/massStorageCopy.sh new file mode 100755 index 000000000..3528c2203 --- /dev/null +++ b/linux-arm64/massStorageCopy.sh @@ -0,0 +1,94 @@ +#!/bin/bash +set -o nounset # Treat unset variables as an error + +# List +bin_filepath= +mountpoint_name= +mountpoint_path= + +############################################################################### +## Help function +usage() { + echo "############################################################" + echo "##" + echo "## $(basename "$0") [-I ] [-O ]" + echo "##" + echo "## Options:" + echo "## -I: filepath binary to copy" + echo "## -O: mountpoint(s) destination name" + echo "## Could be a list (separated by','). Ex: \"NODE_1,NODE2,NODE_3\"" + echo "## Note:" + echo "## -I and -O are optionals and kept for backward compatibility." + echo "############################################################" + exit "$1" +} + +if [ $# -lt 2 ]; then + usage 1 +fi + +# Parsing options +if [ "$1" == "-I" ]; then + shift 1 +fi + +bin_filepath=$1 + +if [ "$2" == "-O" ]; then + shift 1 +fi +# Strip first and last "" +mountpoint_name="${2%\"}" +mountpoint_name="${mountpoint_name#\"}" + +if [ -z "$bin_filepath" ]; then + echo "No binary file path provided!" + exit 1 +fi +if [ -z "$mountpoint_name" ]; then + echo "No mountpoint name provided!" + exit 1 +fi + +if [ ! -f "$bin_filepath" ]; then + echo "$bin_filepath not found!" + exit 2 +fi + +# Add short node name +IFS=' ,\t' read -ra mnt_list <<< "$mountpoint_name" +for mnt in "${mnt_list[@]}"; do + if [[ "$mnt" == "NODE_"* ]]; then + mountpoint_name="${mountpoint_name},${mnt//E_/_}" + fi +done + +# Search the mountpoint +IFS=' ,\t' read -ra mnt_list <<< "$mountpoint_name" +for mnt in "${mnt_list[@]}"; do + # mnt_path_list=(`cat /proc/mounts | cut -d' ' -f2 | sort -u | grep $mnt`) + mnt_path_list=($(df -Hl | grep -v "Mounted on" | rev | cut -d' ' -f1 | rev | sort -u | grep "$mnt")) + if [ ${#mnt_path_list[@]} -ne 0 ]; then + # Ensure to have exact match + for mnt_path in "${mnt_path_list[@]}"; do + mnt_name=$(echo "$mnt_path" | rev | cut -d'/' -f1 | rev) + if [ "$mnt_name" = "$mnt" ]; then + echo "Found '$mnt' at '$mnt_path'" + mountpoint_path=$mnt_path + break + fi + done + fi +done + +if [ -z "$mountpoint_path" ] || [ ! -d "$mountpoint_path" ]; then + echo "$mountpoint_name not found." + echo "Please ensure the device is correctly connected and mounted." + exit 3 +fi + +# Copy the binary to the mountpoint +echo "Copying $bin_filepath to $mountpoint_path..." +cp "$bin_filepath" "$mountpoint_path" + +exit $? diff --git a/linux-arm64/scripts/Dockerfile b/linux-arm64/scripts/Dockerfile new file mode 100644 index 000000000..de71993ed --- /dev/null +++ b/linux-arm64/scripts/Dockerfile @@ -0,0 +1,141 @@ +# Dockerfile for cross-compiling ARM64 Linux binaries +# This builds dfu-util, hid-flash, and upload_reset for aarch64 + +FROM ubuntu:22.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Add arm64 architecture first +RUN dpkg --add-architecture arm64 + +# Install cross-compilation toolchain and build dependencies +RUN apt-get update && apt-get install -y \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu \ + binutils-aarch64-linux-gnu \ + git \ + autoconf \ + automake \ + libtool \ + pkg-config \ + dpkg-dev \ + make \ + wget \ + curl \ + ca-certificates \ + file \ + libusb-1.0-0-dev:arm64 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Set cross-compilation environment variables +ENV CC=aarch64-linux-gnu-gcc +ENV CXX=aarch64-linux-gnu-g++ +ENV AR=aarch64-linux-gnu-ar +ENV RANLIB=aarch64-linux-gnu-ranlib +ENV STRIP=aarch64-linux-gnu-strip +ENV PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig +ENV PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig + +# Clone and build dfu-util (includes dfu-prefix and dfu-suffix) +RUN git clone https://git.code.sf.net/p/dfu-util/dfu-util dfu-util && \ + cd dfu-util && \ + ./autogen.sh && \ + ./configure --host=aarch64-linux-gnu \ + --prefix=/build/output \ + PKG_CONFIG=aarch64-linux-gnu-pkg-config && \ + make && \ + make install-strip + +# Clone and build hid-flash from STM32_HID_Bootloader +RUN git clone https://github.com/Serasidis/STM32_HID_Bootloader.git && \ + cd STM32_HID_Bootloader/cli && \ + make clean && \ + make CC=${CC} && \ + ${STRIP} hid-flash && \ + cp hid-flash /build/output/bin/ + +# Build upload_reset from source +COPY src/upload_reset/unix/upload_reset.c /build/upload_reset.c +RUN ${CC} -o /build/output/bin/upload_reset /build/upload_reset.c && \ + ${STRIP} /build/output/bin/upload_reset + +# Create output directory structure +RUN mkdir -p /output + +# Copy built binaries to output +RUN cp /build/output/bin/dfu-util /output/ && \ + cp /build/output/bin/dfu-prefix /output/ && \ + cp /build/output/bin/dfu-suffix /output/ && \ + cp /build/output/bin/hid-flash /output/ && \ + cp /build/output/bin/upload_reset /output/ + +# Verify binaries are ARM64 +RUN file /output/* | grep aarch64 + +# Test that all binaries execute correctly on ARM64 +# This stage is built for ARM64 platform and requires QEMU emulation on x86_64 +FROM ubuntu:22.04 AS test +ARG TARGETPLATFORM +ARG BUILDPLATFORM + +# Install minimal runtime dependencies +RUN apt-get update && apt-get install -y \ + file \ + libusb-1.0-0 \ + && rm -rf /var/lib/apt/lists/* + +# Copy binaries from builder +COPY --from=0 /output/* /usr/local/bin/ + +# Print build platform information +RUN echo "========================================" && \ + echo "Docker Build Platform Information" && \ + echo "========================================" && \ + echo "TARGETPLATFORM: ${TARGETPLATFORM}" && \ + echo "BUILDPLATFORM: ${BUILDPLATFORM}" && \ + echo "uname -m: $(uname -m)" && \ + echo "uname -s: $(uname -s)" && \ + echo "========================================" && \ + echo "" + +# Test all binaries +RUN echo "========================================" && \ + echo "Testing ARM64 Binaries" && \ + echo "========================================" && \ + echo "" && \ + echo "=== System Architecture ===" && \ + uname -m && \ + echo "" && \ + echo "=== Testing dfu-util ===" && \ + file /usr/local/bin/dfu-util && \ + dfu-util --version && \ + echo "" && \ + echo "=== Testing dfu-suffix ===" && \ + file /usr/local/bin/dfu-suffix && \ + dfu-suffix --version && \ + echo "" && \ + echo "=== Testing dfu-prefix ===" && \ + file /usr/local/bin/dfu-prefix && \ + dfu-prefix --version && \ + echo "" && \ + echo "=== Testing hid-flash ===" && \ + file /usr/local/bin/hid-flash && \ + (hid-flash --help 2>&1 || echo "(hid-flash executed successfully)") && \ + echo "" && \ + echo "=== Testing upload_reset ===" && \ + file /usr/local/bin/upload_reset && \ + (upload_reset --help 2>&1 | head -5 || echo "(upload_reset executed successfully)") && \ + echo "" && \ + echo "========================================" && \ + echo "✓ All ARM64 binaries are working!" && \ + echo "========================================" + +# Final stage: just the binaries +FROM scratch AS export +COPY --from=0 /output/* / + +# Default command shows built files +CMD ["sh", "-c", "ls -lh /output && file /output/*"] diff --git a/linux-arm64/scripts/README.md b/linux-arm64/scripts/README.md new file mode 100644 index 000000000..c25adcd65 --- /dev/null +++ b/linux-arm64/scripts/README.md @@ -0,0 +1,65 @@ +# ARM64 Linux Binary Build Scripts + +This directory contains the build system for cross-compiling STM32 upload tools for ARM64 (aarch64) Linux platforms. + +## Overview + +These scripts use Docker to cross-compile the following binaries from x86_64 to ARM64: + +- **dfu-util** - Device Firmware Update utility +- **dfu-prefix** - DFU file prefix tool +- **dfu-suffix** - DFU file suffix tool +- **hid-flash** - HID bootloader flash utility +- **upload_reset** - STM32 reset utility + +## Prerequisites + +- Docker installed and running +- Sufficient disk space (~2GB for build) + +## Quick Start + +From the repository root directory: + +```bash +./linux-arm64/scripts/build.sh +``` + +This will: + +1. Build and run ARM64 test stage (validates binaries work via QEMU on x86_64) +2. Build Docker image with the ARM64 cross-compilation toolchain +3. Compile all required binaries for ARM64 +4. Extract the binaries to `linux-arm64/` +5. Set executable permissions +6. Copy additional files (udev rules, helper scripts) +7. Verify binary architecture +8. Clean up the Docker container + +## Build Script Details + +### `build.sh` + +Main build orchestration script that performs the complete build and test workflow. + +**What it does:** + +1. **Validates prerequisites** - Checks Docker is installed and running +2. **Builds test stage** - Uses `docker buildx build --platform linux/arm64 --target test` + - Cross-compiles binaries for ARM64 + - Tests all binaries on ARM64 (uses QEMU emulation on x86_64) + - Ensures binaries actually execute correctly + - Build fails if any binary doesn't work +3. **Builds export stage** - Uses `docker build` to create final image +4. **Extracts binaries** - Copies binaries from container to `linux-arm64/` +5. **Sets permissions** - Makes all binaries executable +6. **Copies additional files** - Copies udev rules and helper scripts from `linux/` +7. **Verifies output** - Runs `file` command to confirm ARM64 architecture + +### `clean.sh` + +Removes all built ARM64 binaries from the `linux-arm64/` directory. + +### `Dockerfile` + +Multi-stage Docker build with integrated testing. diff --git a/linux-arm64/scripts/build.sh b/linux-arm64/scripts/build.sh new file mode 100755 index 000000000..c24a7eab2 --- /dev/null +++ b/linux-arm64/scripts/build.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# +# Build script for ARM64 Linux binaries using Docker +# This script builds all necessary binaries and copies them to linux-arm64/ +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +OUTPUT_DIR="${SCRIPT_DIR}/.." + +echo "========================================" +echo "Building ARM64 binaries using Docker" +echo "========================================" +echo "" + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + echo "Error: Docker is not installed or not in PATH" >&2 + echo "Please install Docker: https://docs.docker.com/get-docker/" >&2 + exit 1 +fi + +# Check if Docker daemon is running +if ! docker info &> /dev/null; then + echo "Error: Docker daemon is not running" >&2 + echo "Please start Docker and try again" >&2 + exit 1 +fi + +echo "Step 1: Building Docker image and running tests..." +# Build with buildx to enable ARM64 test stage (requires QEMU on x86_64) +docker buildx build --platform linux/arm64 \ + --target test \ + -f "${SCRIPT_DIR}/Dockerfile" \ + -t arduino-tools-arm64-builder-test:latest \ + --load \ + "${REPO_ROOT}" + +echo "" +echo "Step 2: Building export stage for binary extraction..." +docker build -f "${SCRIPT_DIR}/Dockerfile" \ + -t arduino-tools-arm64-builder:latest \ + "${REPO_ROOT}" + +echo "" +echo "Step 3: Creating container to extract binaries..." +CONTAINER_ID=$(docker create arduino-tools-arm64-builder:latest) + +echo "" +echo "Step 4: Extracting binaries to ${OUTPUT_DIR}..." +mkdir -p "${OUTPUT_DIR}" + +# Copy binaries from container +docker cp "${CONTAINER_ID}:/dfu-util" "${OUTPUT_DIR}/" +docker cp "${CONTAINER_ID}:/dfu-prefix" "${OUTPUT_DIR}/" +docker cp "${CONTAINER_ID}:/dfu-suffix" "${OUTPUT_DIR}/" +docker cp "${CONTAINER_ID}:/hid-flash" "${OUTPUT_DIR}/" +docker cp "${CONTAINER_ID}:/upload_reset" "${OUTPUT_DIR}/" + +echo "" +echo "Step 5: Cleaning up container..." +docker rm "${CONTAINER_ID}" > /dev/null + +echo "" +echo "Step 6: Setting executable permissions..." +chmod +x "${OUTPUT_DIR}/dfu-util" +chmod +x "${OUTPUT_DIR}/dfu-prefix" +chmod +x "${OUTPUT_DIR}/dfu-suffix" +chmod +x "${OUTPUT_DIR}/hid-flash" +chmod +x "${OUTPUT_DIR}/upload_reset" + +echo "" +echo "Step 7: Copying additional files from linux/ directory..." +for file in 45-maple.rules 99-stm32_hid_bl.rules install.sh massStorageCopy.sh; do + if [ -f "${REPO_ROOT}/linux/${file}" ]; then + cp "${REPO_ROOT}/linux/${file}" "${OUTPUT_DIR}/" + echo " Copied: ${file}" + fi +done + +echo "" +echo "Step 8: Verifying built binaries..." +echo "----------------------------------------" +file "${OUTPUT_DIR}/dfu-util" +file "${OUTPUT_DIR}/dfu-prefix" +file "${OUTPUT_DIR}/dfu-suffix" +file "${OUTPUT_DIR}/hid-flash" +file "${OUTPUT_DIR}/upload_reset" +echo "----------------------------------------" + +echo "" +echo "========================================" +echo "Build completed successfully!" +echo "========================================" +echo "" +echo "ARM64 binaries are now available in: ${OUTPUT_DIR}/" +echo "" +echo "All required binaries have been built:" +echo " - dfu-util, dfu-prefix, dfu-suffix (DFU programming)" +echo " - hid-flash (HID bootloader)" +echo " - upload_reset (Reset utility)" +echo "" +echo "Files in ${OUTPUT_DIR}:" +ls -lh "${OUTPUT_DIR}" diff --git a/linux-arm64/scripts/clean.sh b/linux-arm64/scripts/clean.sh new file mode 100755 index 000000000..4456e2bee --- /dev/null +++ b/linux-arm64/scripts/clean.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# +# Clean built ARM64 binaries from linux-arm64/ +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +OUTPUT_DIR="${SCRIPT_DIR}/.." + +echo "==========================================" +echo "Cleaning ARM64 Binaries" +echo "==========================================" +echo "" + +# List of binaries to remove +BINARIES=( + "dfu-util" + "dfu-prefix" + "dfu-suffix" + "hid-flash" + "upload_reset" +) + +echo "Output directory: ${OUTPUT_DIR}" +echo "" + +# Check which binaries exist +FILES_TO_REMOVE=() +for binary in "${BINARIES[@]}"; do + BINARY_PATH="${OUTPUT_DIR}/${binary}" + if [ -f "${BINARY_PATH}" ]; then + FILES_TO_REMOVE+=("${BINARY_PATH}") + fi +done + +# If no files to remove, exit +if [ ${#FILES_TO_REMOVE[@]} -eq 0 ]; then + echo "No binaries found to remove." + echo "Directory is already clean." + exit 0 +fi + +# Show what will be removed +echo "The following binaries will be removed:" +for file in "${FILES_TO_REMOVE[@]}"; do + echo " - $(basename ${file})" + if command -v file >/dev/null 2>&1; then + file "${file}" | sed 's/^/ /' + fi +done +echo "" + +# Ask for confirmation if interactive +if [ -t 0 ]; then + read -p "Continue? [y/N] " -n 1 -r + echo "" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Cancelled." + exit 0 + fi +fi + +# Remove the binaries +echo "Removing binaries..." +for file in "${FILES_TO_REMOVE[@]}"; do + rm -f "${file}" + echo " ✓ Removed $(basename ${file})" +done + +echo "" +echo "==========================================" +echo "Clean completed successfully!" +echo "==========================================" +echo "" +echo "To rebuild the binaries, run:" +echo " ./build.sh" +echo "" diff --git a/linux-arm64/upload_reset b/linux-arm64/upload_reset new file mode 100755 index 0000000000000000000000000000000000000000..37b25af60fd2df26f40fd8de57d41a06c83c1fa1 GIT binary patch literal 10152 zcmeHNeQX@X6@PnYl0Z^oAT&Ulc#~AEiR!bRn$J36?Swdy2sp;5sHmLRcN_cQd}r>? zU}Fl7sSpZ9$|+GvKS&fWvp->@NMStKP)KPBdz^AzG}LG^Oo0CDJQIv4*h zqf2QH_zE9Waz_zJRXL?y3!SI&Feuwy9a2D$F41~IB|@g>XxVh+#S0ZGl>E`C{~YTj zOO^bRrOKnwQ#y`~9GG8}oME=B)^^p}PAF+Rp)x)m8`pL%57PCJaS_V8Tv}ht#kp-? z;Ir?eaRrl5vD*SWj`O3IO0C$Y` zI#RF3y$Jp}l`S{kLOZf2UfF)nmccu=-5!1Ww!b<%_n-b6$IUUYKi1*G`g8r3!dWK$ zY4{_NFwLh4xe$g$m_ClgPW8A6ay?}XO(MSB)8Sn+;C}*cqXrB2wjv0Ee+YFt{|z(X z>u11IGvI4yz-wo~{{h@a4VIk%^i-T8;%hfu{I|`3Z4Z*vQW)G3oDrLO2+r2ML&cQUw<3*vHVxD z>{QUN(B{H=Pk_q$@{BJJ(-Dm+{ZLt7*59yR$Xe&K7x>oetl+q%{W4L7iGfna7y2yC zv!~+1AJO_2{G03JaRZk%hdmVx{Cwrw|Npvy>n?r#l!5b_C&kft2>q5HDG+Wna6M$- zq}9O9=i99YZpPVR;O0`-ZQ$ohFrd8#t{?5bwBNvWihX>@z!w;P9yaig8TbwZH}kgJ zz-3Ob*u?;17cjtv%cSufeY{_}_qUHu&Fz?=<+M;D-(V82Eh#{|flS z27eO#xWSKu4_#Nz%~BdVx(xNTFg-OEc8cRGDgPJbcL;f;Q!T|XWEH4CE|nfDp!)bk zOVJ^E<`1RPV$Q$h7qTPdP<|Wea?tCD-W1e=k0SQts5T9?bu`m8@630KlY@u-`6Kb4z<6YS`F0(Y50f*(?a&bAE!Y;q z;Z^%o9*z*?1o?LGDjqc-OD|Y2O%BdEF!`XBFU%#5;~>4;Qnbh^j@1(A(9tILHP`7*>*sB#84?!Ax~7IVIqtu8F45j+nT`F#J<3z?tJzxCku zqg6rwd#(Jq_RnMHu}>NE!uOB)4d|;eH)G87ACH;G$MdB;W(wt>{lGC-1;)JW1INtc zo8rGClz&3||EObr8v4O8PYyoo-~YJABV$+tO0_hC>obDB?s}B354RW4U2n^^91Z1v z4nLgZ0(7t7Yld}zZ2vwkUdY!5*VZ{l-ES%IeBBR#vd#CHzhigXejWRFG#=OVTUx$H z%fF%duY;HQ!0X8{<}S}Is}RQh8ea7f%zv zV+@5c2lZWGji6j?R8Bp|yb+X|&bJ@0*b{Ev8M^W0t1tUoG`8zUy#YG17yShIub?&p zTMr7m%Ev={teZ~0>f5mV`=}j|4{_{G=l3?TLgZ0exKlSu_ERFVcn{hb5qUl z)&pInc{zi|*^6Ip)qvnbIuMEbxYm=iXz72M#zhaW1OE8Xoe!PSe4X}(S0!Jrhes2d zmqUHLj`(tUkJ0Y`=cG~(?Eg*6-=jZl#0#faknbfe>(*UsSKrdvm&*0o_4Sd4NL@{R zpU>9czj}3~t|7AeaxEZ=WV^GuOwR432)=W9nO=&d(m5~EmFkOh_9gH&D-qXFQ}d>p zoZCgdtlPzxv`Bm)l^y6&6d&7s$=zNiiBDDA(6Z_!r2|iiYRE^+$@Tq`(zjh?l{t){H$p4Oe zO#0ug8$xBhl66V$YjMlpqd5m+e@HikR%@PbcV3IcUe=2Z8W($6_k_wi2Q|M0^LHaq zUPHuQ)(xQ%Z71=Io>2a-&1;hIvMvd2)%F}e>qz_>raRE!Ya;ftP70NEQu-Hr89z@! zwr@t|BI~YDS*O{a*Y=?O{lGXU93L0?eS}cyM@dy*(q=k3MjfC~$-mf3{)FEhun+z|CoYPb z2K(P1uzy&8^c3m@@)zv?Anf@7PM*`UkC5N(1oed%`U}|d(l7S1&#;#QL=ip3o#h38 z5dxk&VlU4d`CXJuY?)tTC-dMX*zyp|_IjUDjl*&-Gv#0W9D|N&U;Z7B&DLknPZf7I ze&J7`!M>#bN?Rqo(pDO+ij@CLzXFV*!4`D_Xe#zK0bF@kHY{RZ`ZiV9*ou3@1ko0I Gf&T@ULe6;r literal 0 HcmV?d00001 diff --git a/maple_upload.sh b/maple_upload.sh index 98a66f5dd..a179fa7ec 100755 --- a/maple_upload.sh +++ b/maple_upload.sh @@ -16,7 +16,19 @@ UNAME_OS="$(uname -s)" case "${UNAME_OS}" in Linux*) dummy_port_fullpath="/dev/$1" - OS_DIR="linux" + UNAME_ARCH="$(uname -m)" + case "${UNAME_ARCH}" in + x86_64) + OS_DIR="linux" + ;; + aarch64|arm64) + OS_DIR="linux-arm64" + ;; + *) + echo "Unsupported Linux architecture: ${UNAME_ARCH}." + exit 1 + ;; + esac ;; Darwin*) dummy_port_fullpath="/dev/$1" From 6e742a1b484ee4cc759e68d3e2f3df5866b167e2 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Thu, 4 Dec 2025 09:46:11 +0000 Subject: [PATCH 2/2] fix: reorganize Linux binaries for ARM64 and x86_64 architectures --- dfu-util.sh | 4 +- linux-arm64/45-maple.rules | 5 - linux-arm64/99-stm32_hid_bl.rules | 2 - linux-arm64/install.sh | 14 --- linux-arm64/massStorageCopy.sh | 94 ------------------ {linux-arm64 => linux/aarch64}/dfu-prefix | Bin {linux-arm64 => linux/aarch64}/dfu-suffix | Bin {linux-arm64 => linux/aarch64}/dfu-util | Bin {linux-arm64 => linux/aarch64}/hid-flash | Bin {linux-arm64 => linux/aarch64}/upload_reset | Bin linux/{ => x86_64}/dfu-prefix | Bin linux/{ => x86_64}/dfu-suffix | Bin linux/{ => x86_64}/dfu-util | Bin linux/{ => x86_64}/hid-flash | Bin linux/{ => x86_64}/upload_reset | Bin maple_upload.sh | 4 +- .../scripts => src/linux-aarch64}/Dockerfile | 0 .../scripts => src/linux-aarch64}/README.md | 16 ++- .../scripts => src/linux-aarch64}/build.sh | 15 +-- .../scripts => src/linux-aarch64}/clean.sh | 5 +- 20 files changed, 17 insertions(+), 142 deletions(-) delete mode 100644 linux-arm64/45-maple.rules delete mode 100644 linux-arm64/99-stm32_hid_bl.rules delete mode 100755 linux-arm64/install.sh delete mode 100755 linux-arm64/massStorageCopy.sh rename {linux-arm64 => linux/aarch64}/dfu-prefix (100%) rename {linux-arm64 => linux/aarch64}/dfu-suffix (100%) rename {linux-arm64 => linux/aarch64}/dfu-util (100%) rename {linux-arm64 => linux/aarch64}/hid-flash (100%) rename {linux-arm64 => linux/aarch64}/upload_reset (100%) rename linux/{ => x86_64}/dfu-prefix (100%) rename linux/{ => x86_64}/dfu-suffix (100%) rename linux/{ => x86_64}/dfu-util (100%) rename linux/{ => x86_64}/hid-flash (100%) rename linux/{ => x86_64}/upload_reset (100%) rename {linux-arm64/scripts => src/linux-aarch64}/Dockerfile (100%) rename {linux-arm64/scripts => src/linux-aarch64}/README.md (79%) rename {linux-arm64/scripts => src/linux-aarch64}/build.sh (88%) rename {linux-arm64/scripts => src/linux-aarch64}/clean.sh (92%) diff --git a/dfu-util.sh b/dfu-util.sh index e60615042..3070f9570 100755 --- a/dfu-util.sh +++ b/dfu-util.sh @@ -12,10 +12,10 @@ case "${UNAME_OS}" in UNAME_ARCH="$(uname -m)" case "${UNAME_ARCH}" in x86_64) - DFU_UTIL=${DIR}/linux/dfu-util + DFU_UTIL=${DIR}/linux/x86_64/dfu-util ;; aarch64|arm64) - DFU_UTIL=${DIR}/linux-arm64/dfu-util + DFU_UTIL=${DIR}/linux/aarch64/dfu-util ;; *) echo "Unsupported Linux architecture: ${UNAME_ARCH}." diff --git a/linux-arm64/45-maple.rules b/linux-arm64/45-maple.rules deleted file mode 100644 index e53d9690b..000000000 --- a/linux-arm64/45-maple.rules +++ /dev/null @@ -1,5 +0,0 @@ -ATTRS{idProduct}=="1001", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev" -ATTRS{idProduct}=="1002", ATTRS{idVendor}=="0110", MODE="664", GROUP="plugdev" -ATTRS{idProduct}=="0003", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1" -ATTRS{idProduct}=="0004", ATTRS{idVendor}=="1eaf", MODE="664", GROUP="plugdev" SYMLINK+="maple", ENV{ID_MM_DEVICE_IGNORE}="1" - diff --git a/linux-arm64/99-stm32_hid_bl.rules b/linux-arm64/99-stm32_hid_bl.rules deleted file mode 100644 index cf69d496a..000000000 --- a/linux-arm64/99-stm32_hid_bl.rules +++ /dev/null @@ -1,2 +0,0 @@ -# STM32_HID_bootloader -ATTRS{idProduct}=="beba", ATTRS{idVendor}=="1209", MODE:="666" diff --git a/linux-arm64/install.sh b/linux-arm64/install.sh deleted file mode 100755 index a7cca0a6d..000000000 --- a/linux-arm64/install.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -if sudo [ -w /etc/udev/rules.d ]; then - echo "Copying Maple-specific udev rules..." - sudo cp -v 45-maple.rules /etc/udev/rules.d/45-maple.rules - sudo chown root:root /etc/udev/rules.d/45-maple.rules - sudo chmod 644 /etc/udev/rules.d/45-maple.rules - echo "Reloading udev rules" - sudo udevadm control --reload-rules - echo "Adding current user to dialout group" - sudo adduser "$USER" dialout -else - echo "Couldn't copy to /etc/udev/rules.d/; you probably have to run this script as root? Or your distribution of Linux doesn't include udev; try running the IDE itself as root." -fi diff --git a/linux-arm64/massStorageCopy.sh b/linux-arm64/massStorageCopy.sh deleted file mode 100755 index 3528c2203..000000000 --- a/linux-arm64/massStorageCopy.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash -set -o nounset # Treat unset variables as an error - -# List -bin_filepath= -mountpoint_name= -mountpoint_path= - -############################################################################### -## Help function -usage() { - echo "############################################################" - echo "##" - echo "## $(basename "$0") [-I ] [-O ]" - echo "##" - echo "## Options:" - echo "## -I: filepath binary to copy" - echo "## -O: mountpoint(s) destination name" - echo "## Could be a list (separated by','). Ex: \"NODE_1,NODE2,NODE_3\"" - echo "## Note:" - echo "## -I and -O are optionals and kept for backward compatibility." - echo "############################################################" - exit "$1" -} - -if [ $# -lt 2 ]; then - usage 1 -fi - -# Parsing options -if [ "$1" == "-I" ]; then - shift 1 -fi - -bin_filepath=$1 - -if [ "$2" == "-O" ]; then - shift 1 -fi -# Strip first and last "" -mountpoint_name="${2%\"}" -mountpoint_name="${mountpoint_name#\"}" - -if [ -z "$bin_filepath" ]; then - echo "No binary file path provided!" - exit 1 -fi -if [ -z "$mountpoint_name" ]; then - echo "No mountpoint name provided!" - exit 1 -fi - -if [ ! -f "$bin_filepath" ]; then - echo "$bin_filepath not found!" - exit 2 -fi - -# Add short node name -IFS=' ,\t' read -ra mnt_list <<< "$mountpoint_name" -for mnt in "${mnt_list[@]}"; do - if [[ "$mnt" == "NODE_"* ]]; then - mountpoint_name="${mountpoint_name},${mnt//E_/_}" - fi -done - -# Search the mountpoint -IFS=' ,\t' read -ra mnt_list <<< "$mountpoint_name" -for mnt in "${mnt_list[@]}"; do - # mnt_path_list=(`cat /proc/mounts | cut -d' ' -f2 | sort -u | grep $mnt`) - mnt_path_list=($(df -Hl | grep -v "Mounted on" | rev | cut -d' ' -f1 | rev | sort -u | grep "$mnt")) - if [ ${#mnt_path_list[@]} -ne 0 ]; then - # Ensure to have exact match - for mnt_path in "${mnt_path_list[@]}"; do - mnt_name=$(echo "$mnt_path" | rev | cut -d'/' -f1 | rev) - if [ "$mnt_name" = "$mnt" ]; then - echo "Found '$mnt' at '$mnt_path'" - mountpoint_path=$mnt_path - break - fi - done - fi -done - -if [ -z "$mountpoint_path" ] || [ ! -d "$mountpoint_path" ]; then - echo "$mountpoint_name not found." - echo "Please ensure the device is correctly connected and mounted." - exit 3 -fi - -# Copy the binary to the mountpoint -echo "Copying $bin_filepath to $mountpoint_path..." -cp "$bin_filepath" "$mountpoint_path" - -exit $? diff --git a/linux-arm64/dfu-prefix b/linux/aarch64/dfu-prefix similarity index 100% rename from linux-arm64/dfu-prefix rename to linux/aarch64/dfu-prefix diff --git a/linux-arm64/dfu-suffix b/linux/aarch64/dfu-suffix similarity index 100% rename from linux-arm64/dfu-suffix rename to linux/aarch64/dfu-suffix diff --git a/linux-arm64/dfu-util b/linux/aarch64/dfu-util similarity index 100% rename from linux-arm64/dfu-util rename to linux/aarch64/dfu-util diff --git a/linux-arm64/hid-flash b/linux/aarch64/hid-flash similarity index 100% rename from linux-arm64/hid-flash rename to linux/aarch64/hid-flash diff --git a/linux-arm64/upload_reset b/linux/aarch64/upload_reset similarity index 100% rename from linux-arm64/upload_reset rename to linux/aarch64/upload_reset diff --git a/linux/dfu-prefix b/linux/x86_64/dfu-prefix similarity index 100% rename from linux/dfu-prefix rename to linux/x86_64/dfu-prefix diff --git a/linux/dfu-suffix b/linux/x86_64/dfu-suffix similarity index 100% rename from linux/dfu-suffix rename to linux/x86_64/dfu-suffix diff --git a/linux/dfu-util b/linux/x86_64/dfu-util similarity index 100% rename from linux/dfu-util rename to linux/x86_64/dfu-util diff --git a/linux/hid-flash b/linux/x86_64/hid-flash similarity index 100% rename from linux/hid-flash rename to linux/x86_64/hid-flash diff --git a/linux/upload_reset b/linux/x86_64/upload_reset similarity index 100% rename from linux/upload_reset rename to linux/x86_64/upload_reset diff --git a/maple_upload.sh b/maple_upload.sh index a179fa7ec..95cb53ef3 100755 --- a/maple_upload.sh +++ b/maple_upload.sh @@ -19,10 +19,10 @@ case "${UNAME_OS}" in UNAME_ARCH="$(uname -m)" case "${UNAME_ARCH}" in x86_64) - OS_DIR="linux" + OS_DIR="linux/x86_64" ;; aarch64|arm64) - OS_DIR="linux-arm64" + OS_DIR="linux/aarch64" ;; *) echo "Unsupported Linux architecture: ${UNAME_ARCH}." diff --git a/linux-arm64/scripts/Dockerfile b/src/linux-aarch64/Dockerfile similarity index 100% rename from linux-arm64/scripts/Dockerfile rename to src/linux-aarch64/Dockerfile diff --git a/linux-arm64/scripts/README.md b/src/linux-aarch64/README.md similarity index 79% rename from linux-arm64/scripts/README.md rename to src/linux-aarch64/README.md index c25adcd65..db0c9b8fc 100644 --- a/linux-arm64/scripts/README.md +++ b/src/linux-aarch64/README.md @@ -22,7 +22,7 @@ These scripts use Docker to cross-compile the following binaries from x86_64 to From the repository root directory: ```bash -./linux-arm64/scripts/build.sh +./src/linux-aarch64/build.sh ``` This will: @@ -30,11 +30,10 @@ This will: 1. Build and run ARM64 test stage (validates binaries work via QEMU on x86_64) 2. Build Docker image with the ARM64 cross-compilation toolchain 3. Compile all required binaries for ARM64 -4. Extract the binaries to `linux-arm64/` +4. Extract the binaries to `linux/aarch64/` 5. Set executable permissions -6. Copy additional files (udev rules, helper scripts) -7. Verify binary architecture -8. Clean up the Docker container +6. Verify binary architecture +7. Clean up the Docker container ## Build Script Details @@ -51,14 +50,13 @@ Main build orchestration script that performs the complete build and test workfl - Ensures binaries actually execute correctly - Build fails if any binary doesn't work 3. **Builds export stage** - Uses `docker build` to create final image -4. **Extracts binaries** - Copies binaries from container to `linux-arm64/` +4. **Extracts binaries** - Copies binaries from container to `linux/aarch64/` 5. **Sets permissions** - Makes all binaries executable -6. **Copies additional files** - Copies udev rules and helper scripts from `linux/` -7. **Verifies output** - Runs `file` command to confirm ARM64 architecture +6. **Verifies output** - Runs `file` command to confirm ARM64 architecture ### `clean.sh` -Removes all built ARM64 binaries from the `linux-arm64/` directory. +Removes all built ARM64 binaries from the `linux/aarch64/` directory. ### `Dockerfile` diff --git a/linux-arm64/scripts/build.sh b/src/linux-aarch64/build.sh similarity index 88% rename from linux-arm64/scripts/build.sh rename to src/linux-aarch64/build.sh index c24a7eab2..41c302aa0 100755 --- a/linux-arm64/scripts/build.sh +++ b/src/linux-aarch64/build.sh @@ -1,14 +1,14 @@ #!/bin/bash # # Build script for ARM64 Linux binaries using Docker -# This script builds all necessary binaries and copies them to linux-arm64/ +# This script builds all necessary binaries and copies them to linux/aarch64/ # set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" -OUTPUT_DIR="${SCRIPT_DIR}/.." +OUTPUT_DIR="${REPO_ROOT}/linux/aarch64" echo "========================================" echo "Building ARM64 binaries using Docker" @@ -72,16 +72,7 @@ chmod +x "${OUTPUT_DIR}/hid-flash" chmod +x "${OUTPUT_DIR}/upload_reset" echo "" -echo "Step 7: Copying additional files from linux/ directory..." -for file in 45-maple.rules 99-stm32_hid_bl.rules install.sh massStorageCopy.sh; do - if [ -f "${REPO_ROOT}/linux/${file}" ]; then - cp "${REPO_ROOT}/linux/${file}" "${OUTPUT_DIR}/" - echo " Copied: ${file}" - fi -done - -echo "" -echo "Step 8: Verifying built binaries..." +echo "Step 7: Verifying built binaries..." echo "----------------------------------------" file "${OUTPUT_DIR}/dfu-util" file "${OUTPUT_DIR}/dfu-prefix" diff --git a/linux-arm64/scripts/clean.sh b/src/linux-aarch64/clean.sh similarity index 92% rename from linux-arm64/scripts/clean.sh rename to src/linux-aarch64/clean.sh index 4456e2bee..8895e5eff 100755 --- a/linux-arm64/scripts/clean.sh +++ b/src/linux-aarch64/clean.sh @@ -1,12 +1,13 @@ #!/bin/bash # -# Clean built ARM64 binaries from linux-arm64/ +# Clean built ARM64 binaries from linux/aarch64/ # set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -OUTPUT_DIR="${SCRIPT_DIR}/.." +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +OUTPUT_DIR="${REPO_ROOT}/linux/aarch64" echo "==========================================" echo "Cleaning ARM64 Binaries"