~aleteoryx/muditaos

a906ec6422d83cac25d9fb101a9febbbe227e89b — Marek Niepieklo 4 years ago a620ef7
[CP-411] Add updater.bin to Update package

Packaging updater.{bin, ver} using embedded assets
M CMakeLists.txt => CMakeLists.txt +4 -0
@@ 17,6 17,7 @@ include(CopyGdbInit)
include(Utils)
include(ModuleUtils)
include(FetchBootloader)
include(AddPureUpdater)
include(DiskImage)
include(AddPackage)
include(Product)


@@ 155,6 156,9 @@ add_custom_target(
        "Generating version info"
    )


copy_updater_bin()
copy_updater_ver()
fetch_ecoboot()
add_subdirectory(products)


M cmake/modules/AddPackage.cmake => cmake/modules/AddPackage.cmake +4 -0
@@ 40,6 40,8 @@ function(add_standalone_image SOURCE_TARGET)
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        DEPENDS ${BIN_FILE}
        DEPENDS ecoboot.bin-target
        DEPENDS updater.bin-target
        DEPENDS updater.ver-target
        DEPENDS ${SOURCE_TARGET}-version.json-target
        DEPENDS ${SOURCE_TARGET}.img
        )


@@ 67,6 69,8 @@ function(add_update_package SOURCE_TARGET)
        DEPENDS ${SOURCE_TARGET}-boot.bin
        DEPENDS ${SOURCE_TARGET}-version.json-target
        DEPENDS ecoboot.bin-target
        DEPENDS updater.bin-target
        DEPENDS updater.ver-target
        DEPENDS assets
        COMMAND ${CMAKE_SOURCE_DIR}/tools/generate_update_image.sh ${SOURCE_TARGET} ${CMAKE_PROJECT_VERSION} ${CPACK_SYSTEM_NAME}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}

A cmake/modules/AddPureUpdater.cmake => cmake/modules/AddPureUpdater.cmake +34 -0
@@ 0,0 1,34 @@
function(copy_updater_bin)
    set(ASSETS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/image)
    set(UPDATER_ASSET_BIN PureUpdater_RT.bin)

    add_custom_command(OUTPUT updater.bin
        COMMAND cp
            ${ASSETS_SOURCE_DIR}/${UPDATER_ASSET_BIN}
            ${CMAKE_BINARY_DIR}/updater.bin
        COMMENT "Copying PureUpdater_RT.bin"
    )

    add_custom_target(updater.bin-target DEPENDS updater.bin)

    multicomp_install(PROGRAMS ${CMAKE_BINARY_DIR}/updater.bin DESTINATION "./"
        COMPONENTS Standalone Update)
endfunction()


function(copy_updater_ver)
    set(ASSETS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/image)
    set(UPDATER_ASSET_VER PureUpdater.version)

    add_custom_command(OUTPUT PureUpdater.version
        COMMAND cp
            ${ASSETS_SOURCE_DIR}/${UPDATER_ASSET_VER}
            ${CMAKE_BINARY_DIR}/PureUpdater.version
        COMMENT "Downloading PureUpdater.version"
    )

    add_custom_target(updater.ver-target DEPENDS PureUpdater.version)

    multicomp_install(PROGRAMS ${CMAKE_BINARY_DIR}/PureUpdater.version DESTINATION "./"
        COMPONENTS Standalone Update)
endfunction()

M cmake/modules/AddVersionJson.cmake => cmake/modules/AddVersionJson.cmake +5 -0
@@ 10,9 10,14 @@ function(add_version_json SOURCE_TARGET)
            -DBOOT_FILENAME=boot.bin
            -DBOOT_FILE=$<TARGET_FILE:${SOURCE_TARGET}>
            -DBOOT_VERSION=${CMAKE_PROJECT_VERSION}
            -DUPDATER_FILENAME=updater.bin
            -DUPDATER_FILE=${CMAKE_BINARY_DIR}/updater.bin
            -DUPDATER_VERSION_FILE=${CMAKE_BINARY_DIR}/PureUpdater.version
            -B ${CMAKE_BINARY_DIR}
            -P ${CMAKE_SOURCE_DIR}/cmake/modules/ConfigureVersionJson.cmake
        DEPENDS ecoboot.bin-target
        DEPENDS updater.bin-target
        DEPENDS updater.ver-target
        DEPENDS ${SOURCE_TARGET}-boot.bin
    )


