Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/scripts/build_bootloaders.py
9515 views
1
#!/usr/bin/env python3
2
3
# flake8: noqa
4
5
"""
6
script to build all of our bootloaders using AP_Bootloader and put the resulting binaries in Tools/bootloaders
7
"""
8
9
import os
10
import shutil
11
import subprocess
12
import sys
13
import fnmatch
14
import re
15
16
# get command line arguments
17
from argparse import ArgumentParser
18
parser = ArgumentParser(description='This Program is used to build ArduPilot bootloaders for boards.')
19
parser.add_argument("--signing-key", type=str, action='append', help="signing key for secure bootloader (can be used multiple times)")
20
parser.add_argument("--omit-ardupilot-keys", action='store_true', default=False, help="omit ArduPilot signing keys")
21
parser.add_argument("--debug", action='store_true', default=False, help="build with debug symbols")
22
parser.add_argument("--periph-only", action='store_true', default=False, help="only build AP_Periph boards")
23
parser.add_argument("pattern", type=str, default='*', help="board wildcard pattern", nargs='?')
24
args = parser.parse_args()
25
26
os.environ['PYTHONUNBUFFERED'] = '1'
27
28
failed_boards = set()
29
30
def has_hwdef_bl(board):
31
"""Return True if libraries/AP_HAL_ChibiOS/hwdef/<board>/hwdef-bl.dat exists"""
32
hwdef = os.path.join('libraries', 'AP_HAL_ChibiOS', 'hwdef', board, 'hwdef-bl.dat')
33
return os.path.exists(hwdef)
34
35
36
def read_hwdef(filepath):
37
'''read a hwdef file recursively'''
38
fh = open(filepath)
39
ret = []
40
text = fh.readlines()
41
for line in text:
42
m = re.match(r"^\s*include\s+(.+)\s*$", line)
43
if m is not None:
44
ret += read_hwdef(os.path.join(os.path.dirname(filepath), m.group(1)))
45
else:
46
ret += [line]
47
return ret
48
49
def is_ap_periph(hwdef):
50
'''return True if a hwdef is for a AP_Periph board'''
51
lines = read_hwdef(hwdef)
52
for line in lines:
53
if line.find('AP_PERIPH') != -1:
54
return True
55
return False
56
57
def get_board_list():
58
'''add boards based on existence of hwdef-bl.dat in subdirectories for ChibiOS'''
59
board_list = []
60
dirname, dirlist, filenames = next(os.walk('libraries/AP_HAL_ChibiOS/hwdef'))
61
for d in dirlist:
62
hwdef = os.path.join(dirname, d, 'hwdef-bl.dat')
63
if os.path.exists(hwdef):
64
if args.periph_only and not is_ap_periph(hwdef):
65
continue
66
board_list.append(d)
67
return board_list
68
69
def validate_signing_keys(keys):
70
"""Validate that all signing key files exist and are not private keys"""
71
missing_keys = []
72
private_keys = []
73
74
for key in keys:
75
if not os.path.isfile(key):
76
missing_keys.append(key)
77
elif os.path.basename(key).lower().find("private") != -1:
78
private_keys.append(key)
79
80
if missing_keys:
81
print("Error: The following files were not found:")
82
for key in missing_keys:
83
print(f" {key}")
84
sys.exit(1)
85
86
if private_keys:
87
print("Error: You must use the public key in the bootloader. Check the following files:")
88
for key in private_keys:
89
print(f" {key}")
90
sys.exit(1)
91
92
if args.signing_key is not None:
93
validate_signing_keys(args.signing_key)
94
95
def run_program(cmd_list):
96
print("Running (%s)" % " ".join(cmd_list))
97
retcode = subprocess.call(cmd_list)
98
if retcode != 0:
99
print("Build failed: %s" % ' '.join(cmd_list))
100
return False
101
return True
102
103
104
def build_board(board):
105
# do not attempt to build a bootloader for boards without hwdef-bl.dat
106
if not has_hwdef_bl(board):
107
print(f"Skipping {board}: no hwdef-bl.dat (no bootloader for this board)")
108
return True # treat as success, since there is nothing to build
109
110
configure_args = "--board %s --bootloader --no-submodule-update --Werror" % board
111
configure_args = configure_args.split()
112
if args.signing_key is not None:
113
print("Building secure bootloader")
114
configure_args.append("--signed-fw")
115
if args.debug:
116
print("Building with debug symbols")
117
configure_args.append("--debug")
118
if not run_program(["./waf", "configure"] + configure_args):
119
return False
120
if not run_program(["./waf", "clean"]):
121
return False
122
if not run_program(["./waf", "bootloader"]):
123
return False
124
return True
125
126
board_list = get_board_list()
127
def get_all_board_dirs():
128
dirname, dirlist, filenames = next(os.walk('libraries/AP_HAL_ChibiOS/hwdef'))
129
return dirlist
130
131
all_board_dirs = get_all_board_dirs()
132
133
# Determine pattern matches against *all* directories and against buildable boards
134
matches_all = [b for b in all_board_dirs if fnmatch.fnmatch(b, args.pattern)]
135
matches_buildable = [b for b in board_list if fnmatch.fnmatch(b, args.pattern)]
136
137
# If nothing matches any directory name at all, warn once
138
if args.pattern != '*' and not matches_all:
139
print(f"Warning: no board matches pattern '{args.pattern}'. Continuing.")
140
141
# For directories that match the pattern but *aren't* buildable (no hwdef-bl.dat),
142
# print the explicit skip message now so users see why their requested board didn't build.
143
for b in matches_all:
144
if b not in board_list:
145
print(f"Skipping {b}: no hwdef-bl.dat (no bootloader for this board)")
146
147
additional_args = []
148
if args.omit_ardupilot_keys:
149
# If the user has requested to omit ardupilot keys, ensure it is forwarded to the make_secure_bl program
150
additional_args.append("--omit-ardupilot-keys")
151
152
# check that the user-supplied board pattern matches something; if not, warn and exit
153
for board in board_list:
154
if not fnmatch.fnmatch(board, args.pattern):
155
continue
156
if not has_hwdef_bl(board):
157
print(f"Skipping {board}: no hwdef-bl.dat (no bootloader for this board)")
158
continue
159
print("Building for %s" % board)
160
if not build_board(board):
161
failed_boards.add(board)
162
continue
163
bl_file = 'Tools/bootloaders/%s_bl.bin' % board
164
hex_file = 'Tools/bootloaders/%s_bl.hex' % board
165
elf_file = 'Tools/bootloaders/%s_bl.elf' % board
166
shutil.copy('build/%s/bin/AP_Bootloader.bin' % board, bl_file)
167
print("Created %s" % bl_file)
168
shutil.copy('build/%s/bootloader/AP_Bootloader' % board, elf_file)
169
print("Created %s" % elf_file)
170
if args.signing_key is not None:
171
print("Signing bootloader with %s" % ", ".join(args.signing_key))
172
if not run_program(["./Tools/scripts/signing/make_secure_bl.py", *additional_args, bl_file] + args.signing_key):
173
print("Failed to sign bootloader for %s" % board)
174
sys.exit(1)
175
if not run_program(["./Tools/scripts/signing/make_secure_bl.py", *additional_args, elf_file] + args.signing_key):
176
print("Failed to sign ELF bootloader for %s" % board)
177
sys.exit(1)
178
if not run_program([sys.executable, "Tools/scripts/bin2hex.py", "--offset", "0x08000000", bl_file, hex_file]):
179
failed_boards.add(board)
180
continue
181
print("Created %s" % hex_file)
182
183
if len(failed_boards):
184
print("Failed boards: %s" % list(failed_boards))
185
186