send_ota.sh 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #!/usr/bin/env bash
  2. # send_ota.sh/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro).
  3. # This copyright was auto-generated on Wed Oct 19 15:33:20 UTC 2022
  4. set -e
  5. BASE_URL=http://10.5.5.9:8080
  6. USE_DOCKER=false
  7. FILE=
  8. POLLING_PERIOD_SEC=0.500
  9. help() {
  10. cat <<EOF
  11. Usage: $0 [-d] OTA_UPDATE_FILE
  12. Given a target FW .zip file, calculate its SHA1 hash, then send it over-the-air to an already connected camera.
  13. Required positional arguments:
  14. OTA_UPDATE_FILE target .zip file to send over-the-air. If using docker, must be passed as relative path
  15. from the directory of this script
  16. Optional arguments:
  17. -d Use docker for openssl and curl commands.
  18. -h Print this Help.
  19. EOF
  20. }
  21. ##############################################################################################################
  22. # Argument parsing and Setup
  23. ##############################################################################################################
  24. # Parse optional arguments
  25. while getopts "hd" option; do
  26. case ${option} in
  27. h) #For option h (help)
  28. help
  29. exit 0
  30. ;;
  31. d) #For option d (use docker)
  32. USE_DOCKER=true
  33. ;;
  34. \? | :)
  35. echo
  36. help
  37. exit 1
  38. ;;
  39. *)
  40. echo "Unexpected error occurred." >&2
  41. help
  42. exit 1
  43. ;;
  44. esac
  45. done
  46. # Jump to positional arguments and parse
  47. shift $((OPTIND - 1))
  48. if [[ $# < 1 ]]; then
  49. echo "ERROR: Missing OTA_UPDATE_FILE argument" >&2
  50. echo
  51. help
  52. exit 1
  53. fi
  54. FILE="$1"
  55. if [ ! -f "$FILE" ]; then
  56. echo "ERROR: Cannot find file: \"$FILE\""
  57. echo
  58. help
  59. exit 1
  60. fi
  61. # Configure curl and openssl commands to be native or docker
  62. IN_FILE="$FILE" # Store original file name since it might change if using Docker (to the docker image absolute path)
  63. if $USE_DOCKER; then
  64. # Check to see if we need sudo
  65. case "$(uname -sr)" in
  66. Linux*Microsoft*) ;; # WSL does not need sudo
  67. Linux*)
  68. SUDO=sudo
  69. ;;
  70. *) ;;
  71. esac
  72. export MSYS_NO_PATHCONV=1 # Handle variable expansion in Windows MSYS / Git Bash
  73. DOCKER_BASE_CMD="$SUDO docker run --rm --mount type=bind,source=$(pwd)/$IN_FILE,target=/test_image"
  74. OPENSSL="$DOCKER_BASE_CMD alpine/openssl"
  75. CURL="$DOCKER_BASE_CMD curlimages/curl"
  76. FILE="/test_image"
  77. else
  78. OPENSSL="openssl"
  79. CURL="curl"
  80. fi
  81. ##############################################################################################################
  82. # Local Functions
  83. ##############################################################################################################
  84. function log() {
  85. echo
  86. echo =====================================================================================================
  87. echo $1
  88. }
  89. # Get the camera statuses and extract status 8 (System Busy)
  90. # Return 1 (busy) or 0 (not busy)
  91. function is_system_busy {
  92. $CURL -s "$BASE_URL/gopro/camera/state" |
  93. grep -v 'settings' |
  94. grep -o '\"8\":[0-9]\+' |
  95. cut -d':' -f'2'
  96. }
  97. # Takes curl parameters as input. Then performs the curl command, validates the return, and reads the Busy
  98. # status until the camera is ready
  99. # Exits with error 1 if curl command fails
  100. function curl_validate_pend() {
  101. # Send command and check error code
  102. if ! $CURL "$@"; then
  103. echo "❌ Error!! Command failed. ❌"
  104. exit 1
  105. fi
  106. # Wait for system to be ready for next command
  107. while [ "$(is_system_busy)" = '1' ]; do
  108. sleep $POLLING_PERIOD_SEC
  109. done
  110. }
  111. ##############################################################################################################
  112. # Main script
  113. ##############################################################################################################
  114. echo "Calculating SHA1 hash of file: $IN_FILE..."
  115. sha1_hash=$($OPENSSL dgst -sha1 -hex "$FILE" | sed 's|.*= \(.*\)|\1|g')
  116. if [ $? -ne 0 ]; then
  117. echo "ERROR: Unable to get sha1 digest from file: \"$IN_FILE\""
  118. exit 1
  119. fi
  120. echo "SHA1 is $sha1_hash"
  121. log "Deleting any partially stored OTA data..."
  122. curl_validate_pend "$BASE_URL/gp/gpSoftUpdate?request=delete"
  123. log "Showing OTA update UI..."
  124. curl_validate_pend "$BASE_URL/gp/gpSoftUpdate?request=showui"
  125. log "Sending $IN_FILE to the camera..."
  126. curl_validate_pend "$BASE_URL/gp/gpSoftUpdate" \
  127. -X POST \
  128. -H "Content-Type: multipart/form-data" \
  129. -F "sha1=$sha1_hash" \
  130. -F "offset=0" \
  131. -F "file=@$FILE"
  132. log "Notifying camera that transfer is complete..."
  133. curl_validate_pend "$BASE_URL/gp/gpSoftUpdate" \
  134. -X POST \
  135. -H "Content-Type: multipart/form-data" \
  136. -F "sha1=$sha1_hash" \
  137. -F "complete=true"
  138. log "Notifying camera that it should start loading the new firmware..."
  139. curl_validate_pend "$BASE_URL/gp/gpSoftUpdate?request=start"
  140. log "👍 Image has been transferred succesfully! The camera will now apply the firmware update."
  141. exit 0