Skip to content

Commit

Permalink
samples: dfu: report FW state and reboot from main thread
Browse files Browse the repository at this point in the history
So far there were 3 threads involved:
 * Zephyr main
   * initialize network
   * start Golioth system client
 * Golioth system_client
   * handle incoming Golioth communication
   * report FW states
 * Zephyr sysworkq
   * trigger reboot

This is overly complicated and makes callbacks implementation hard to read
due to FW state reporting logic taking most of callback body.

Change implementation to utilize only 2 threads instead, with following
changes:
 * Zephyr main
   * initialize network (as before)
   * start Golioth system client (as before)
   * report FW reporting (new)
   * trigger reboot (new)
 * Golioth system_client
   * handle incoming Golioth communication

There is little data shared among those threads and most important thing
is to notify about state of FW download. For that reason use
semaphores, which make main() execution continue step by step, making
overall logic easy to follow.

This change solves one of the issues with pytest scripts expecting a
specific sequence of FW states. So far this sequence was not followed from
time to time, due to UDP packets reordering. This issue is now partly
solved by reporting FW states from Zephyr main thread and remaining fix
will be a conversion from asynchronous to synchronous
golioth_fw_report_state() API.

Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
  • Loading branch information
mniestroj committed Oct 19, 2022
1 parent c297f50 commit 1660ba7
Showing 1 changed file with 66 additions and 55 deletions.
121 changes: 66 additions & 55 deletions samples/dfu/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ LOG_MODULE_REGISTER(golioth_dfu, LOG_LEVEL_DBG);

#include "flash.h"

#define REBOOT_DELAY_SEC 1

static void reboot_handler(struct k_work *work)
{
sys_reboot(SYS_REBOOT_COLD);
}
K_SEM_DEFINE(sem_connected, 0, 1);
K_SEM_DEFINE(sem_downloading, 0, 1);
K_SEM_DEFINE(sem_downloaded, 0, 1);

K_WORK_DELAYABLE_DEFINE(reboot_work, reboot_handler);
#define REBOOT_DELAY_SEC 1

static struct golioth_client *client = GOLIOTH_SYSTEM_CLIENT_GET();

Expand Down Expand Up @@ -66,38 +63,7 @@ static int data_received(struct golioth_req_rsp *rsp)
}

if (last) {
err = golioth_fw_report_state(client, "main",
current_version_str,
dfu->version,
GOLIOTH_FW_STATE_DOWNLOADED,
GOLIOTH_DFU_RESULT_INITIAL);
if (err) {
LOG_ERR("Failed to update to '%s' state: %d", "downloaded", err);
}

err = golioth_fw_report_state(client, "main",
current_version_str,
dfu->version,
GOLIOTH_FW_STATE_UPDATING,
GOLIOTH_DFU_RESULT_INITIAL);
if (err) {
LOG_ERR("Failed to update to '%s' state: %d", "updating", err);
}

LOG_INF("Requesting upgrade");

err = boot_request_upgrade(BOOT_UPGRADE_TEST);
if (err) {
LOG_ERR("Failed to request upgrade: %d", err);
return err;
}

LOG_INF("Rebooting in %d second(s)", REBOOT_DELAY_SEC);

/* Synchronize logs */
LOG_PANIC();

k_work_schedule(&reboot_work, K_SECONDS(REBOOT_DELAY_SEC));
k_sem_give(&sem_downloaded);
}

if (rsp->get_next) {
Expand Down Expand Up @@ -158,14 +124,7 @@ static int golioth_desired_update(struct golioth_req_rsp *rsp)

uri_p = uri_strip_leading_slash(uri, &uri_len);

err = golioth_fw_report_state(client, "main",
current_version_str,
dfu->version,
GOLIOTH_FW_STATE_DOWNLOADING,
GOLIOTH_DFU_RESULT_INITIAL);
if (err) {
LOG_ERR("Failed to update to '%s' state: %d", "downloading", err);
}
k_sem_give(&sem_downloading);

err = golioth_fw_download(client, uri_p, uri_len, data_received, dfu);
if (err) {
Expand All @@ -180,14 +139,7 @@ static void golioth_on_connect(struct golioth_client *client)
{
int err;

err = golioth_fw_report_state(client, "main",
current_version_str,
NULL,
GOLIOTH_FW_STATE_IDLE,
dfu_initial_result);
if (err) {
LOG_ERR("Failed to report firmware state: %d", err);
}
k_sem_give(&sem_connected);

err = golioth_fw_observe_desired(client, golioth_desired_update, &update_ctx);
if (err) {
Expand Down Expand Up @@ -222,4 +174,63 @@ void main(void)

client->on_connect = golioth_on_connect;
golioth_system_client_start();

k_sem_take(&sem_connected, K_FOREVER);

err = golioth_fw_report_state(client, "main",
current_version_str,
NULL,
GOLIOTH_FW_STATE_IDLE,
dfu_initial_result);
if (err) {
LOG_ERR("Failed to report firmware state: %d", err);
}

k_sem_take(&sem_downloading, K_FOREVER);

err = golioth_fw_report_state(client, "main",
current_version_str,
update_ctx.version,
GOLIOTH_FW_STATE_DOWNLOADING,
GOLIOTH_DFU_RESULT_INITIAL);
if (err) {
LOG_ERR("Failed to update to '%s' state: %d", "downloading", err);
}

k_sem_take(&sem_downloaded, K_FOREVER);

err = golioth_fw_report_state(client, "main",
current_version_str,
update_ctx.version,
GOLIOTH_FW_STATE_DOWNLOADED,
GOLIOTH_DFU_RESULT_INITIAL);
if (err) {
LOG_ERR("Failed to update to '%s' state: %d", "downloaded", err);
}

err = golioth_fw_report_state(client, "main",
current_version_str,
update_ctx.version,
GOLIOTH_FW_STATE_UPDATING,
GOLIOTH_DFU_RESULT_INITIAL);
if (err) {
LOG_ERR("Failed to update to '%s' state: %d", "updating", err);
}

LOG_INF("Requesting upgrade");

err = boot_request_upgrade(BOOT_UPGRADE_TEST);
if (err) {
LOG_ERR("Failed to request upgrade: %d", err);
return;
}

LOG_INF("Rebooting in %d second(s)", REBOOT_DELAY_SEC);

/* Synchronize logs */
LOG_PANIC();

k_sleep(K_SECONDS(REBOOT_DELAY_SEC));

sys_reboot(SYS_REBOOT_COLD);
}

0 comments on commit 1660ba7

Please sign in to comment.