Skip to content

Commit 1babfda

Browse files
committed
net: nrf_cloud_fota_poll: Add API to apply FOTA images
Add API to apply FOTA images for asyncronous use. Signed-off-by: Simen S. Røstad <simen.rostad@nordicsemi.no>
1 parent 693b886 commit 1babfda

File tree

3 files changed

+77
-22
lines changed

3 files changed

+77
-22
lines changed

include/net/nrf_cloud.h

+1
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ enum nrf_cloud_fota_status {
294294
NRF_CLOUD_FOTA_CANCELED = 5,
295295
NRF_CLOUD_FOTA_REJECTED = 6,
296296
NRF_CLOUD_FOTA_DOWNLOADING = 7,
297+
NRF_CLOUD_FOTA_VALIDATION_NEEDED = 8,
297298
};
298299

299300
/** @brief FOTA update type. */

include/net/nrf_cloud_fota_poll.h

+10
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ int nrf_cloud_fota_poll_process_pending(struct nrf_cloud_fota_poll_ctx *ctx);
136136
*/
137137
int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx);
138138

139+
/**
140+
* @brief Apply downloaded image. For full modem FOTA this must be called after the network has
141+
* been disconnected. Only applicable in non-blocking mode.
142+
*
143+
* @param[in] ctx Pointer to context used for FOTA polling operations.
144+
*
145+
* @return 0 on success, negative value on failure.
146+
*/
147+
int nrf_cloud_fota_poll_update_apply(struct nrf_cloud_fota_poll_ctx *ctx);
148+
139149
/** @} */
140150

141151
#ifdef __cplusplus

subsys/net/lib/nrf_cloud/src/nrf_cloud_fota_poll.c

+66-22
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static enum nrf_cloud_fota_status fota_status = NRF_CLOUD_FOTA_QUEUED;
5050
static char const *fota_status_details = FOTA_STATUS_DETAILS_SUCCESS;
5151

5252
/* Forward-declarations */
53-
static void handle_download_succeeded_and_reboot(struct nrf_cloud_fota_poll_ctx *ctx);
53+
static int handle_downloaded_image(struct nrf_cloud_fota_poll_ctx *ctx, bool cloud_disconnect);
5454
static int update_job_status(struct nrf_cloud_fota_poll_ctx *ctx);
5555

5656
/****************************************************/
@@ -103,7 +103,7 @@ static int disconnect(struct nrf_cloud_fota_poll_ctx *ctx)
103103
err = -ENOTSUP;
104104
#endif
105105
#if defined(CONFIG_LTE_LINK_CONTROL)
106-
(void)lte_lc_power_off();
106+
err = lte_lc_power_off();
107107
#endif
108108

109109
return err;
@@ -118,6 +118,21 @@ static void cleanup(void)
118118
#endif
119119
}
120120

121+
static void fota_status_callback(struct nrf_cloud_fota_poll_ctx *ctx,
122+
enum nrf_cloud_fota_status status)
123+
{ if (ctx->status_fn) {
124+
ctx->status_fn(status, NULL);
125+
}
126+
}
127+
128+
static void fota_reboot_callback(struct nrf_cloud_fota_poll_ctx *ctx,
129+
enum nrf_cloud_fota_reboot_status status)
130+
{
131+
if (ctx->reboot_fn) {
132+
ctx->reboot_fn(status);
133+
}
134+
}
135+
121136
/****************************************************/
122137
/* End of transport-specific wrappers. */
123138
/****************************************************/
@@ -139,10 +154,24 @@ static void http_fota_dl_handler(const struct fota_download_evt *evt)
139154

140155
if (ctx_ptr->is_nonblocking) {
141156
k_work_cancel_delayable(&ctx_ptr->timeout_work);
142-
handle_download_succeeded_and_reboot(ctx_ptr);
157+
}
158+
159+
if (IS_ENABLED(CONFIG_NRF_CLOUD_FOTA_POLL_VALIDATE_UPDATE)) {
160+
int err = handle_downloaded_image(ctx_ptr, true);
161+
162+
if (err) {
163+
LOG_ERR("handle_downloaded_image() failed: %d", err);
164+
nrf_cloud_download_cancel();
165+
}
166+
143167
} else {
168+
fota_status_callback(ctx_ptr, NRF_CLOUD_FOTA_VALIDATION_NEEDED);
169+
}
170+
171+
if (!ctx_ptr->is_nonblocking) {
144172
k_sem_give(&fota_download_sem);
145173
}
174+
146175
break;
147176
case FOTA_DOWNLOAD_EVT_ERASE_PENDING:
148177
case FOTA_DOWNLOAD_EVT_ERASE_TIMEOUT:
@@ -233,9 +262,7 @@ static void process_pending_job(struct nrf_cloud_fota_poll_ctx *ctx)
233262
/* Save validate status and reboot */
234263
(void)nrf_cloud_fota_settings_save(&pending_job);
235264

236-
if (ctx->reboot_fn) {
237-
ctx->reboot_fn(FOTA_REBOOT_REQUIRED);
238-
}
265+
fota_reboot_callback(ctx, FOTA_REBOOT_REQUIRED);
239266
}
240267
}
241268

