Created
April 2, 2026 20:50
-
-
Save jwiegley/16305d8b247841eae4d0cb6028bfdada to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # update-bitfiles — Update FPGA bitfiles on all BittWare cards via pho | |
| # | |
| # Usage: | |
| # update-bitfiles <path-to-rbf-file> | |
| # update-bitfiles /ice/svt/releases/archer/archer_agm_01.05.06.00_02.24.26/archer_agm_01.05.06.00.rbf | |
| # update-bitfiles -c 5 <path-to-rbf-file> # update only card 5 | |
| # update-bitfiles --list-releases # browse available releases on ICE | |
| # update-bitfiles --status # show current card/image status | |
| # | |
| set -euo pipefail | |
| readonly IMAGES_DIR="/opt/positron/images" | |
| readonly ICE_RELEASES="/ice/svt/releases/archer" | |
| readonly SCRIPT_NAME="${0##*/}" | |
| CARD_FLAG=() # empty = all cards; set by -c | |
| # ── Helpers ────────────────────────────────────────────────────────────────── | |
| die() { printf '%s: error: %s\n' "$SCRIPT_NAME" "$*" >&2; exit 1; } | |
| info() { printf '==> %s\n' "$*"; } | |
| warn() { printf '*** %s\n' "$*" >&2; } | |
| usage() { | |
| cat <<'USAGE' | |
| Usage: update-bitfiles [-c <card>] <path-to-rbf-file> | |
| update-bitfiles --status Show current card/image state | |
| update-bitfiles --list-releases List .rbf files available on ICE | |
| Options: | |
| -c <card> Target a specific card by index (default: all cards) | |
| Examples: | |
| update-bitfiles /ice/svt/releases/archer/archer_agm_01.05.06.00_02.24.26/archer_agm_01.05.06.00.rbf | |
| update-bitfiles -c 5 /opt/positron/images/archer_agm_01.05.06.00.rbf | |
| USAGE | |
| } | |
| command_exists() { command -v "$1" &>/dev/null; } | |
| check_prereqs() { | |
| command_exists pho || die "pho is not installed (install platformd to get it)" | |
| } | |
| # ── Status ─────────────────────────────────────────────────────────────────── | |
| show_status() { | |
| info "Detected cards:" | |
| pho bw cards list | |
| echo | |
| info "Current active images:" | |
| pho bw images current | |
| echo | |
| info "Images in flash table:" | |
| pho bw images list | |
| } | |
| # ── List available releases on ICE ─────────────────────────────────────────── | |
| list_releases() { | |
| if [[ ! -d "$ICE_RELEASES" ]]; then | |
| die "ICE releases directory not found: $ICE_RELEASES (is ICE mounted?)" | |
| fi | |
| info "Available releases in $ICE_RELEASES:" | |
| echo | |
| for dir in "$ICE_RELEASES"/*/; do | |
| [[ -d "$dir" ]] || continue | |
| local rbf | |
| rbf=$(find "$dir" -maxdepth 1 -name '*.rbf' 2>/dev/null | head -n1) | |
| if [[ -n "$rbf" ]]; then | |
| printf ' %s\n' "$rbf" | |
| fi | |
| done | |
| } | |
| # ── Main update flow ───────────────────────────────────────────────────────── | |
| do_update() { | |
| local rbf_source="$1" | |
| # Validate input file | |
| [[ -f "$rbf_source" ]] || die "File not found: $rbf_source" | |
| [[ "$rbf_source" == *.rbf ]] || die "Expected an .rbf file, got: $rbf_source" | |
| local rbf_name | |
| rbf_name="$(basename "$rbf_source")" | |
| local card_label="all cards" | |
| if [[ ${#CARD_FLAG[@]} -gt 0 ]]; then | |
| card_label="card ${CARD_FLAG[1]}" | |
| fi | |
| info "Bitfile update plan:" | |
| echo " Source: $rbf_source" | |
| echo " Image: $rbf_name" | |
| echo " Target: $card_label" | |
| echo " Staging: $IMAGES_DIR/$rbf_name" | |
| echo | |
| # Show current state | |
| info "Current card status:" | |
| pho bw "${CARD_FLAG[@]}" cards list | |
| echo | |
| info "Current active images:" | |
| pho bw "${CARD_FLAG[@]}" images current | |
| echo | |
| # Confirm | |
| [[ -t 0 ]] || die "stdin is not a terminal; cannot prompt for confirmation (use a tty)" | |
| printf 'Proceed with update? [y/N] ' | |
| read -r answer | |
| [[ "$answer" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 0; } | |
| echo | |
| # Step 1: Copy .rbf to local images directory | |
| info "Step 1/4: Copying bitfile to $IMAGES_DIR ..." | |
| if [[ ! -d "$IMAGES_DIR" ]]; then | |
| sudo mkdir -p "$IMAGES_DIR" || die "Failed to create $IMAGES_DIR (need sudo?)" | |
| fi | |
| sudo cp -v "$rbf_source" "$IMAGES_DIR/$rbf_name" || die "Failed to copy bitfile to $IMAGES_DIR" | |
| echo | |
| # Step 2: Upload to cards | |
| info "Step 2/4: Uploading image to $card_label (this may take a while) ..." | |
| if [[ ${#CARD_FLAG[@]} -eq 0 ]]; then | |
| warn "Be patient -- uploading to 8 cards takes significant time." | |
| fi | |
| pho bw "${CARD_FLAG[@]}" images upload --force --plain "$IMAGES_DIR/$rbf_name" | |
| echo | |
| # Step 3: Set as active image | |
| info "Step 3/4: Setting $rbf_name as active image on $card_label ..." | |
| pho bw "${CARD_FLAG[@]}" images use "$rbf_name" | |
| echo | |
| # Step 4: Set as default for post-reboot | |
| info "Step 4/4: Setting $rbf_name as default boot image on $card_label ..." | |
| pho bw "${CARD_FLAG[@]}" images default "$rbf_name" | |
| echo | |
| # Verify | |
| info "Update complete. Verifying final state:" | |
| echo | |
| pho bw "${CARD_FLAG[@]}" images current | |
| echo | |
| info "Done. The new bitfile ($rbf_name) is active and set as default." | |
| info "No reboot required -- the image is already active on the FPGA." | |
| } | |
| # ── Entry point ────────────────────────────────────────────────────────────── | |
| main() { | |
| check_prereqs | |
| if [[ $# -eq 0 ]]; then | |
| usage | |
| exit 0 | |
| fi | |
| # Parse leading -c <card> if present | |
| if [[ "$1" == "-c" ]]; then | |
| [[ $# -ge 2 ]] || die "-c requires a card number" | |
| CARD_FLAG=(-c "$2") | |
| shift 2 | |
| [[ $# -ge 1 ]] || die "missing <path-to-rbf-file> after -c" | |
| fi | |
| case "$1" in | |
| --status) show_status ;; | |
| --list-releases|--list) list_releases ;; | |
| --help|-h) usage; exit 0 ;; | |
| -*) die "Unknown option: $1" ;; | |
| *) do_update "$1" ;; | |
| esac | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment