Skip to content

Commit

Permalink
mgmt: hawkbit: add callbacks for events
Browse files Browse the repository at this point in the history
add callbacks for events.

Signed-off-by: Fin Maaß <[email protected]>
  • Loading branch information
maass-hamburg committed Jun 5, 2024
1 parent 17d6539 commit 4199637
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 2 deletions.
161 changes: 161 additions & 0 deletions include/zephyr/mgmt/hawkbit/event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2024 Vogl Electronic GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @file
* @brief hawkBit event header file
*/

/**
* @brief hawkBit event API.
* @defgroup hawkbit_event hawkBit event API
* @ingroup hawkbit
* @{
*/

#ifndef ZEPHYR_INCLUDE_MGMT_HAWKBIT_EVENT_H_
#define ZEPHYR_INCLUDE_MGMT_HAWKBIT_EVENT_H_

#include <zephyr/kernel.h>
#include <zephyr/sys/slist.h>

/**
* @brief hawkBit event type.
*
* @details These events are used to register the callback functions.
*
*/
enum hawkbit_event_type {
/** Event triggered when there was an error */
HAWKBIT_EVENT_ERROR,
/** Event triggered when there was a networking error */
HAWKBIT_EVENT_ERROR_NETWORKING,
/** Event triggered when there was a permission error */
HAWKBIT_EVENT_ERROR_PERMISSION,
/** Event triggered when there was a metadata error */
HAWKBIT_EVENT_ERROR_METADATA,
/** Event triggered when there was a download error */
HAWKBIT_EVENT_ERROR_DOWNLOAD,
/** Event triggered when there was an allocation error */
HAWKBIT_EVENT_ERROR_ALLOC,
/** Event triggered when a new update was downloaded */
HAWKBIT_EVENT_UPDATE_DOWNLOADED,
/** Event triggered when there is no update available */
HAWKBIT_EVENT_NO_UPDATE,
/** Event triggered when the update was canceled by the server */
HAWKBIT_EVENT_CANCEL_UPDATE,
/** Event triggered before the download starts */
HAWKBIT_EVENT_START_DOWNLOAD,
/** Event triggered after the download ends */
HAWKBIT_EVENT_END_DOWNLOAD,
/** Event triggered before the hawkBit run starts */
HAWKBIT_EVENT_START_RUN,
/** Event triggered after the hawkBit run ends */
HAWKBIT_EVENT_END_RUN,
/** Event triggered before hawkBit does a reboot */
HAWKBIT_EVENT_BEFORE_REBOOT,
};

struct hawkbit_event_callback;

/**
* @typedef hawkbit_event_callback_handler_t
* @brief Define the application callback handler function signature
*
* @param cb Original struct hawkbit_event_callback owning this handler
* @param event The event that triggered the callback
*
* Note: cb pointer can be used to retrieve private data through
* CONTAINER_OF() if original struct hawkbit_event_callback is stored in
* another private structure.
*/
typedef void (*hawkbit_event_callback_handler_t)(struct hawkbit_event_callback *cb,
enum hawkbit_event_type event);

/** @cond INTERNAL_HIDDEN */

/**
* @brief hawkBit callback structure
*
* Used to register a callback in the hawkBit callback list.
* As many callbacks as needed can be added as long as each of them
* are unique pointers of struct hawkbit_event_callback.
* Beware such structure should not be allocated on stack.
*
* Note: To help setting it, see hawkbit_event_init_callback() below
*/
struct hawkbit_event_callback {
/** This is meant to be used internally and the user should not
* mess with it.
*/
sys_snode_t node;

/** Actual callback function being called when relevant. */
hawkbit_event_callback_handler_t handler;

/** The event type this callback is attached to. */
enum hawkbit_event_type event;
};

/** @endcond */


/**
* @brief Macro to create and initialize a struct hawkbit_event_callback properly.
*
* @details This macro can be used instead of hawkbit_event_init_callback().
*
* @param _callback Name of the callback structure
* @param _handler A valid handler function pointer.
* @param _event The event of ::hawkbit_event_type that will trigger the callback
*/
#define HAWKBIT_EVENT_CREATE_CALLBACK(_callback, _handler, _event) \
struct hawkbit_event_callback _callback = { \
.handler = _handler, \
.event = _event, \
}

