Skip to content

Commit

Permalink
src: modules: Block during FOTA download
Browse files Browse the repository at this point in the history
 - Add new FOTA ongoing state in trigger module, which blocks triggers
   while FOTA download is in progress.

 - Update FOTA module to send download start and stop events

 - Update manifest to pull in needed changes in sdk-nrf.
   Most notably, the new event type for FOTA download start and stop.
   Handle image type so that we can reset the modem in the feature on
   modem FOTA instead of rebooting the device.

Signed-off-by: Simen S. Røstad <[email protected]>
  • Loading branch information
simensrostad committed Sep 13, 2024
1 parent 8cabb92 commit 1a0c583
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 37 deletions.
6 changes: 3 additions & 3 deletions app/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ CONFIG_AT_SHELL=y

# nRF Cloud
CONFIG_NRF_CLOUD_COAP=y
CONFIG_NRF_CLOUD_COAP_DISCONNECT_ON_FAILED_REQUEST=y
CONFIG_MODEM_JWT=y

# On initial connection to the cloud, add info sections to the shadow
Expand Down Expand Up @@ -102,12 +103,11 @@ CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_STREAM_FLASH=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_NRF_CLOUD_ALERT=y
CONFIG_NRF_CLOUD_LOG_DIRECT=y
CONFIG_NRF_CLOUD_LOG_DIRECT=n
CONFIG_NRF_CLOUD_LOG_OUTPUT_LEVEL=3
CONFIG_NRF_CLOUD_FOTA_POLL=y
CONFIG_NRF_CLOUD_FOTA_FULL_MODEM_UPDATE=y
CONFIG_NRF_CLOUD_FOTA_DOWNLOAD_FRAGMENT_SIZE=1700
CONFIG_NRF_CLOUD_FOTA_DOWNLOAD_FRAGMENT_SIZE=1900
CONFIG_FOTA_DOWNLOAD=y
CONFIG_FOTA_DL_TIMEOUT_MIN=30
CONFIG_DFU_TARGET=y
Expand Down
2 changes: 1 addition & 1 deletion app/src/common/message_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ ZBUS_CHAN_DEFINE(FOTA_STATUS_CHAN,
NULL,
NULL,
ZBUS_OBSERVERS_EMPTY,
ZBUS_MSG_INIT(false)
ZBUS_MSG_INIT(0)
);

