15
15
#include <uavcan.protocol.RestartNode.h>
16
16
#include <uavcan.protocol.GetNodeInfo.h>
17
17
18
+ #ifdef MODULE_UAVCAN_DEBUG_ENABLED
19
+ #include <modules/uavcan_debug/uavcan_debug.h>
20
+ #define BL_DEBUG (...) uavcan_send_debug_msg(UAVCAN_PROTOCOL_DEBUG_LOGLEVEL_DEBUG, "BL", __VA_ARGS__)
21
+ #else
22
+ #define BL_DEBUG (...) {}
23
+ #endif
24
+
25
+ #ifdef BOOTLOADER_SUPPORT_BROADCAST_UPDATE
26
+ #include <com.hex.file.FileStreamStart.h>
27
+ #include <com.hex.file.FileStreamChunk.h>
28
+ #endif // BOOTLOADER_SUPPORT_BROADCAST_UPDATE
29
+
18
30
#if __GNUC__ != 6 || __GNUC_MINOR__ != 3 || __GNUC_PATCHLEVEL__ != 1
19
31
#error Please use arm-none-eabi-gcc 6.3.1.
20
32
#endif
@@ -40,13 +52,17 @@ static const struct shared_hw_info_s _hw_info = BOARD_CONFIG_HW_INFO_STRUCTURE;
40
52
static struct {
41
53
bool in_progress ;
42
54
uint32_t ofs ;
55
+ uint32_t read_req_ofs ;
43
56
uint32_t app_start_ofs ;
44
57
uint8_t uavcan_idx ;
45
58
uint8_t read_transfer_id ;
46
59
uint8_t retries ;
47
60
uint8_t source_node_id ;
48
61
int32_t last_erased_page ;
49
62
char path [201 ];
63
+ #ifdef BOOTLOADER_SUPPORT_BROADCAST_UPDATE
64
+ bool using_stream_mode ;
65
+ #endif // BOOTLOADER_SUPPORT_BROADCAST_UPDATE
50
66
} flash_state ;
51
67
52
68
static struct {
@@ -64,11 +80,18 @@ static struct worker_thread_listener_task_s restart_req_listener_task;
64
80
static struct worker_thread_timer_task_s delayed_restart_task ;
65
81
static struct worker_thread_listener_task_s getnodeinfo_req_listener_task ;
66
82
83
+ #ifdef BOOTLOADER_SUPPORT_BROADCAST_UPDATE
84
+ static struct worker_thread_listener_task_s filestreamchunk_listener_task ;
85
+ static void filestreamchunk_handler (size_t msg_size , const void * buf , void * ctx );
86
+
87
+ // static struct worker_thread_listener_task_s filestreamstart_res_listener_task;
88
+ // static void filestreamstart_res_handler(size_t msg_size, const void* buf, void* ctx);
89
+ #endif // BOOTLOADER_SUPPORT_BROADCAST_UPDATE
90
+
67
91
static void file_beginfirmwareupdate_request_handler (size_t msg_size , const void * buf , void * ctx );
68
92
static void begin_flash_from_path (uint8_t uavcan_idx , uint8_t source_node_id , const char * path );
69
93
static void file_read_response_handler (size_t msg_size , const void * buf , void * ctx );
70
- static void do_resend_read_request (void );
71
- static void do_send_read_request (void );
94
+ static void do_send_read_request (bool retry );
72
95
static uint32_t get_app_sec_size (void );
73
96
static void start_boot (struct worker_thread_timer_task_s * task );
74
97
static void update_app_info (void );
@@ -110,6 +133,14 @@ RUN_AFTER(UAVCAN_INIT) {
110
133
111
134
struct pubsub_topic_s * getnodeinfo_req_topic = uavcan_get_message_topic (0 , & uavcan_protocol_GetNodeInfo_req_descriptor );
112
135
worker_thread_add_listener_task (& WT , & getnodeinfo_req_listener_task , getnodeinfo_req_topic , getnodeinfo_req_handler , NULL );
136
+
137
+ #ifdef BOOTLOADER_SUPPORT_BROADCAST_UPDATE
138
+ struct pubsub_topic_s * filestreamchunk_topic = uavcan_get_message_topic (0 , & com_hex_file_FileStreamChunk_descriptor );
139
+ worker_thread_add_listener_task (& WT , & filestreamchunk_listener_task , filestreamchunk_topic , filestreamchunk_handler , NULL );
140
+
141
+ // struct pubsub_topic_s* filestreamstart_res_topic = uavcan_get_message_topic(0, &com_hex_file_FileStreamStart_res_descriptor);
142
+ // worker_thread_add_listener_task(&WT, &filestreamstart_res_listener_task, filestreamstart_res_topic, filestreamstart_res_handler, NULL);
143
+ #endif // BOOTLOADER_SUPPORT_BROADCAST_UPDATE
113
144
}
114
145
115
146
static void getnodeinfo_req_handler (size_t msg_size , const void * buf , void * ctx ) {
@@ -168,71 +199,141 @@ static void begin_flash_from_path(uint8_t uavcan_idx, uint8_t source_node_id, co
168
199
cancel_boot_timer ();
169
200
memset (& flash_state , 0 , sizeof (flash_state ));
170
201
flash_state .in_progress = true;
171
- flash_state .ofs = 0 ;
202
+ flash_state .ofs = 0 ;
203
+ flash_state .read_transfer_id = 255 ;
172
204
flash_state .source_node_id = source_node_id ;
173
205
flash_state .uavcan_idx = uavcan_idx ;
174
206
strncpy (flash_state .path , path , 200 );
175
- worker_thread_add_timer_task (& WT , & read_timeout_task , read_request_response_timeout , NULL , chTimeMS2I (500 ), false);
176
- do_send_read_request ();
207
+ worker_thread_add_timer_task (& WT , & read_timeout_task , read_request_response_timeout , NULL , chTimeMS2I (2000 ), false);
208
+ do_send_read_request (false );
177
209
178
210
corrupt_app ();
179
211
flash_state .last_erased_page = -1 ;
180
212
}
181
213
182
- static void file_read_response_handler (size_t msg_size , const void * buf , void * ctx ) {
214
+ static void process_chunk (size_t chunk_size , const void * chunk ) {
215
+ if (flash_state .ofs + chunk_size > get_app_sec_size ()) {
216
+ do_fail_update ();
217
+ BL_DEBUG ("fail: file too large" );
218
+ return ;
219
+ }
220
+
221
+ if (chunk_size == 0 ) {
222
+ on_update_complete ();
223
+ return ;
224
+ }
225
+
226
+ int32_t curr_page = get_app_page_from_ofs (flash_state .ofs + chunk_size );
227
+ if (curr_page > flash_state .last_erased_page ) {
228
+ for (int32_t i = flash_state .last_erased_page + 1 ; i <=curr_page ; i ++ ) {
229
+ erase_app_page (i );
230
+ }
231
+ }
232
+
233
+ if (chunk_size < 256 ) {
234
+ struct flash_write_buf_s buf = {((chunk_size /FLASH_WORD_SIZE ) + 1 ) * FLASH_WORD_SIZE , chunk };
235
+ flash_write ((void * )get_app_address_from_ofs (flash_state .ofs ), 1 , & buf );
236
+ on_update_complete ();
237
+ } else {
238
+ struct flash_write_buf_s buf = {chunk_size , chunk };
239
+ flash_write ((void * )get_app_address_from_ofs (flash_state .ofs ), 1 , & buf );
240
+ flash_state .ofs += chunk_size ;
241
+ do_send_read_request (false);
242
+ }
243
+ }
244
+
245
+ // TODO factor common code out of read_response_handler and filestreamchunk_handler
246
+ #ifdef BOOTLOADER_SUPPORT_BROADCAST_UPDATE
247
+ static void filestreamchunk_handler (size_t msg_size , const void * buf , void * ctx ) {
183
248
(void )msg_size ;
184
249
(void )ctx ;
250
+
185
251
if (flash_state .in_progress ) {
186
252
const struct uavcan_deserialized_message_s * msg_wrapper = buf ;
187
- const struct uavcan_protocol_file_Read_res_s * res = (const struct uavcan_protocol_file_Read_res_s * )msg_wrapper -> msg ;
253
+ const struct com_hex_file_FileStreamChunk_s * msg = (const struct com_hex_file_FileStreamChunk_s * )msg_wrapper -> msg ;
188
254
189
- if (msg_wrapper -> transfer_id != flash_state .read_transfer_id ) {
255
+ if (msg -> path .path_len != strnlen (flash_state .path , 200 ) || memcmp (flash_state .path , msg -> path .path , msg -> path .path_len ) != 0 ) {
256
+ // Not our stream
190
257
return ;
191
258
}
192
259
193
- if (res -> error .value != 0 || flash_state .ofs + res -> data_len > get_app_sec_size ()) {
194
- do_fail_update ();
260
+ flash_state .using_stream_mode = true;
261
+ worker_thread_timer_task_reschedule (& WT , & read_timeout_task , chTimeMS2I (2000 ));
262
+
263
+ if (msg -> offset > flash_state .ofs ) {
264
+ // We need to ask for the stream to go back to our offset
265
+ struct com_hex_file_FileStreamStart_req_s req ;
266
+ req .path .path_len = strnlen (flash_state .path , 200 );
267
+ req .offset = flash_state .ofs ;
268
+ memcpy (req .path .path , flash_state .path , req .path .path_len );
269
+ uavcan_request (flash_state .uavcan_idx , & com_hex_file_FileStreamStart_req_descriptor , CANARD_TRANSFER_PRIORITY_MEDIUM + 1 , flash_state .source_node_id , & req );
195
270
return ;
196
271
}
197
272
198
- if (res -> data_len == 0 ) {
199
- on_update_complete ();
273
+ if (msg -> offset != flash_state .ofs ) {
200
274
return ;
201
275
}
202
276
203
- int32_t curr_page = get_app_page_from_ofs (flash_state .ofs + res -> data_len );
204
- if (curr_page > flash_state .last_erased_page ) {
205
- for (int32_t i = flash_state .last_erased_page + 1 ; i <=curr_page ; i ++ ) {
206
- erase_app_page (i );
207
- }
277
+ process_chunk (msg -> data_len , msg -> data );
278
+ }
279
+ }
280
+ #endif // BOOTLOADER_SUPPORT_BROADCAST_UPDATE
281
+
282
+ static void file_read_response_handler (size_t msg_size , const void * buf , void * ctx ) {
283
+ (void )msg_size ;
284
+ (void )ctx ;
285
+ if (flash_state .in_progress ) {
286
+ const struct uavcan_deserialized_message_s * msg_wrapper = buf ;
287
+ const struct uavcan_protocol_file_Read_res_s * res = (const struct uavcan_protocol_file_Read_res_s * )msg_wrapper -> msg ;
288
+
289
+ if (msg_wrapper -> transfer_id != flash_state .read_transfer_id || flash_state .ofs != flash_state .read_req_ofs ) {
290
+ return ;
208
291
}
209
292
210
- if (res -> data_len < 256 ) {
211
- struct flash_write_buf_s buf = {((res -> data_len /FLASH_WORD_SIZE ) + 1 ) * FLASH_WORD_SIZE , (void * )res -> data };
212
- flash_write ((void * )get_app_address_from_ofs (flash_state .ofs ), 1 , & buf );
213
- on_update_complete ();
214
- } else {
215
- struct flash_write_buf_s buf = {res -> data_len , (void * )res -> data };
216
- flash_write ((void * )get_app_address_from_ofs (flash_state .ofs ), 1 , & buf );
217
- flash_state .ofs += res -> data_len ;
218
- do_send_read_request ();
293
+ if (res -> error .value != 0 ) {
294
+ do_fail_update ();
295
+ BL_DEBUG ("fail: file read error" );
296
+ return ;
219
297
}
298
+
299
+ process_chunk (res -> data_len , res -> data );
220
300
}
221
301
}
222
302
223
- static void do_resend_read_request (void ) {
303
+ static void do_send_read_request (bool retry ) {
304
+
305
+ #ifdef BOOTLOADER_SUPPORT_BROADCAST_UPDATE
306
+ if (!flash_state .using_stream_mode ) {
307
+ struct uavcan_protocol_file_Read_req_s read_req ;
308
+ flash_state .read_req_ofs = read_req .offset = flash_state .ofs ;
309
+ strncpy ((char * )read_req .path .path ,flash_state .path ,sizeof (read_req .path ));
310
+ read_req .path .path_len = strnlen (flash_state .path ,sizeof (read_req .path ));
311
+ flash_state .read_transfer_id = uavcan_request (flash_state .uavcan_idx , & uavcan_protocol_file_Read_req_descriptor , CANARD_TRANSFER_PRIORITY_MEDIUM + 1 , flash_state .source_node_id , & read_req );
312
+ }
313
+
314
+ if ((retry && flash_state .using_stream_mode ) || (flash_state .ofs < 2048 && !flash_state .using_stream_mode )) {
315
+ // attempt to start stream mode with the first few requests
316
+ struct com_hex_file_FileStreamStart_req_s req ;
317
+ req .offset = flash_state .ofs ;
318
+ req .path .path_len = strnlen (flash_state .path , 200 );
319
+ memcpy (req .path .path , flash_state .path , req .path .path_len );
320
+ uavcan_request (flash_state .uavcan_idx , & com_hex_file_FileStreamStart_req_descriptor , CANARD_TRANSFER_PRIORITY_MEDIUM + 1 , flash_state .source_node_id , & req );
321
+ }
322
+ #else
224
323
struct uavcan_protocol_file_Read_req_s read_req ;
225
324
read_req .offset = flash_state .ofs ;
226
325
strncpy ((char * )read_req .path .path ,flash_state .path ,sizeof (read_req .path ));
227
326
read_req .path .path_len = strnlen (flash_state .path ,sizeof (read_req .path ));
228
- flash_state .read_transfer_id = uavcan_request (flash_state .uavcan_idx , & uavcan_protocol_file_Read_req_descriptor , CANARD_TRANSFER_PRIORITY_HIGH , flash_state .source_node_id , & read_req );
229
- worker_thread_timer_task_reschedule (& WT , & read_timeout_task , chTimeMS2I (500 ));
230
- flash_state .retries ++ ;
231
- }
327
+ flash_state .read_transfer_id = uavcan_request (flash_state .uavcan_idx , & uavcan_protocol_file_Read_req_descriptor , CANARD_TRANSFER_PRIORITY_MEDIUM + 1 , flash_state .source_node_id , & read_req );
328
+ #endif
232
329
233
- static void do_send_read_request (void ) {
234
- do_resend_read_request ();
235
- flash_state .retries = 0 ;
330
+ worker_thread_timer_task_reschedule (& WT , & read_timeout_task , chTimeMS2I (1000 ));
331
+
332
+ if (retry ) {
333
+ flash_state .retries ++ ;
334
+ } else {
335
+ flash_state .retries = 0 ;
336
+ }
236
337
}
237
338
238
339
static uint32_t get_app_sec_size (void ) {
@@ -414,9 +515,10 @@ static void delayed_restart_func(struct worker_thread_timer_task_s* task) {
414
515
static void read_request_response_timeout (struct worker_thread_timer_task_s * task ) {
415
516
(void )task ;
416
517
if (flash_state .in_progress ) {
417
- do_resend_read_request ( );
418
- if (flash_state .retries > 10 ) { // retry for 5 seconds
518
+ do_send_read_request (true );
519
+ if (flash_state .retries > 100 ) { // retry for 5 seconds
419
520
do_fail_update ();
521
+ BL_DEBUG ("fail: out of retries" );
420
522
}
421
523
}
422
524
}
0 commit comments