thingsSDK / flasher.js

A GUI tool for flashing the Espruino JavaScript runtime on ESP8266 based boards
154 stars 25 forks source link

Add OTA updates #38

Open chalkers opened 8 years ago

chalkers commented 8 years ago

The ESP8266 can be flashed over the air. Would be awesome to flash the chip OTA - we'll need to probably add a line to the manifest to say what binaries need to be flashed OTA.

This is the wiflash.sh code that's used to flash for reference:

#! /bin/bash
#
# Flash an esp8266 over wifi. This communicates with the esphttpd's /flash handlers
# and POSTS the correct binary depending on the partition that needs to be flashed
# next.
#

show_help() {
  cat <<EOT
Usage: ${0##*/} [-options...] hostname user1.bin user2.bin
Flash the esp8266 running esphttpd at <hostname> with either <user1.bin> or <user2.bin>
depending on its current state. Reboot the esp8266 after flashing and wait for it to come
up again.
  -v                    Be verbose
  -h                    show this help

Example: ${0##*/} -v esp8266 firmware/user1.bin firmware/user2.bin
         ${0##*/} 192.168.4.1 firmware/user1.bin firmware/user2.bin
EOT
}

if ! which curl >/dev/null; then
  echo "ERROR: Cannot find curl: it is required for this script." >&2
  exit 1
fi

start=`date +%s`

# ===== Parse arguments

verbose=

while getopts "hvx:" opt; do
  case "$opt" in
    h) show_help; exit 0 ;;
    v) verbose=1 ;;
    x) foo="$OPTARG" ;;
    '?') show_help >&2; exit 1 ;;
  esac
done

# Shift off the options and optional --.
shift "$((OPTIND-1))"

# Get the fixed arguments
if [[ $# != 3 ]]; then
    show_help >&2
    exit 1
fi
hostname=$1
user1=$2
user2=$3

re='[-A-Za-z0-9.]+'
if [[ ! "$hostname" =~ $re ]]; then
    echo "ERROR: hostname ${hostname} is not a valid hostname or ip address" >&2
    exit 1
fi

if [[ ! -r "$user1" ]]; then
    echo "ERROR: cannot read user1 firmware file ($user1)" >&2
    exit 1
fi

if [[ ! -r "$user2" ]]; then
    echo "ERROR: cannot read user2 firmware file ($user2)" >&2
    exit 1
fi

# ===== Retrieve the 'next' firmware required

fw=
while true; do
    [[ -n "$verbose" ]] && echo "Fetching http://$hostname/flash/next" >&2
    v=; [[ -n "$verbose" ]] && v=-v
    next=`curl -m 10 $v -s "http://$hostname/flash/next"`
    if [[ $? != 0 ]]; then
        echo "Error retrieving http://$hostname/flash/next" >&2
        exit 1
    fi
    case "$next" in
    user1.bin)
      echo "Flashing user1.bin"  >&2
        fw="$user1"
        break;;
    user2.bin)
      echo "Flashing user2.bin"  >&2
        fw="$user2"
        break;;
    *)
      echo "Error retrieving or parsing http://$hostname/flash/next" >&2
        exit 1
        ;;
    esac
done

#silent=-s
[[ -n "$verbose" ]] && silent=
res=`curl $silent -XPOST --data-binary "@$fw" "http://$hostname/flash/upload"`
if [[ $? != 0 || "$res" != "" ]]; then
    echo "Error flashing $fw" >&2
    echo $res >&2
    exit 1
fi

sleep 2
echo "Rebooting into new firmware" >&2
curl -m 10 -s -XPOST "http://$hostname/flash/reboot"

sleep 2
echo "Waiting for ESP8266 to come back"
while true; do
    [[ -n "$verbose" ]] && echo "Fetching http://$hostname/flash/next" >&2
    next2=`curl -m 10 $v -s "http://$hostname/flash/next"`
    [[ -n "$verbose" ]] && echo "got: $next2"
    re='user[12]\.bin'
    if [[ "$next2" =~ $re ]]; then
        if [[ "$next2" != "$next" ]]; then
            sec=$(( `date +%s` - $start ))
            echo "Success, took $sec seconds" >&2
            exit 0
        else
            echo "Flashing seems to have failed and it reverted to the old firmware?" >&2
            exit 1
        fi
    fi
    sleep 1
done
chalkers commented 8 years ago

There are two binaries if the flashing of the first binary fails.

wilberforce commented 7 years ago

The way this works is the /flash/next end point on port 88 is hit to find out which area should be flashed too.

If you have flashed using serial you will be using the user1.bin area - so the update will then post and the firmware will be saved into user2.bin. If this is successful, then the boot area is modified to point to user2.bin, and in reboot this is the new area the board in booted into. The next ota update would then write into user1.bin.

So if a firmware ota update fails, the board will still boot.

User1.bin is in the same place. User2.bin is in a difference area depending on the flash size of the chip.