# Revert firmware on the Beaglebone Black
#
# To use:
#   1. Run `fwup -c -f fwup-revert.conf -o revert.fw` and copy revert.fw to
#      the device. This is done automatically as part of the Nerves system
#      build process. The file is stored in `/usr/share/fwup/revert.fw`.
#   2. On the device, run `fwup -t revert revert.fw -d $NERVES_FW_DEVPATH`. If
#      it succeeds, reboot. If not, then it's possible that there isn't a previous
#      firmware or the metadata about what's stored where is corrupt or out of
#      sync.
#
# It is critical that this is kept in sync with the main fwup.conf.

require-fwup-version="1.0.0"

#
# Firmware metadata
#

# All of these can be overriden using environment variables of the same name.
#
#  Run 'fwup -m' to query values in a .fw file.
#  Use 'fw_printenv' to query values on the target.
#
# These are used by Nerves libraries to introspect.
define(NERVES_FW_PRODUCT, "Nerves Firmware")
define(NERVES_FW_DESCRIPTION, "")
define(NERVES_FW_VERSION, "${NERVES_SDK_VERSION}")
define(NERVES_FW_PLATFORM, "bbb")
define(NERVES_FW_ARCHITECTURE, "arm")
define(NERVES_FW_AUTHOR, "The Nerves Team")

# This configuration file will create an image that
# has an MBR and the following layout:
#
# +----------------------------+
# | MBR                        |
# +----------------------------+
# | Firmware configuration data|
# | (formatted as uboot env)   |
# +----------------------------+
# | p0: Boot partition (FAT32) |
# | u-boot.img                 |
# | zImage.a                   |
# | zImage.b                   |
# +----------------------------+
# | p1: Rootfs A (squashfs)    |
# +----------------------------+
# | p2: Rootfs B (squashfs)    |
# +----------------------------+
# | p3: Application (f2fs)     |
# +----------------------------+

# The U-Boot environment is written directly to the SDCard/eMMC. It is not
# in any partition
define(UBOOT_ENV_OFFSET, 2048)
define(UBOOT_ENV_COUNT, 256)  # 128 KB

# Firmware archive metadata
meta-product = ${NERVES_FW_PRODUCT}
meta-description = ${NERVES_FW_DESCRIPTION}
meta-version = ${NERVES_FW_VERSION}
meta-platform = ${NERVES_FW_PLATFORM}
meta-architecture = ${NERVES_FW_ARCHITECTURE}
meta-author = ${NERVES_FW_AUTHOR}
meta-vcs-identifier = ${NERVES_FW_VCS_IDENTIFIER}
meta-misc = ${NERVES_FW_MISC}

# Location where installed firmware information is stored.
uboot-environment uboot-env {
    block-offset = ${UBOOT_ENV_OFFSET}
    block-count = ${UBOOT_ENV_COUNT}
}

task revert.a {
    # This task reverts to the A partition, so check that we're running on B
    require-uboot-variable(uboot-env, "nerves_fw_active", "b")

    # Verify that partition A has the expected platform/architecture
    require-uboot-variable(uboot-env, "a.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
    require-uboot-variable(uboot-env, "a.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")

    on-init {
        info("Reverting to partition A")

	# Switch over
        uboot_setenv(uboot-env, "nerves_fw_active", "a")
	uboot_setenv(uboot-env, "nerves_fw_validated", "1")
    }
}

task revert.b {
    # This task reverts to the B partition, so check that we're running on A
    require-uboot-variable(uboot-env, "nerves_fw_active", "a")

    # Verify that partition B has the expected platform/architecture
    require-uboot-variable(uboot-env, "b.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
    require-uboot-variable(uboot-env, "b.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")

    on-init {
        info("Reverting to partition B")

	# Switch over
        uboot_setenv(uboot-env, "nerves_fw_active", "b")
	uboot_setenv(uboot-env, "nerves_fw_validated", "1")
    }
}

task revert.unexpected.a {
    require-uboot-variable(uboot-env, "a.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
    require-uboot-variable(uboot-env, "a.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")
    on-init {
        # Case where A is good, and the desire is to go to B.
        error("It doesn't look like there's anything to revert to in partition B.")
    }
}
task revert.unexpected.b {
    require-uboot-variable(uboot-env, "b.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
    require-uboot-variable(uboot-env, "b.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")
    on-init {
        # Case where B is good, and the desire is to go to A.
        error("It doesn't look like there's anything to revert to in partition A.")
    }
}

task revert.wrongplatform {
    on-init {
        error("Expecting platform=${NERVES_FW_PLATFORM} and architecture=${NERVES_FW_ARCHITECTURE}")
    }
}

# Run "fwup /usr/share/fwup/revert.fw -t status -d /dev/mmcblk0 -q -U" to check the status.
task status.aa {
    require-path-on-device("/", "/dev/mmcblk0p2")
    require-uboot-variable(uboot-env, "nerves_fw_active", "a")
    on-init { info("a") }
}
task status.ab {
    require-path-on-device("/", "/dev/mmcblk0p2")
    require-uboot-variable(uboot-env, "nerves_fw_active", "b")
    on-init { info("a->b") }
}
task status.bb {
    require-path-on-device("/", "/dev/mmcblk0p3")
    require-uboot-variable(uboot-env, "nerves_fw_active", "b")
    on-init { info("b") }
}
task status.ba {
    require-path-on-device("/", "/dev/mmcblk0p3")
    require-uboot-variable(uboot-env, "nerves_fw_active", "a")
    on-init { info("b->a") }
}
task status.fail {
    on-init { error("fail") }
}