/**
* @brief Helper to initialize a struct hawkbit_event_callback properly
*
* @param callback A valid Application's callback structure pointer.
* @param handler A valid handler function pointer.
* @param event The event of ::hawkbit_event_type that will trigger the callback.
*/
static inline void hawkbit_event_init_callback(struct hawkbit_event_callback *callback,
hawkbit_event_callback_handler_t handler,
enum hawkbit_event_type event)
{
__ASSERT(callback, "Callback pointer should not be NULL");
__ASSERT(handler, "Callback handler pointer should not be NULL");

callback->handler = handler;
callback->event = event;
}

/**
* @brief Add an application callback.
*
* @param cb A valid application's callback structure pointer.
*
* @return 0 if successful, negative errno code on failure.
*/
int hawkbit_event_add_callback(struct hawkbit_event_callback *cb);

/**
* @brief Remove an application callback.
*
* @param cb A valid application's callback structure pointer.
*
* @return 0 if successful, negative errno code on failure.
*/
int hawkbit_event_remove_callback(struct hawkbit_event_callback *cb);

/**
* @}
*/

#endif /* ZEPHYR_INCLUDE_MGMT_HAWKBIT_EVENT_H_ */
5 changes: 5 additions & 0 deletions subsys/mgmt/hawkbit/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ config HAWKBIT_REBOOT_COLD

endchoice

config HAWKBIT_EVENT_CALLBACKS
bool "Set hawkBit event callbacks"
help
Be able to set event callbacks for hawkBit.

module = HAWKBIT
module-str = Log Level for hawkbit
module-help = Enables logging for hawkBit code.
Expand Down
108 changes: 106 additions & 2 deletions subsys/mgmt/hawkbit/hawkbit.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <zephyr/logging/log_ctrl.h>
#include <zephyr/mgmt/hawkbit/hawkbit.h>
#include <zephyr/mgmt/hawkbit/config.h>
#include <zephyr/mgmt/hawkbit/event.h>
#include <zephyr/net/dns_resolve.h>
#include <zephyr/net/http/client.h>
#include <zephyr/net/net_ip.h>
Expand Down Expand Up @@ -166,6 +167,10 @@ static hawkbit_config_device_data_cb_handler_t hawkbit_config_device_data_cb_han

K_SEM_DEFINE(probe_sem, 1, 1);

#ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
static sys_slist_t event_callbacks = SYS_SLIST_STATIC_INIT(&event_callbacks);
#endif

static const struct json_obj_descr json_href_descr[] = {
JSON_OBJ_DESCR_PRIM(struct hawkbit_href, href, JSON_TOK_STRING),
};
Expand Down Expand Up @@ -359,6 +364,56 @@ static int hawkbit_settings_export(int (*cb)(const char *name, const void *value
SETTINGS_STATIC_HANDLER_DEFINE(hawkbit, "hawkbit", NULL, hawkbit_settings_set, NULL,
hawkbit_settings_export);

static void hawkbit_event_raise(enum hawkbit_event_type event)
{
#ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
struct hawkbit_event_callback *cb, *tmp;

SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&event_callbacks, cb, tmp, node) {
if (cb->event == event && cb->handler) {
cb->handler(cb, event);
}
}
#endif
}

#ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
int hawkbit_event_add_callback(struct hawkbit_event_callback *cb)
{
int ret = 0;

if (cb == NULL || cb->handler == NULL) {
return -EINVAL;
}

ret = k_sem_take(&probe_sem, K_FOREVER);
if (ret == 0) {
sys_slist_prepend(&event_callbacks, &cb->node);
k_sem_give(&probe_sem);
}
return ret;
}

int hawkbit_event_remove_callback(struct hawkbit_event_callback *cb)
{
int ret = 0;

if (cb == NULL || cb->handler == NULL) {
return -EINVAL;
}

ret = k_sem_take(&probe_sem, K_FOREVER);
if (ret == 0) {
if (!sys_slist_find_and_remove(&event_callbacks, &cb->node)) {
ret = -EINVAL;
}
k_sem_give(&probe_sem);
}

return ret;
}
#endif /* CONFIG_HAWKBIT_EVENT_CALLBACKS */

static bool start_http_client(int *hb_sock)
{
int ret = -1;
Expand Down Expand Up @@ -1030,6 +1085,7 @@ static bool send_request(struct hawkbit_context *hb_context, enum hawkbit_http_r

void hawkbit_reboot(void)
{
hawkbit_event_raise(HAWKBIT_EVENT_BEFORE_REBOOT);
LOG_PANIC();
sys_reboot(IS_ENABLED(CONFIG_HAWKBIT_REBOOT_COLD) ? SYS_REBOOT_COLD : SYS_REBOOT_WARM);
}
Expand Down Expand Up @@ -1184,6 +1240,7 @@ static void s_probe(void *o)
}

s->hb_context.code_status = HAWKBIT_NO_UPDATE;
hawkbit_event_raise(HAWKBIT_EVENT_NO_UPDATE);
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
}

Expand Down Expand Up @@ -1243,6 +1300,10 @@ static void s_cancel(void *o)
LOG_INF("From hawkBit server requested update cancellation %s",
hb_cfg.action_id == cancel_action_id ? "rejected" : "accepted");

if (hb_cfg.action_id != cancel_action_id) {
hawkbit_event_raise(HAWKBIT_EVENT_CANCEL_UPDATE);
}

smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_PROBE]);
}

Expand Down Expand Up @@ -1367,6 +1428,16 @@ static void s_report(void *o)
smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_PROBE]);
}

static void s_download_start(void *o)
{
hawkbit_event_raise(HAWKBIT_EVENT_START_DOWNLOAD);
}

static void s_download_end(void *o)
{
hawkbit_event_raise(HAWKBIT_EVENT_END_DOWNLOAD);
}

/*
* Resource for software module (Deployment Base)
* GET: /{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/
Expand Down Expand Up @@ -1425,6 +1496,7 @@ static void s_download(void *o)
/* If everything is successful */
s->hb_context.code_status = HAWKBIT_UPDATE_INSTALLED;
hawkbit_device_acid_update(s->hb_context.json_action_id);
hawkbit_event_raise(HAWKBIT_EVENT_UPDATE_DOWNLOADED);

smf_set_state(SMF_CTX(s), &hawkbit_states[S_HAWKBIT_TERMINATE]);
}
Expand All @@ -1433,6 +1505,36 @@ static void s_terminate(void *o)
{
struct s_object *s = (struct s_object *)o;

#ifdef CONFIG_HAWKBIT_EVENT_CALLBACKS
if (IN_RANGE(s->hb_context.code_status, HAWKBIT_NETWORKING_ERROR,
HAWKBIT_PROBE_IN_PROGRESS)) {
hawkbit_event_raise(HAWKBIT_EVENT_ERROR);
switch (s->hb_context.code_status) {
case HAWKBIT_NETWORKING_ERROR:
hawkbit_event_raise(HAWKBIT_EVENT_ERROR_NETWORKING);
break;

case HAWKBIT_PERMISSION_ERROR:
hawkbit_event_raise(HAWKBIT_EVENT_ERROR_PERMISSION);
break;

case HAWKBIT_METADATA_ERROR:
hawkbit_event_raise(HAWKBIT_EVENT_ERROR_METADATA);
break;

case HAWKBIT_DOWNLOAD_ERROR:
hawkbit_event_raise(HAWKBIT_EVENT_ERROR_DOWNLOAD);
break;

case HAWKBIT_ALLOC_ERROR:
hawkbit_event_raise(HAWKBIT_EVENT_ERROR_ALLOC);
break;
default:
break;
}
}
#endif

smf_set_terminate(SMF_CTX(s), s->hb_context.code_status);
}

Expand Down Expand Up @@ -1480,9 +1582,9 @@ static const struct smf_state hawkbit_states[] = {
&hawkbit_states[S_HAWKBIT_HTTP],
NULL),
[S_HAWKBIT_DOWNLOAD] = SMF_CREATE_STATE(
NULL,
s_download_start,
s_download,
NULL,
s_download_end,
&hawkbit_states[S_HAWKBIT_HTTP],
NULL),
[S_HAWKBIT_TERMINATE] = SMF_CREATE_STATE(
Expand All @@ -1499,10 +1601,12 @@ enum hawkbit_response hawkbit_probe(void)
struct s_object s_obj = {0};

smf_set_initial(SMF_CTX(&s_obj), &hawkbit_states[S_HAWKBIT_PROBE]);
hawkbit_event_raise(HAWKBIT_EVENT_START_RUN);

while (1) {
ret = smf_run_state(SMF_CTX(&s_obj));
if (ret != 0) {
hawkbit_event_raise(HAWKBIT_EVENT_END_RUN);
return (enum hawkbit_response)ret;
}
}
Expand Down

0 comments on commit 4199637

Please sign in to comment.