ZBUS_CHAN_DEFINE(PAYLOAD_CHAN,
Expand Down
11 changes: 4 additions & 7 deletions app/src/common/message_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,11 @@ enum fota_status {
/* No FOTA job is ongoing */
FOTA_STATUS_IDLE = 0x1,

/* The cloud is about to be polled for new FOTA jobs. If a job is found, the
* FOTA job will be started, which includes downloading the firmware and applying it.
* Depending on the formware type, the modem may be rebooted.
*/
FOTA_STATUS_PROCESSING_START,
/* FOTA dowdload started. */
FOTA_STATUS_DOWNLOAD_STARTED,

/* FOTA processing completed. */
FOTA_STATUS_PROCESSING_DONE,
/* FOTA download completed. */
FOTA_STATUS_DOWNLOAD_STOPPED,

/* A firmware image has been downloaded and a reboot is required to apply it.
* The FOTA module will perform the reboot CONFIG_APP_FOTA_REBOOT_DELAY_SECONDS seconds
Expand Down
53 changes: 29 additions & 24 deletions app/src/modules/fota/fota.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ ZBUS_CHAN_ADD_OBS(CLOUD_CHAN, fota, 0);
/* FOTA support context */
static void fota_reboot(enum nrf_cloud_fota_reboot_status status);
static void fota_error(enum nrf_cloud_fota_status status, const char *const status_details);
static void fota_download_status(enum nrf_cloud_fota_download_status status);

/* State machine */

Expand Down Expand Up @@ -97,12 +98,12 @@ static void state_wait_for_cloud_run(void *o);
static void state_wait_for_trigger_run(void *o);
static void state_poll_and_process_entry(void *o);
static void state_poll_and_process_run(void *o);
static void state_poll_and_process_exit(void *o);
static void state_reboot_pending_entry(void *o);

static struct s_object s_obj = {
.fota_ctx.reboot_fn = fota_reboot,
.fota_ctx.error_fn = fota_error,
.fota_ctx.download_status_fn = fota_download_status,
};

static const struct smf_state states[] = {
Expand All @@ -120,7 +121,7 @@ static const struct smf_state states[] = {
NULL),
[STATE_POLL_AND_PROCESS] =
SMF_CREATE_STATE(state_poll_and_process_entry, state_poll_and_process_run,
state_poll_and_process_exit,
NULL,
&states[STATE_RUNNING],
NULL),
[STATE_REBOOT_PENDING] =
Expand Down Expand Up @@ -188,17 +189,10 @@ static void state_wait_for_trigger_run(void *o)
static void state_poll_and_process_entry(void *o)
{
struct s_object *state_object = o;
/* Notify the rest of the system that FOTA processing is starting */
enum fota_status fota_status = FOTA_STATUS_PROCESSING_START;

int err = zbus_chan_pub(&FOTA_STATUS_CHAN, &fota_status, K_SECONDS(1));
if (err) {
LOG_ERR("zbus_chan_pub, error: %d", err);
SEND_FATAL_ERROR();
}

/* Start the FOTA processing */
err = nrf_cloud_fota_poll_process(&state_object->fota_ctx);
int err = nrf_cloud_fota_poll_process(&state_object->fota_ctx);

if (err) {
enum priv_fota_evt evt = FOTA_PRIV_PROCESSING_DONE;

Expand Down Expand Up @@ -237,19 +231,6 @@ static void state_poll_and_process_run(void *o)
}
}

static void state_poll_and_process_exit(void *o)
{
enum fota_status fota_status = FOTA_STATUS_PROCESSING_DONE;

ARG_UNUSED(o);

int err = zbus_chan_pub(&FOTA_STATUS_CHAN, &fota_status, K_SECONDS(1));
if (err) {
LOG_ERR("zbus_chan_pub, error: %d", err);
SEND_FATAL_ERROR();
}
}

static void state_reboot_pending_entry(void *o)
{
ARG_UNUSED(o);
Expand Down Expand Up @@ -314,6 +295,30 @@ static void fota_error(enum nrf_cloud_fota_status status, const char *const stat
}
}

static void download_events_notify(enum nrf_cloud_fota_download_status status)
{
int err;

__ASSERT_NO_MSG(status == NRF_CLOUD_FOTA_DOWNLOAD_STARTED ||
status == NRF_CLOUD_FOTA_DOWNLOAD_STOPPED);

enum fota_status fota_status = status == NRF_CLOUD_FOTA_DOWNLOAD_STARTED ?
FOTA_STATUS_DOWNLOAD_STARTED : FOTA_STATUS_DOWNLOAD_STOPPED;

err = zbus_chan_pub(&FOTA_STATUS_CHAN, &fota_status, K_SECONDS(1));
if (err) {
LOG_ERR("zbus_chan_pub, error: %d", err);
SEND_FATAL_ERROR();
return;
}
}

static void fota_download_status(enum nrf_cloud_fota_download_status status)
{
LOG_DBG("FOTA download status: %s", (status == NRF_CLOUD_FOTA_DOWNLOAD_STARTED) ? "started" : "stopped");
download_events_notify(status);
}

static void fota_task(void)
{
int err;
Expand Down
61 changes: 60 additions & 1 deletion app/src/modules/trigger/trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ZBUS_CHAN_ADD_OBS(CONFIG_CHAN, trigger, 0);
ZBUS_CHAN_ADD_OBS(CLOUD_CHAN, trigger, 0);
ZBUS_CHAN_ADD_OBS(BUTTON_CHAN, trigger, 0);
ZBUS_CHAN_ADD_OBS(LOCATION_CHAN, trigger, 0);
ZBUS_CHAN_ADD_OBS(FOTA_STATUS_CHAN, trigger, 0);

/* Data sample trigger interval in the frequent poll state */
#define FREQUENT_POLL_DATA_SAMPLE_TRIGGER_INTERVAL_SEC 60
Expand Down Expand Up @@ -54,7 +55,8 @@ enum state {
STATE_NORMAL,
/* Sub-state to STATE_CONNECTED */
STATE_BLOCKED,
STATE_DISCONNECTED
STATE_DISCONNECTED,
STATE_FOTA_DL_ONGOING
};

/* Private channel used to signal when the duration in the frequent poll state expires */
Expand Down Expand Up @@ -101,6 +103,9 @@ struct s_object {
/* Cloud status */
enum cloud_status status;

/* FOTA download status */
enum fota_status fota_status;

/* Trigger mode */
enum trigger_mode trigger_mode;
};
Expand Down Expand Up @@ -237,6 +242,14 @@ static void connected_run(void *o)
smf_set_state(SMF_CTX(&state_object), &states[STATE_DISCONNECTED]);
return;
}

if (user_object->chan == &FOTA_STATUS_CHAN) {
if (user_object->fota_status == FOTA_STATUS_DOWNLOAD_STARTED) {
LOG_DBG("FOTA download started, going into FOTA download ongoing state");
smf_set_state(SMF_CTX(&state_object), &states[STATE_FOTA_DL_ONGOING]);
return;
}
}
}

/* STATE_BLOCKED */
Expand Down Expand Up @@ -463,6 +476,40 @@ static void disconnected_run(void *o)
}
}

