lib: updatehub: Add UpdateHub.io support
UpdateHub is an enterprise-grade solution which makes simple to remotely update all your embedded devices in the field. It handles all aspects related to sending Firmware Over-the-Air(FOTA) updates with maximum security and efficiency, while you focus in adding value to your product. Signed-off-by: Christian Tavares <christian.tavares@ossystems.com.br> Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
This commit is contained in:
parent
5a2c6d33e4
commit
297ac3765f
19 changed files with 1724 additions and 0 deletions
|
@ -254,6 +254,7 @@
|
|||
/include/sys_io.h @andrewboie @andyross
|
||||
/include/toolchain.h @andrewboie @andyross @nashif
|
||||
/include/toolchain/ @andrewboie @andyross
|
||||
/include/updatehub.h @chtavares592 @otavio
|
||||
/include/zephyr.h @andrewboie @andyross
|
||||
/kernel/ @andrewboie @andyross
|
||||
/lib/gui/ @vanwinkeljan
|
||||
|
@ -270,6 +271,8 @@
|
|||
/samples/basic/minimal/ @carlescufi
|
||||
/samples/basic/servo_motor/*microbit* @jhe
|
||||
/samples/bluetooth/ @joerchan @jhedberg @Vudentz
|
||||
/lib/updatehub/ @chtavares592 @otavio
|
||||
/samples/bluetooth/ @sjanc @jhedberg @Vudentz
|
||||
/samples/boards/intel_s1000_crb/ @sathishkuttan @dcpleung @nashif
|
||||
/samples/display/ @vanwinkeljan
|
||||
/samples/drivers/CAN/ @alexanderwachter
|
||||
|
@ -282,6 +285,8 @@
|
|||
/samples/net/sockets/coap_*/ @rveerama1
|
||||
/samples/net/sockets/ @jukkar @tbursztyka @pfalcon
|
||||
/samples/sensor/ @MaureenHelm
|
||||
/samples/net/updatehub/ @chtavares592 @otavio
|
||||
/samples/sensor/ @bogdan-davidoaia
|
||||
/samples/subsys/logging/ @nordic-krch @jarz-nordic
|
||||
/samples/subsys/shell/ @jarz-nordic @nordic-krch
|
||||
/samples/subsys/usb/ @jfischer-phytec-iot @finikorg
|
||||
|
|
76
include/updatehub.h
Normal file
76
include/updatehub.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief UpdateHub Firmware Over-the-Air for Zephyr Project.
|
||||
* @defgroup updatehub UpdateHub Firmware Over-the-Air
|
||||
* @ingroup lib
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _UPDATEHUB_H_
|
||||
#define _UPDATEHUB_H_
|
||||
|
||||
/**
|
||||
* @brief Responses messages from UpdateHub.
|
||||
*
|
||||
* @details These messages are used to inform the server and the
|
||||
* user about the process status of the UpdateHub and also
|
||||
* used to standardize the errors that may occur.
|
||||
*
|
||||
*/
|
||||
enum updatehub_response {
|
||||
UPDATEHUB_NETWORKING_ERROR = 0,
|
||||
UPDATEHUB_INCOMPATIBLE_HARDWARE,
|
||||
UPDATEHUB_UNCONFIRMED_IMAGE,
|
||||
UPDATEHUB_METADATA_ERROR,
|
||||
UPDATEHUB_DOWNLOAD_ERROR,
|
||||
UPDATEHUB_INSTALL_ERROR,
|
||||
UPDATEHUB_FLASH_INIT_ERROR,
|
||||
UPDATEHUB_OK,
|
||||
UPDATEHUB_HAS_UPDATE,
|
||||
UPDATEHUB_NO_UPDATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Runs UpdateHub probe and UpdateHub update automatically.
|
||||
*
|
||||
* @details The updatehub_autohandler handles the whole process
|
||||
* in pre-determined time intervals.
|
||||
*/
|
||||
void updatehub_autohandler(void);
|
||||
|
||||
/**
|
||||
* @brief The UpdateHub probe verify if there is some update to be performed.
|
||||
*
|
||||
* @return UPDATEHUB_HAS_UPDATE has an update available.
|
||||
* @return UPDATEHUB_NO_UPDATE no update available.
|
||||
* @return UPDATEHUB_NETWORKING_ERROR fail to connect to the UpdateHub server.
|
||||
* @return UPDATEHUB_INCOMPATIBLE_HARDWARE if Incompatible hardware.
|
||||
* @return UPDATEHUB_METADATA_ERROR fail to parse or to encode the metadata.
|
||||
*/
|
||||
enum updatehub_response updatehub_probe(void);
|
||||
|
||||
/**
|
||||
* @brief Apply the update package.
|
||||
*
|
||||
* @details Must be used after the UpdateHub probe, if you have updates to
|
||||
* be made, will perform the installation of the new image and the hardware
|
||||
* will rebooting.
|
||||
*
|
||||
* @return Return UPDATEHUB_OK if success
|
||||
* @return UPDATEHUB_NETWORKING_ERROR if fail to connect to the server.
|
||||
* @return UPDATEHUB_DOWNLOAD_ERROR fail while downloading the update package.
|
||||
* @return UPDATEHUB_INSTALL_ERROR fail while installing the update package.
|
||||
* @return UPDATEHUB_FLASH_INIT_ERROR fail to initilialize the flash.
|
||||
*/
|
||||
enum updatehub_response updatehub_update(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* _UPDATEHUB_H_ */
|
|
@ -8,3 +8,4 @@ add_subdirectory_ifdef(CONFIG_CMSIS_RTOS_V1 cmsis_rtos_v1)
|
|||
add_subdirectory_ifdef(CONFIG_CMSIS_RTOS_V2 cmsis_rtos_v2)
|
||||
add_subdirectory(gui)
|
||||
add_subdirectory(os)
|
||||
add_subdirectory_ifdef(CONFIG_UPDATEHUB updatehub)
|
||||
|
|
|
@ -18,4 +18,6 @@ source "lib/os/Kconfig"
|
|||
|
||||
source "lib/posix/Kconfig"
|
||||
|
||||
source "lib/updatehub/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
12
lib/updatehub/CMakeLists.txt
Normal file
12
lib/updatehub/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Copyright (c) 2018 O.S.Systems
|
||||
#
|
||||
# SPDX -License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_UPDATEHUB updatehub.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_UPDATEHUB updatehub_device.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_UPDATEHUB updatehub_firmware.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_UPDATEHUB_SHELL shell.c)
|
85
lib/updatehub/Kconfig
Normal file
85
lib/updatehub/Kconfig
Normal file
|
@ -0,0 +1,85 @@
|
|||
#
|
||||
# Copyright (c) 2018 O.S.Systems
|
||||
#
|
||||
# SPDX -License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
menuconfig UPDATEHUB
|
||||
bool"UpdateHub Firmware Over-the-Air support"
|
||||
select FLASH
|
||||
select REBOOT
|
||||
select IMG_MANAGER
|
||||
select BOOTLOADER_MCUBOOT
|
||||
select MPU_ALLOW_FLASH_WRITE
|
||||
select NETWORKING
|
||||
select NEWLIB_LIBC
|
||||
select NET_UDP
|
||||
select NET_SOCKETS
|
||||
select NET_SOCKETS_POSIX_NAMES
|
||||
select COAP
|
||||
select NET_CONFIG_NEED_IPV4
|
||||
select NET_CONFIG_SETTINGS
|
||||
select DNS_RESOLVER
|
||||
select JSON_LIBRARY
|
||||
select TINYCRYPT
|
||||
select TINYCRYPT_SHA256
|
||||
select HWINFO
|
||||
help
|
||||
UpdateHub is an enterprise-grade solution which makes simple to
|
||||
remotely update all your embbeded devices in the field. It
|
||||
handles all aspects related to sending Firmware Over-the-Air
|
||||
(FOTA) updates with maximum security and efficiency, while you
|
||||
focus in adding value to your product.
|
||||
|
||||
config UPDATEHUB_POLL_INTERVAL
|
||||
int "Time to poll interval (in minutes)"
|
||||
default 1440
|
||||
range 0 43200
|
||||
depends on UPDATEHUB
|
||||
help
|
||||
Set the interval that the UpdateHub update server will be polled.
|
||||
This time interval is zero and 43200 minutes(30 days).
|
||||
|
||||
config UPDATEHUB_PRODUCT_UID
|
||||
string "Product Unique Identifier (UID)"
|
||||
depends on UPDATEHUB
|
||||
help
|
||||
The product unique identifier is used when communicating
|
||||
with the UpdateHub server.
|
||||
|
||||
config UPDATEHUB_SUPPORTED_HARDWARE_MAX
|
||||
int "Max number of supported hardware"
|
||||
default 1
|
||||
range 1 100
|
||||
depends on UPDATEHUB
|
||||
help
|
||||
Configure the max number of supported hardware
|
||||
by the same image.
|
||||
|
||||
config UPDATEHUB_CE
|
||||
bool "Use UpdateHub Community Edition Sever"
|
||||
depends on UPDATEHUB
|
||||
help
|
||||
Allow the use of UpdateHub Community
|
||||
Server (updatehub-ce) as alternative to the
|
||||
updatehub.io enterprise server.
|
||||
|
||||
config UPDATEHUB_SERVER
|
||||
string "User address for the updatehub-ce-server"
|
||||
depends on UPDATEHUB_CE
|
||||
help
|
||||
This configuration is default, if need to use
|
||||
other address, must be set on the UpdateHub shell
|
||||
|
||||
config UPDATEHUB_SHELL
|
||||
bool "Enable UpdateHub shell utilities"
|
||||
depends on UPDATEHUB
|
||||
depends on SHELL
|
||||
select KERNEL_SHELL
|
||||
help
|
||||
Activate shell module that provides UpdateHub commands like
|
||||
|
||||
module = UPDATEHUB
|
||||
module-str = Log level for UpdateHub
|
||||
module-help = Enables logging for UpdateHub code.
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
83
lib/updatehub/shell.c
Normal file
83
lib/updatehub/shell.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <shell/shell.h>
|
||||
#include <flash.h>
|
||||
#include <dfu/mcuboot.h>
|
||||
#include <dfu/flash_img.h>
|
||||
#include <updatehub.h>
|
||||
#include "updatehub_firmware.h"
|
||||
#include "updatehub_device.h"
|
||||
|
||||
#if defined(CONFIG_UPDATEHUB_CE_SERVER)
|
||||
#define UPDATEHUB_SERVER CONFIG_UPDATEHUB_SERVER
|
||||
#else
|
||||
#define UPDATEHUB_SERVER "coap.updatehub.io"
|
||||
#endif
|
||||
|
||||
static int cmd_run(const struct shell *shell, size_t argc,
|
||||
char **argv)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
shell_fprintf(shell, SHELL_INFO, "Starting UpdateHub run...\n");
|
||||
|
||||
switch (updatehub_probe()) {
|
||||
case UPDATEHUB_HAS_UPDATE:
|
||||
switch (updatehub_update()) {
|
||||
case UPDATEHUB_OK:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
shell_fprintf(shell, SHELL_ERROR, "Error installing update.\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UPDATEHUB_NO_UPDATE:
|
||||
shell_fprintf(shell, SHELL_INFO, "No update found\n");
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
shell_fprintf(shell, SHELL_ERROR, "Invalid response\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmd_info(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
ARG_UNUSED(argc);
|
||||
ARG_UNUSED(argv);
|
||||
|
||||
char *device_id = k_malloc(DEVICE_ID_MAX_SIZE);
|
||||
char *firmware_version = k_malloc(BOOT_IMG_VER_STRLEN_MAX);
|
||||
|
||||
updatehub_get_firmware_version(firmware_version, BOOT_IMG_VER_STRLEN_MAX);
|
||||
updatehub_get_device_identity(device_id, DEVICE_ID_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);
|
||||
shell_fprintf(shell, SHELL_NORMAL, "Product uid: %s\n",
|
||||
CONFIG_UPDATEHUB_PRODUCT_UID);
|
||||
shell_fprintf(shell, SHELL_NORMAL, "UpdateHub Server: %s\n",
|
||||
UPDATEHUB_SERVER);
|
||||
|
||||
k_free(device_id);
|
||||
k_free(firmware_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_updatehub, SHELL_CMD(info, NULL, "Dump UpdateHub information",
|
||||
cmd_info),
|
||||
SHELL_CMD(run, NULL, "Trigger an UpdateHub update run", cmd_run),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_CMD_REGISTER(updatehub, &sub_updatehub, "UpdateHub commands", NULL);
|
768
lib/updatehub/updatehub.c
Normal file
768
lib/updatehub/updatehub.c
Normal file
|
@ -0,0 +1,768 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(updatehub);
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#include <logging/log_ctrl.h>
|
||||
#include <net/socket.h>
|
||||
#include <net/net_mgmt.h>
|
||||
#include <net/net_ip.h>
|
||||
#include <net/udp.h>
|
||||
#include <net/coap.h>
|
||||
#include <net/dns_resolve.h>
|
||||
#include <flash.h>
|
||||
#include <misc/reboot.h>
|
||||
#include <tinycrypt/sha256.h>
|
||||
#include <json.h>
|
||||
|
||||
#include <updatehub.h>
|
||||
#include "updatehub_priv.h"
|
||||
#include "updatehub_firmware.h"
|
||||
#include "updatehub_device.h"
|
||||
|
||||
#define NETWORK_TIMEOUT K_SECONDS(2)
|
||||
#define UPDATEHUB_POLL_INTERVAL K_MINUTES(CONFIG_UPDATEHUB_POLL_INTERVAL)
|
||||
#define MAX_PATH_SIZE 255
|
||||
#define MAX_PAYLOAD_SIZE 500
|
||||
#define MAX_DOWNLOAD_DATA 1100
|
||||
#define COAP_MAX_RETRY 3
|
||||
#define MAX_IP_SIZE 30
|
||||
|
||||
#if defined(CONFIG_UPDATEHUB_CE)
|
||||
#define UPDATEHUB_SERVER CONFIG_UPDATEHUB_SERVER
|
||||
#else
|
||||
#define UPDATEHUB_SERVER "coap.updatehub.io"
|
||||
#endif
|
||||
|
||||
static struct updatehub_context {
|
||||
struct coap_block_context block;
|
||||
struct k_sem semaphore;
|
||||
struct flash_img_context flash_ctx;
|
||||
struct tc_sha256_state_struct sha256sum;
|
||||
enum updatehub_response code_status;
|
||||
u8_t uri_path[MAX_PATH_SIZE];
|
||||
u8_t payload[MAX_PAYLOAD_SIZE];
|
||||
int downloaded_size;
|
||||
struct pollfd fds[1];
|
||||
int sock;
|
||||
int nfds;
|
||||
} ctx;
|
||||
|
||||
static struct update_info {
|
||||
char package_uid[TC_SHA256_BLOCK_SIZE + 1];
|
||||
char sha256sum_image[TC_SHA256_BLOCK_SIZE + 1];
|
||||
int image_size;
|
||||
} update_info;
|
||||
|
||||
static void wait_fds(void)
|
||||
{
|
||||
if (poll(ctx.fds, ctx.nfds, NETWORK_TIMEOUT) < 0) {
|
||||
LOG_ERR("Error in poll");
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_fds(void)
|
||||
{
|
||||
ctx.fds[ctx.nfds].fd = ctx.sock;
|
||||
ctx.fds[ctx.nfds].events = 1;
|
||||
ctx.nfds++;
|
||||
}
|
||||
|
||||
static int metadata_hash_get(char *metadata)
|
||||
{
|
||||
struct tc_sha256_state_struct sha256sum;
|
||||
unsigned char hash[TC_SHA256_DIGEST_SIZE];
|
||||
char buffer[3];
|
||||
int buffer_len = 0;
|
||||
|
||||
if (tc_sha256_init(&sha256sum) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tc_sha256_update(&sha256sum, metadata, strlen(metadata)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tc_sha256_final(hash, &sha256sum) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(update_info.package_uid, 0, TC_SHA256_BLOCK_SIZE + 1);
|
||||
for (int i = 0; i < TC_SHA256_DIGEST_SIZE; i++) {
|
||||
snprintk(buffer, sizeof(buffer), "%02x",
|
||||
hash[i]);
|
||||
buffer_len = buffer_len + strlen(buffer);
|
||||
strncat(&update_info.package_uid[i], buffer,
|
||||
MIN(TC_SHA256_BLOCK_SIZE, buffer_len));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_compatible_hardware(struct resp_probe_some_boards *metadata_some_boards)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < metadata_some_boards->supported_hardware_len; i++) {
|
||||
if (strncmp(metadata_some_boards->supported_hardware[i],
|
||||
CONFIG_BOARD, strlen(CONFIG_BOARD)) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool start_coap_client(void)
|
||||
{
|
||||
static struct addrinfo hints = { .ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM };
|
||||
struct addrinfo *addr;
|
||||
int resolve_attempts = 10;
|
||||
|
||||
while (resolve_attempts--) {
|
||||
if (getaddrinfo(UPDATEHUB_SERVER, "5683", &hints, &addr) == 0) {
|
||||
break;
|
||||
}
|
||||
if (resolve_attempts-- == 0) {
|
||||
LOG_ERR("Could not resolve dns");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.sock = socket(addr->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (ctx.sock < 0) {
|
||||
LOG_ERR("Failed to create UDP socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connect(ctx.sock, addr->ai_addr, addr->ai_addrlen) < 0) {
|
||||
LOG_ERR("Cannot connect to UDP remote");
|
||||
return false;
|
||||
}
|
||||
|
||||
prepare_fds();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cleanup_conection(void)
|
||||
{
|
||||
if (close(ctx.sock) < 0) {
|
||||
LOG_ERR("Could not close the socket");
|
||||
}
|
||||
|
||||
memset(&ctx.fds[1], 0, sizeof(ctx.fds[1]));
|
||||
ctx.nfds = 0;
|
||||
}
|
||||
|
||||
static int send_request(enum coap_msgtype msgtype, enum coap_method method,
|
||||
enum updatehub_uri_path type)
|
||||
{
|
||||
struct coap_packet request_packet;
|
||||
int ret = -1;
|
||||
u8_t content_application_json = 50;
|
||||
u8_t *data = k_malloc(MAX_PAYLOAD_SIZE);
|
||||
|
||||
if (data == NULL) {
|
||||
LOG_ERR("Could not alloc data memory");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_packet_init(&request_packet, data, MAX_PAYLOAD_SIZE, 1,
|
||||
COAP_TYPE_CON, 8, coap_next_token(), method,
|
||||
coap_next_id());
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not init packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case COAP_METHOD_GET:
|
||||
snprintk(ctx.uri_path, MAX_PATH_SIZE,
|
||||
"%s/%s/packages/%s/objects/%s", uri_path(type),
|
||||
CONFIG_UPDATEHUB_PRODUCT_UID, update_info.package_uid,
|
||||
update_info.sha256sum_image);
|
||||
|
||||
ret = coap_packet_append_option(&request_packet,
|
||||
COAP_OPTION_URI_PATH,
|
||||
ctx.uri_path,
|
||||
strlen(ctx.uri_path));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable add option to request path");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_append_block2_option(&request_packet,
|
||||
&ctx.block);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable coap append block 2");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_packet_append_option(&request_packet, 2048,
|
||||
UPDATEHUB_API_HEADER, strlen(UPDATEHUB_API_HEADER));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable add option to add updatehub header");
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case COAP_METHOD_POST:
|
||||
ret = coap_packet_append_option(&request_packet,
|
||||
COAP_OPTION_URI_PATH,
|
||||
uri_path(type),
|
||||
strlen(uri_path(type)));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable add option to request path");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_packet_append_option(&request_packet,
|
||||
COAP_OPTION_CONTENT_FORMAT,
|
||||
&content_application_json,
|
||||
sizeof(content_application_json));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable add option to request format");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_packet_append_option(&request_packet, 2048,
|
||||
UPDATEHUB_API_HEADER, strlen(UPDATEHUB_API_HEADER));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable add option to add updatehub header");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_packet_append_payload_marker(&request_packet);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to append payload marker");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = coap_packet_append_payload(&request_packet,
|
||||
&ctx.payload,
|
||||
strlen(ctx.payload));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Not able to append payload");
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("Invalid method");
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = send(ctx.sock, request_packet.data, request_packet.offset, 0);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not send request");
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
k_free(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void install_update_cb(void)
|
||||
{
|
||||
struct coap_packet response_packet;
|
||||
char buffer[3], sha256_image_dowloaded[TC_SHA256_BLOCK_SIZE + 1];
|
||||
u8_t *data = k_malloc(MAX_DOWNLOAD_DATA);
|
||||
int i, buffer_len = 0;
|
||||
int rcvd = -1;
|
||||
|
||||
if (data == NULL) {
|
||||
LOG_ERR("Could not alloc data memory");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wait_fds();
|
||||
|
||||
rcvd = recv(ctx.sock, data, MAX_DOWNLOAD_DATA, MSG_DONTWAIT);
|
||||
if (rcvd <= 0) {
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
LOG_ERR("Could not receive data");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (coap_packet_parse(&response_packet, data, rcvd, NULL, 0) < 0) {
|
||||
LOG_ERR("Invalid data received");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ctx.downloaded_size = ctx.downloaded_size +
|
||||
(response_packet.max_len - response_packet.offset);
|
||||
|
||||
if (tc_sha256_update(&ctx.sha256sum,
|
||||
response_packet.data + response_packet.offset,
|
||||
response_packet.max_len - response_packet.offset) < 1) {
|
||||
LOG_ERR("Could not update sha256sum");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (flash_img_buffered_write(&ctx.flash_ctx,
|
||||
response_packet.data + response_packet.offset,
|
||||
response_packet.max_len - response_packet.offset,
|
||||
ctx.downloaded_size == ctx.block.total_size) < 0) {
|
||||
LOG_ERR("Error to write on the flash");
|
||||
ctx.code_status = UPDATEHUB_INSTALL_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (coap_update_from_block(&response_packet, &ctx.block) < 0) {
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (coap_next_block(&response_packet, &ctx.block) == 0) {
|
||||
LOG_ERR("Could not get the next");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ctx.downloaded_size == ctx.block.total_size) {
|
||||
u8_t image_hash[TC_SHA256_DIGEST_SIZE];
|
||||
|
||||
if (tc_sha256_final(image_hash, &ctx.sha256sum) < 1) {
|
||||
LOG_ERR("Could not finish sha256sum");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(&sha256_image_dowloaded, 0, TC_SHA256_BLOCK_SIZE + 1);
|
||||
for (i = 0; i < TC_SHA256_DIGEST_SIZE; i++) {
|
||||
snprintk(buffer, sizeof(buffer), "%02x", image_hash[i]);
|
||||
buffer_len = buffer_len + strlen(buffer);
|
||||
strncat(&sha256_image_dowloaded[i], buffer,
|
||||
MIN(TC_SHA256_BLOCK_SIZE, buffer_len));
|
||||
}
|
||||
|
||||
if (strncmp(sha256_image_dowloaded,
|
||||
update_info.sha256sum_image,
|
||||
strlen(update_info.sha256sum_image)) != 0) {
|
||||
LOG_ERR("SHA256SUM of image are not the same");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.code_status = UPDATEHUB_OK;
|
||||
|
||||
cleanup:
|
||||
k_free(data);
|
||||
}
|
||||
|
||||
static enum updatehub_response install_update(void)
|
||||
{
|
||||
int verification_download = 0;
|
||||
int attempts_download = 0;
|
||||
|
||||
if (boot_erase_img_bank(DT_FLASH_AREA_IMAGE_1_ID) != 0) {
|
||||
LOG_ERR("Failed to init flash and erase second slot");
|
||||
ctx.code_status = UPDATEHUB_FLASH_INIT_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (tc_sha256_init(&ctx.sha256sum) < 1) {
|
||||
LOG_ERR("Could not start sha256sum");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!start_coap_client()) {
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (coap_block_transfer_init(&ctx.block, COAP_BLOCK_1024,
|
||||
update_info.image_size) < 0) {
|
||||
LOG_ERR("Unable init block transfer");
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
flash_img_init(&ctx.flash_ctx);
|
||||
|
||||
ctx.downloaded_size = 0;
|
||||
|
||||
while (ctx.downloaded_size != ctx.block.total_size) {
|
||||
verification_download = ctx.downloaded_size;
|
||||
|
||||
if (send_request(COAP_TYPE_CON, COAP_METHOD_GET,
|
||||
UPDATEHUB_DOWNLOAD) < 0) {
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
install_update_cb();
|
||||
|
||||
if (ctx.code_status != UPDATEHUB_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (verification_download == ctx.downloaded_size) {
|
||||
if (attempts_download == COAP_MAX_RETRY) {
|
||||
LOG_ERR("Could not get the packet");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
attempts_download++;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
cleanup_conection();
|
||||
|
||||
error:
|
||||
ctx.downloaded_size = 0;
|
||||
|
||||
return ctx.code_status;
|
||||
}
|
||||
|
||||
static int report(enum updatehub_state state)
|
||||
{
|
||||
struct report report;
|
||||
int ret = -1;
|
||||
const char *exec = state_name(state);
|
||||
char *device_id = k_malloc(DEVICE_ID_MAX_SIZE);
|
||||
char *firmware_version = k_malloc(BOOT_IMG_VER_STRLEN_MAX);
|
||||
|
||||
if (device_id == NULL || firmware_version == NULL) {
|
||||
LOG_ERR("Could not alloc device_id or firmware_version memory");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!updatehub_get_device_identity(device_id, DEVICE_ID_MAX_SIZE)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!updatehub_get_firmware_version(firmware_version, BOOT_IMG_VER_STRLEN_MAX)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&report, 0, sizeof(report));
|
||||
report.product_uid = CONFIG_UPDATEHUB_PRODUCT_UID;
|
||||
report.device_identity.id = device_id;
|
||||
report.version = firmware_version;
|
||||
report.hardware = CONFIG_BOARD;
|
||||
report.status = exec;
|
||||
report.package_uid = update_info.package_uid;
|
||||
|
||||
switch (ctx.code_status) {
|
||||
case UPDATEHUB_INSTALL_ERROR:
|
||||
report.previous_state =
|
||||
state_name(UPDATEHUB_STATE_INSTALLING);
|
||||
break;
|
||||
case UPDATEHUB_DOWNLOAD_ERROR:
|
||||
report.previous_state =
|
||||
state_name(UPDATEHUB_STATE_DOWNLOADING);
|
||||
break;
|
||||
case UPDATEHUB_FLASH_INIT_ERROR:
|
||||
report.previous_state =
|
||||
state_name(UPDATEHUB_FLASH_INIT_ERROR);
|
||||
break;
|
||||
default:
|
||||
report.previous_state = "";
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(report.previous_state, "", sizeof("") - 1) != 0) {
|
||||
report.error_message = updatehub_response(ctx.code_status);
|
||||
} else {
|
||||
report.error_message = "";
|
||||
}
|
||||
|
||||
memset(&ctx.payload, 0, MAX_PAYLOAD_SIZE);
|
||||
ret = json_obj_encode_buf(send_report_descr,
|
||||
ARRAY_SIZE(send_report_descr),
|
||||
&report, ctx.payload,
|
||||
MAX_PAYLOAD_SIZE - 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not encode metadata");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!start_coap_client()) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = send_request(COAP_TYPE_NON_CON, COAP_METHOD_POST,
|
||||
UPDATEHUB_REPORT);
|
||||
if (ret < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wait_fds();
|
||||
|
||||
cleanup:
|
||||
cleanup_conection();
|
||||
|
||||
error:
|
||||
k_free(firmware_version);
|
||||
k_free(device_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void probe_cb(char *metadata)
|
||||
{
|
||||
struct coap_packet reply;
|
||||
char tmp[MAX_PAYLOAD_SIZE];
|
||||
int rcvd = -1;
|
||||
|
||||
wait_fds();
|
||||
|
||||
rcvd = recv(ctx.sock, metadata, MAX_PAYLOAD_SIZE, MSG_DONTWAIT);
|
||||
if (rcvd <= 0) {
|
||||
LOG_ERR("Could not receive data");
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (coap_packet_parse(&reply, metadata, rcvd, NULL, 0) < 0) {
|
||||
LOG_ERR("Invalid data received");
|
||||
ctx.code_status = UPDATEHUB_DOWNLOAD_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (COAP_RESPONSE_CODE_NOT_FOUND == coap_header_get_code(&reply)) {
|
||||
LOG_INF("No update available");
|
||||
ctx.code_status = UPDATEHUB_NO_UPDATE;
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&tmp, 0, MAX_PAYLOAD_SIZE);
|
||||
memcpy(tmp, reply.data + reply.offset, reply.max_len - reply.offset);
|
||||
memset(metadata, 0, MAX_PAYLOAD_SIZE);
|
||||
memcpy(metadata, tmp, strlen(tmp));
|
||||
|
||||
ctx.code_status = UPDATEHUB_OK;
|
||||
|
||||
LOG_INF("Probe metadata received");
|
||||
}
|
||||
|
||||
enum updatehub_response updatehub_probe(void)
|
||||
{
|
||||
struct probe request;
|
||||
struct resp_probe_some_boards metadata_some_boards;
|
||||
struct resp_probe_any_boards metadata_any_boards;
|
||||
|
||||
char *metadata = k_malloc(MAX_PAYLOAD_SIZE);
|
||||
char *metadata_copy = k_malloc(MAX_PAYLOAD_SIZE);
|
||||
char *device_id = k_malloc(DEVICE_ID_MAX_SIZE);
|
||||
char *firmware_version = k_malloc(BOOT_IMG_VER_STRLEN_MAX);
|
||||
|
||||
if (device_id == NULL || firmware_version == NULL ||
|
||||
metadata == NULL || metadata_copy == NULL) {
|
||||
LOG_ERR("Could not alloc probe memory");
|
||||
ctx.code_status = UPDATEHUB_METADATA_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
k_sem_init(&ctx.semaphore, 0, 1);
|
||||
|
||||
if (!boot_is_img_confirmed()) {
|
||||
LOG_ERR("The current image is not confirmed");
|
||||
ctx.code_status = UPDATEHUB_UNCONFIRMED_IMAGE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!updatehub_get_firmware_version(firmware_version, BOOT_IMG_VER_STRLEN_MAX)) {
|
||||
ctx.code_status = UPDATEHUB_METADATA_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!updatehub_get_device_identity(device_id, DEVICE_ID_MAX_SIZE)) {
|
||||
ctx.code_status = UPDATEHUB_METADATA_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.product_uid = CONFIG_UPDATEHUB_PRODUCT_UID;
|
||||
request.device_identity.id = device_id;
|
||||
request.version = firmware_version;
|
||||
request.hardware = CONFIG_BOARD;
|
||||
|
||||
memset(&ctx.payload, 0, MAX_PAYLOAD_SIZE);
|
||||
if (json_obj_encode_buf(send_probe_descr,
|
||||
ARRAY_SIZE(send_probe_descr),
|
||||
&request, ctx.payload,
|
||||
MAX_PAYLOAD_SIZE - 1) < 0) {
|
||||
LOG_ERR("Could not encode metadata");
|
||||
ctx.code_status = UPDATEHUB_METADATA_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!start_coap_client()) {
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (send_request(COAP_TYPE_CON, COAP_METHOD_POST, UPDATEHUB_PROBE) < 0) {
|
||||
ctx.code_status = UPDATEHUB_NETWORKING_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(metadata, 0, MAX_PAYLOAD_SIZE);
|
||||
probe_cb(metadata);
|
||||
|
||||
if (ctx.code_status != UPDATEHUB_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(&update_info, 0, sizeof(update_info));
|
||||
if (metadata_hash_get(metadata) < 0) {
|
||||
LOG_ERR("Could not get metadata hash");
|
||||
ctx.code_status = UPDATEHUB_METADATA_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(metadata_copy, metadata, strlen(metadata));
|
||||
if (json_obj_parse(metadata, strlen(metadata),
|
||||
recv_probe_sh_array_descr,
|
||||
ARRAY_SIZE(recv_probe_sh_array_descr),
|
||||
&metadata_some_boards) < 0) {
|
||||
|
||||
if (json_obj_parse(metadata_copy, strlen(metadata_copy),
|
||||
recv_probe_sh_string_descr,
|
||||
ARRAY_SIZE(recv_probe_sh_string_descr),
|
||||
&metadata_any_boards) < 0) {
|
||||
LOG_ERR("Could not parse json");
|
||||
ctx.code_status = UPDATEHUB_METADATA_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(update_info.sha256sum_image,
|
||||
metadata_any_boards.objects[1].objects.sha256sum,
|
||||
strlen(metadata_any_boards.objects[1].objects.sha256sum));
|
||||
update_info.image_size = metadata_any_boards.objects[1].objects.size;
|
||||
} else {
|
||||
if (!is_compatible_hardware(&metadata_some_boards)) {
|
||||
LOG_ERR("Incompatible hardware");
|
||||
ctx.code_status =
|
||||
UPDATEHUB_INCOMPATIBLE_HARDWARE;
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(update_info.sha256sum_image,
|
||||
metadata_some_boards.objects[1].objects.sha256sum,
|
||||
strlen(metadata_some_boards.objects[1]
|
||||
.objects.sha256sum));
|
||||
update_info.image_size =
|
||||
metadata_some_boards.objects[1].objects.size;
|
||||
}
|
||||
|
||||
ctx.code_status = UPDATEHUB_HAS_UPDATE;
|
||||
|
||||
cleanup:
|
||||
cleanup_conection();
|
||||
|
||||
error:
|
||||
k_free(metadata);
|
||||
k_free(metadata_copy);
|
||||
k_free(firmware_version);
|
||||
k_free(device_id);
|
||||
|
||||
return ctx.code_status;
|
||||
}
|
||||
|
||||
enum updatehub_response updatehub_update(void)
|
||||
{
|
||||
if (report(UPDATEHUB_STATE_DOWNLOADING) < 0) {
|
||||
LOG_ERR("Could not reporting downloading state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (report(UPDATEHUB_STATE_INSTALLING) < 0) {
|
||||
LOG_ERR("Could not reporting installing state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (install_update() != UPDATEHUB_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (report(UPDATEHUB_STATE_DOWNLOADED) < 0) {
|
||||
LOG_ERR("Could not reporting downloaded state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (report(UPDATEHUB_STATE_INSTALLED) < 0) {
|
||||
LOG_ERR("Could not reporting installed state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (report(UPDATEHUB_STATE_REBOOTING) < 0) {
|
||||
LOG_ERR("Could not reporting rebooting state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOG_INF("Image flashed successfully, you can reboot now");
|
||||
|
||||
return ctx.code_status;
|
||||
|
||||
error:
|
||||
if (ctx.code_status != UPDATEHUB_NETWORKING_ERROR) {
|
||||
if (report(UPDATEHUB_STATE_ERROR) < 0) {
|
||||
LOG_ERR("Could not reporting error state");
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.code_status;
|
||||
}
|
||||
|
||||
static void autohandler(struct k_delayed_work *work)
|
||||
{
|
||||
switch (updatehub_probe()) {
|
||||
case UPDATEHUB_UNCONFIRMED_IMAGE:
|
||||
LOG_ERR("Image is unconfirmed. Rebooting to revert back to previous"
|
||||
"confirmed image.");
|
||||
|
||||
sys_reboot(SYS_REBOOT_WARM);
|
||||
break;
|
||||
|
||||
case UPDATEHUB_HAS_UPDATE:
|
||||
switch (updatehub_update()) {
|
||||
case UPDATEHUB_OK:
|
||||
sys_reboot(SYS_REBOOT_WARM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case UPDATEHUB_NO_UPDATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
k_delayed_work_submit(work, UPDATEHUB_POLL_INTERVAL);
|
||||
}
|
||||
|
||||
void updatehub_autohandler(void)
|
||||
{
|
||||
static struct k_delayed_work work;
|
||||
|
||||
k_delayed_work_init(&work, autohandler);
|
||||
k_delayed_work_submit(&work, 0);
|
||||
}
|
||||
|
29
lib/updatehub/updatehub_device.c
Normal file
29
lib/updatehub/updatehub_device.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "updatehub_device.h"
|
||||
|
||||
bool updatehub_get_device_identity(char *id, int id_max_len)
|
||||
{
|
||||
int i, id_len = 0, buf_len = 0;
|
||||
char buf[3];
|
||||
u8_t hwinfo_id[id_max_len];
|
||||
size_t length;
|
||||
|
||||
length = hwinfo_get_device_id(hwinfo_id, sizeof(hwinfo_id) - 1);
|
||||
if (length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(id, 0, id_max_len);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
snprintk(buf, sizeof(buf), "%02x", hwinfo_id[i]);
|
||||
id_len = strlen(id);
|
||||
strncat(id, buf, id_max_len - id_len);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
17
lib/updatehub/updatehub_device.h
Normal file
17
lib/updatehub/updatehub_device.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __UPDATEHUB_DEVICE_H__
|
||||
#define __UPDATEHUB_DEVICE_H__
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <hwinfo.h>
|
||||
|
||||
#define DEVICE_ID_MAX_SIZE 65
|
||||
|
||||
bool updatehub_get_device_identity(char *id, int id_max_len);
|
||||
|
||||
#endif /* __UPDATEHUB_DEVICE_H__ */
|
24
lib/updatehub/updatehub_firmware.c
Normal file
24
lib/updatehub/updatehub_firmware.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "updatehub_firmware.h"
|
||||
|
||||
bool updatehub_get_firmware_version(char *version, int version_len)
|
||||
{
|
||||
struct mcuboot_img_header header;
|
||||
|
||||
if (boot_read_bank_header(DT_FLASH_AREA_IMAGE_0_ID, &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;
|
||||
}
|
16
lib/updatehub/updatehub_firmware.h
Normal file
16
lib/updatehub/updatehub_firmware.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __UPDATEHUB_FIRMWARE_H__
|
||||
#define __UPDATEHUB_FIRMWARE_H__
|
||||
|
||||
#include <flash.h>
|
||||
#include <dfu/mcuboot.h>
|
||||
#include <dfu/flash_img.h>
|
||||
|
||||
bool updatehub_get_firmware_version(char *version, int version_len);
|
||||
|
||||
#endif /* __UPDATEHUB_FIRMWARE_H__ */
|
222
lib/updatehub/updatehub_priv.h
Normal file
222
lib/updatehub/updatehub_priv.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* @brief This file contains structures representing JSON messages
|
||||
* exchanged with a UpdateHub
|
||||
*/
|
||||
|
||||
#ifndef __UPDATEHUB_PRIV_H__
|
||||
#define __UPDATEHUB_PRIV_H__
|
||||
|
||||
#define UPDATEHUB_API_HEADER \
|
||||
"Api-Content-Type: application/vnd.updatehub-v1+json"
|
||||
|
||||
enum updatehub_uri_path {
|
||||
UPDATEHUB_PROBE = 0,
|
||||
UPDATEHUB_REPORT,
|
||||
UPDATEHUB_DOWNLOAD,
|
||||
};
|
||||
|
||||
enum updatehub_state {
|
||||
UPDATEHUB_STATE_DOWNLOADING = 0,
|
||||
UPDATEHUB_STATE_DOWNLOADED,
|
||||
UPDATEHUB_STATE_INSTALLING,
|
||||
UPDATEHUB_STATE_INSTALLED,
|
||||
UPDATEHUB_STATE_REBOOTING,
|
||||
UPDATEHUB_STATE_ERROR,
|
||||
};
|
||||
|
||||
static char *updatehub_response(enum updatehub_response response)
|
||||
{
|
||||
switch (response) {
|
||||
case UPDATEHUB_NETWORKING_ERROR:
|
||||
return "Fail to connect to the UpdateHub server";
|
||||
case UPDATEHUB_INCOMPATIBLE_HARDWARE:
|
||||
return "Incompatible hardware";
|
||||
case UPDATEHUB_METADATA_ERROR:
|
||||
return "Fail to parse or to encode the metadata";
|
||||
case UPDATEHUB_DOWNLOAD_ERROR:
|
||||
return "Fail while downloading the update package";
|
||||
case UPDATEHUB_INSTALL_ERROR:
|
||||
return "Fail while installing the update package";
|
||||
case UPDATEHUB_FLASH_INIT_ERROR:
|
||||
return "Fail to initilialize the flash";
|
||||
case UPDATEHUB_NO_UPDATE:
|
||||
return "No update available";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *uri_path(enum updatehub_uri_path type)
|
||||
{
|
||||
switch (type) {
|
||||
case UPDATEHUB_PROBE:
|
||||
return "upgrades";
|
||||
case UPDATEHUB_REPORT:
|
||||
return "report";
|
||||
case UPDATEHUB_DOWNLOAD:
|
||||
return "products";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *state_name(enum updatehub_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case UPDATEHUB_STATE_DOWNLOADING:
|
||||
return "downloading";
|
||||
case UPDATEHUB_STATE_DOWNLOADED:
|
||||
return "downloaded";
|
||||
case UPDATEHUB_STATE_INSTALLING:
|
||||
return "installing";
|
||||
case UPDATEHUB_STATE_INSTALLED:
|
||||
return "installed";
|
||||
case UPDATEHUB_STATE_REBOOTING:
|
||||
return "rebooting";
|
||||
case UPDATEHUB_STATE_ERROR:
|
||||
return "error";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct resp_probe_objects {
|
||||
const char *mode;
|
||||
const char *sha256sum;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct resp_probe_objects_array {
|
||||
struct resp_probe_objects objects;
|
||||
};
|
||||
|
||||
struct resp_probe_any_boards {
|
||||
struct resp_probe_objects_array objects[2];
|
||||
size_t objects_len;
|
||||
const char *product;
|
||||
const char *supported_hardware;
|
||||
};
|
||||
|
||||
struct resp_probe_some_boards {
|
||||
struct resp_probe_objects_array objects[2];
|
||||
size_t objects_len;
|
||||
const char *product;
|
||||
const char *supported_hardware[CONFIG_UPDATEHUB_SUPPORTED_HARDWARE_MAX];
|
||||
size_t supported_hardware_len;
|
||||
};
|
||||
|
||||
struct updatehub_config_device_identity {
|
||||
const char *id;
|
||||
};
|
||||
|
||||
struct report {
|
||||
const char *product_uid;
|
||||
const char *hardware;
|
||||
const char *version;
|
||||
struct updatehub_config_device_identity device_identity;
|
||||
const char *status;
|
||||
const char *package_uid;
|
||||
const char *error_message;
|
||||
const char *previous_state;
|
||||
};
|
||||
|
||||
struct probe {
|
||||
const char *product_uid;
|
||||
const char *hardware;
|
||||
const char *version;
|
||||
struct updatehub_config_device_identity device_identity;
|
||||
};
|
||||
|
||||
static const struct json_obj_descr recv_probe_objects_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM(struct resp_probe_objects,
|
||||
mode, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM(struct resp_probe_objects,
|
||||
sha256sum, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM(struct resp_probe_objects,
|
||||
size, JSON_TOK_NUMBER),
|
||||
};
|
||||
|
||||
static const struct json_obj_descr recv_probe_objects_descr_array[] = {
|
||||
JSON_OBJ_DESCR_OBJECT(struct resp_probe_objects_array,
|
||||
objects, recv_probe_objects_descr),
|
||||
};
|
||||
|
||||
static const struct json_obj_descr recv_probe_sh_string_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM(struct resp_probe_any_boards,
|
||||
product, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM_NAMED(struct resp_probe_any_boards,
|
||||
"supported-hardware", supported_hardware,
|
||||
JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_ARRAY_ARRAY(struct resp_probe_any_boards,
|
||||
objects, 2, objects_len,
|
||||
recv_probe_objects_descr_array,
|
||||
ARRAY_SIZE(recv_probe_objects_descr_array)),
|
||||
};
|
||||
|
||||
static const struct json_obj_descr recv_probe_sh_array_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM(struct resp_probe_some_boards,
|
||||
product, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_ARRAY_NAMED(struct resp_probe_some_boards,
|
||||
"supported-hardware", supported_hardware,
|
||||
CONFIG_UPDATEHUB_SUPPORTED_HARDWARE_MAX,
|
||||
supported_hardware_len, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_ARRAY_ARRAY(struct resp_probe_some_boards,
|
||||
objects, 2, objects_len,
|
||||
recv_probe_objects_descr_array,
|
||||
ARRAY_SIZE(recv_probe_objects_descr_array)),
|
||||
};
|
||||
|
||||
static const struct json_obj_descr device_identity_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM(struct updatehub_config_device_identity,
|
||||
id, JSON_TOK_STRING),
|
||||
};
|
||||
|
||||
static const struct json_obj_descr send_report_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM_NAMED(struct report,
|
||||
"product-uid", product_uid,
|
||||
JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_OBJECT_NAMED(struct report,
|
||||
"device-identity", device_identity,
|
||||
device_identity_descr),
|
||||
JSON_OBJ_DESCR_PRIM_NAMED(struct report,
|
||||
"error-message", error_message,
|
||||
JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM_NAMED(struct report,
|
||||
"previous-state", previous_state,
|
||||
JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM(struct report,
|
||||
version, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM(struct report,
|
||||
hardware, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM_NAMED(struct report,
|
||||
"package-uid", package_uid,
|
||||
JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM(struct report,
|
||||
status, JSON_TOK_STRING),
|
||||
};
|
||||
|
||||
static const struct json_obj_descr send_probe_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM_NAMED(struct probe,
|
||||
"product-uid", product_uid,
|
||||
JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_OBJECT_NAMED(struct probe,
|
||||
"device-identity", device_identity,
|
||||
device_identity_descr),
|
||||
JSON_OBJ_DESCR_PRIM(struct probe,
|
||||
version, JSON_TOK_STRING),
|
||||
JSON_OBJ_DESCR_PRIM(struct probe,
|
||||
hardware, JSON_TOK_STRING),
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __UPDATEHUB_PRIV_H__ */
|
13
samples/net/updatehub/CMakeLists.txt
Normal file
13
samples/net/updatehub/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2018 O.S.Systems
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
# This application has its own Kconfig options.
|
||||
set(KCONFIG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/Kconfig)
|
||||
|
||||
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
||||
project(NONE)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
25
samples/net/updatehub/Kconfig
Normal file
25
samples/net/updatehub/Kconfig
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# Copyright (c) 2018 O.S.Systems
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
mainmenu "Sample app Configuration"
|
||||
|
||||
config UPDATEHUB_MANUAL
|
||||
bool "UpdateHub manual mode"
|
||||
help
|
||||
Manual mode requires the user to call the server probe and then, if
|
||||
there is an available update, also requires the user to decide if
|
||||
it is appropriate to update now or later.
|
||||
|
||||
if !UPDATEHUB_MANUAL
|
||||
config UPDATEHUB_POLLING
|
||||
bool "UpdateHub polling mode"
|
||||
default y
|
||||
help
|
||||
Polling mode runs automatically on a predefined period, probing the
|
||||
server for updates and installing them without requiring user
|
||||
intervention.
|
||||
endif #!UPDATEHUB_MANUAL
|
||||
|
||||
source "$ZEPHYR_BASE/Kconfig.zephyr"
|
246
samples/net/updatehub/README.rst
Normal file
246
samples/net/updatehub/README.rst
Normal file
|
@ -0,0 +1,246 @@
|
|||
UpdateHub sample
|
||||
################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
UpdateHub is an enterprise-grade solution which makes it simple to remotely
|
||||
update all your embedded devices. It handles all aspects
|
||||
related to sending Firmware Over-the-Air (FOTA) updates with maximum
|
||||
security and efficiency, while you focus on adding value to your product.
|
||||
It is possible to read more about at `docs.updatehub.io`_.
|
||||
|
||||
This sample shows how to use UpdateHub in both a polling and manual update
|
||||
mode.
|
||||
|
||||
Polling mode runs automatically on a predefined period, probing the server
|
||||
for updates and installing them without requiring user intervention. You
|
||||
can access the sample source code for this mode updatehub_polling.
|
||||
|
||||
Manual mode requires the user to call the server probe and then, if there is
|
||||
an available update, also requires the user to decide if it is appropriate to
|
||||
update now or later. You can access the sample source code for this mode
|
||||
updatehub_manual.
|
||||
|
||||
Caveats
|
||||
*******
|
||||
|
||||
* The Zephyr port of ``UpdateHub`` is configured to run on a :ref:`Freedom-K64F <frdm_k64f>`
|
||||
MCU by default. The application should build and run for other platforms
|
||||
with offer support internet connection. Some platforms need some modification.
|
||||
Overlay files would be needed to support BLE 6lowpan, 802.15.4 or OpenThread
|
||||
configurations as well as the understanding that most other connectivity
|
||||
options would require an edge gateway of some sort (Border Router, etc).
|
||||
|
||||
* The MCUboot bootloader is required for ``UpdateHub`` to function
|
||||
properly. More information about the Device Firmware Upgrade subsystem and
|
||||
MCUboot can be found in :ref:`mcuboot`.
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
The below steps describe how to build and run the ``UpdateHub`` sample in
|
||||
Zephyr. Where examples are given, it is assumed the sample is being built for
|
||||
the Freedom-K64F Development Kit (``BOARD=fdrm_k64f``).
|
||||
|
||||
Step 1: Build MCUboot
|
||||
=====================
|
||||
|
||||
Build MCUboot by following the instructions in the :ref:`mcuboot` documentation
|
||||
page.
|
||||
|
||||
Step 2: Flash MCUboot
|
||||
=====================
|
||||
|
||||
Flash the resulting image file to the 0x0 address of the flash memory. This can
|
||||
be done in multiple ways, but the most common ones would be using make or ninja:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
make flash
|
||||
# or
|
||||
ninja flash
|
||||
|
||||
Step 3: Start the updatehub Community Edition
|
||||
=============================================
|
||||
|
||||
By default, the updatehub application is set to start on the UpdateHub Cloud.
|
||||
For more details on how to use the UpdateHub Cloud please refer to the
|
||||
documentation on `updatehub.io`_.
|
||||
|
||||
If you would like to use your own server, the steps below explain how
|
||||
updatehub works with updatehub-ce running, started by the
|
||||
following Docker command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
docker run -it -p 8080:8080 -p 5683:5683/udp --rm updatehub/updatehub-ce:latest
|
||||
|
||||
Using this server the user need create own ``overaly-prj.conf`` setting the option
|
||||
:option:`CONFIG_UPDATEHUB_SERVER` with your local ip address and the option
|
||||
:option:`CONFIG_UPDATEHUB_CE` with true. If the user will use polling mode on
|
||||
UpdateHub need too set the option :option:`CONFIG_UPDATEHUB_POLL_INTERVAL` with the period of
|
||||
your preference, remembering that the limit is between 0 minute until 43200 minutes(30 days).
|
||||
|
||||
Step 4: Build UpdateHub
|
||||
=======================
|
||||
|
||||
``UpdateHub`` can be built for the fdrm_k64f as follows:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/net/updatehub/
|
||||
:board: fdrm_k64f
|
||||
:conf: "prj.conf overlay-prj.conf"
|
||||
:goals: build
|
||||
|
||||
.. _updatehub_sample_sign:
|
||||
|
||||
Step 5: Sign the first image
|
||||
============================
|
||||
|
||||
From this section onwards you use a binary (``.bin``) image format.
|
||||
|
||||
Using MCUboot's :file:`imgtool.py` script, sign the :file:`zephyr.bin`
|
||||
file you built in Step 3. In the below example, the MCUboot repo is located at
|
||||
:file:`~/src/mcuboot`.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
~/src/mcuboot/scripts/imgtool.py sign \
|
||||
--key ~/src/mcuboot/root-rsa-2048.pem \
|
||||
--align 8 \
|
||||
--version 1.0.0 \
|
||||
--header-size 0x200 \
|
||||
--slot-size <image-slot-size> \
|
||||
--pad \
|
||||
<path-to-zephyr.bin> signed.bin
|
||||
|
||||
The command above creates an image file called :file:`signed.bin` in the
|
||||
current directory.
|
||||
|
||||
Step 6: Flash the first image
|
||||
=============================
|
||||
|
||||
Upload the :file:`signed.bin` file from Step 4 to image slot-0 of your
|
||||
board. The location of image slot-0 varies by board, as described in
|
||||
:ref:`mcuboot_partitions`. For the fdrm_k64f, slot-0 is located at address
|
||||
``0xc000``.
|
||||
|
||||
Using :file:`pyocd` you don't need to specify the slot-0 starting address.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
sudo pyocd-flashtool <path-to-signed.bin>
|
||||
|
||||
|
||||
Step 7: Signing the test image
|
||||
==============================
|
||||
|
||||
For the update to be correctly validated on the server, you must need sign the
|
||||
(``bin``) image, piping the output to another file.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
~/src/mcuboot/scripts/imgtool.py sign \
|
||||
--key ~/src/mcuboot/root-rsa-2048.pem \
|
||||
--align 8 \
|
||||
--version 2.0.0 \
|
||||
--header-size 0x200 \
|
||||
--slot-size <image-slot-size> \
|
||||
--pad \
|
||||
<path-to-zephyr.bin> signed_v2.bin
|
||||
|
||||
|
||||
Step 8: Create a package with UpdateHub Utilities (uhu)
|
||||
=======================================================
|
||||
|
||||
First, install UpdateHub Utilities (``uhu``) on your system, using:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip3 install --user uhu
|
||||
|
||||
After installing uhu you will need to set the ``product-uid``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
uhu product use "e4d37cfe6ec48a2d069cc0bbb8b078677e9a0d8df3a027c4d8ea131130c4265f"
|
||||
|
||||
Then, add the package and its mode (``zephyr``):
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
uhu package add signed_v2.bin -m zephyr
|
||||
|
||||
Then inform what ``version`` this image is:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
uhu package version 2.0.0
|
||||
|
||||
And finally you can build the package by running:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
uhu package archive --output <name-of-package>.pkg
|
||||
|
||||
|
||||
Step 9: Add the package to server
|
||||
==================================
|
||||
|
||||
Now, add the package to the updatehub-ce by, opening your browser to
|
||||
the server URL, ``<your-ip-address>:8080``, and logging into the server using
|
||||
``admin`` as the login and password by default. After logging in, click on
|
||||
the package menu, then ``UPLOAD PACKAGE``, and select the package built in
|
||||
step 7.
|
||||
|
||||
Step 10: Register device on server
|
||||
==================================
|
||||
|
||||
Register your device at updatehub-ce by using a terminal session on
|
||||
the system where you were debugging the board, and type the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
updatehub run
|
||||
|
||||
If everything is alright, it will print on the screen ``No update available``.
|
||||
|
||||
Step 11: Create a rollout
|
||||
=========================
|
||||
|
||||
In the browser where the updatehub-ce is open, click on ``menu Rollout``
|
||||
and then ``CREATE ROLLOUT``. Select the version of the package that you added
|
||||
in step 9. With that, the update is published, and the server is ready to
|
||||
accept update requests.
|
||||
|
||||
Step 12: Run the update
|
||||
=======================
|
||||
|
||||
Back in the terminal session that you used for debugging the board, type the
|
||||
following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
updatehub run
|
||||
|
||||
And then wait. The board will ping the server, check if there are any new
|
||||
updates, and then download the update package you've just created. If
|
||||
everything goes fine the message ``Image flashed successfully, you can reboot
|
||||
now`` will be printed on the terminal.
|
||||
|
||||
Step 13: Reboot the system
|
||||
==========================
|
||||
|
||||
In the terminal you used for debugging the board, type the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
kernel reboot cold
|
||||
|
||||
Your board will reboot and then start with the new image. After rebooting the
|
||||
board will automatically ping the server again and the message ``No update
|
||||
available`` will be printed on the terminal.
|
||||
|
||||
.. _updatehub.io: https://updatehub.io
|
||||
.. _docs.updatehub.io: https://docs.updatehub.io/
|
21
samples/net/updatehub/overlay-prj.conf.example
Normal file
21
samples/net/updatehub/overlay-prj.conf.example
Normal file
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# Copyright (c) 2018 O.S.Systems
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
|
||||
#Example of product_uid, you must set you product uid.
|
||||
CONFIG_UPDATEHUB_PRODUCT_UID="e4d37cfe6ec48a2d069cc0bbb8b078677e9a0d8df3a027c4d8ea131130c4265f"
|
||||
|
||||
#If you use the autorandler, need set UPDATEHUB_POLL_INTERVAL.
|
||||
#This example, the updatehub will poll on the server
|
||||
#request for updates one to one minute.
|
||||
#(min: 0 minute, máx: 30 days)
|
||||
CONFIG_UPDATEHUB_POLL_INTERVAL=1
|
||||
|
||||
CONFIG_UPDATEHUB_CE=y
|
||||
|
||||
#You need set the updatehub-ce ip Address.
|
||||
#This is a example of ip address
|
||||
CONFIG_UPDATEHUB_SERVER="10.5.3.67"
|
16
samples/net/updatehub/prj.conf
Normal file
16
samples/net/updatehub/prj.conf
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Turn on the updatehub
|
||||
CONFIG_UPDATEHUB=y
|
||||
|
||||
#Minimal Heap mem pool size for the updatehub working
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=2048
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
|
||||
|
||||
CONFIG_NET_DHCPV4=y
|
||||
|
||||
#Optional if you would like test on the your server
|
||||
CONFIG_SHELL=y
|
||||
CONFIG_UPDATEHUB_SHELL=y
|
||||
|
||||
# Debug helpers
|
||||
CONFIG_LOG=y
|
||||
CONFIG_UPDATEHUB_LOG_LEVEL_INF=y
|
63
samples/net/updatehub/src/main.c
Normal file
63
samples/net/updatehub/src/main.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2018 O.S.Systems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <updatehub.h>
|
||||
#include <dfu/mcuboot.h>
|
||||
#include <misc/printk.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(main);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
LOG_INF("UpdateHub sample app started");
|
||||
|
||||
/* The image of application needed be confirmed */
|
||||
LOG_INF("Confirming the boot image");
|
||||
ret = boot_write_img_confirmed();
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Error to confirm the image");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_UPDATEHUB_POLLING)
|
||||
LOG_INF("Starting UpdateHub polling mode");
|
||||
updatehub_autohandler();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_UPDATEHUB_MANUAL)
|
||||
LOG_INF("Starting UpdateHub manual mode");
|
||||
|
||||
enum updatehub_response resp;
|
||||
|
||||
switch (updatehub_probe()) {
|
||||
case UPDATEHUB_HAS_UPDATE:
|
||||
switch (updatehub_update()) {
|
||||
case UPDATEHUB_OK:
|
||||
ret = 0;
|
||||
sys_reboot(SYS_REBOOT_WARM);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("Error installing update.");
|
||||
break;
|
||||
}
|
||||
|
||||
case UPDATEHUB_NO_UPDATE:
|
||||
LOG_INF("No update found");
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("Invalid response");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue