#!/usr/bin/env bash PYTHON=${PYTHON:-$(which python3 python | head -n 1)} BPS_RESET=false MCU="" # Constants RESET_BAUD=1200 FIRMWARE_OFFSET=0x00 # Default littlefs* offset. OFFSET=0x300000 # Default OTA Offset OTA_OFFSET=0x260000 # Determine the correct esptool command to use if "$PYTHON" -m esptool version >/dev/null 2>&1; then ESPTOOL_CMD="$PYTHON -m esptool" elif command -v esptool >/dev/null 2>&1; then ESPTOOL_CMD="esptool" elif command -v esptool.py >/dev/null 2>&1; then ESPTOOL_CMD="esptool.py" else echo "Error: esptool not found" exit 1 fi # Check for jq if ! command -v jq >/dev/null 2>&1; then echo "Error: jq not found" >&2 echo "Install jq with your package manager." >&2 echo "e.g. 'apt install jq', 'dnf install jq', 'brew install jq', etc." >&2 exit 1 fi # esptool v5 supports commands with dashes and deprecates commands with # underscores. Prior versions only support commands with underscores if ${ESPTOOL_CMD} | grep --quiet write-flash then ESPTOOL_WRITE_FLASH=write-flash ESPTOOL_ERASE_FLASH=erase-flash ESPTOOL_READ_FLASH_STATUS=read-flash-status else ESPTOOL_WRITE_FLASH=write_flash ESPTOOL_ERASE_FLASH=erase_flash ESPTOOL_READ_FLASH_STATUS=read_flash_status fi set -e # Usage info show_help() { cat <&2 exit 1 ;; esac shift # Move to the next argument done if [[ $BPS_RESET == true ]]; then $ESPTOOL_CMD --baud $RESET_BAUD --after no_reset ${ESPTOOL_READ_FLASH_STATUS} exit 0 fi [ -z "$FILENAME" ] && [ -n "$1" ] && { FILENAME="$1" shift } if [[ $(basename "$FILENAME") != firmware-*.factory.bin ]]; then echo "Filename must be a firmware-*.factory.bin file." exit 1 fi # Extract PROGNAME from %FILENAME% for later use. PROGNAME="${FILENAME/.factory.bin/}" # Derive metadata filename from %PROGNAME%. METAFILE="${PROGNAME}.mt.json" if [[ -f "$FILENAME" && "$FILENAME" == *.factory.bin ]]; then # Display metadata if it exists if [[ -f "$METAFILE" ]]; then echo "Firmware metadata: ${METAFILE}" jq . "$METAFILE" # Extract relevant fields from metadata if [[ $(jq -r '.part' "$METAFILE") != "null" ]]; then OTA_OFFSET=$(jq -r '.part[] | select(.subtype == "ota_1") | .offset' "$METAFILE") SPIFFS_OFFSET=$(jq -r '.part[] | select(.subtype == "spiffs") | .offset' "$METAFILE") fi MCU=$(jq -r '.mcu' "$METAFILE") else echo "ERROR: No metadata file found at ${METAFILE}" exit 1 fi # Determine OTA filename based on MCU type if [ "$MCU" == "esp32s3" ]; then OTAFILE=bleota-s3.bin elif [ "$MCU" == "esp32c3" ]; then OTAFILE=bleota-c3.bin else OTAFILE=bleota.bin fi # Set SPIFFS filename with "littlefs-" prefix. SPIFFSFILE="littlefs-${PROGNAME/firmware-/}.bin" if [[ ! -f "$FILENAME" ]]; then echo "Error: file ${FILENAME} wasn't found. Terminating." exit 1 fi if [[ ! -f "$OTAFILE" ]]; then echo "Error: file ${OTAFILE} wasn't found. Terminating." exit 1 fi if [[ ! -f "$SPIFFSFILE" ]]; then echo "Error: file ${SPIFFSFILE} wasn't found. Terminating." exit 1 fi echo "Trying to flash ${FILENAME}, but first erasing and writing system information" $ESPTOOL_CMD ${ESPTOOL_ERASE_FLASH} $ESPTOOL_CMD ${ESPTOOL_WRITE_FLASH} $FIRMWARE_OFFSET "${FILENAME}" echo "Trying to flash ${OTAFILE} at offset ${OTA_OFFSET}" $ESPTOOL_CMD ${ESPTOOL_WRITE_FLASH} $OTA_OFFSET "${OTAFILE}" echo "Trying to flash ${SPIFFSFILE}, at offset ${OFFSET}" $ESPTOOL_CMD ${ESPTOOL_WRITE_FLASH} $OFFSET "${SPIFFSFILE}" else show_help echo "Invalid file: ${FILENAME}" fi exit 0