# Post-installation firmware operations for the SAMA5D27
#
# Tasks include:
#
# * `factory-reset` - Clear out the writable filesystem and any other writable
#                   areas so that they can be re-initialized on the next boot.
# * `prevent-revert` - Prevent `revert` from working until the next firmware
# * `revert` - Revert to the previous firmware if it's still available
# * `validate` - Mark this firmware as a good update.
# * `status` - Print out which partition is active (`a` or `b`)
#
# To use:
#
# 1. Run `fwup -c -f fwup-ops.conf -o ops.fw` and copy ops.fw to
#    the device. This is done automatically as part of the Nerves system
#    build process. The file is stored in `/usr/share/fwup/ops.fw`.
# 2. On the device, run `fwup -t <task> -d /dev/rootdisk0 --enable-trim /usr/share/fwup/ops.fw`.
# 3. Reboot after running `revert` or `factory-reset`.

require-fwup-version="1.0.0"

include("${NERVES_SDK_IMAGES:-.}/fwup_include/fwup-common.conf")

##
# factory-reset
##
task factory-reset {
    on-init {
        info("Erasing all writable data")
        # This requires --enable-trim
        trim(${APP_PART_OFFSET}, ${APP_PART_COUNT})
        raw_memset(${APP_PART_OFFSET}, 256, 0xff)
    }
}

##
# prevent-revert
#
# Pass `--enable-trim` to also clear out the partition that no longer should be used.
##
task prevent-revert.a {
    # Check that we're running on B
    require-uboot-variable(uboot-env, "nerves_fw_active", "b")

    on-init {
        info("Preventing reverts to partition A")
        # Remove U-Boot variables that fwup uses to allow reverting images
        uboot_unsetenv(uboot-env, "a.nerves_fw_platform")
        uboot_unsetenv(uboot-env, "a.nerves_fw_architecture")
        # Clear out the old image using TRIM. This requires --enable-trim
        trim(${ROOTFS_A_PART_OFFSET}, ${ROOTFS_A_PART_COUNT})
        fat_rm(${BOOT_PART_OFFSET}, "zImage.a")
    }
}
task prevent-revert.b {
    # Check that we're running on A
    require-uboot-variable(uboot-env, "nerves_fw_active", "a")

    on-init {
        info("Preventing reverts to partition B")
        # Remove U-Boot variables that fwup uses to allow reverting images
        uboot_unsetenv(uboot-env, "b.nerves_fw_platform")
        uboot_unsetenv(uboot-env, "b.nerves_fw_architecture")
        # Clear out the old image using TRIM. This requires --enable-trim
        trim(${ROOTFS_B_PART_OFFSET}, ${ROOTFS_B_PART_COUNT})
        fat_rm(${BOOT_PART_OFFSET}, "zImage.b")
    }
}
task prevent-revert.fail {
    on-init {
        error("Error detecting active partition")
    }
}

##
# revert
##
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}")
    }
}

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

##
# validate
##
task validate {
    on-init {
        info("Validate")
        uboot_setenv(uboot-env, "nerves_fw_validated", "1")
        uboot_setenv(uboot-env, "upgrade_available", "0")
        uboot_setenv(uboot-env, "bootcount", "1")
    }
}