@@ -494,7 +521,7 @@ static int wait_for_download(void)
494521
return 0;
495522
}
496523

497-
static void handle_download_succeeded_and_reboot(struct nrf_cloud_fota_poll_ctx *ctx)
524+
static int handle_downloaded_image(struct nrf_cloud_fota_poll_ctx *ctx, bool cloud_disconnect)
498525
{
499526
int err;
500527

@@ -506,17 +533,26 @@ static void handle_download_succeeded_and_reboot(struct nrf_cloud_fota_poll_ctx
506533

507534
err = nrf_cloud_bootloader_fota_slot_set(&pending_job);
508535
if (err) {
509-
LOG_WRN("Failed to set B1 slot flag, BOOT FOTA validation may be incorrect");
536+
LOG_ERR("Failed to set B1 slot flag, BOOT FOTA validation may be incorrect");
537+
return err;
510538
}
511539

512-
disconnect(ctx);
540+
if (cloud_disconnect) {
541+
err = disconnect(ctx);
542+
if (err) {
543+
LOG_ERR("Failed to disconnect from nRF Cloud, error: %d", err);
544+
return err;
545+
}
546+
}
513547

514548
#if defined(CONFIG_NRF_CLOUD_FOTA_FULL_MODEM_UPDATE)
515549
if (job.type == NRF_CLOUD_FOTA_MODEM_FULL) {
516550
LOG_INF("Applying full modem FOTA update...");
551+
517552
err = nrf_cloud_fota_fmfu_apply();
518553
if (err) {
519554
LOG_ERR("Failed to apply full modem FOTA update %d", err);
555+
520556
pending_job.validate = NRF_CLOUD_FOTA_VALIDATE_FAIL;
521557
} else {
522558
pending_job.validate = NRF_CLOUD_FOTA_VALIDATE_PASS;
@@ -529,9 +565,11 @@ static void handle_download_succeeded_and_reboot(struct nrf_cloud_fota_poll_ctx
529565
bool reboot_required = false;
530566

531567
LOG_INF("Installing SMP FOTA update...");
568+
532569
err = nrf_cloud_pending_fota_job_process(&pending_job, &reboot_required);
533570
if (err < 0) {
534571
LOG_ERR("Failed to install SMP FOTA update %d", err);
572+
535573
pending_job.validate = NRF_CLOUD_FOTA_VALIDATE_FAIL;
536574
} else {
537575
pending_job.validate = NRF_CLOUD_FOTA_VALIDATE_PASS;
@@ -541,18 +579,14 @@ static void handle_download_succeeded_and_reboot(struct nrf_cloud_fota_poll_ctx
541579

542580
err = nrf_cloud_fota_settings_save(&pending_job);
543581
if (err) {
544-
LOG_WRN("FOTA job will be marked as successful without validation");
545-
fota_status_details = FOTA_STATUS_DETAILS_NO_VALIDATE;
546-
(void)update_job_status(ctx);
582+
LOG_ERR("Failed saving pending FOTA job, error: %d", err);
583+
return err;
547584
}
548585

549-
if (ctx_ptr->status_fn) {
550-
ctx_ptr->status_fn(NRF_CLOUD_FOTA_SUCCEEDED, NULL);
551-
}
586+
fota_status_callback(ctx, NRF_CLOUD_FOTA_SUCCEEDED);
587+
fota_reboot_callback(ctx, FOTA_REBOOT_SUCCESS);
552588

553-
if (ctx->reboot_fn) {
554-
ctx->reboot_fn(FOTA_REBOOT_SUCCESS);
555-
}
589+
return 0;
556590
}
557591

558592
static void wait_after_job_update(void)
@@ -563,6 +597,18 @@ static void wait_after_job_update(void)
563597
k_sleep(K_SECONDS(JOB_WAIT_S));
564598
}
565599

600+
int nrf_cloud_fota_poll_update_apply(struct nrf_cloud_fota_poll_ctx *ctx)
601+
{
602+
int err = handle_downloaded_image(ctx, false);
603+
604+
if (err) {
605+
LOG_ERR("handle_downloaded_image, error: %d", err);
606+
return err;
607+
}
608+
609+
return 0;
610+
}
611+
566612
int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx)
567613
{
568614
int err;
@@ -592,9 +638,7 @@ int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx)
592638
return -EAGAIN;
593639
}
594640

595-
if (ctx_ptr->status_fn) {
596-
ctx_ptr->status_fn(NRF_CLOUD_FOTA_DOWNLOADING, NULL);
597-
}
641+
fota_status_callback(ctx, NRF_CLOUD_FOTA_DOWNLOADING);
598642

599643
/* Start the FOTA download process and wait for completion (or timeout) */
600644
err = start_download();
@@ -624,7 +668,7 @@ int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx)
624668
* Job status will be sent to nRF Cloud after reboot and validation.
625669
*/
626670
if (fota_status == NRF_CLOUD_FOTA_SUCCEEDED) {
627-
handle_download_succeeded_and_reboot(ctx);
671+
handle_downloaded_image(ctx, true);
628672
/* Application was expected to reboot... */
629673
return -EBUSY;
630674
}

0 commit comments

Comments
 (0)