@@ -33,8 +33,10 @@ ZBUS_MSG_SUBSCRIBER_DEFINE(fota);
33
33
/* Observe channels */
34
34
ZBUS_CHAN_ADD_OBS (TRIGGER_CHAN , fota , 0 );
35
35
ZBUS_CHAN_ADD_OBS (CLOUD_CHAN , fota , 0 );
36
+ ZBUS_CHAN_ADD_OBS (NETWORK_CHAN , fota , 0 );
36
37
37
- #define MAX_MSG_SIZE MAX(sizeof(enum trigger_type), sizeof(enum cloud_status))
38
+ #define MAX_MSG_SIZE MAX(MAX(sizeof(enum trigger_type), sizeof(enum cloud_status)), \
39
+ sizeof(enum network_status))
38
40
39
41
/* FOTA support context */
40
42
static void fota_reboot (enum nrf_cloud_fota_reboot_status status );
@@ -48,13 +50,15 @@ static void fota_status(enum nrf_cloud_fota_status status, const char *const sta
48
50
* STATE_WAIT_FOR_CLOUD: The FOTA module is initialized and waiting for cloud connection.
49
51
* STATE_WAIT_FOR_TRIGGER: The FOTA module is waiting for a trigger to poll for updates.
50
52
* STATE_POLL_AND_PROCESS: The FOTA module is polling for updates and processing them.
53
+ * STATE_WAIT_FOR_NETWORK_DISCONNECT: Waiting for network to disconnect before applying FMFU.
51
54
* STATE_REBOOT_PENDING: The nRF Cloud FOTA library has requested a reboot to complete an update.
52
55
*/
53
56
enum fota_module_state {
54
57
STATE_RUNNING ,
55
58
STATE_WAIT_FOR_CLOUD ,
56
59
STATE_WAIT_FOR_TRIGGER ,
57
60
STATE_POLL_AND_PROCESS ,
61
+ STATE_WAIT_FOR_NETWORK_DISCONNECT ,
58
62
STATE_REBOOT_PENDING ,
59
63
};
60
64
@@ -64,7 +68,10 @@ enum priv_fota_evt {
64
68
FOTA_PRIV_PROCESSING_DONE ,
65
69
/* FOTA processing is completed, reboot is needed */
66
70
FOTA_PRIV_REBOOT_PENDING ,
71
+ /* FMFU download complete, need validation of image */
72
+ FOTA_PRIV_FMFU_VALIDATION_NEEDED
67
73
};
74
+
68
75
/* User defined state object.
69
76
* Used to transfer data between state changes.
70
77
*/
@@ -99,6 +106,8 @@ static void state_wait_for_cloud_run(void *o);
99
106
static void state_wait_for_trigger_run (void * o );
100
107
static void state_poll_and_process_entry (void * o );
101
108
static void state_poll_and_process_run (void * o );
109
+ static void state_wait_for_network_disconnect_entry (void * o );
110
+ static void state_wait_for_network_disconnect_run (void * o );
102
111
static void state_reboot_pending_entry (void * o );
103
112
104
113
static struct s_object s_obj = {
@@ -124,6 +133,12 @@ static const struct smf_state states[] = {
124
133
NULL ,
125
134
& states [STATE_RUNNING ],
126
135
NULL ),
136
+ [STATE_WAIT_FOR_NETWORK_DISCONNECT ] =
137
+ SMF_CREATE_STATE (state_wait_for_network_disconnect_entry ,
138
+ state_wait_for_network_disconnect_run ,
139
+ NULL ,
140
+ & states [STATE_RUNNING ],
141
+ NULL ),
127
142
[STATE_REBOOT_PENDING ] =
128
143
SMF_CREATE_STATE (state_reboot_pending_entry , NULL , NULL ,
129
144
& states [STATE_RUNNING ],
@@ -224,13 +239,63 @@ static void state_poll_and_process_run(void *o)
224
239
/* The FOTA module has requested a reboot to complete an update */
225
240
STATE_SET (STATE_REBOOT_PENDING );
226
241
break ;
242
+ case FOTA_PRIV_FMFU_VALIDATION_NEEDED :
243
+ /* FMFU download is complete, need to validate the image */
244
+ STATE_SET (STATE_WAIT_FOR_NETWORK_DISCONNECT );
245
+ break ;
227
246
default :
228
247
LOG_ERR ("Unknown event: %d" , evt );
229
248
break ;
230
249
}
231
250
}
232
251
}
233
252
253
+ static void state_wait_for_network_disconnect_entry (void * o )
254
+ {
255
+ int err ;
256
+ enum network_status network_msg = NETWORK_DISCONNECT_REQUEST ;
257
+
258
+ ARG_UNUSED (o );
259
+
260
+ LOG_DBG ("Requesting network disconnect for FMFU application" );
261
+
262
+ err = zbus_chan_pub (& NETWORK_CHAN , & network_msg , K_SECONDS (1 ));
263
+ if (err ) {
264
+ LOG_ERR ("zbus_chan_pub, error: %d" , err );
265
+ SEND_FATAL_ERROR ();
266
+ }
267
+ }
268
+
269
+ static void state_wait_for_network_disconnect_run (void * o )
270
+ {
271
+ struct s_object * state_object = o ;
272
+ int err ;
273
+
274
+ if (& NETWORK_CHAN == state_object -> chan ) {
275
+ const enum network_status status = MSG_TO_NETWORK_STATUS (state_object -> msg_buf );
276
+
277
+ if (status == NETWORK_DISCONNECTED ) {
278
+ LOG_DBG ("Network disconnected, applying FMFU" );
279
+
280
+ err = nrf_cloud_fota_poll_update_apply (& state_object -> fota_ctx );
281
+ if (err ) {
282
+ LOG_ERR ("nrf_cloud_fota_poll_update_apply, error: %d" , err );
283
+ SEND_FATAL_ERROR ();
284
+ return ;
285
+ }
286
+ }
287
+ }
288
+
289
+ if (& PRIV_FOTA_CHAN == state_object -> chan ) {
290
+ const enum priv_fota_evt evt = * (const enum priv_fota_evt * )state_object -> msg_buf ;
291
+
292
+ if (evt == FOTA_PRIV_REBOOT_PENDING ) {
293
+ STATE_SET (STATE_REBOOT_PENDING );
294
+ return ;
295
+ }
296
+ }
297
+ }
298
+
234
299
static void state_reboot_pending_entry (void * o )
235
300
{
236
301
ARG_UNUSED (o );
@@ -357,6 +422,11 @@ static void fota_status(enum nrf_cloud_fota_status status, const char *const sta
357
422
case NRF_CLOUD_FOTA_FAILED :
358
423
LOG_ERR ("Firmware download failed" );
359
424
425
+ status_events_notify (FOTA_STATUS_STOP );
426
+ break ;
427
+ case NRF_CLOUD_FOTA_CANCELED :
428
+ LOG_WRN ("Firmware download canceled" );
429
+
360
430
status_events_notify (FOTA_STATUS_STOP );
361
431
break ;
362
432
case NRF_CLOUD_FOTA_TIMED_OUT :
@@ -369,6 +439,11 @@ static void fota_status(enum nrf_cloud_fota_status status, const char *const sta
369
439
370
440
status_events_notify (FOTA_STATUS_STOP );
371
441
return ;
442
+ case NRF_CLOUD_FOTA_FMFU_VALIDATION_NEEDED :
443
+ LOG_DBG ("Full modem FOTA validation needed" );
444
+
445
+ evt = FOTA_PRIV_FMFU_VALIDATION_NEEDED ;
446
+ break ;
372
447
default :
373
448
LOG_ERR ("Unknown FOTA status: %d" , status );
374
449
break ;
0 commit comments