diff --git a/.github/workflows/custom_build.yml b/.github/workflows/custom_build.yml index 595b5d7..3a0d13e 100644 --- a/.github/workflows/custom_build.yml +++ b/.github/workflows/custom_build.yml @@ -214,12 +214,8 @@ jobs: ROOT=$(cat /tmp/fw-src-root.txt) BUILD_DIR="$ROOT/.pio/build/${{ inputs.target_env }}" - # Path 1: MeshCore produces firmware.zip (Nordic DFU package) when adafruit-nrfutil - # is available during pio run. Unzip it to get bin/dat/manifest.json at build root. - if [ -f "$BUILD_DIR/firmware.zip" ]; then - echo "Found firmware.zip; extracting Nordic DFU files to build root" - unzip -j "$BUILD_DIR/firmware.zip" "*.bin" "*.dat" "manifest.json" -d "$BUILD_DIR/" || true - fi + # Path 1: unpack any DFU-shaped *.zip from the PIO build dir, normalize to firmware.bin/dat. + bash "${{ github.workspace }}/scripts/stage-nrf52-dfu-from-build.sh" "$BUILD_DIR" # Path 2: firmware/ subdirectory fallback (local builds or alternate PIO layouts). if [ -d "$BUILD_DIR/firmware" ] && ! ls "$BUILD_DIR"/*.dat >/dev/null 2>&1; then diff --git a/.github/workflows/custom_build_test.yml b/.github/workflows/custom_build_test.yml index 595b5d7..3a0d13e 100644 --- a/.github/workflows/custom_build_test.yml +++ b/.github/workflows/custom_build_test.yml @@ -214,12 +214,8 @@ jobs: ROOT=$(cat /tmp/fw-src-root.txt) BUILD_DIR="$ROOT/.pio/build/${{ inputs.target_env }}" - # Path 1: MeshCore produces firmware.zip (Nordic DFU package) when adafruit-nrfutil - # is available during pio run. Unzip it to get bin/dat/manifest.json at build root. - if [ -f "$BUILD_DIR/firmware.zip" ]; then - echo "Found firmware.zip; extracting Nordic DFU files to build root" - unzip -j "$BUILD_DIR/firmware.zip" "*.bin" "*.dat" "manifest.json" -d "$BUILD_DIR/" || true - fi + # Path 1: unpack any DFU-shaped *.zip from the PIO build dir, normalize to firmware.bin/dat. + bash "${{ github.workspace }}/scripts/stage-nrf52-dfu-from-build.sh" "$BUILD_DIR" # Path 2: firmware/ subdirectory fallback (local builds or alternate PIO layouts). if [ -d "$BUILD_DIR/firmware" ] && ! ls "$BUILD_DIR"/*.dat >/dev/null 2>&1; then diff --git a/scripts/stage-nrf52-dfu-from-build.sh b/scripts/stage-nrf52-dfu-from-build.sh new file mode 100755 index 0000000..88c5eca --- /dev/null +++ b/scripts/stage-nrf52-dfu-from-build.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# Unpack PlatformIO nRF52 DFU archives from the build directory (any *.zip name), +# then normalize application + init packet to firmware.bin / firmware.dat and align +# manifest.json when present. Typical layout is one zip per environment; multiple +# zips are processed in glob order (same member names are last-wins). +# +# Usage: stage-nrf52-dfu-from-build.sh BUILD_DIR +set -euo pipefail + +BUILD_DIR="${1:?usage: stage-nrf52-dfu-from-build.sh BUILD_DIR}" + +zip_looks_like_dfu() { + # Heuristic: DFU package includes a .dat init packet (member path ends in .dat). + unzip -l "$1" 2>/dev/null | grep -qE '[.]dat$' +} + +normalize_pair() { + local src_bin="$1" + local src_dat="$2" + + if [ -z "$src_bin" ] || [ -z "$src_dat" ]; then + return 0 + fi + if [ "$src_bin" = 'firmware.bin' ] && [ "$src_dat" = 'firmware.dat' ]; then + echo "DFU application already firmware.bin / firmware.dat" + return 0 + fi + if [ ! -f "$BUILD_DIR/$src_bin" ] || [ ! -f "$BUILD_DIR/$src_dat" ]; then + return 0 + fi + + echo "Normalizing DFU payload: $src_bin + $src_dat -> firmware.bin + firmware.dat" + cp -a "$BUILD_DIR/$src_bin" "$BUILD_DIR/firmware.bin" + cp -a "$BUILD_DIR/$src_dat" "$BUILD_DIR/firmware.dat" + + if [ -f "$BUILD_DIR/manifest.json" ] && command -v jq >/dev/null 2>&1; then + local tmp + tmp="$(mktemp)" + jq '.manifest.application.bin_file = "firmware.bin" | .manifest.application.dat_file = "firmware.dat"' \ + "$BUILD_DIR/manifest.json" >"$tmp" && mv "$tmp" "$BUILD_DIR/manifest.json" + fi +} + +shopt -s nullglob +for z in "$BUILD_DIR"/*.zip; do + [ -f "$z" ] || continue + if ! zip_looks_like_dfu "$z"; then + echo "Skipping zip (no .dat member): $z" + continue + fi + echo "Extracting DFU zip: $z" + unzip -jo "$z" '*.bin' '*.dat' 'manifest.json' -d "$BUILD_DIR/" || true +done +shopt -u nullglob + +src_bin="" +src_dat="" + +if [ -f "$BUILD_DIR/manifest.json" ] && command -v jq >/dev/null 2>&1; then + src_bin="$(jq -r '.manifest.application.bin_file // empty' "$BUILD_DIR/manifest.json" 2>/dev/null || true)" + src_dat="$(jq -r '.manifest.application.dat_file // empty' "$BUILD_DIR/manifest.json" 2>/dev/null || true)" +fi + +if [ -n "$src_bin" ] && [ -n "$src_dat" ] && [ -f "$BUILD_DIR/$src_bin" ] && [ -f "$BUILD_DIR/$src_dat" ]; then + normalize_pair "$src_bin" "$src_dat" +elif [ -f "$BUILD_DIR/firmware.bin" ] && [ -f "$BUILD_DIR/firmware.dat" ]; then + echo "DFU payload already firmware.bin / firmware.dat" +else + shopt -s nullglob + dats=("$BUILD_DIR"/*.dat) + shopt -u nullglob + if [ "${#dats[@]}" -eq 1 ]; then + dat="${dats[0]}" + base="$(basename "$dat" .dat)" + if [ -f "$BUILD_DIR/${base}.bin" ]; then + normalize_pair "${base}.bin" "$(basename "$dat")" + fi + fi +fi