mgmt: hawkbit: seperate autohandler

seperate the autohandler from the main
hawkbit source. This way the autohandler can
be disabled if it is not needed.

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
This commit is contained in:
Fin Maaß 2024-05-21 17:11:00 +02:00 committed by Fabio Baltieri
parent 621cf5baec
commit dce3d2de66
5 changed files with 198 additions and 171 deletions

View file

@ -88,62 +88,6 @@ int hawkbit_set_custom_data_cb(hawkbit_config_device_data_cb_handler_t cb);
*/ */
int hawkbit_init(void); 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.
*
* @param auto_reschedule If true, the handler will reschedule itself
*/
void hawkbit_autohandler(bool auto_reschedule);
/**
* @brief Wait for the autohandler to finish.
*
* @param events Set of desired events on which to wait. Set to ::UINT32_MAX to wait for the
* autohandler to finish one run, or BIT() together with a value from
* ::hawkbit_response to wait for a specific event.
* @param timeout Waiting period for the desired set of events or one of the
* special values ::K_NO_WAIT and ::K_FOREVER.
*
* @retval HAWKBIT_OK if success.
* @retval HAWKBIT_NO_RESPONSE if matching events were not received within the specified time
* @retval HAWKBIT_NETWORKING_ERROR fail to connect to the hawkBit server.
* @retval HAWKBIT_UNCONFIRMED_IMAGE image is unconfirmed.
* @retval HAWKBIT_PERMISSION_ERROR fail to get the permission to access the hawkBit server.
* @retval HAWKBIT_METADATA_ERROR fail to parse or to encode the metadata.
* @retval HAWKBIT_DOWNLOAD_ERROR fail while downloading the update package.
* @retval HAWKBIT_UPDATE_INSTALLED if an update was installed. Reboot is required to apply it.
* @retval HAWKBIT_NO_UPDATE if no update was available.
* @retval HAWKBIT_CANCEL_UPDATE update was cancelled.
* @retval HAWKBIT_NOT_INITIALIZED if hawkBit is not initialized.
* @retval HAWKBIT_PROBE_IN_PROGRESS if probe is currently running.
*/
enum hawkbit_response hawkbit_autohandler_wait(uint32_t events, k_timeout_t timeout);
/**
* @brief Cancel the run of the hawkBit autohandler.
*
* @return a value from k_work_cancel_delayable().
*/
int hawkbit_autohandler_cancel(void);
/**
* @brief Set the delay for the next run of the autohandler.
*
* @details This function will only delay the next run of the autohandler. The delay will not
* persist after the autohandler runs.
*
* @param timeout The delay to set.
* @param if_bigger If true, the delay will be set only if the new delay is bigger than the current
* one.
*
* @retval 0 if @a if_bigger was true and the current delay was bigger than the new one.
* @retval otherwise, a value from k_work_reschedule().
*/
int hawkbit_autohandler_set_delay(k_timeout_t timeout, bool if_bigger);
/** /**
* @brief The hawkBit probe verify if there is some update to be performed. * @brief The hawkBit probe verify if there is some update to be performed.
* *
@ -330,6 +274,70 @@ uint32_t hawkbit_get_poll_interval(void);
int hawkbit_reset_action_id(void); int hawkbit_reset_action_id(void);
/** /**
* @brief hawkBit autohandler.
* @defgroup hawkbit_autohandler hawkBit autohandler
* @ingroup hawkbit
* @{
*/
/**
* @brief Runs hawkBit probe and hawkBit update automatically
*
* @details The hawkbit_autohandler handles the whole process
* in pre-determined time intervals.
*
* @param auto_reschedule If true, the handler will reschedule itself
*/
void hawkbit_autohandler(bool auto_reschedule);
/**
* @brief Wait for the autohandler to finish.
*
* @param events Set of desired events on which to wait. Set to ::UINT32_MAX to wait for the
* autohandler to finish one run, or BIT() together with a value from
* ::hawkbit_response to wait for a specific event.
* @param timeout Waiting period for the desired set of events or one of the
* special values ::K_NO_WAIT and ::K_FOREVER.
*
* @retval HAWKBIT_OK if success.
* @retval HAWKBIT_NO_RESPONSE if matching events were not received within the specified time
* @retval HAWKBIT_NETWORKING_ERROR fail to connect to the hawkBit server.
* @retval HAWKBIT_UNCONFIRMED_IMAGE image is unconfirmed.
* @retval HAWKBIT_PERMISSION_ERROR fail to get the permission to access the hawkBit server.
* @retval HAWKBIT_METADATA_ERROR fail to parse or to encode the metadata.
* @retval HAWKBIT_DOWNLOAD_ERROR fail while downloading the update package.
* @retval HAWKBIT_UPDATE_INSTALLED if an update was installed. Reboot is required to apply it.
* @retval HAWKBIT_NO_UPDATE if no update was available.
* @retval HAWKBIT_CANCEL_UPDATE update was cancelled.
* @retval HAWKBIT_NOT_INITIALIZED if hawkBit is not initialized.
* @retval HAWKBIT_PROBE_IN_PROGRESS if probe is currently running.
*/
enum hawkbit_response hawkbit_autohandler_wait(uint32_t events, k_timeout_t timeout);
/**
* @brief Cancel the run of the hawkBit autohandler.
*
* @return a value from k_work_cancel_delayable().
*/
int hawkbit_autohandler_cancel(void);
/**
* @brief Set the delay for the next run of the autohandler.
*
* @details This function will only delay the next run of the autohandler. The delay will not
* persist after the autohandler runs.
*
* @param timeout The delay to set.
* @param if_bigger If true, the delay will be set only if the new delay is bigger than the current
* one.
*
* @retval 0 if @a if_bigger was true and the current delay was bigger than the new one.
* @retval otherwise, a value from k_work_reschedule().
*/
int hawkbit_autohandler_set_delay(k_timeout_t timeout, bool if_bigger);
/**
* @}
* @} * @}
*/ */

