CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/AP_Bootloader/can.cpp
Views: 1798
1
/*
2
This program is free software: you can redistribute it and/or modify
3
it under the terms of the GNU General Public License as published by
4
the Free Software Foundation, either version 3 of the License, or
5
(at your option) any later version.
6
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
11
12
You should have received a copy of the GNU General Public License
13
along with this program. If not, see <http://www.gnu.org/licenses/>.
14
*/
15
/*
16
CAN bootloader support
17
*/
18
#include <AP_HAL/AP_HAL.h>
19
#include <hal.h>
20
#if HAL_USE_CAN == TRUE || HAL_NUM_CAN_IFACES
21
#include <AP_Math/AP_Math.h>
22
#include <AP_Math/crc.h>
23
#include <canard.h>
24
#include "support.h"
25
#include <dronecan_msgs.h>
26
#include "can.h"
27
#include "bl_protocol.h"
28
#include <drivers/stm32/canard_stm32.h>
29
#include "app_comms.h"
30
#include <AP_HAL_ChibiOS/hwdef/common/watchdog.h>
31
#include <stdio.h>
32
#include <AP_HAL_ChibiOS/CANIface.h>
33
#include <AP_CheckFirmware/AP_CheckFirmware.h>
34
35
static CanardInstance canard;
36
static uint32_t canard_memory_pool[4096/4];
37
#ifndef HAL_CAN_DEFAULT_NODE_ID
38
#define HAL_CAN_DEFAULT_NODE_ID CANARD_BROADCAST_NODE_ID
39
#endif
40
static uint8_t initial_node_id = HAL_CAN_DEFAULT_NODE_ID;
41
42
// can config for 1MBit
43
static uint32_t baudrate = 1000000U;
44
45
#if HAL_USE_CAN
46
static CANConfig cancfg = {
47
CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
48
0 // filled in below
49
};
50
// pipelining is not faster when using ChibiOS CAN driver
51
#define FW_UPDATE_PIPELINE_LEN 1
52
#else
53
ChibiOS::CANIface can_iface[HAL_NUM_CAN_IFACES];
54
#endif
55
56
#ifndef CAN_APP_VERSION_MAJOR
57
#define CAN_APP_VERSION_MAJOR 2
58
#endif
59
#ifndef CAN_APP_VERSION_MINOR
60
#define CAN_APP_VERSION_MINOR 0
61
#endif
62
#ifndef CAN_APP_NODE_NAME
63
#define CAN_APP_NODE_NAME "org.ardupilot." CHIBIOS_BOARD_NAME
64
#endif
65
66
#ifdef EXT_FLASH_SIZE_MB
67
static_assert(EXT_FLASH_SIZE_MB == 0, "DroneCAN bootloader cannot support external flash");
68
#endif
69
70
static uint8_t node_id_allocation_transfer_id;
71
static uavcan_protocol_NodeStatus node_status;
72
static uint32_t send_next_node_id_allocation_request_at_ms;
73
static uint8_t node_id_allocation_unique_id_offset;
74
75
static void processTx(void);
76
77
// keep up to 4 transfers in progress
78
#ifndef FW_UPDATE_PIPELINE_LEN
79
#define FW_UPDATE_PIPELINE_LEN 4
80
#endif
81
82
#if CH_CFG_USE_MUTEXES == TRUE
83
static HAL_Semaphore can_mutex;
84
#endif
85
86
static struct {
87
uint32_t rtt_ms;
88
uint32_t ofs;
89
uint8_t node_id;
90
uint8_t path[sizeof(uavcan_protocol_file_Path::path.data)+1];
91
uint8_t sector;
92
uint32_t sector_ofs;
93
uint8_t transfer_id;
94
uint8_t idx;
95
struct {
96
uint8_t tx_id;
97
uint32_t sent_ms;
98
uint32_t offset;
99
bool have_reply;
100
uavcan_protocol_file_ReadResponse pkt;
101
} reads[FW_UPDATE_PIPELINE_LEN];
102
uint16_t erased_to;
103
} fw_update;
104
105
/*
106
get cpu unique ID
107
*/
108
static void readUniqueID(uint8_t* out_uid)
109
{
110
uint8_t len = sizeof(uavcan_protocol_dynamic_node_id_Allocation::unique_id.data);
111
memset(out_uid, 0, len);
112
memcpy(out_uid, (const void *)UDID_START, MIN(len,12));
113
}
114
115
/*
116
simple 16 bit random number generator
117
*/
118
static uint16_t get_randomu16(void)
119
{
120
static uint32_t m_z = 1234;
121
static uint32_t m_w = 76542;
122
m_z = 36969 * (m_z & 0xFFFFu) + (m_z >> 16);
123
m_w = 18000 * (m_w & 0xFFFFu) + (m_w >> 16);
124
return ((m_z << 16) + m_w) & 0xFFFF;
125
}
126
127
128
/**
129
* Returns a pseudo random integer in a given range
130
*/
131
static uint32_t get_random_range(uint16_t range)
132
{
133
return get_randomu16() % range;
134
}
135
136
/*
137
handle a GET_NODE_INFO request
138
*/
139
static void handle_get_node_info(CanardInstance* ins,
140
CanardRxTransfer* transfer)
141
{
142
uint8_t buffer[UAVCAN_PROTOCOL_GETNODEINFO_RESPONSE_MAX_SIZE];
143
uavcan_protocol_GetNodeInfoResponse pkt {};
144
145
node_status.uptime_sec = AP_HAL::millis() / 1000U;
146
147
pkt.status = node_status;
148
pkt.software_version.major = CAN_APP_VERSION_MAJOR;
149
pkt.software_version.minor = CAN_APP_VERSION_MINOR;
150
151
readUniqueID(pkt.hardware_version.unique_id);
152
153
// use hw major/minor for APJ_BOARD_ID so we know what fw is
154
// compatible with this hardware
155
pkt.hardware_version.major = APJ_BOARD_ID >> 8;
156
pkt.hardware_version.minor = APJ_BOARD_ID & 0xFF;
157
158
char name[strlen(CAN_APP_NODE_NAME)+1];
159
strcpy(name, CAN_APP_NODE_NAME);
160
pkt.name.len = strlen(CAN_APP_NODE_NAME);
161
memcpy(pkt.name.data, name, pkt.name.len);
162
163
uint16_t total_size = uavcan_protocol_GetNodeInfoResponse_encode(&pkt, buffer, true);
164
165
canardRequestOrRespond(ins,
166
transfer->source_node_id,
167
UAVCAN_PROTOCOL_GETNODEINFO_SIGNATURE,
168
UAVCAN_PROTOCOL_GETNODEINFO_ID,
169
&transfer->transfer_id,
170
transfer->priority,
171
CanardResponse,
172
&buffer[0],
173
total_size);
174
}
175
176
/*
177
send a read for a fw update
178
*/
179
static bool send_fw_read(uint8_t idx)
180
{
181
auto &r = fw_update.reads[idx];
182
r.tx_id = fw_update.transfer_id;
183
r.have_reply = false;
184
185
uavcan_protocol_file_ReadRequest pkt {};
186
pkt.path.path.len = strlen((const char *)fw_update.path);
187
pkt.offset = r.offset;
188
memcpy(pkt.path.path.data, fw_update.path, pkt.path.path.len);
189
190
uint8_t buffer[UAVCAN_PROTOCOL_FILE_READ_REQUEST_MAX_SIZE];
191
uint16_t total_size = uavcan_protocol_file_ReadRequest_encode(&pkt, buffer, true);
192
193
if (canardRequestOrRespond(&canard,
194
fw_update.node_id,
195
UAVCAN_PROTOCOL_FILE_READ_SIGNATURE,
196
UAVCAN_PROTOCOL_FILE_READ_ID,
197
&fw_update.transfer_id,
198
CANARD_TRANSFER_PRIORITY_HIGH,
199
CanardRequest,
200
&buffer[0],
201
total_size) > 0) {
202
// mark it as having been sent
203
r.sent_ms = AP_HAL::millis();
204
return true;
205
}
206
return false;
207
}
208
209
/*
210
send a read for a fw update
211
*/
212
static void send_fw_reads(void)
213
{
214
const uint32_t now = AP_HAL::millis();
215
216
for (uint8_t i=0; i<FW_UPDATE_PIPELINE_LEN; i++) {
217
const uint8_t idx = (fw_update.idx+i) % FW_UPDATE_PIPELINE_LEN;
218
const auto &r = fw_update.reads[idx];
219
if (r.have_reply) {
220
continue;
221
}
222
if (r.sent_ms != 0 && now - r.sent_ms < 10+2*MAX(250,fw_update.rtt_ms)) {
223
// waiting on a response
224
continue;
225
}
226
if (!send_fw_read(idx)) {
227
break;
228
}
229
}
230
}
231
232
/*
233
erase up to at least the given sector number
234
*/
235
static void erase_to(uint16_t sector)
236
{
237
if (sector < fw_update.erased_to) {
238
return;
239
}
240
flash_func_erase_sector(sector);
241
fw_update.erased_to = sector+1;
242
243
/*
244
pre-erase any non-erased pages up to end of flash. This puts all
245
the load of erasing at the start of flashing which is much
246
faster than flashing as we go on boards with small flash
247
sectors. We stop at the first already erased page so we don't
248
end up wasting time erasing already erased pages when the
249
firmware is much smaller than the total flash size
250
*/
251
while (flash_func_sector_size(fw_update.erased_to) != 0 &&
252
!flash_func_is_erased(fw_update.erased_to)) {
253
flash_func_erase_sector(fw_update.erased_to);
254
fw_update.erased_to++;
255
}
256
}
257
258
/*
259
handle response to file read for fw update
260
*/
261
static void handle_file_read_response(CanardInstance* ins, CanardRxTransfer* transfer)
262
{
263
if (transfer->source_node_id != fw_update.node_id) {
264
return;
265
}
266
/*
267
match the response to a sent request
268
*/
269
uint8_t idx = 0;
270
bool found = false;
271
for (idx=0; idx<FW_UPDATE_PIPELINE_LEN; idx++) {
272
const auto &r = fw_update.reads[idx];
273
if (r.tx_id == transfer->transfer_id) {
274
found = true;
275
break;
276
}
277
}
278
if (!found) {
279
// not a current transfer, we may be getting long delays
280
fw_update.rtt_ms = MIN(3000, fw_update.rtt_ms+250);
281
return;
282
}
283
if (uavcan_protocol_file_ReadResponse_decode(transfer, &fw_update.reads[idx].pkt)) {
284
return;
285
}
286
fw_update.reads[idx].have_reply = true;
287
uint32_t rtt = MIN(3000,MAX(AP_HAL::millis() - fw_update.reads[idx].sent_ms, 25));
288
fw_update.rtt_ms = uint32_t(0.9 * fw_update.rtt_ms + 0.1 * rtt);
289
290
while (fw_update.reads[fw_update.idx].have_reply) {
291
auto &r = fw_update.reads[fw_update.idx];
292
if (r.offset != fw_update.ofs) {
293
// bad sequence
294
r.have_reply = false;
295
r.sent_ms = 0;
296
break;
297
}
298
const auto &pkt = r.pkt;
299
const uint16_t len = pkt.data.len;
300
const uint16_t len_words = (len+3U)/4U;
301
const uint8_t *buf = (uint8_t *)pkt.data.data;
302
uint32_t buf32[len_words] {};
303
memcpy((uint8_t*)buf32, buf, len);
304
305
if (fw_update.ofs == 0) {
306
flash_set_keep_unlocked(true);
307
}
308
309
const uint32_t sector_size = flash_func_sector_size(fw_update.sector);
310
if (sector_size == 0) {
311
// firmware is too big
312
fw_update.node_id = 0;
313
flash_write_flush();
314
flash_set_keep_unlocked(false);
315
node_status.vendor_specific_status_code = uint8_t(check_fw_result_t::FAIL_REASON_BAD_LENGTH_APP);
316
break;
317
}
318
if (fw_update.sector_ofs == 0) {
319
erase_to(fw_update.sector);
320
}
321
if (fw_update.sector_ofs+len > sector_size) {
322
erase_to(fw_update.sector+1);
323
}
324
if (!flash_write_buffer(fw_update.ofs, buf32, len_words)) {
325
continue;
326
}
327
328
fw_update.ofs += len;
329
fw_update.sector_ofs += len;
330
if (fw_update.sector_ofs >= flash_func_sector_size(fw_update.sector)) {
331
fw_update.sector++;
332
fw_update.sector_ofs -= sector_size;
333
}
334
335
if (len < sizeof(uavcan_protocol_file_ReadResponse::data.data)) {
336
fw_update.node_id = 0;
337
flash_write_flush();
338
flash_set_keep_unlocked(false);
339
const auto ok = check_good_firmware();
340
node_status.vendor_specific_status_code = uint8_t(ok);
341
if (ok == check_fw_result_t::CHECK_FW_OK) {
342
jump_to_app();
343
}
344
return;
345
}
346
347
r.have_reply = false;
348
r.sent_ms = 0;
349
r.offset += FW_UPDATE_PIPELINE_LEN*sizeof(uavcan_protocol_file_ReadResponse::data.data);
350
send_fw_read(fw_update.idx);
351
processTx();
352
353
fw_update.idx = (fw_update.idx + 1) % FW_UPDATE_PIPELINE_LEN;
354
}
355
356
// show offset number we are flashing in kbyte as crude progress indicator
357
node_status.vendor_specific_status_code = 1 + (fw_update.ofs / 1024U);
358
}
359
360
/*
361
handle a begin firmware update request. We start pulling in the file data
362
*/
363
static void handle_begin_firmware_update(CanardInstance* ins, CanardRxTransfer* transfer)
364
{
365
if (fw_update.node_id == 0) {
366
uavcan_protocol_file_BeginFirmwareUpdateRequest pkt;
367
if (uavcan_protocol_file_BeginFirmwareUpdateRequest_decode(transfer, &pkt)) {
368
return;
369
}
370
if (pkt.image_file_remote_path.path.len > sizeof(fw_update.path)-1) {
371
return;
372
}
373
memset(&fw_update, 0, sizeof(fw_update));
374
for (uint8_t i=0; i<FW_UPDATE_PIPELINE_LEN; i++) {
375
fw_update.reads[i].offset = i*sizeof(uavcan_protocol_file_ReadResponse::data.data);
376
}
377
memcpy(fw_update.path, pkt.image_file_remote_path.path.data, pkt.image_file_remote_path.path.len);
378
fw_update.path[pkt.image_file_remote_path.path.len] = 0;
379
fw_update.node_id = pkt.source_node_id;
380
if (fw_update.node_id == 0) {
381
fw_update.node_id = transfer->source_node_id;
382
}
383
}
384
385
uint8_t buffer[UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_RESPONSE_MAX_SIZE];
386
uavcan_protocol_file_BeginFirmwareUpdateResponse reply {};
387
reply.error = UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_RESPONSE_ERROR_OK;
388
389
uint32_t total_size = uavcan_protocol_file_BeginFirmwareUpdateResponse_encode(&reply, buffer, true);
390
canardRequestOrRespond(ins,
391
transfer->source_node_id,
392
UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_SIGNATURE,
393
UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_ID,
394
&transfer->transfer_id,
395
transfer->priority,
396
CanardResponse,
397
&buffer[0],
398
total_size);
399
}
400
401
static void handle_allocation_response(CanardInstance* ins, CanardRxTransfer* transfer)
402
{
403
// Rule C - updating the randomized time interval
404
send_next_node_id_allocation_request_at_ms =
405
AP_HAL::millis() + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
406
get_random_range(UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MAX_FOLLOWUP_DELAY_MS);
407
408
if (transfer->source_node_id == CANARD_BROADCAST_NODE_ID)
409
{
410
node_id_allocation_unique_id_offset = 0;
411
return;
412
}
413
414
struct uavcan_protocol_dynamic_node_id_Allocation msg;
415
if (uavcan_protocol_dynamic_node_id_Allocation_decode(transfer, &msg)) {
416
return;
417
}
418
419
// Obtaining the local unique ID
420
uint8_t my_unique_id[sizeof(uavcan_protocol_dynamic_node_id_Allocation::unique_id.data)];
421
readUniqueID(my_unique_id);
422
423
// Matching the received UID against the local one
424
if (memcmp(msg.unique_id.data, my_unique_id, msg.unique_id.len) != 0) {
425
node_id_allocation_unique_id_offset = 0;
426
return; // No match, return
427
}
428
429
if (msg.unique_id.len < sizeof(msg.unique_id.data)) {
430
// The allocator has confirmed part of unique ID, switching to the next stage and updating the timeout.
431
node_id_allocation_unique_id_offset = msg.unique_id.len;
432
send_next_node_id_allocation_request_at_ms -= UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS;
433
} else if (msg.node_id != CANARD_BROADCAST_NODE_ID) { // new ID valid? (if not we will time out and start over)
434
// Allocation complete - copying the allocated node ID from the message
435
canardSetLocalNodeID(ins, msg.node_id);
436
}
437
}
438
439
/**
440
* This callback is invoked by the library when a new message or request or response is received.
441
*/
442
static void onTransferReceived(CanardInstance* ins,
443
CanardRxTransfer* transfer)
444
{
445
/*
446
* Dynamic node ID allocation protocol.
447
* Taking this branch only if we don't have a node ID, ignoring otherwise.
448
*/
449
if (canardGetLocalNodeID(ins) == CANARD_BROADCAST_NODE_ID) {
450
if (transfer->transfer_type == CanardTransferTypeBroadcast &&
451
transfer->data_type_id == UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID) {
452
handle_allocation_response(ins, transfer);
453
}
454
return;
455
}
456
457
switch (transfer->data_type_id) {
458
case UAVCAN_PROTOCOL_GETNODEINFO_ID:
459
handle_get_node_info(ins, transfer);
460
break;
461
462
case UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_ID:
463
handle_begin_firmware_update(ins, transfer);
464
break;
465
466
case UAVCAN_PROTOCOL_FILE_READ_ID:
467
handle_file_read_response(ins, transfer);
468
break;
469
470
case UAVCAN_PROTOCOL_RESTARTNODE_ID:
471
NVIC_SystemReset();
472
break;
473
}
474
}
475
476
477
/**
478
* This callback is invoked by the library when it detects beginning of a new transfer on the bus that can be received
479
* by the local node.
480
* If the callback returns true, the library will receive the transfer.
481
* If the callback returns false, the library will ignore the transfer.
482
* All transfers that are addressed to other nodes are always ignored.
483
*/
484
static bool shouldAcceptTransfer(const CanardInstance* ins,
485
uint64_t* out_data_type_signature,
486
uint16_t data_type_id,
487
CanardTransferType transfer_type,
488
uint8_t source_node_id)
489
{
490
(void)source_node_id;
491
492
if (canardGetLocalNodeID(ins) == CANARD_BROADCAST_NODE_ID) {
493
/*
494
* If we're in the process of allocation of dynamic node ID, accept only relevant transfers.
495
*/
496
if ((transfer_type == CanardTransferTypeBroadcast) &&
497
(data_type_id == UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID))
498
{
499
*out_data_type_signature = UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_SIGNATURE;
500
return true;
501
}
502
return false;
503
}
504
505
switch (data_type_id) {
506
case UAVCAN_PROTOCOL_GETNODEINFO_ID:
507
*out_data_type_signature = UAVCAN_PROTOCOL_GETNODEINFO_SIGNATURE;
508
return true;
509
case UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_ID:
510
*out_data_type_signature = UAVCAN_PROTOCOL_FILE_BEGINFIRMWAREUPDATE_SIGNATURE;
511
return true;
512
case UAVCAN_PROTOCOL_RESTARTNODE_ID:
513
*out_data_type_signature = UAVCAN_PROTOCOL_RESTARTNODE_SIGNATURE;
514
return true;
515
case UAVCAN_PROTOCOL_FILE_READ_ID:
516
*out_data_type_signature = UAVCAN_PROTOCOL_FILE_READ_SIGNATURE;
517
return true;
518
default:
519
break;
520
}
521
522
return false;
523
}
524
525
#if HAL_USE_CAN
526
static void processTx(void)
527
{
528
static uint8_t fail_count;
529
for (const CanardCANFrame* txf = NULL; (txf = canardPeekTxQueue(&canard)) != NULL;) {
530
CANTxFrame txmsg {};
531
txmsg.DLC = txf->data_len;
532
memcpy(txmsg.data8, txf->data, 8);
533
txmsg.EID = txf->id & CANARD_CAN_EXT_ID_MASK;
534
txmsg.IDE = 1;
535
txmsg.RTR = 0;
536
if (canTransmit(&CAND1, CAN_ANY_MAILBOX, &txmsg, TIME_IMMEDIATE) == MSG_OK) {
537
canardPopTxQueue(&canard);
538
fail_count = 0;
539
} else {
540
// just exit and try again later. If we fail 8 times in a row
541
// then start discarding to prevent the pool filling up
542
if (fail_count < 8) {
543
fail_count++;
544
} else {
545
canardPopTxQueue(&canard);
546
}
547
return;
548
}
549
}
550
}
551
552
static void processRx(void)
553
{
554
CANRxFrame rxmsg {};
555
while (canReceive(&CAND1, CAN_ANY_MAILBOX, &rxmsg, TIME_IMMEDIATE) == MSG_OK) {
556
CanardCANFrame rx_frame {};
557
558
#ifdef HAL_GPIO_PIN_LED_BOOTLOADER
559
palToggleLine(HAL_GPIO_PIN_LED_BOOTLOADER);
560
#endif
561
const uint64_t timestamp = AP_HAL::micros64();
562
memcpy(rx_frame.data, rxmsg.data8, 8);
563
rx_frame.data_len = rxmsg.DLC;
564
if(rxmsg.IDE) {
565
rx_frame.id = CANARD_CAN_FRAME_EFF | rxmsg.EID;
566
} else {
567
rx_frame.id = rxmsg.SID;
568
}
569
canardHandleRxFrame(&canard, &rx_frame, timestamp);
570
}
571
}
572
#else
573
// Use HAL CAN interface
574
static void processTx(void)
575
{
576
static uint8_t fail_count;
577
for (const CanardCANFrame* txf = NULL; (txf = canardPeekTxQueue(&canard)) != NULL;) {
578
AP_HAL::CANFrame txmsg {};
579
txmsg.dlc = txf->data_len;
580
memcpy(txmsg.data, txf->data, 8);
581
txmsg.id = (txf->id | AP_HAL::CANFrame::FlagEFF);
582
// push message with 1s timeout
583
bool send_ok = false;
584
for (uint8_t i=0; i<HAL_NUM_CAN_IFACES; i++) {
585
send_ok |= (can_iface[i].send(txmsg, AP_HAL::micros64() + 1000000, 0) > 0);
586
}
587
if (send_ok) {
588
canardPopTxQueue(&canard);
589
fail_count = 0;
590
} else {
591
// just exit and try again later. If we fail 8 times in a row
592
// then start discarding to prevent the pool filling up
593
if (fail_count < 8) {
594
fail_count++;
595
} else {
596
canardPopTxQueue(&canard);
597
}
598
return;
599
}
600
}
601
}
602
603
static void processRx(void)
604
{
605
AP_HAL::CANFrame rxmsg;
606
while (true) {
607
bool got_pkt = false;
608
for (uint8_t i=0; i<HAL_NUM_CAN_IFACES; i++) {
609
bool read_select = true;
610
bool write_select = false;
611
can_iface[i].select(read_select, write_select, nullptr, 0);
612
if (!read_select) {
613
continue;
614
}
615
#ifdef HAL_GPIO_PIN_LED_BOOTLOADER
616
palToggleLine(HAL_GPIO_PIN_LED_BOOTLOADER);
617
#endif
618
CanardCANFrame rx_frame {};
619
620
//palToggleLine(HAL_GPIO_PIN_LED);
621
uint64_t timestamp;
622
AP_HAL::CANIface::CanIOFlags flags;
623
can_iface[i].receive(rxmsg, timestamp, flags);
624
memcpy(rx_frame.data, rxmsg.data, 8);
625
rx_frame.data_len = rxmsg.dlc;
626
rx_frame.id = rxmsg.id;
627
canardHandleRxFrame(&canard, &rx_frame, timestamp);
628
got_pkt = true;
629
}
630
if (!got_pkt) {
631
break;
632
}
633
}
634
}
635
#endif //#if HAL_USE_CAN
636
637
/*
638
wrapper around broadcast
639
*/
640
static void canard_broadcast(uint64_t data_type_signature,
641
uint16_t data_type_id,
642
uint8_t &transfer_id,
643
uint8_t priority,
644
const void* payload,
645
uint16_t payload_len)
646
{
647
#if CH_CFG_USE_MUTEXES == TRUE
648
WITH_SEMAPHORE(can_mutex);
649
#endif
650
canardBroadcast(&canard,
651
data_type_signature,
652
data_type_id,
653
&transfer_id,
654
priority,
655
payload,
656
payload_len);
657
}
658
659
660
/*
661
handle waiting for a node ID
662
*/
663
static void can_handle_DNA(void)
664
{
665
if (canardGetLocalNodeID(&canard) != CANARD_BROADCAST_NODE_ID) {
666
return;
667
}
668
669
if (AP_HAL::millis() < send_next_node_id_allocation_request_at_ms) {
670
return;
671
}
672
673
send_next_node_id_allocation_request_at_ms =
674
AP_HAL::millis() + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
675
get_random_range(UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MAX_FOLLOWUP_DELAY_MS);
676
677
// Structure of the request is documented in the DSDL definition
678
// See http://uavcan.org/Specification/6._Application_level_functions/#dynamic-node-id-allocation
679
uint8_t allocation_request[CANARD_CAN_FRAME_MAX_DATA_LEN - 1];
680
allocation_request[0] = (uint8_t)(CANARD_BROADCAST_NODE_ID << 1U);
681
682
if (node_id_allocation_unique_id_offset == 0) {
683
allocation_request[0] |= 1; // First part of unique ID
684
}
685
686
uint8_t my_unique_id[sizeof(uavcan_protocol_dynamic_node_id_Allocation::unique_id.data)];
687
readUniqueID(my_unique_id);
688
689
static const uint8_t MaxLenOfUniqueIDInRequest = 6;
690
uint8_t uid_size = (uint8_t)(sizeof(uavcan_protocol_dynamic_node_id_Allocation::unique_id.data) - node_id_allocation_unique_id_offset);
691
if (uid_size > MaxLenOfUniqueIDInRequest) {
692
uid_size = MaxLenOfUniqueIDInRequest;
693
}
694
695
memmove(&allocation_request[1], &my_unique_id[node_id_allocation_unique_id_offset], uid_size);
696
697
// Broadcasting the request
698
canard_broadcast(UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_SIGNATURE,
699
UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_ID,
700
node_id_allocation_transfer_id,
701
CANARD_TRANSFER_PRIORITY_LOW,
702
&allocation_request[0],
703
(uint16_t) (uid_size + 1));
704
705
// Preparing for timeout; if response is received, this value will be updated from the callback.
706
node_id_allocation_unique_id_offset = 0;
707
}
708
709
static void send_node_status(void)
710
{
711
uint8_t buffer[UAVCAN_PROTOCOL_NODESTATUS_MAX_SIZE];
712
node_status.uptime_sec = AP_HAL::millis() / 1000U;
713
714
uint32_t len = uavcan_protocol_NodeStatus_encode(&node_status, buffer, true);
715
716
static uint8_t transfer_id; // Note that the transfer ID variable MUST BE STATIC (or heap-allocated)!
717
718
canard_broadcast(UAVCAN_PROTOCOL_NODESTATUS_SIGNATURE,
719
UAVCAN_PROTOCOL_NODESTATUS_ID,
720
transfer_id,
721
CANARD_TRANSFER_PRIORITY_LOW,
722
buffer,
723
len);
724
}
725
726
727
/**
728
* This function is called at 1 Hz rate from the main loop.
729
*/
730
static void process1HzTasks(uint64_t timestamp_usec)
731
{
732
canardCleanupStaleTransfers(&canard, timestamp_usec);
733
734
if (canardGetLocalNodeID(&canard) != CANARD_BROADCAST_NODE_ID) {
735
node_status.mode = fw_update.node_id?UAVCAN_PROTOCOL_NODESTATUS_MODE_SOFTWARE_UPDATE:UAVCAN_PROTOCOL_NODESTATUS_MODE_MAINTENANCE;
736
send_node_status();
737
}
738
}
739
740
void can_set_node_id(uint8_t node_id)
741
{
742
initial_node_id = node_id;
743
}
744
745
// check for a firmware update marker left by app
746
bool can_check_update(void)
747
{
748
bool ret = false;
749
#if HAL_RAM_RESERVE_START >= 256
750
struct app_bootloader_comms *comms = (struct app_bootloader_comms *)HAL_RAM0_START;
751
if (comms->magic == APP_BOOTLOADER_COMMS_MAGIC && comms->my_node_id != 0) {
752
can_set_node_id(comms->my_node_id);
753
fw_update.node_id = comms->server_node_id;
754
for (uint8_t i=0; i<FW_UPDATE_PIPELINE_LEN; i++) {
755
fw_update.reads[i].offset = i*sizeof(uavcan_protocol_file_ReadResponse::data.data);
756
}
757
memcpy(fw_update.path, comms->path, sizeof(uavcan_protocol_file_Path::path.data)+1);
758
ret = true;
759
// clear comms region
760
memset(comms, 0, sizeof(struct app_bootloader_comms));
761
}
762
#endif
763
#if defined(CAN1_BASE) && defined(RCC_APB1ENR_CAN1EN)
764
// check for px4 fw update. px4 uses the filter registers in CAN1
765
// to communicate with the bootloader. This only works on CAN1
766
if (!ret && stm32_was_software_reset()) {
767
uint32_t *fir = (uint32_t *)(CAN1_BASE + 0x240);
768
struct PACKED app_shared {
769
union {
770
uint64_t ull;
771
uint32_t ul[2];
772
uint8_t valid;
773
} crc;
774
uint32_t signature;
775
uint32_t bus_speed;
776
uint32_t node_id;
777
} *app = (struct app_shared *)&fir[4];
778
/* we need to enable the CAN peripheral in order to look at
779
the FIR registers.
780
*/
781
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
782
static const uint32_t app_signature = 0xb0a04150;
783
if (app->signature == app_signature &&
784
app->node_id > 0 && app->node_id < 128) {
785
// crc is in reversed word order in FIR registers
786
uint32_t sig[3];
787
memcpy((uint8_t *)&sig[0], (const uint8_t *)&app->signature, sizeof(sig));
788
const uint64_t crc = crc_crc64(sig, 3);
789
const uint32_t *crc32 = (const uint32_t *)&crc;
790
if (crc32[0] == app->crc.ul[1] &&
791
crc32[1] == app->crc.ul[0]) {
792
// reset signature so we don't get in a boot loop
793
app->signature = 0;
794
// setup node ID
795
can_set_node_id(app->node_id);
796
// and baudrate
797
baudrate = app->bus_speed;
798
ret = true;
799
}
800
}
801
}
802
#endif
803
return ret;
804
}
805
806
void can_start()
807
{
808
node_status.vendor_specific_status_code = uint8_t(check_good_firmware());
809
node_status.mode = UAVCAN_PROTOCOL_NODESTATUS_MODE_MAINTENANCE;
810
811
#if HAL_USE_CAN
812
// calculate optimal CAN timings given PCLK1 and baudrate
813
CanardSTM32CANTimings timings {};
814
canardSTM32ComputeCANTimings(STM32_PCLK1, baudrate, &timings);
815
cancfg.btr = CAN_BTR_SJW(0) |
816
CAN_BTR_TS2(timings.bit_segment_2-1) |
817
CAN_BTR_TS1(timings.bit_segment_1-1) |
818
CAN_BTR_BRP(timings.bit_rate_prescaler-1);
819
canStart(&CAND1, &cancfg);
820
#else
821
for (uint8_t i=0; i<HAL_NUM_CAN_IFACES; i++) {
822
can_iface[i].init(baudrate, AP_HAL::CANIface::NormalMode);
823
}
824
#endif
825
canardInit(&canard, (uint8_t *)canard_memory_pool, sizeof(canard_memory_pool),
826
onTransferReceived, shouldAcceptTransfer, NULL);
827
828
if (initial_node_id != CANARD_BROADCAST_NODE_ID) {
829
canardSetLocalNodeID(&canard, initial_node_id);
830
}
831
832
send_next_node_id_allocation_request_at_ms =
833
AP_HAL::millis() + UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MIN_REQUEST_PERIOD_MS +
834
get_random_range(UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_ALLOCATION_MAX_FOLLOWUP_DELAY_MS);
835
836
if (stm32_was_watchdog_reset()) {
837
node_status.vendor_specific_status_code = uint8_t(check_fw_result_t::FAIL_REASON_WATCHDOG);
838
}
839
}
840
841
842
void can_update()
843
{
844
// do one loop of CAN support. If we are doing a firmware update
845
// then loop until it is finished
846
do {
847
processTx();
848
processRx();
849
can_handle_DNA();
850
static uint32_t last_1Hz_ms;
851
uint32_t now = AP_HAL::millis();
852
if (now - last_1Hz_ms >= 1000) {
853
last_1Hz_ms = now;
854
process1HzTasks(AP_HAL::micros64());
855
}
856
if (fw_update.node_id != 0) {
857
send_fw_reads();
858
}
859
#if CH_CFG_ST_FREQUENCY >= 1000000
860
// give a bit of time for background processing
861
chThdSleepMicroseconds(200);
862
#endif
863
} while (fw_update.node_id != 0);
864
}
865
866
// printf to CAN LogMessage for debugging
867
void can_vprintf(const char *fmt, va_list ap)
868
{
869
// only on H7 for now, where we have plenty of flash
870
#if defined(STM32H7)
871
uavcan_protocol_debug_LogMessage pkt {};
872
uint8_t buffer[UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_MAX_SIZE];
873
uint32_t n = vsnprintf((char*)pkt.text.data, sizeof(pkt.text.data), fmt, ap);
874
pkt.text.len = MIN(n, sizeof(pkt.text.data));
875
876
uint32_t len = uavcan_protocol_debug_LogMessage_encode(&pkt, buffer, true);
877
static uint8_t logmsg_transfer_id;
878
879
canard_broadcast(UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_SIGNATURE,
880
UAVCAN_PROTOCOL_DEBUG_LOGMESSAGE_ID,
881
logmsg_transfer_id,
882
CANARD_TRANSFER_PRIORITY_LOW,
883
buffer,
884
len);
885
#endif // defined(STM32H7)
886
}
887
888
// printf to CAN LogMessage for debugging
889
void can_printf(const char *fmt, ...)
890
{
891
// only on H7 for now, where we have plenty of flash
892
#if defined(STM32H7)
893
va_list ap;
894
va_start(ap, fmt);
895
can_vprintf(fmt, ap);
896
va_end(ap);
897
#endif // defined(STM32H7)
898
}
899
900
void can_printf_severity(uint8_t severity, const char *fmt, ...)
901
{
902
// only on H7 for now, where we have plenty of flash
903
#if defined(STM32H7)
904
va_list ap;
905
va_start(ap, fmt);
906
can_vprintf(fmt, ap);
907
va_end(ap);
908
#endif
909
}
910
911
912
#endif // HAL_USE_CAN
913
914