mgmt: hawkbit: Add Hawkbit FOTA Support

Add Hawkbit FOTA support

Signed-off-by: NavinSankar Velliangiri <navin@linumiz.com>
This commit is contained in:
NavinSankar Velliangiri 2020-07-24 22:54:49 +05:30 committed by Carles Cufí
commit ddd6a650e2
13 changed files with 1748 additions and 0 deletions

View file

@ -487,6 +487,7 @@
/subsys/logging/ @nordic-krch
/subsys/logging/log_backend_net.c @nordic-krch @jukkar
/subsys/mgmt/mcumgr/ @carlescufi @nvlsianpu
/subsys/mgmt/hawkbit/ @Navin-Sankar
/subsys/mgmt/mcumgr/smp_udp.c @aunsbjerg
/subsys/mgmt/updatehub/ @nandojve @otavio
/subsys/mgmt/osdp/ @cbsiddharth

68
include/mgmt/hawkbit.h Normal file
View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Hawkbit Firmware Over-the-Air for Zephyr Project.
* @defgroup hawkbit Hawkbit Firmware Over-the-Air
* @ingroup lib
* @{
*/
#ifndef ZEPHYR_INCLUDE_MGMT_HAWKBIT_H_
#define ZEPHYR_INCLUDE_MGMT_HAWKBIT_H_
#define HAWKBIT_JSON_URL "/default/controller/v1"
/**
* @brief Response message from Hawkbit.
*
* @details These messages are used to inform the server and the
* user about the process status of the Hawkbit and also
* used to standardize the errors that may occur.
*
*/
enum hawkbit_response {
HAWKBIT_NETWORKING_ERROR,
HAWKBIT_UNCONFIRMED_IMAGE,
HAWKBIT_METADATA_ERROR,
HAWKBIT_DOWNLOAD_ERROR,
HAWKBIT_OK,
HAWKBIT_UPDATE_INSTALLED,
HAWKBIT_NO_UPDATE,
HAWKBIT_CANCEL_UPDATE,
};
/**
* @brief Init the flash partition
*
* @return 0 on success, negative on error.
*/
int hawkbit_init(void);
/**
* @brief Runs Hawkbit probe and Hawkbit update automatically
*
* @details The hawkbit_autohandler handles the whole process
* in pre-determined time intervals.
*/
void hawkbit_autohandler(void);
/**
* @brief The Hawkbit probe verify if there is some update to be performed.
*
* @return HAWKBIT_UPDATE_INSTALLED has an update available.
* @return HAWKBIT_NO_UPDATE no update available.
* @return HAWKBIT_NETWORKING_ERROR fail to connect to the Hawkbit server.
* @return HAWKBIT_METADATA_ERROR fail to parse or to encode the metadata.
* @return HAWKBIT_OK if success.
* @return HAWKBIT_DOWNLOAD_ERROR faile while downloading the update package.
*/
enum hawkbit_response hawkbit_probe(void);
/**
* @}
*/
#endif /* _HAWKBIT_H_ */

View file

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
add_subdirectory_ifdef(CONFIG_MCUMGR mcumgr)
add_subdirectory_ifdef(CONFIG_HAWKBIT hawkbit)
add_subdirectory_ifdef(CONFIG_UPDATEHUB updatehub)
add_subdirectory_ifdef(CONFIG_OSDP osdp)

View file

@ -6,6 +6,8 @@ menu "Device Management"
source "subsys/mgmt/mcumgr/Kconfig"
source "subsys/mgmt/hawkbit/Kconfig"
source "subsys/mgmt/updatehub/Kconfig"
source "subsys/mgmt/osdp/Kconfig"

View file

@ -0,0 +1,12 @@
#
# Copyright (c) 2020 Linumiz
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_HAWKBIT hawkbit.c)
zephyr_library_sources_ifdef(CONFIG_HAWKBIT hawkbit_device.c)
zephyr_library_sources_ifdef(CONFIG_HAWKBIT hawkbit_firmware.c)
zephyr_library_sources_ifdef(CONFIG_HAWKBIT_SHELL shell.c)

View file