View file

@ -7,6 +7,7 @@
zephyr_library() zephyr_library()
zephyr_library_sources_ifdef(CONFIG_HAWKBIT hawkbit.c) zephyr_library_sources_ifdef(CONFIG_HAWKBIT hawkbit.c)
zephyr_library_sources_ifdef(CONFIG_HAWKBIT_AUTOHANDLER hawkbit_autohandler.c)
zephyr_library_sources_ifdef(CONFIG_HAWKBIT hawkbit_device.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 hawkbit_firmware.c)
zephyr_library_sources_ifdef(CONFIG_HAWKBIT_SHELL shell.c) zephyr_library_sources_ifdef(CONFIG_HAWKBIT_SHELL shell.c)

View file

@ -15,7 +15,6 @@ menuconfig HAWKBIT
depends on DNS_RESOLVER depends on DNS_RESOLVER
depends on JSON_LIBRARY depends on JSON_LIBRARY
depends on BOOTLOADER_MCUBOOT depends on BOOTLOADER_MCUBOOT
select EVENTS
select MPU_ALLOW_FLASH_WRITE select MPU_ALLOW_FLASH_WRITE
select IMG_ENABLE_IMAGE_CHECK select IMG_ENABLE_IMAGE_CHECK
select IMG_ERASE_PROGRESSIVELY select IMG_ERASE_PROGRESSIVELY
@ -34,9 +33,17 @@ config HAWKBIT_POLL_INTERVAL
This time interval is zero and 43200 minutes(30 days). This will be overridden This time interval is zero and 43200 minutes(30 days). This will be overridden
by the value configured in the settings of the hawkBit server. by the value configured in the settings of the hawkBit server.
config HAWKBIT_AUTOHANDLER
bool "hawkBit autohandler"
select EVENTS
default y
help
Activate autohandler to handle the update process automatically.
config HAWKBIT_SHELL config HAWKBIT_SHELL
bool "hawkBit shell utilities" bool "hawkBit shell utilities"
depends on SHELL depends on SHELL
depends on HAWKBIT_AUTOHANDLER
help help
Activate shell module that provides hawkBit commands. Activate shell module that provides hawkBit commands.

