1 /*
2  * Copyright (c) 2024 Vogl Electronic GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/mgmt/hawkbit/hawkbit.h>
10 #include <zephyr/mgmt/hawkbit/config.h>
11 #include <zephyr/mgmt/hawkbit/autohandler.h>
12 
13 LOG_MODULE_DECLARE(hawkbit);
14 
15 static void autohandler(struct k_work *work);
16 
17 static K_WORK_DELAYABLE_DEFINE(hawkbit_work_handle, autohandler);
18 static K_WORK_DELAYABLE_DEFINE(hawkbit_work_handle_once, autohandler);
19 
20 static K_EVENT_DEFINE(hawkbit_autohandler_event);
21 
autohandler(struct k_work * work)22 static void autohandler(struct k_work *work)
23 {
24 	k_event_clear(&hawkbit_autohandler_event, UINT32_MAX);
25 
26 	enum hawkbit_response response = hawkbit_probe();
27 
28 	k_event_set(&hawkbit_autohandler_event, BIT(response));
29 
30 	switch (response) {
31 	case HAWKBIT_UNCONFIRMED_IMAGE:
32 		LOG_ERR("Current image is not confirmed");
33 		LOG_ERR("Rebooting to previous confirmed image");
34 		LOG_ERR("If this image is flashed using a hardware tool");
35 		LOG_ERR("Make sure that it is a confirmed image");
36 		hawkbit_reboot();
37 		break;
38 
39 	case HAWKBIT_NO_UPDATE:
40 		LOG_INF("No update found");
41 		break;
42 
43 	case HAWKBIT_UPDATE_INSTALLED:
44 		LOG_INF("Update installed");
45 		hawkbit_reboot();
46 		break;
47 
48 	case HAWKBIT_ALLOC_ERROR:
49 		LOG_INF("Memory allocation error");
50 		break;
51 
52 	case HAWKBIT_DOWNLOAD_ERROR:
53 		LOG_INF("Update failed");
54 		break;
55 
56 	case HAWKBIT_NETWORKING_ERROR:
57 		LOG_INF("Network error");
58 		break;
59 
60 	case HAWKBIT_PERMISSION_ERROR:
61 		LOG_INF("Permission error");
62 		break;
63 
64 	case HAWKBIT_METADATA_ERROR:
65 		LOG_INF("Metadata error");
66 		break;
67 
68 	case HAWKBIT_NOT_INITIALIZED:
69 		LOG_INF("hawkBit not initialized");
70 		break;
71 
72 	case HAWKBIT_PROBE_IN_PROGRESS:
73 		LOG_INF("hawkBit is already running");
74 		break;
75 
76 	default:
77 		LOG_ERR("Invalid response: %d", response);
78 		break;
79 	}
80 
81 	if (k_work_delayable_from_work(work) == &hawkbit_work_handle) {
82 		k_work_reschedule(&hawkbit_work_handle, K_SECONDS(hawkbit_get_poll_interval()));
83 	}
84 }
85 
hawkbit_autohandler_wait(uint32_t events,k_timeout_t timeout)86 enum hawkbit_response hawkbit_autohandler_wait(uint32_t events, k_timeout_t timeout)
87 {
88 	uint32_t ret = k_event_wait(&hawkbit_autohandler_event, events, false, timeout);
89 
90 	for (int i = 1; i < HAWKBIT_PROBE_IN_PROGRESS; i++) {
91 		if (ret & BIT(i)) {
92 			return i;
93 		}
94 	}
95 	return HAWKBIT_NO_RESPONSE;
96 }
97 
hawkbit_autohandler_cancel(void)98 int hawkbit_autohandler_cancel(void)
99 {
100 	return k_work_cancel_delayable(&hawkbit_work_handle);
101 }
102 
hawkbit_autohandler_set_delay(k_timeout_t timeout,bool if_bigger)103 int hawkbit_autohandler_set_delay(k_timeout_t timeout, bool if_bigger)
104 {
105 	if (!if_bigger || timeout.ticks > k_work_delayable_remaining_get(&hawkbit_work_handle)) {
106 		hawkbit_autohandler_cancel();
107 		LOG_INF("Setting new delay for next run: %02u:%02u:%02u",
108 			(uint32_t)(timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) / 3600,
109 			(uint32_t)((timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) % 3600) / 60,
110 			(uint32_t)(timeout.ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC) % 60);
111 		return k_work_reschedule(&hawkbit_work_handle, timeout);
112 	}
113 	return 0;
114 }
115 
hawkbit_autohandler(bool auto_reschedule)116 void hawkbit_autohandler(bool auto_reschedule)
117 {
118 	if (auto_reschedule) {
119 		k_work_reschedule(&hawkbit_work_handle, K_NO_WAIT);
120 	} else {
121 		k_work_reschedule(&hawkbit_work_handle_once, K_NO_WAIT);
122 	}
123 }
124