/* STATE_FOTA_DL_ONGOING */

static void fota_dl_ongoing_entry(void *o)
{
ARG_UNUSED(o);

LOG_DBG("fota_dl_ongoing_entry");
/* Cancel frequent poll duration timer if running. This can happen when state machine was
* in BLOCKED state when the FOTA download starts.
*/
frequent_poll_duration_timer_stop();
}

static void fota_dl_ongoing_run(void *o)
{
struct s_object *user_object = o;

LOG_DBG("fota_dl_ongoing_run");

if (user_object->chan == &FOTA_STATUS_CHAN) {
if (user_object->fota_status == FOTA_STATUS_DOWNLOAD_STOPPED) {
LOG_DBG("FOTA download stopped");

if (user_object->status == CLOUD_CONNECTED_READY_TO_SEND) {
smf_set_state(SMF_CTX(&state_object), &states[STATE_CONNECTED]);
} else {
smf_set_state(SMF_CTX(&state_object), &states[STATE_DISCONNECTED]);
}

return;
}
}
}

/* Construct state table */
static const struct smf_state states[] = {
[STATE_INIT] = SMF_CREATE_STATE(
Expand Down Expand Up @@ -506,6 +553,13 @@ static const struct smf_state states[] = {
NULL,
NULL,
NULL
),
[STATE_FOTA_DL_ONGOING] = SMF_CREATE_STATE(
fota_dl_ongoing_entry,
fota_dl_ongoing_run,
NULL,
NULL,
NULL
)
};

Expand All @@ -518,6 +572,7 @@ void trigger_callback(const struct zbus_channel *chan)
(chan != &CLOUD_CHAN) &&
(chan != &LOCATION_CHAN) &&
(chan != &BUTTON_CHAN) &&
(chan != &FOTA_STATUS_CHAN) &&
(chan != &PRIV_TRIGGER_CHAN)) {
LOG_ERR("Unknown channel");
return;
Expand All @@ -539,6 +594,10 @@ void trigger_callback(const struct zbus_channel *chan)
const enum cloud_status *status = zbus_chan_const_msg(chan);

state_object.status = *status;
} else if (&FOTA_STATUS_CHAN == chan) {
const enum fota_status *fota_status = zbus_chan_const_msg(chan);

state_object.fota_status = *fota_status;
} else if (&BUTTON_CHAN == chan) {
const int *button_number = zbus_chan_const_msg(chan);

Expand Down
2 changes: 1 addition & 1 deletion west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ manifest:
- name: nrf
remote: ncs
repo-path: sdk-nrf
revision: pull/17113/head
revision: pull/17300/head
import: true

0 comments on commit 1a0c583

Please sign in to comment.