View file

@ -145,13 +145,6 @@ int hawkbit_default_config_data_cb(const char *device_id, uint8_t *buffer,
static hawkbit_config_device_data_cb_handler_t hawkbit_config_device_data_cb_handler = static hawkbit_config_device_data_cb_handler_t hawkbit_config_device_data_cb_handler =
hawkbit_default_config_data_cb; hawkbit_default_config_data_cb;
static void autohandler(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(hawkbit_work_handle, autohandler);
static K_WORK_DELAYABLE_DEFINE(hawkbit_work_handle_once, autohandler);
static K_EVENT_DEFINE(hawkbit_autohandler_event);
K_SEM_DEFINE(probe_sem, 1, 1); K_SEM_DEFINE(probe_sem, 1, 1);
static const struct json_obj_descr json_href_descr[] = { static const struct json_obj_descr json_href_descr[] = {
@ -1480,110 +1473,3 @@ error:
k_sem_give(&probe_sem); k_sem_give(&probe_sem);
return hb_context.code_status; return hb_context.code_status;
} }
static void autohandler(struct k_work *work)
{
k_event_clear(&hawkbit_autohandler_event, UINT32_MAX);
enum hawkbit_response response = hawkbit_probe();
k_event_set(&hawkbit_autohandler_event, BIT(response));
switch (response) {
case HAWKBIT_UNCONFIRMED_IMAGE:
LOG_ERR("Current image is not confirmed");
LOG_ERR("Rebooting to previous confirmed image");
LOG_ERR("If this image is flashed using a hardware tool");
LOG_ERR("Make sure that it is a confirmed image");
hawkbit_reboot();
break;
case HAWKBIT_NO_UPDATE:
LOG_INF("No update found");
break;
case HAWKBIT_CANCEL_UPDATE:
LOG_INF("hawkBit update cancelled from server");
break;
case HAWKBIT_OK:
LOG_INF("Image is already updated");
break;
case HAWKBIT_UPDATE_INSTALLED:
LOG_INF("Update installed");
hawkbit_reboot();
break;
case HAWKBIT_DOWNLOAD_ERROR:
LOG_INF("Update failed");
break;
case HAWKBIT_NETWORKING_ERROR:
LOG_INF("Network error");
break;
case HAWKBIT_PERMISSION_ERROR:
LOG_INF("Permission error");
break;
case HAWKBIT_METADATA_ERROR:
LOG_INF("Metadata error");
break;
case HAWKBIT_NOT_INITIALIZED:
LOG_INF("hawkBit not initialized");
break;
case HAWKBIT_PROBE_IN_PROGRESS:
LOG_INF("hawkBit is already running");
break;
default:
LOG_ERR("Invalid response: %d", response);
break;
}
if (k_work_delayable_from_work(work) == &hawkbit_work_handle) {
k_work_reschedule(&hawkbit_work_handle, K_SECONDS(poll_sleep));
}
}
enum hawkbit_response hawkbit_autohandler_wait(uint32_t events, k_timeout_t timeout)
{
uint32_t ret = k_event_wait(&hawkbit_autohandler_event, events, false, timeout);
for (int i = 1; i < HAWKBIT_PROBE_IN_PROGRESS; i++) {
if (ret & BIT(i)) {
return i;
}
}
return HAWKBIT_NO_RESPONSE;
}
int hawkbit_autohandler_cancel(void)
{
return k_work_cancel_delayable(&hawkbit_work_handle);
}
int hawkbit_autohandler_set_delay(k_timeout_t timeout, bool if_bigger)
{
if (!if_bigger || timeout.ticks > k_work_delayable_remaining_get(&hawkbit_work_handle)) {
hawkbit_autohandler_cancel();
LOG_INF("Setting new delay for next run: %02u:%02u:%02u",
(uint32_t)(timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) / 3600,
(uint32_t)((timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) % 3600) / 60,
(uint32_t)(timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) % 60);
return k_work_reschedule(&hawkbit_work_handle, timeout);
}
return 0;
}
void hawkbit_autohandler(bool auto_reschedule)
{
if (auto_reschedule) {
k_work_reschedule(&hawkbit_work_handle, K_NO_WAIT);
} else {
k_work_reschedule(&hawkbit_work_handle_once, K_NO_WAIT);
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2024 Vogl Electronic GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/mgmt/hawkbit.h>
LOG_MODULE_DECLARE(hawkbit);
static void autohandler(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(hawkbit_work_handle, autohandler);
static K_WORK_DELAYABLE_DEFINE(hawkbit_work_handle_once, autohandler);
static K_EVENT_DEFINE(hawkbit_autohandler_event);
static void autohandler(struct k_work *work)
{
k_event_clear(&hawkbit_autohandler_event, UINT32_MAX);
enum hawkbit_response response = hawkbit_probe();
k_event_set(&hawkbit_autohandler_event, BIT(response));
switch (response) {
case HAWKBIT_UNCONFIRMED_IMAGE:
LOG_ERR("Current image is not confirmed");
LOG_ERR("Rebooting to previous confirmed image");
LOG_ERR("If this image is flashed using a hardware tool");
LOG_ERR("Make sure that it is a confirmed image");
hawkbit_reboot();
break;
case HAWKBIT_NO_UPDATE:
LOG_INF("No update found");
break;
case HAWKBIT_CANCEL_UPDATE:
LOG_INF("hawkBit update cancelled from server");
break;
case HAWKBIT_OK:
LOG_INF("Image is already updated");
break;
case HAWKBIT_UPDATE_INSTALLED:
LOG_INF("Update installed");
hawkbit_reboot();
break;
case HAWKBIT_DOWNLOAD_ERROR:
LOG_INF("Update failed");
break;
case HAWKBIT_NETWORKING_ERROR:
LOG_INF("Network error");
break;
case HAWKBIT_PERMISSION_ERROR:
LOG_INF("Permission error");
break;
case HAWKBIT_METADATA_ERROR:
LOG_INF("Metadata error");
break;
case HAWKBIT_NOT_INITIALIZED:
LOG_INF("hawkBit not initialized");
break;
case HAWKBIT_PROBE_IN_PROGRESS:
LOG_INF("hawkBit is already running");
break;
default:
LOG_ERR("Invalid response: %d", response);
break;
}
if (k_work_delayable_from_work(work) == &hawkbit_work_handle) {
k_work_reschedule(&hawkbit_work_handle, K_SECONDS(hawkbit_get_poll_interval()));
}
}
enum hawkbit_response hawkbit_autohandler_wait(uint32_t events, k_timeout_t timeout)
{
uint32_t ret = k_event_wait(&hawkbit_autohandler_event, events, false, timeout);
for (int i = 1; i < HAWKBIT_PROBE_IN_PROGRESS; i++) {
if (ret & BIT(i)) {
return i;
}
}
return HAWKBIT_NO_RESPONSE;
}
int hawkbit_autohandler_cancel(void)
{
return k_work_cancel_delayable(&hawkbit_work_handle);
}
int hawkbit_autohandler_set_delay(k_timeout_t timeout, bool if_bigger)
{
if (!if_bigger || timeout.ticks > k_work_delayable_remaining_get(&hawkbit_work_handle)) {
hawkbit_autohandler_cancel();
LOG_INF("Setting new delay for next run: %02u:%02u:%02u",
(uint32_t)(timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) / 3600,
(uint32_t)((timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) % 3600) / 60,
(uint32_t)(timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) % 60);
return k_work_reschedule(&hawkbit_work_handle, timeout);
}
return 0;
}
void hawkbit_autohandler(bool auto_reschedule)
{
if (auto_reschedule) {
k_work_reschedule(&hawkbit_work_handle, K_NO_WAIT);
} else {
k_work_reschedule(&hawkbit_work_handle_once, K_NO_WAIT);
}
}