@ -0,0 +1,59 @@
# Copyright (c) 2020 Linumiz
# SPDX -License-Identifier: Apache-2.0
menuconfig HAWKBIT
bool "Hawkbit Firmware Over-the-Air support"
select NVS
select FLASH
select REBOOT
select HWINFO
select NET_TCP
select NET_SOCKETS
select IMG_MANAGER
select NETWORKING
select HTTP_CLIENT
select DNS_RESOLVER
select JSON_LIBRARY
select BOOTLOADER_MCUBOOT
select MPU_ALLOW_FLASH_WRITE
select IMG_ERASE_PROGRESSIVELY
select NET_SOCKETS_POSIX_NAMES
help
Hawkbit is a domain independent back-end framework for polling out
software updates to constrained edge devices as well as more powerful
controllers and gateways connected to IP based networking infrastructure.
config HAWKBIT_POLL_INTERVAL
int "Time to poll interval (in minutes)"
default 5
range 1 43200
depends on HAWKBIT
help
Set the interval that the hawkbit update server will be polled.
This time interval is zero and 43200 minutes(30 days).
config HAWKBIT_SHELL
bool "Enable Hawkbit shell utilities"
depends on HAWKBIT
depends on SHELL
help
Activate shell module that provides Hawkbit commands.
config HAWKBIT_SERVER
string "User address for the hawkbit server"
depends on HAWKBIT
default ""
help
Configure the hawkbit server address.
config HAWKBIT_PORT
string "Port address for the hawkbit server"
default "8080"
depends on HAWKBIT
help
Configure the hawkbit port number.
module = HAWKBIT
module-str = Log Level for hawkbit
module-help = Enables logging for Hawkbit code.
source "subsys/logging/Kconfig.template.log_config"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hawkbit_device.h"
#include <string.h>
bool hawkbit_get_device_identity(char *id, int id_max_len)
{
uint8_t hwinfo_id[DEVICE_ID_BIN_MAX_SIZE];
size_t length;
length = hwinfo_get_device_id(hwinfo_id, DEVICE_ID_BIN_MAX_SIZE);
if (length <= 0) {
return false;
}
memset(id, 0, id_max_len);
length = bin2hex(hwinfo_id, length, id, id_max_len - 1);
return length > 0;
}

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identiier: Apache-2.0
*/
#ifndef __HAWKBIT_DEVICE_H__
#define __HAWKBIT_DEVICE_H__
#include <zephyr.h>
#include <drivers/hwinfo.h>
#define DEVICE_ID_BIN_MAX_SIZE 16
#define DEVICE_ID_HEX_MAX_SIZE ((DEVICE_ID_BIN_MAX_SIZE * 2) + 1)
bool hawkbit_get_device_identity(char *id, int id_max_len);
#endif /* __HAWKBIT_DEVICE_H__ */

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <storage/flash_map.h>
#include "hawkbit_firmware.h"
bool hawkbit_get_firmware_version(char *version, int version_len)
{
struct mcuboot_img_header header;
if (boot_read_bank_header(FLASH_AREA_ID(image_0), &header,
version_len) != 0) {
return false;
}
snprintk(version, version_len, "%d.%d.%d", header.h.v1.sem_ver.major,
header.h.v1.sem_ver.minor, header.h.v1.sem_ver.revision);
return true;
}

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __HAWKBIT_FIRMWARE_H__
#define __HAWKBIT_FIRMWARE_H__
#include <drivers/flash.h>
#include <dfu/mcuboot.h>
#include <dfu/flash_img.h>
bool hawkbit_get_firmware_version(char *version, int version_len);
#endif /* __HAWKBIT_FIRMWARE_H__ */

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
*
* @brief This file contains structures representing JSON messages
* exchanged with a hawkbit
*/
#ifndef __HAWKBIT_PRIV_H__
#define __HAWKBIT_PRIV_H__
#include <data/json.h>
#define HAWKBIT_SLEEP_LENGTH 8
enum hawkbit_http_request {
HAWKBIT_PROBE,
HAWKBIT_CONFIG_DEVICE,
HAWKBIT_CLOSE,
HAWKBIT_PROBE_DEPLOYMENT_BASE,
HAWKBIT_REPORT,
HAWKBIT_DOWNLOAD,
};
enum hawkbit_status_fini {
HAWKBIT_STATUS_FINISHED_SUCCESS,
HAWKBIT_STATUS_FINISHED_FAILURE,
HAWKBIT_STATUS_FINISHED_NONE,
};
enum hawkbit_status_exec {
HAWKBIT_STATUS_EXEC_CLOSED = 0,
HAWKBIT_STATUS_EXEC_PROCEEDING,
HAWKBIT_STATUS_EXEC_CANCELED,
HAWKBIT_STATUS_EXEC_SCHEDULED,
HAWKBIT_STATUS_EXEC_REJECTED,
HAWKBIT_STATUS_EXEC_RESUMED,
HAWKBIT_STATUS_EXEC_NONE,
};
enum hawkbit_dev_acid_t {
HAWKBIT_ACTION_ID_CURRENT = 0,
HAWKBIT_ACTION_ID_UPDATE,
};
struct hawkbit_href {
const char *href;
};
struct hawkbit_status_result {
const char *finished;
};
struct hawkbit_status {
struct hawkbit_status_result result;
const char *execution;
};
struct hawkbit_ctl_res_sleep {
const char *sleep;
};
struct hawkbit_ctl_res_polling {
struct hawkbit_ctl_res_sleep polling;
};
struct hawkbit_ctl_res_links {
struct hawkbit_href deploymentBase;
struct hawkbit_href configData;
struct hawkbit_href cancelAction;
};
struct hawkbit_ctl_res {
struct hawkbit_ctl_res_polling config;
struct hawkbit_ctl_res_links _links;
};
struct hawkbit_cfg_data {
const char *VIN;
const char *hwRevision;
};
struct hawkbit_cfg {
const char *mode;
struct hawkbit_cfg_data data;
const char *id;
const char *time;
struct hawkbit_status status;
};
struct hawkbit_close {
char *id;
const char *time;
struct hawkbit_status status;
};
/* Maximum number of chunks we support */
#define HAWKBIT_DEP_MAX_CHUNKS 1
/* Maximum number of artifacts per chunk. */
#define HAWKBIT_DEP_MAX_CHUNK_ARTS 1
struct hawkbit_dep_res_hashes {
const char *sha1;
const char *md5;
const char *sha256;
};
struct hawkbit_dep_res_links {
struct hawkbit_href download_http;
struct hawkbit_href md5sum_http;
};
struct hawkbit_dep_res_arts {
const char *filename;
struct hawkbit_dep_res_hashes hashes;
struct hawkbit_dep_res_links _links;
int size;
};
struct hawkbit_dep_res_chunk {
const char *part;
const char *name;
const char *version;
struct hawkbit_dep_res_arts artifacts[HAWKBIT_DEP_MAX_CHUNK_ARTS];
size_t num_artifacts;
};
struct hawkbit_dep_res_deploy {
const char *download;
const char *update;
struct hawkbit_dep_res_chunk chunks[HAWKBIT_DEP_MAX_CHUNKS];
size_t num_chunks;
};
struct hawkbit_dep_res {
const char *id;
struct hawkbit_dep_res_deploy deployment;
};
struct hawkbit_dep_fbk {
const char *id;
struct hawkbit_status status;
};
struct hawkbit_cancel {
struct hawkbit_href cancelBase;
};
struct entry {
char *http_req_str;
int n;
};
struct entry http_request[] = {
{"HAWKBIT_PROBE", 0},
{"HAWKBIT_CONFIG_DEVICE", 1},
{"HAWKBIT_CLOSE", 2},
{"HAWKBIT_PROBE_DEPLOYMENT_BASE", 3},
{"HAWKBIT_REPORT", 4},
{"HAWKBIT_DOWNLOAD", 5},
};
#endif /* __HAWKBIT_PRIV_H__ */

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <shell/shell.h>
#include <drivers/flash.h>
#include <dfu/mcuboot.h>
#include <dfu/flash_img.h>
#include <power/reboot.h>
#include "mgmt/hawkbit.h"
#include "hawkbit_firmware.h"
#include "hawkbit_device.h"
static void cmd_run(const struct shell *shell, size_t argc, char **argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
shell_fprintf(shell, SHELL_INFO, "Starting Hawkbit run...\n");
switch (hawkbit_probe()) {
case HAWKBIT_UNCONFIRMED_IMAGE:
shell_fprintf(
shell, SHELL_ERROR,
"Image is unconfirmed."
"Rebooting to revert back to previous confirmed image\n");
sys_reboot(SYS_REBOOT_WARM);
break;
case HAWKBIT_CANCEL_UPDATE:
shell_fprintf(shell, SHELL_INFO,
"Hawkbit update Cancelled from server\n");
break;
case HAWKBIT_NO_UPDATE:
shell_fprintf(shell, SHELL_INFO, "No update found\n");
break;
case HAWKBIT_OK:
shell_fprintf(shell, SHELL_INFO, "Image Already updated\n");
break;
case HAWKBIT_UPDATE_INSTALLED:
shell_fprintf(shell, SHELL_INFO, "Update Installed\n");
break;
case HAWKBIT_DOWNLOAD_ERROR:
shell_fprintf(shell, SHELL_INFO, "Download Error\n");
break;
case HAWKBIT_NETWORKING_ERROR:
shell_fprintf(shell, SHELL_INFO, "Networking Error\n");
break;
case HAWKBIT_METADATA_ERROR:
shell_fprintf(shell, SHELL_INFO, "Metadata Error\n");
break;
default:
shell_fprintf(shell, SHELL_ERROR, "Invalid response\n");
break;
}
k_sleep(K_MSEC(1));
}
static int cmd_info(const struct shell *shell, size_t argc, char *argv)
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
char device_id[DEVICE_ID_HEX_MAX_SIZE] = {0},
firmware_version[BOOT_IMG_VER_STRLEN_MAX] = {0};
hawkbit_get_firmware_version(firmware_version, BOOT_IMG_VER_STRLEN_MAX);
hawkbit_get_device_identity(device_id, DEVICE_ID_HEX_MAX_SIZE);
shell_fprintf(shell, SHELL_NORMAL, "Unique device id: %s\n", device_id);
shell_fprintf(shell, SHELL_NORMAL, "Firmware Version: %s\n",
firmware_version);
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(
sub_hawkbit,
SHELL_CMD(info, NULL, "Dump Hawkbit information", cmd_info),
SHELL_CMD(run, NULL, "Trigger an Hawkbit update run", cmd_run),
SHELL_SUBCMD_SET_END);
SHELL_CMD_REGISTER(hawkbit, &sub_hawkbit, "Hawkbit commands", NULL);