Skip to content

Commit 00b34f9

Browse files
committed
modules: Update FOTA process
Include more states in app.c to differ between different FOTA scenarios. Change events according to offline state diagrams. Signed-off-by: Simen S. Røstad <simen.rostad@nordicsemi.no>
1 parent 334d8f1 commit 00b34f9

File tree

4 files changed

+119
-78
lines changed

4 files changed

+119
-78
lines changed

app/src/modules/app/app.c

+77-38
Original file line numberDiff line numberDiff line change
@@ -62,31 +62,33 @@ static void idle_run(void *o);
6262
static void fota_entry(void *o);
6363
static void fota_run(void *o);
6464

65-
static void fota_network_disconnect_pending_entry(void *o);
66-
static void fota_network_disconnect_pending_run(void *o);
65+
static void fota_downloading_run(void *o);
6766

68-
static void fota_image_apply_pending_entry(void *o);
69-
static void fota_image_apply_pending_run(void *o);
67+
static void fota_network_disconnect_entry(void *o);
68+
static void fota_network_disconnect_run(void *o);
69+
70+
static void fota_applying_image_entry(void *o);
71+
static void fota_applying_image_run(void *o);
7072

7173
static void fota_rebooting_entry(void *o);
7274

73-
/* Defining the hierarchical trigger module states:
74-
* STATE_RUNNING: The module is operating normally.
75-
* STATE_PERIODIC_TRIGGERING: The module is sending triggers to the rest of the system.
76-
* STATE_IDLE: The module is disconnected from the cloud, triggers are blocked.
77-
* STATE_FOTA: The module is in the FOTA process, triggers are blocked.
78-
* STATE_FOTA_NETWORK_DISCONNECT_PENDING: The module is waiting for the network to disconnect.
79-
* STATE_FOTA_IMAGE_APPLY_PENDING: The module is waiting for the FOTA image to be applied.
80-
* STATE_FOTA_REBOOTING: The module is rebooting after applying the FOTA image.
81-
*/
8275
enum state {
76+
/* Normal operation */
8377
STATE_RUNNING,
84-
STATE_PERIODIC_TRIGGERING,
85-
STATE_IDLE,
78+
/* Triggers are periodically sent at a configured interval */
79+
STATE_PERIODIC_TRIGGERING,
80+
/* Disconnected from the network, no triggers are sent */
81+
STATE_IDLE,
82+
/* Ongoing FOTA process, triggers are blocked */
8683
STATE_FOTA,
87-
STATE_FOTA_NETWORK_DISCONNECT_PENDING,
88-
STATE_FOTA_IMAGE_APPLY_PENDING,
89-
STATE_FOTA_REBOOTING,
84+
/* FOTA image is being downloaded */
85+
STATE_FOTA_DOWNLOADING,
86+
/* Disconnecting from the network */
87+
STATE_FOTA_NETWORK_DISCONNECT,
88+
/* Applying the image */
89+
STATE_FOTA_APPLYING_IMAGE,
90+
/* Rebooting */
91+
STATE_FOTA_REBOOTING,
9092
};
9193

9294
/* State object for the app module.
@@ -148,18 +150,25 @@ static const struct smf_state states[] = {
148150
fota_run,
149151
NULL,
150152
NULL,
153+
&states[STATE_FOTA_DOWNLOADING]
154+
),
155+
[STATE_FOTA_DOWNLOADING] = SMF_CREATE_STATE(
156+
NULL,
157+
fota_downloading_run,
158+
NULL,
159+
&states[STATE_FOTA],
151160
NULL
152161
),
153-
[STATE_FOTA_NETWORK_DISCONNECT_PENDING] = SMF_CREATE_STATE(
154-
fota_network_disconnect_pending_entry,
155-
fota_network_disconnect_pending_run,
162+
[STATE_FOTA_NETWORK_DISCONNECT] = SMF_CREATE_STATE(
163+
fota_network_disconnect_entry,
164+
fota_network_disconnect_run,
156165
NULL,
157166
&states[STATE_FOTA],
158167
NULL
159168
),
160-
[STATE_FOTA_IMAGE_APPLY_PENDING] = SMF_CREATE_STATE(
161-
fota_image_apply_pending_entry,
162-
fota_image_apply_pending_run,
169+
[STATE_FOTA_APPLYING_IMAGE] = SMF_CREATE_STATE(
170+
fota_applying_image_entry,
171+
fota_applying_image_run,
163172
NULL,
164173
&states[STATE_FOTA],
165174
NULL
@@ -400,11 +409,26 @@ static void fota_run(void *o)
400409
case FOTA_DOWNLOAD_FAILED:
401410
STATE_SET(app_state, STATE_RUNNING);
402411
return;
403-
case FOTA_NETWORK_DISCONNECT_NEEDED:
404-
STATE_SET(app_state, STATE_FOTA_NETWORK_DISCONNECT_PENDING);
412+
default:
413+
/* Don't care */
414+
break;
415+
}
416+
}
417+
}
418+
419+
/* STATE_FOTA_DOWNLOADING */
420+
421+
static void fota_downloading_run(void *o)
422+
{
423+
const struct app_state_object *state_object = (const struct app_state_object *)o;
424+
425+
if (state_object->chan == &FOTA_CHAN) {
426+
switch (state_object->fota_status) {
427+
case FOTA_SUCCESS_REBOOT_NEEDED:
428+
STATE_SET(app_state, STATE_FOTA_NETWORK_DISCONNECT);
405429
return;
406-
case FOTA_REBOOT_NEEDED:
407-
STATE_SET(app_state, STATE_FOTA_REBOOTING);
430+
case FOTA_IMAGE_APPLY_NEEDED:
431+
STATE_SET(app_state, STATE_FOTA_APPLYING_IMAGE);
408432
return;
409433
default:
410434
/* Don't care */
@@ -413,9 +437,9 @@ static void fota_run(void *o)
413437
}
414438
}
415439

416-
/* STATE_FOTA_NETWORK_DISCONNECT_PENDING */
440+
/* STATE_FOTA_NETWORK_DISCONNECT */
417441

418-
static void fota_network_disconnect_pending_entry(void *o)
442+
static void fota_network_disconnect_entry(void *o)
419443
{
420444
ARG_UNUSED(o);
421445

@@ -433,40 +457,55 @@ static void fota_network_disconnect_pending_entry(void *o)
433457
}
434458
}
435459

436-
static void fota_network_disconnect_pending_run(void *o)
460+
static void fota_network_disconnect_run(void *o)
437461
{
438462
const struct app_state_object *state_object = (const struct app_state_object *)o;
439463

440464
if (state_object->chan == &NETWORK_CHAN &&
441465
state_object->network_status == NETWORK_DISCONNECTED) {
442-
STATE_SET(app_state, STATE_FOTA_IMAGE_APPLY_PENDING);
466+
STATE_SET(app_state, STATE_FOTA_REBOOTING);
443467
return;
444468
}
445469
}
446470

447-
/* STATE_FOTA_IMAGE_APPLY_PENDING */
471+
/* STATE_FOTA_APPLYING_IMAGE, */
448472

449-
static void fota_image_apply_pending_entry(void *o)
473+
static void fota_applying_image_entry(void *o)
450474
{
451475
ARG_UNUSED(o);
452476

453477
LOG_DBG("%s", __func__);
454478

455479
int err;
456-
enum fota_msg_type msg = FOTA_APPLY_IMAGE;
480+
struct network_msg msg = {
481+
.type = NETWORK_DISCONNECT
482+
};
457483

458-
err = zbus_chan_pub(&FOTA_CHAN, &msg, K_SECONDS(1));
484+
err = zbus_chan_pub(&NETWORK_CHAN, &msg, K_SECONDS(1));
459485
if (err) {
460486
LOG_ERR("zbus_chan_pub, error: %d", err);
461487
SEND_FATAL_ERROR();
462488
}
463489
}
464490

465-
static void fota_image_apply_pending_run(void *o)
491+
static void fota_applying_image_run(void *o)
466492
{
467493
const struct app_state_object *state_object = (const struct app_state_object *)o;
468494

469-
if (state_object->chan == &FOTA_CHAN && state_object->fota_status == FOTA_REBOOT_NEEDED) {
495+
if (state_object->chan == &NETWORK_CHAN &&
496+
state_object->network_status == NETWORK_DISCONNECTED) {
497+
498+
int err;
499+
enum fota_msg_type msg = FOTA_IMAGE_APPLY;
500+
501+
err = zbus_chan_pub(&FOTA_CHAN, &msg, K_SECONDS(1));
502+
if (err) {
503+
LOG_ERR("zbus_chan_pub, error: %d", err);
504+
SEND_FATAL_ERROR();
505+
}
506+
507+
} else if (state_object->chan == &FOTA_CHAN &&
508+
state_object->fota_status == FOTA_SUCCESS_REBOOT_NEEDED) {
470509
STATE_SET(app_state, STATE_FOTA_REBOOTING);
471510
return;
472511
}

app/src/modules/fota/fota.c

+32-31
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,21 @@ ZBUS_CHAN_ADD_OBS(FOTA_CHAN, fota, 0);
4747
static void fota_reboot(enum nrf_cloud_fota_reboot_status status);
4848
static void fota_status(enum nrf_cloud_fota_status status, const char *const status_details);
4949

50-
/* State machine */
51-
52-
/* Defining modules states.
53-
* STATE_RUNNING: The FOTA module is initializing and waiting for a poll request.
54-
* STATE_WAITING_FOR_POLL_REQUEST: The FOTA module is waiting for a poll request.
55-
* STATE_POLLING_FOR_UPDATE: The FOTA module is polling for an update.
56-
* STATE_DOWNLOADING_UPDATE: The FOTA module is downloading an update.
57-
* STATE_WAITING_FOR_NETWORK_DISCONNECT: The FOTA module is waiting for a network disconnect
58-
* in order to apply the update.
59-
* STATE_REBOOT_NEEDED: The FOTA module is waiting for a reboot.
60-
* STATE_CANCELED: The FOTA module has been canceled, cleaning up.
61-
*/
6250
enum fota_module_state {
51+
/* The module is initialized and running */
6352
STATE_RUNNING,
64-
STATE_WAITING_FOR_POLL_REQUEST,
65-
STATE_POLLING_FOR_UPDATE,
66-
STATE_DOWNLOADING_UPDATE,
67-
STATE_WAITING_FOR_NETWORK_DISCONNECT,
68-
STATE_REBOOT_NEEDED,
69-
STATE_CANCELED,
53+
/* The module is waiting for a poll request */
54+
STATE_WAITING_FOR_POLL_REQUEST,
55+
/* The module is polling for an update */
56+
STATE_POLLING_FOR_UPDATE,
57+
/* The module is downloading an update */
58+
STATE_DOWNLOADING_UPDATE,
59+
/* The module is waiting for the event FOTA_IMAGE_APPLY to apply the image */
60+
STATE_WAITING_FOR_IMAGE_APPLY,
61+
/* The FOTA module is waiting for a reboot */
62+
STATE_REBOOT_NEEDED,
63+
/* The FOTA module has been canceled, cleaning up */
64+
STATE_CANCELED,
7065
};
7166

7267
/* User defined state object.
@@ -89,15 +84,21 @@ struct fota_state {
8984
/* Forward declarations */
9085
static void state_running_entry(void *o);
9186
static void state_running_run(void *o);
87+
9288
static void state_waiting_for_poll_request_entry(void *o);
9389
static void state_waiting_for_poll_request_run(void *o);
90+
9491
static void state_polling_for_update_entry(void *o);
9592
static void state_polling_for_update_run(void *o);
93+
9694
static void state_downloading_update_entry(void *o);
9795
static void state_downloading_update_run(void *o);
98-
static void state_waiting_for_network_disconnect_entry(void *o);
99-
static void state_waiting_for_network_disconnect_run(void *o);
96+
97+
static void state_waiting_for_image_apply_entry(void *o);
98+
static void state_waiting_for_image_apply_run(void *o);
99+
100100
static void state_reboot_needed_entry(void *o);
101+
101102
static void state_canceled_entry(void *o);
102103

103104
static struct fota_state fota_state = {
@@ -130,9 +131,9 @@ static const struct smf_state states[] = {
130131
NULL,
131132
&states[STATE_RUNNING],
132133
NULL),
133-
[STATE_WAITING_FOR_NETWORK_DISCONNECT] =
134-
SMF_CREATE_STATE(state_waiting_for_network_disconnect_entry,
135-
state_waiting_for_network_disconnect_run,
134+
[STATE_WAITING_FOR_IMAGE_APPLY] =
135+
SMF_CREATE_STATE(state_waiting_for_image_apply_entry,
136+
state_waiting_for_image_apply_run,
136137
NULL,
137138
&states[STATE_RUNNING],
138139
NULL),
@@ -155,7 +156,7 @@ static const struct smf_state states[] = {
155156
static void fota_reboot(enum nrf_cloud_fota_reboot_status status)
156157
{
157158
int err;
158-
enum fota_msg_type evt = FOTA_REBOOT_NEEDED;
159+
enum fota_msg_type evt = FOTA_SUCCESS_REBOOT_NEEDED;
159160

160161
LOG_DBG("Reboot requested with FOTA status %d", status);
161162

@@ -200,7 +201,7 @@ static void fota_status(enum nrf_cloud_fota_status status, const char *const sta
200201
case NRF_CLOUD_FOTA_FMFU_VALIDATION_NEEDED:
201202
LOG_DBG("Full Modem FOTA Update validation needed, network disconnect required");
202203

203-
evt = FOTA_NETWORK_DISCONNECT_NEEDED;
204+
evt = FOTA_IMAGE_APPLY_NEEDED;
204205
break;
205206
default:
206207
LOG_DBG("Unknown FOTA status: %d", status);
@@ -354,8 +355,8 @@ static void state_downloading_update_run(void *o)
354355
const enum fota_msg_type evt = MSG_TO_FOTA_TYPE(state_object->msg_buf);
355356

356357
switch (evt) {
357-
case FOTA_NETWORK_DISCONNECT_NEEDED:
358-
STATE_SET(fota_state, STATE_WAITING_FOR_NETWORK_DISCONNECT);
358+
case FOTA_IMAGE_APPLY_NEEDED:
359+
STATE_SET(fota_state, STATE_WAITING_FOR_IMAGE_APPLY);
359360
break;
360361
case FOTA_DOWNLOAD_FAILED:
361362
STATE_SET(fota_state, STATE_WAITING_FOR_POLL_REQUEST);
@@ -367,22 +368,22 @@ static void state_downloading_update_run(void *o)
367368
}
368369
}
369370

370-
static void state_waiting_for_network_disconnect_entry(void *o)
371+
static void state_waiting_for_image_apply_entry(void *o)
371372
{
372373
ARG_UNUSED(o);
373374

374375
LOG_DBG("%s", __func__);
375376
}
376377

377-
static void state_waiting_for_network_disconnect_run(void *o)
378+
static void state_waiting_for_image_apply_run(void *o)
378379
{
379380
struct fota_state *state_object = o;
380381

381382
if (&FOTA_CHAN == state_object->chan) {
382383
const enum fota_msg_type evt = MSG_TO_FOTA_TYPE(state_object->msg_buf);
383384

384385
switch (evt) {
385-
case FOTA_APPLY_IMAGE:
386+
case FOTA_IMAGE_APPLY:
386387

387388
LOG_DBG("Applying downloaded firmware image");
388389

@@ -395,7 +396,7 @@ static void state_waiting_for_network_disconnect_run(void *o)
395396
}
396397

397398
break;
398-
case FOTA_REBOOT_NEEDED:
399+
case FOTA_SUCCESS_REBOOT_NEEDED:
399400
STATE_SET(fota_state, STATE_REBOOT_NEEDED);
400401
break;
401402
default:

app/src/modules/fota/fota.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ enum fota_msg_type {
3232
/* Event notified if there is no available update. */
3333
FOTA_NO_AVAILABLE_UPDATE,
3434

35-
/* Event notified when a FOTA update has succeeded, reboot is needed */
36-
FOTA_REBOOT_NEEDED,
35+
/* Event notified when a FOTA update has succeeded, reboot is needed to apply the image. */
36+
FOTA_SUCCESS_REBOOT_NEEDED,
3737

3838
/* Event notified when the module needs the network to disconnect in order to apply
39-
* an update. When network has been disconnect, send the event FOTA_APPLY_IMAGE.
39+
* an update. When disconnected from the network, send the event FOTA_IMAGE_APPLY.
40+
* This is needed for Full Modem FOTA updates.
4041
*/
41-
FOTA_NETWORK_DISCONNECT_NEEDED,
42+
FOTA_IMAGE_APPLY_NEEDED,
4243

4344
/* Event notified when the FOTA update has been canceled. */
4445
FOTA_CANCELED,
@@ -49,7 +50,7 @@ enum fota_msg_type {
4950
FOTA_POLL_REQUEST,
5051

5152
/* Request to apply the downloaded firmware image. */
52-
FOTA_APPLY_IMAGE,
53+
FOTA_IMAGE_APPLY,
5354

5455
/* Cancel the FOTA process. */
5556
FOTA_CANCEL,

tests/module/fota/src/fota_module_test.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,15 @@ void test_fota_module_should_succeed(void)
158158

159159
/* 3. Download succeeded, validation needed */
160160
invoke_nrf_cloud_fota_callback_stub_status(NRF_CLOUD_FOTA_FMFU_VALIDATION_NEEDED);
161-
event_expect(FOTA_NETWORK_DISCONNECT_NEEDED);
161+
event_expect(FOTA_IMAGE_APPLY_NEEDED);
162162

163163
/* 4. Apply image */
164-
event_send(FOTA_APPLY_IMAGE);
165-
event_expect(FOTA_APPLY_IMAGE);
164+
event_send(FOTA_IMAGE_APPLY);
165+
event_expect(FOTA_IMAGE_APPLY);
166166

167167
/* 5. Reboot needed */
168168
invoke_nrf_cloud_fota_callback_stub_reboot(FOTA_REBOOT_SUCCESS);
169-
event_expect(FOTA_REBOOT_NEEDED);
169+
event_expect(FOTA_SUCCESS_REBOOT_NEEDED);
170170
}
171171

172172
void test_fota_module_should_fail_on_timeout(void)

0 commit comments

Comments
 (0)