Created
September 27, 2022 02:22
-
-
Save parkerlreed/27e69579e064e33e3a676d5b92e9b066 to your computer and use it in GitHub Desktop.
This file contains 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
#!/bin/bash | |
set -euo pipefail | |
info() { printf "%s\n" "$*" >&2; } | |
die() { info "!! $*"; exit 1; } | |
# D21 Date 14-Sep-2022 | |
CURRENT_D21_FIRMWARE_TIMESTAMP=1663179557 | |
CURRENT_FIRMWARE_FILE_D21=/usr/share/jupiter_controller_fw_updater/D21_APP_REL_63221B25.bin | |
# D20 Date 14-Sep-2022 | |
CURRENT_D20_FIRMWARE_TIMESTAMP=1663179557 | |
CURRENT_FIRMWARE_FILE_D20=/usr/share/jupiter_controller_fw_updater/D20_APP_REL_63221B25.bin | |
# RA Date 14-Sep-2022 | |
CURRENT_RA_FIRMWARE_TIMESTAMP=1663179557 | |
CURRENT_FIRMWARE_FILE_RA=/usr/share/jupiter_controller_fw_updater/RA_APP_REL_63221B25.bin | |
FIRMWARE_TOOL_TYPE_1=/usr/share/jupiter_controller_fw_updater/d21bootloader16.py | |
FIRMWARE_TOOL_TYPE_2=/usr/share/jupiter_controller_fw_updater/d20bootloader.py | |
FIRMWARE_TOOL_TYPE_3=/usr/share/jupiter_controller_fw_updater/d20bootloader.py | |
# Start with this tool -- it will suffice for getting the HW ID which is required | |
FIRMWARE_TOOL=$FIRMWARE_TOOL_TYPE_1 | |
JQ=jq | |
checkmode="" | |
if [[ $# -eq 1 && ${1-} = "--check" ]]; then | |
checkmode=1 | |
elif [[ $# -ne 0 ]]; then | |
die "Usage: $0 [--check]" | |
fi | |
############################################################################################################################### | |
# STAGE 1: Determine device type | |
############################################################################################################################### | |
devs=$("$FIRMWARE_TOOL" getdevicesjson) || die "Failed to enumerate devices" | |
devjq() { $JQ "$@" <<< "$devs"; } | |
# Is the first device enumerating as a Bootloader? | |
bootloader=$(devjq '.[0].is_bootloader | select(. != null)') | |
# If multiple devices, no action if not bootloader (some dev situation w/ multiple controllers?) | |
# The Type 2 bootloader presents as 2x interfaces, so don't exit if this looks like a bootloader. | |
count=$(devjq 'length') | |
if [[ $count -gt 1 && $bootloader = "false" ]]; then | |
info "Multiple devices found, not performing check/update:" | |
devjq >&2 | |
exit 1 | |
elif [[ $count -lt 1 ]]; then | |
die "No compatible devices found" | |
fi | |
build_timestamp=$(devjq '.[0].build_timestamp | select(. != null)') | |
secondary_build_timestamp=$(devjq '.[0].secondary_build_timestamp | select(. != null)') | |
info "PTS: ${build_timestamp}, STS: ${secondary_build_timestamp}" | |
# Determine the bootloader type (1,2,3) This is indicated by major release # of USB device (vs. 1 for older, 2 hybrid, 3 for RA). | |
# This value must be presented properly by both the FW applications and bootloaders to work properly. | |
release_number=$(devjq '.[0].release_number') | |
major_release=$((release_number>>8)) # Shift to reserve only major version byte | |
bootloader_type=1 | |
if [[ $major_release -eq 2 ]]; then | |
bootloader_type=2 | |
FIRMWARE_TOOL=$FIRMWARE_TOOL_TYPE_2 | |
elif [[ $major_release -eq 3 ]]; then | |
bootloader_type=3 | |
FIRMWARE_TOOL=$FIRMWARE_TOOL_TYPE_3 | |
fi | |
############################################################################################################################### | |
# STAGE 1b: Do not do anything presently w/ Type 3 units: ENABLE this exit for Stable Hotfix | |
############################################################################################################################### | |
#if [[ $bootloader_type} -eq 3 ]]; then | |
# exit 0 | |
#fi | |
devjq >&2 | |
############################################################################################################################### | |
# STAGE 2: Now check if we need to update or not. | |
############################################################################################################################### | |
needupdate="" | |
# In OOBE builds, we only want to attempt to touch the firmware if it looks to be in the bootloader. | |
# Else, leave everything be, and let the subsequent update do the first firmware-touching. | |
if [[ -e /etc/steamos-oobe-image && $bootloader != "true" ]]; then | |
info "OOBE Build: Firmware looks valid, not attempting a flash" | |
exit 0 | |
fi | |
# If Primary MCU is in bootloader, then always update | |
if [[ $bootloader = "true" ]]; then | |
info "Device is in bootloader mode, update required" | |
needupdate=1 | |
# If either timestamp is 0 in non-Type 3 units (Only check dual MCU Types (1 and 2)) | |
elif [[ $build_timestamp -eq 0 ]] || [[ $secondary_build_timestamp -eq 0 ]] && [[ $bootloader_type -ne 3 ]]; then | |
info "Device has missing build timestamp, update required" | |
needupdate=1 | |
# Type 1: Check D21 FW timestamp | |
elif [[ $bootloader_type -eq 1 ]]; then | |
if [[ ${build_timestamp} -eq $CURRENT_D21_FIRMWARE_TIMESTAMP ]]; then | |
info "NO UPDATE: Type 1 device is running latest build $CURRENT_D21_FIRMWARE_TIMESTAMP" | |
else | |
needupdate=1 | |
info "UPDATE: Type 1 device is running build '$build_timestamp', updating to build $CURRENT_D21_FIRMWARE_TIMESTAMP" | |
fi | |
# Type 2: Check both primary and secondary timestamps. We're not going to determine Type 2 a or b sub-types | |
elif [[ $bootloader_type -eq 2 ]]; then | |
if [[ ${build_timestamp} -eq $CURRENT_D21_FIRMWARE_TIMESTAMP ]] && [[ ${secondary_build_timestamp} -eq $CURRENT_D21_FIRMWARE_TIMESTAMP || ${secondary_build_timestamp} -eq $CURRENT_D20_FIRMWARE_TIMESTAMP ]]; then | |
info "NO UPDATE: Type 1/2 Device is running latest build $CURRENT_D21_FIRMWARE_TIMESTAMP" | |
else | |
needupdate=1 | |
info "UPDATE: Type 1/2 Device is running builds ($build_timestamp | $secondary_build_timestamp), updating to build ($CURRENT_D21_FIRMWARE_TIMESTAMP | $CURRENT_D21_FIRMWARE_TIMESTAMP or $CURRENT_D20_FIRMWARE_TIMESTAMP)" | |
fi | |
# Type 3: Check the single-MCU's timesamp | |
elif [[ ${bootloader_type} -eq 3 ]]; then | |
if [[ ${build_timestamp} -eq $CURRENT_RA_FIRMWARE_TIMESTAMP ]]; then | |
info "NO UPDATE: Type 3 Device is running latest build $CURRENT_RA_FIRMWARE_TIMESTAMP" | |
else | |
needupdate=1 | |
info "UPDATE: Type 3 Device is running build '$build_timestamp', updating to build $CURRENT_RA_FIRMWARE_TIMESTAMP" | |
fi | |
else | |
info "EXIT: Unknown Device Type ${boottloader_type}" | |
exit 0 | |
fi | |
# If no update needed, then done. | |
if [[ -z $needupdate ]]; then | |
exit 0 | |
fi | |
############################################################################################################################### | |
# STAGE 3: Perform the update | |
############################################################################################################################### | |
# If Type 2 BL, we need the HW ID to determine if the secondary controller is D21 or D20 | |
# For Type 1 bootloader we have all the info we need. Only the orig. D21 / D21 system has that BL | |
# Orig D21/D21 system Type 1 BL, Primary HWID = 27 (provided for reference) | |
# Hybrid D21 / D20 system Type 2 BL, Primary HWID = 30 | |
# Homog D21 / D21 system Type 2 BL, Primary HWID = 31 | |
hybrid=false | |
if [[ $bootloader_type -eq 2 ]]; then | |
hwid=$("$FIRMWARE_TOOL" gethwid --clean) || die "Failed to get HW ID" | |
info "HWID: ${hwid}" | |
if [[ $hwid -eq 30 ]]; then | |
hybrid=true | |
elif [[ $hwid -eq 31 ]]; then | |
hybrid=false | |
else | |
die "Type 2 BL found w/ unknown Primary HWID: ${hwid}" | |
fi | |
fi | |
info "Found candidate device, build timestamp ${build_timestamp:-unknown}, BL $bootloader, BL_Type $major_release, HYB ${hybrid}" | |
# Done if check mode | |
if [[ -n $checkmode ]]; then | |
info " --check specified, not performing update" | |
if [[ $bootloader = "true" ]]; then | |
"$FIRMWARE_TOOL" reset | |
fi | |
# status code 7 to determine update-needed in check mode, vs general failure | |
exit 7 | |
fi | |
# Otherwise, perform the udpate. | |
# Add a handler to stop the updater if we die while it is running | |
# (because we can be run as a service, and get SIGTERM'd. The shell does not kill the foreground process in this case.) | |
unset update_pid | |
on_error() { | |
ret=$? | |
if [[ -n ${update_pid-} ]]; then | |
info "Interrupted, killing update process $update_pid" | |
kill $update_pid | |
wait | |
info "Update failed, attempting to reset controller..." | |
"$FIRMWARE_TOOL" reset || true | |
fi | |
info "!! Failed to apply firmware update, see above" | |
exit $ret | |
} | |
trap on_error EXIT | |
run_firmware_tool() { | |
"$FIRMWARE_TOOL" "$@" & | |
update_pid=$! | |
wait $update_pid | |
} | |
# The background+wait is so our exit handler above can kill it if the script itself is asked to stop. Because bash. | |
if [[ $bootloader_type -eq 1 ]]; then | |
info "Updating Type 1 System" | |
run_firmware_tool program "$CURRENT_FIRMWARE_FILE_D21" | |
info "Firmware updated to $CURRENT_D21_FIRMWARE_TIMESTAMP" | |
elif [[ $bootloader_type -eq 3 ]]; then | |
info "Updating Type 3 System" | |
run_firmware_tool program "$CURRENT_FIRMWARE_FILE_RA" | |
info "Firmware updated to $CURRENT_RA_FIRMWARE_TIMESTAMP" | |
elif [[ $bootloader_type -eq 2 ]]; then | |
if [[ $hybrid = "true" ]]; then | |
info "Updating Hybrid SECONDARY of Type 2 System" | |
run_firmware_tool program --secondary "$CURRENT_FIRMWARE_FILE_D20" | |
else | |
info "Updating Homogeneous SECONDARY of Type 2 System" | |
run_firmware_tool program --secondary "$CURRENT_FIRMWARE_FILE_D21" | |
fi | |
info "Updating PRIMARY of Type 2 System" | |
run_firmware_tool program --primary "$CURRENT_FIRMWARE_FILE_D21" | |
info "Firmware updated to $CURRENT_D21_FIRMWARE_TIMESTAMP" | |
else | |
info "Unknown System Type " + $bootloader_type | |
fi | |
trap - EXIT |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment