Skip to content

Firmware Update

Prepare Your Environment to Build Firmware Update

This tutorial provides the necessary information to prepare SWUpdate for your device firmware to communicate with the Industrial Edge Management system. This enables full remote and mass management of firmware updates.

NOTICE

Tutorial is provided as a guidance and underlying details might differ operating system you use in your device.

Firmware Update Agent

The SWUpdate framework is an Open Source Software (OSS) that can be used as an firmware update agent for edge devices. It provides general software update functionality. SWUpdate uses .swu files (cpio format) as update artifact container. Hence, the provided firmware update artifact must be a .swu file.

For usage with the Industrial Edge Management you need a binding to communicate to the workflowexecutor. To get those components please contact your Ecosystem contact.

NOTICE

In the reference service implementation for Device Builders, the Onboard Service writes the Edge Device ID to /var/device.id while onboarding the Edge Device.The Edge Device ID is required for firmwarea updates.

Overview

The graphic below gives an overview about the preparation for SWUpdate at Industrial Edge.

swupdate_compile_steps

Procedure

  1. Clone Repositories
    Clone the recommended version of the SWUpdate repository and suricatta wfx binding provided on request by your Ecosystem contact.

  2. Prepare and Configure
    The tools and packages needed to compile SWUpdate must be installed on Linux. There are two scripts in the ci directory of the SWUpdate repository to support you with the preparation. The files are executed using the following commands.

    bash setup.sh
    bash install-src-deps.sh
    

    After running these commands, the .config file needs to be created so that SWUpdate can be compiled. There is a Makefile in the home directory of the SWUpdate repository. This Makefile will both create the .config file and compile the SWUpdate. More information about the Makefile can be obtained by running the make help command in the home directory of the SWUpdate repository.

    To create a .config file, run the make menuconfig command in the main directory of the SWUpdate repository. After running this command, an interactive user interface will open. These configurations may vary depending on your environment and the tests you are running.

    NOTICE

    Suricatta module must be enabled to communicate with IEM (server).
    suricatta_module_enabled

    NOTICE

    libcurl must be configured to use the host system's CA trust store (e.g. /etc/ssl/certs/ca-certificates.crt). The Industrial Edge Core will take care of updating this if custom certificates are used for IEM.

  3. Compile
    Run the make all command and compile the SWUpdate. If SWUpdate compiles successfully, the SWUpdate binary is created.

  4. Create a Debian Package for the SWUpdate

    1. Apply Patch

      In order to build the .deb package of SWUpdate, a .patch file in the main directory of this repository is required.

      First you need to download the git-chglog binary. This binary can be installed on the device by following the commands and images below.

      wget https://github.com/git-chglog/git-chglog/releases/download/v0.15.2/git-chglog_0.15.2_linux_amd64.tar.gz
      tar -xf git-chglog_0.15.2_linux_amd64.tar.gz
      sudo cp git-chglog /usr/bin/
      

      After installing the git-chglog binary, the package_creation.patch file should be created in the debian directory at the root of the SWUpdate directory. The following commands can be examined.

      mkdir debian
      cd debian/
      

      Now copy the .patch file from the example below into the directory created above.

      Example
      diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md
      new file mode 100644
      index 0000000..3da7ca6
      --- /dev/null
      +++ b/.chglog/CHANGELOG.tpl.md
      @@ -0,0 +1,19 @@
      +{{ if .Unreleased.Commits -}}
      +swupdate ({{$V := index .Versions 0}}{{$V.Tag.Name}}.1-experimental) experimental; urgency=low;
      +{{ range .Unreleased.Commits }}
      +
      +{{ .Header -}}
      +{{ end }}
      +
      +-- {{$C := index .Unreleased.Commits 0}}{{ $C.Committer.Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}
      +{{""}}
      +{{ end -}}
      +{{ range .Versions -}}
      +swupdate ({{ .Tag.Name }}) released; urgency=low;
      +{{ range .Commits }}
      +
      +{{ .Header -}}
      +{{ end }}
      +
      +-- {{ .Tag.Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}
      +{{ end }}
      \ No newline at end of file
      diff --git a/.chglog/config.yml b/.chglog/config.yml
      new file mode 100644
      index 0000000..7409f57
      --- /dev/null
      +++ b/.chglog/config.yml
      @@ -0,0 +1,33 @@
      +style: gitlab
      +template: CHANGELOG.tpl.md
      +info:
      +  title: CHANGELOG
      +  repository_url: ""
      +options:
      +  commits:
      +      filters:
      +        Type:
      +          - feat
      +          - fix
      +          - chore
      +          - refactor
      +          - test
      +          - style
      +          - docs
      +  commit_groups:
      +      title_maps:
      +        feat: Features
      +        fix: Bug Fixes
      +        chore: Minor Tasks
      +        refactor: Code Refactoring
      +        test: Test
      +        style: Style
      +        docs: Documentation
      +  header:
      +    pattern: ^(\\\w*)\\\:\\\s(.*)$
      +    pattern_maps:
      +      - Type
      +      - Subject
      +  notes:
      +    keywords:
      +      - BREAKING CHANGE
      diff --git a/debian/compat b/debian/compat
      new file mode 100644
      index 0000000..f11c82a
      --- /dev/null
      +++ b/debian/compat
      @@ -0,0 +1 @@
      +9
      \ No newline at end of file
      diff --git a/debian/control b/debian/control
      new file mode 100644
      index 0000000..d17acb0
      --- /dev/null
      +++ b/debian/control
      @@ -0,0 +1,17 @@
      +Source: swupdate
      +Section: universe/embedded
      +Priority: optional
      +Maintainer: Stefano Babic <sba...@denx.de>
      +Build-Depends: debhelper (>=9), libconfig9
      +Standards-Version: 3.9.6
      +Homepage: http://sbabic.github.io/swupdate
      +#Vcs-Git: git://anonscm.debian.org/collab-maint/swupdate.git
      +#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/swupdate.git
      +
      +Package: swupdate
      +Architecture: any
      +Depends: ${shlibs:Depends}, ${misc:Depends}
      +Description: SWUpdate provides a reliable way to update an embedded system
      + This project is thought to help to update an embedded system from a storage media or from network.
      + However, it should be mainly considered as a framework, where further protocols or installers
      + (in SWUpdate they are called handlers) can be easily added to the application.
      diff --git a/debian/postinst b/debian/postinst
      new file mode 100644
      index 0000000..af480fd
      --- /dev/null
      +++ b/debian/postinst
      @@ -0,0 +1,6 @@
      +#!/bin/sh
      +
      +systemctl daemon-reload
      +systemctl enable swupdate.service
      +systemctl restart swupdate.service
      +echo "Daemon reloaded and Swupdate service restarted"
      \ No newline at end of file
      diff --git a/debian/rules b/debian/rules
      new file mode 100644
      index 0000000..661cac6
      --- /dev/null
      +++ b/debian/rules
      @@ -0,0 +1,31 @@
      +#!/usr/bin/make -f
      +# See debhelper(7) (uncomment to enable)
      +# output every command that modifies files on the build system.
      +export DH_VERBOSE = 1
      +
      +
      +# see FEATURE AREAS in dpkg-buildflags(1)
      +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
      +
      +# see ENVIRONMENT in dpkg-buildflags(1)
      +# package maintainers to append CFLAGS
      +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
      +# package maintainers to append LDFLAGS
      +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
      +
      +
      +configure:
      + make silentoldconfig
      +
      +build: configure
      + dh $@
      +
      +%:
      + dh $@
      +
      +
      +# dh_make generated override targets
      +# This is example for Cmake (See https://bugs.debian.org/641051 )
      +#override_dh_auto_configure:
      +# dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
      +
      diff --git a/debian/swupdate.service b/debian/swupdate.service
      new file mode 100644
      index 0000000..8a4671f
      --- /dev/null
      +++ b/debian/swupdate.service
      @@ -0,0 +1,14 @@
      +[Unit]
      +Description=SWUpdate service for workflow executor
      +Documentation=https://github.com/sbabic/swupdate
      +Documentation=https://sbabic.github.io/swupdate
      +ConditionPathExists=/etc/swupdate/swupdate.cfg
      +
      +[Service]
      +Type=notify
      +ExecStart=/usr/bin/swupdate -f /etc/swupdate/swupdate.cfg -H industrial-edge:v1.0 -v -l 10 -u ''
      +Restart=always
      +RestartSec=2
      +
      +[Install]
      +WantedBy=multi-user.target
      

      The patch can then be created.

      patch < package_creation.patch
      

      For chglog, the .chglog directory should be created in the main directory of the SWUpdate repository, and the CHANGELOG.tpl.md and config.yml files created with package_creation.patch should also be copied to this directory. Then the changelog file should be created using the git-chglog command.

      mkdir .chglog
      cp debian/CHANGELOG.tpl.md debian/config.yml .chglog
      git-chglog --output debian/changelog
      
    2. Prepare swupdate-active binary

      The suricatta module needs the swupdate-activate binary. Therefore, this binary should be built using the following steps.

      ln -s libswupdate.so.0.1 libswupdate.so
      sudo cp libswupdate.so /usr/lib/
      sudo cp include/progress_ipc.h include/swupdate_status.h /usr/include/
      cp ../swupdate-suricatta-wfx/swupdate-activate.c .
      gcc swupdate-activate.c -D _GNU_SOURCE -lswupdate -pthread -o swupdate-activate
      

      Now you can see the swupdate-activate binary.

    3. Build -deb package
      The .deb package can now be build using the following commands.

      sudo apt install debhelper
      dpkg-buildpackage -us -uc -nc
      
  5. Run binary
    SWUpdate should be installed and running as a system service on the device prior to onboarding.

    The .deb package located at the top of the SWUpdate directory can be installed as a system service on Ubuntu with the following command.

    sudo dpkg -i swupdate_2022.12_amd64.deb
    

    install_swupdate_deb_package

    As you can see from the status logs, the SWUpdate system service is in inactive mode. This is because a conditionPath is defined for the service to be active, and this conditionPath is the swupdate.cfg file in the /etc/swupdate directory. This file is created by the onboard service on ied-os systems. However, this feature is not available in the onboard service within the reference services. For this reason, the file must be created manually, or you can adapt it to your onboard service, as shown above.

    globals:
    {
        public-key-file = "/etc/swupdate/public.pem";
    }
    processes :
    (
        {
            name = "swupdate-activate";
            exec = "/usr/bin/swupdate-activate";
        }
    )
    suricatta :
    {
        id = "deviceId";
        url = "http://127.0.0.1:8081/api/wfx/v1";
    }
    

    NOTICE

    If you are using the Industrial-2.1.x Version of suricatta module, you should change URL as http://127.0.0.1/firmwaredeployment/api/v1/instances.

  6. Prepare Artifact
    The .swu file should be prepared based on your edge device firmware and your update logic, such as A/B partitioning.

    Example of SWU File Preparation

    This section has been prepared as an example to give basic information about the workflow.

    An Ubuntu environment has been used for this example. Please prepare the following files on your local environment.

    sample_update.sh

    #!/bin/bash
    
    # "======================================================"
    # "<Script to be implemented for update operations>"
    # "======================================================"
    

    sample_file
    test
    

    sw-description
    software =
    {
        version = "2.1";
        hardware-compatibility: [ "v1.0" ];
    
        files: (
            {
                filename = "sample_file";
                sha256 = "49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14";
                path = "just-large_file";
                #installed-directly = false;
                #encrypted = false;
                #filesystem = "vfat";
                #type = "text";
            }
        );
        scripts: (
            {
                filename = "sample_update.sh";
                sha256 = "68239f0b9f5f0328e58c2004130bdc8fb34ee2c74b8dba009db9aa989630a8d1";
                type = "shellscript";
            }
        );
    }
    

    The sha256 variable should be the same as the sha256sum file. You can get sha256 using the command below.

    sha256sum <file_name>
    

    generate_swu.sh
    #!/bin/bash
    
    CONTAINER_VER="1.3"
    PRODUCT_NAME="iceEdge-replace-file"
    FILES="sw-description sw-description.sig sample_file sample_update.sh"
    
    openssl genrsa -aes256 -out priv.pem
    openssl rsa -in priv.pem -out public.pem -outform PEM -pubout
    openssl dgst -sha256 -sign priv.pem sw-description > sw-description.sig
    
    for i in $FILES;do
            echo $i;done | cpio -ov -H crc >  ${PRODUCT_NAME}_${CONTAINER_VER}.swu
    

    The following commands can be used to create a .swu file.

    bash generate_swu.sh
    

    NOTICE

    The public.pem file obtained at this stage should be copied to the /etc/swupdate directory. And the swupdate-activate binary should be copied to the /usr/bin directory.

    sudo cp public.pem /etc/swupdate/
    sudo cp swupdate-activate /usr/bin/
    
  7. Restart and verify
    After all these operations, SWUpdate should be restarted and the SWUpdate logs can be checked.

    Examine logs to verify results.

    sudo systemctl restart swupdate
    journalctl -fu swupdate