M cmake/modules/ConfigureVersionJson.cmake => cmake/modules/ConfigureVersionJson.cmake +4 -0
@@ 5,5 5,9 @@ file(READ ${BOOTLOADER_VERSION_FILE} BOOTLOADER_VERSION)
file(MD5 ${BOOTLOADER_FILE} BOOTLOADER_MD5SUM)
file(MD5 ${BOOT_FILE} BOOT_MD5SUM)

file(READ ${UPDATER_VERSION_FILE} UPDATER_VERSION)
string(STRIP ${UPDATER_VERSION} UPDATER_VERSION)
file(MD5 ${UPDATER_FILE} UPDATER_MD5SUM)

message("Configuring version.json file")
configure_file(${SRC_FILE} ${DST_FILE} @ONLY)

M cmake/modules/DiskImage.cmake => cmake/modules/DiskImage.cmake +13 -1
@@ 9,9 9,10 @@ function(add_image)

    if(NOT ${PROJECT_TARGET_NAME} STREQUAL "linux")
        set(HAS_BOOTFILE YES)
        set(HAS_UPDATER YES)
    endif()

    set(SCRIPT_PATH ${CMAKE_SOURCE_DIR}/generate_image.sh)
    set(SCRIPT_PATH ${CMAKE_SOURCE_DIR}/tools/generate_image.sh)

    set(DISK_IMAGE_NAME ${_ARG_PRODUCT}.img)
    set(DISK_IMAGE_PATH ${CMAKE_BINARY_DIR}/${DISK_IMAGE_NAME})


@@ 23,6 24,12 @@ function(add_image)
        set(BIN_FILE_PATH "")
    endif()

    if(HAS_UPDATER)
        set(UPDATER_FILE_PATH ${CMAKE_BINARY_DIR}/updater.bin)
    else()
        set(UPDATER_FILE_PATH "")
    endif()

    set(COMMAND_DEPENDS "genlittlefs")
    list(APPEND COMMNDS_DEPENDS ${SCRIPT_PATH})
    if(_ARG_ASSETS)


@@ 32,6 39,10 @@ function(add_image)
        list(APPEND COMMAND_DEPENDS ${BIN_FILE_TARGET})
    endif()

    if(HAS_UPDATER)
        list(APPEND COMMAND_DEPENDS updater.bin-target updater.ver-target)
    endif()

    add_custom_command(
        OUTPUT ${DISK_IMAGE_NAME}
        DEPENDS ${COMMAND_DEPENDS}


@@ 40,6 51,7 @@ function(add_image)
            ${DISK_IMAGE_NAME}
            ${CMAKE_BINARY_DIR}/${_ARG_SYSROOT}
            "${BIN_FILE_PATH}"
            "${UPDATER_FILE_PATH}"
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        COMMENT "Generate ${DISK_IMAGE_NAME}"
    )

A cmake/modules/FetchPureUpdater.cmake => cmake/modules/FetchPureUpdater.cmake +20 -0
@@ 0,0 1,20 @@
function(fetch_updater)
    set(UPDATER_ASSET_NAME PureUpdater_RT.bin)

    add_custom_command(OUTPUT updater.bin
        COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py
            "$<$<BOOL:$ENV{ASSETS_LOGIN}>:-l$ENV{ASSETS_LOGIN}>"
            "$<$<BOOL:$ENV{ASSETS_TOKEN}>:-t$ENV{ASSETS_TOKEN}>"
            -w ${CMAKE_BINARY_DIR}
            PureUpdater download
            -n ${UPDATER_ASSET_NAME}
            -o updater.bin
        COMMENT "Downloading updater.bin"
        BYPRODUCTS PureUpdater.version
    )

    add_custom_target(updater.bin-target DEPENDS updater.bin)

    multicomp_install(PROGRAMS ${CMAKE_BINARY_DIR}/updater.bin DESTINATION "./"
        COMPONENTS Standalone Update)
endfunction()

D config/genupdatepkg.sh => config/genupdatepkg.sh +0 -145
@@ 1,145 0,0 @@
#!/bin/bash
# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

# set -eo pipefail
# this is useless for now

if [ ! -e config/common.sh ]; then
  echo "No config/common.sh refuse to continue"
  exit 1
else
  source ./config/common.sh
fi

VERSION_KERNEL=`grep tskKERNEL_VERSION_NUMBER module-os/FreeRTOS/include/task.h | awk '{print $3}' | tr -d '\"'`
VERSION_CODENAME="salvador"
print_help() {
	echo "Usage: $0 [OPTION] [BUILD-DIR]"
	echo "  -h print help"
	echo "  -c version codename to embed"
	echo "  -k kernel version if needed"
	echo "  -b bootloader file to include"
	echo "  -v bootloader file version"
	echo "  -d build directory"
	echo "  -s sql migration JSON"
	echo
	exit 1
}

while getopts "s:c:k:b:v:d:h" arg; do
	case "${arg}" in
		c)
			VERSION_CODENAME=$OPTARG
			;;
		k)
			VERSION_KERNEL=$OPTARG
			;;
		b)
			BOOTLOADER_FILE=$OPTARG
			;;
		v)
			BOOTLOADER_VERSION=$OPTARG
			;;
		d)
			BUILD_PATH=$OPTARG
			;;
		h)
			print_help
			;;
		*)
			print_help
			;;
	esac
done
shift $((OPTIND-1))

if [ ! -d "$BUILD_PATH" ]; then
	if [ ! -z $BUILD_PATH ]; then
		echo "$BUILD_PATH does not exist"
	fi
	print_help
fi

check_target_rt1051 "$BUILD_PATH"

if [ ! -f $BUILD_PATH/boot.bin ]; then
	echo "No boot.bin in $BUILD_PATH, refuse to continue"
	exit 1
fi

if [ ! -x $(which rhash) ]; then
  echo "Please install the rhash command"
  exit 1
fi

if [ -d update ]; then
	rm -rf update
fi

mkdir -p update/
mkdir -p update/tmp

if [ ! -f config/version.json.template ]; then
	echo "No config/version.json.template"
	exit 1
fi

vjson=update/tmp/version.json
cp config/version.json.template $vjson

sed -i -e 's/__GIT_BRANCH__/'$MUDITAOS_GIT_BRANCH'/g' $vjson
sed -i -e 's/__GIT_TAG__/'$MUDITAOS_GIT_TAG'/g' $vjson
sed -i -e 's/__GIT_REVISION__/'$MUDITAOS_GIT_REV'/g' $vjson

sed -i -e 's/__VERSION_MAJOR__/'$MUDITAOS_VERSION_MAJOR'/g' $vjson
sed -i -e 's/__VERSION_MINOR__/'$MUDITAOS_VERSION_MINOR'/g' $vjson
sed -i -e 's/__VERSION_PATCH__/'$MUDITAOS_VERSION_PATCH'/g' $vjson
sed -i -e 's/__VERSION_STRING__/'$MUDITAOS_GIT_TAG'/g' $vjson

BUILD_HOST=`uname -r`
BUILD_USER=`whoami`
BUILD_DATE=`date +'%F-%T'`

sed -i -e 's/__MISC_CODENAME__/'$VERSION_CODENAME'/g' $vjson
sed -i -e 's/__MISC_KERNEL__/'$VERSION_KERNEL'/g' $vjson

sed -i -e 's/__MISC_BUILD_HOST__/'$BUILD_HOST'/g' $vjson
sed -i -e 's/__MISC_BUILD_DATE__/'$BUILD_DATE'/g' $vjson
sed -i -e 's/__MISC_BUILD_USER__/'$BUILD_USER'/g' $vjson

echo "-- copy $BUILD_PATH/boot.bin"

cp $BUILD_PATH/boot.bin update/tmp/
for file in $IMAGE_FILES; do
	echo "-- copy $file"
	cp -r image/$file update/tmp/
done

# don't include function files
rm -f update/tmp/.boot.ini
rm -f update/tmp/.boot.ini.crc32

# check for bootloader update
if [ -f "$BOOTLOADER_FILE" ]; then
	echo "-- including bootloader update file: $BOOTLOADER_FILE"
	sed -i -e 's/__BOOTLOADER_INCLUDED__/1/g' $vjson
	sed -i -e 's/__BOOTLOADER_INCLUDED_VERSION__/'$BOOTLOADER_VERSION'/g' $vjson
	sed -i -e 's/__BOOTLOADER_INCLUDED_FILENAME__/'$(basename $BOOTLOADER_FILE)'/g' $vjson
	cp $BOOTLOADER_FILE update/tmp/
else
	sed -i -e 's/__BOOTLOADER_INCLUDED__/0/g' $vjson
	sed -i -e 's/__BOOTLOADER_INCLUDED_VERSION__//g' $vjson
	sed -i -e 's/__BOOTLOADER_INCLUDED_FILENAME__//g' $vjson
fi

rm -f update/*.tar
curpwd=`pwd`
vstr=$MUDITAOS_VERSION_MAJOR.$MUDITAOS_VERSION_MINOR.$MUDITAOS_VERSION_PATCH-$MUDITAOS_GIT_REV
echo -ne "-- "
cd update/tmp && rhash -ru checksums.txt .
cd $curpwd
echo "-- create tar update/muditaos-$vstr.tar"
cd update/tmp && tar -cf ../muditaos-$vstr.tar .
cd $curpwd
ls -alh update/muditaos-$vstr.tar

M config/version.json.cmake_template => config/version.json.cmake_template +6 -0
@@ 31,5 31,11 @@
        "version": "@BOOT_VERSION@",
        "filename": "@BOOT_FILENAME@",
        "md5sum": "@BOOT_MD5SUM@"
    },
    "updater":
    {
        "version": "@UPDATER_VERSION@",
        "filename": "@UPDATER_FILENAME@",
        "md5sum": "@UPDATER_MD5SUM@"
    }
}

M doc/download_assets.md => doc/download_assets.md +4 -4
@@ 1,9 1,9 @@
# Download Assets 
# Download Assets

Building update packages requires some external assets.
For now we need only `ecoboot.bin`.
This file may be manually downloaded from [ecoboot releases page](https://github.com/mudita/ecoboot/releases),
from the "Assets" section. This requires the user to log in to GitHub and click inside the web browser, which is a "no go" for automated builds.
For now we need only `ecoboot.bin` and `PureUpdater_RT.bin`.
The files may be downloaded manually from [ecoboot](https://github.com/mudita/ecoboot/releases) and [PureUpdater](https://github.com/mudita/PureUpdater/releases) release pages, respectively, from the "Assets" section.
This requires the user to log in to GitHub and click inside the web browser, which is a "no go" for automated builds.
To automate this process we have introduced a tool `tools/download_asset.py`.

## GitHub API token

A image/PureUpdater.version => image/PureUpdater.version +2 -0
@@ 0,0 1,2 @@
0.0.3


A image/PureUpdater_RT.bin => image/PureUpdater_RT.bin +0 -0
M test/firmware_update_test/update.py => test/firmware_update_test/update.py +20 -6
@@ 6,8 6,11 @@ import sys
import time
import sys
import os.path
import atexit
import json

from tqdm import tqdm

sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))



@@ 16,14 19,21 @@ from harness.harness import Harness
from harness.interface.defs import key_codes, endpoint, method
from harness.utils import Timeout
from harness.interface.error import TestError, Error
from harness.api.developermode import PhoneModeLock
from functools import partial

def set_passcode(harness: Harness, flag: bool):
    '''
    on exit -> restore PhoneModeLock
    '''
    PhoneModeLock(flag).run(harness)

# uploaded file chunk size - according to
# https://appnroll.atlassian.net/wiki/spaces/MFP/pages/656637953/Protocol+description
CHUNK_SIZE = 1024 * 16
CHUNK_SIZE = 1024 * 128

# update performing timeout
UPDATE_TIMEOUT = 90
UPDATE_TIMEOUT = 300

update_status_code = {
    0: "Initial",


@@ 50,9 60,10 @@ def update(harness, update_filepath: str):

    log.info("Downloading update file to the target")
    with open(update_filepath, 'rb') as file:
        for chunk in iter(partial(file.read, CHUNK_SIZE), b''):
            print(".", end='', flush=True)
            serial.write(chunk)
        with tqdm(total=file_size, unit='B', unit_scale=True) as p_bar:
            for chunk in iter(partial(file.read, CHUNK_SIZE), b''):
                p_bar.update(CHUNK_SIZE)
                serial.write(chunk)
    print(" ")

    body = {"fileName": filename}


@@ 67,7 78,7 @@ def update(harness, update_filepath: str):
            log.error("Update timeout!")
            return False
        if serial.in_waiting > 0:
            result = connection.read(10)
            result = connection.read(10)[0]
            ret = json.loads(result)
            body = ret['body']
            if "status" in body:


@@ 112,6 123,9 @@ def main():
            except TestError:
                pass

    atexit.register(set_passcode, harness, True)
    set_passcode(harness, False)

    update_filename = str(sys.argv[1])
    history, fails = get_update_list(harness)


M tools/download_asset.py => tools/download_asset.py +7 -3
@@ 14,17 14,18 @@ import json
import os
import requests
import sys

from tqdm import tqdm
import time


class Getter(object):
    '''Download latest ecooboot.bin image'''
    '''Download latest ecooboot.bin/updater.bin images'''

    def __init__(self):
        self.host = 'https://api.github.com/repos'
        self.organisation = 'mudita'
        self.repo = 'ecoboot'
        self.repo = ''
        self.apitoken = None
        self.ghLogin = None
        self.getGitRoot()


@@ 38,6 39,8 @@ class Getter(object):
        self.restPrefix += '/'
        self.restPrefix += self.organisation
        self.restPrefix += '/'
        if self.repo == '':
            raise ValueError("Repository must be set")
        self.restPrefix += self.repo
        self.restPrefix += '/'
        return self.restPrefix


@@ 57,7 60,7 @@ class Getter(object):
        try:
            gitConfigReader = self.gitRepo.config_reader()
            self.apitoken = gitConfigReader.get_value("user", "apitoken")
        except: 
        except:
            pass

    def getGHLogin(self, args=None):


@@ 175,6 178,7 @@ class Getter(object):


def main():

    getter = Getter()

    parser = argparse.ArgumentParser(description="Download ecooboot")

R generate_image.sh => tools/generate_image.sh +19 -10
@@ 4,14 4,15 @@

usage() {
cat << ==usage
Usage: $(basename $0) image_path build_dir [boot.bin_file]
    image_path    - Destination image path name e.g., PurePhone.img
    sysroot       - product's system root e.g., build-rt1051-RelWithDebInfo/sysroot
    boot.bin_file - optional for linux image - name of the boot.bin file (for different targets)
Usage: $(basename $0) image_path build_dir [boot.bin_file] [updater.bin_file]
    image_path       - Destination image path name e.g., PurePhone.img
    sysroot          - product's system root e.g., build-rt1051-RelWithDebInfo/sysroot
    boot.bin_file    - optional for linux image - name of the boot.bin file (for different targets)
    updater.bin_file - optional for linux image - name of the updater.bin file
==usage
}

if [[ ( $# -ne 2 ) && ( $# -ne 3 ) ]]; then
if [[ ( $# -ne 2 ) && ( $# -ne 4 ) ]]; then
	echo "Error! Invalid argument count"
	usage
	exit -1


@@ 20,6 21,7 @@ fi
IMAGE_NAME=$(realpath $1)
SYSROOT=$(realpath $2)
BIN_FILE=$3
UPDATER_FILE=$4

if [ ! -d "$SYSROOT" ]; then
	echo "Error! ${SYSROOT} is not a directory"


@@ 35,12 37,12 @@ for cmd in $_REQ_CMDS; do
done
#mtools version
_AWK_SCRIPT='
/[0-9]/ { 
	split($4,vers,"."); 
	if(vers[1]>=4 && vers[2]>=0 && vers[3] >= 24) { 
		print "true"; 
/[0-9]/ {
	split($4,vers,".");
	if(vers[1]>=4 && vers[2]>=0 && vers[3] >= 24) {
		print "true";
	}
	exit 0; 
	exit 0;
}'
MTOOLS_OK=$(mtools --version | awk "${_AWK_SCRIPT}")



@@ 112,6 114,13 @@ else
	echo "(it's fine for a Linux build)"
fi

if [[ -n "${UPDATER_FILE}" && -f "${UPDATER_FILE}" ]]; then
	mcopy -v -s -i "$PART1" ${UPDATER_FILE} ::/current/updater.bin
else
	echo "Warning! Missing updater.bin"
	echo "(it's fine for a Linux build)"
fi

mcopy -s -i "$PART1" .boot.json ::
mcopy -s -i "$PART1" .boot.json.crc32 ::


M tools/generate_update_image.sh => tools/generate_update_image.sh +2 -0
@@ 36,6 36,7 @@ function setVars() {
        "sysroot/sys/current/Luts.bin"
        "version.json"
        "ecoboot.bin"
        "updater.bin"
        )
}



@@ 70,6 71,7 @@ function linkInStageing(){
    ln -s ../sysroot/sys/current/country-codes.db
    ln -s ../sysroot/sys/current/Luts.bin
    ln -s ../ecoboot.bin
    ln -s ../updater.bin
    ln -s ../${SOURCE_TARGET}-version.json version.json
    popd 1> /dev/null
}