Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/ardupilotwaf/chibios.py
9734 views
1
# encoding: utf-8
2
3
# flake8: noqa
4
5
"""
6
Waf tool for ChibiOS build
7
"""
8
9
from waflib import Errors, Logs, Task, Utils, Context
10
from waflib.TaskGen import after_method, before_method, feature
11
12
import os
13
import shutil
14
import sys
15
import re
16
import pickle
17
import struct
18
import base64
19
import subprocess
20
import traceback
21
22
import hal_common
23
24
# sys.path already set up at the top of boards.py
25
import chibios_hwdef
26
27
_dynamic_env_data = {}
28
def _load_dynamic_env_data(bld):
29
bldnode = bld.bldnode.make_node('modules/ChibiOS')
30
include_dirs_node = bldnode.find_node('include_dirs')
31
if include_dirs_node is None:
32
_dynamic_env_data['include_dirs'] = []
33
return
34
tmp_str = include_dirs_node.read()
35
tmp_str = tmp_str.replace(';\n','')
36
tmp_str = tmp_str.replace('-I','') #remove existing -I flags
37
# split, coping with separator
38
idirs = re.split('; ', tmp_str)
39
40
# create unique list, coping with relative paths
41
idirs2 = []
42
for d in idirs:
43
if d.startswith('../'):
44
# relative paths from the make build are relative to BUILDROOT
45
d = os.path.join(bld.env.BUILDROOT, d)
46
d = os.path.normpath(d)
47
if d not in idirs2:
48
idirs2.append(d)
49
_dynamic_env_data['include_dirs'] = idirs2
50
51
@feature('ch_ap_library', 'ch_ap_program')
52
@before_method('process_source')
53
def ch_dynamic_env(self):
54
# The generated files from configuration possibly don't exist if it's just
55
# a list command (TODO: figure out a better way to address that).
56
if self.bld.cmd == 'list':
57
return
58
59
if not _dynamic_env_data:
60
_load_dynamic_env_data(self.bld)
61
self.env.append_value('INCLUDES', _dynamic_env_data['include_dirs'])
62
63
64
class upload_fw(Task.Task):
65
color='BLUE'
66
always_run = True
67
def run(self):
68
import platform
69
upload_tools = self.env.get_flat('UPLOAD_TOOLS')
70
upload_port = self.generator.bld.options.upload_port
71
src = self.inputs[0]
72
# Refer Tools/scripts/macos_remote_upload.sh for details
73
if 'AP_OVERRIDE_UPLOAD_CMD' in os.environ:
74
cmd = "{} '{}'".format(os.environ['AP_OVERRIDE_UPLOAD_CMD'], src.abspath())
75
elif "microsoft-standard-WSL2" in platform.release():
76
if not self.wsl2_prereq_checks():
77
return
78
print("If this takes takes too long here, try power-cycling your hardware\n")
79
cmd = "{} -u '{}/uploader.py' '{}'".format('python.exe', upload_tools, src.abspath())
80
else:
81
cmd = "{} '{}/uploader.py' '{}'".format(self.env.get_flat('PYTHON'), upload_tools, src.abspath())
82
if upload_port is not None:
83
cmd += " '--port' '%s'" % upload_port
84
if self.generator.bld.options.upload_force:
85
cmd += " '--force'"
86
return self.exec_command(cmd)
87
88
def wsl2_prereq_checks(self):
89
# As of July 2022 WSL2 does not support native USB support. The workaround from Microsoft
90
# using 'usbipd' does not work due to the following workflow:
91
#
92
# 1) connect USB device to Windows computer running WSL2
93
# 2) device boots into app
94
# 3) use 'usbipd' from Windows Cmd/PowerShell to determine busid, this is very hard to automate on Windows
95
# 4) use 'usbipd' from Windows Cmd/PowerShell to attach, this is very hard to automate on Windows
96
# -- device is now viewable via 'lsusb' but you need sudo to read from it.
97
# either run 'chmod666 /dev/ttyACM*' or use udev to automate chmod on device connect
98
# 5) uploader.py detects device, sends reboot command which disconnects the USB port and reboots into
99
# bootloader (different USB device)
100
# 6) manually repeat steps 3 & 4
101
# 7) doing steps 3 and 4 will most likely take several seconds and in many cases the bootloader has
102
# moved on into the app
103
#
104
# Solution: simply call "python.exe" instead of 'python' which magically calls it from the windows
105
# system using the same absolute path back into the WSL2's user's directory
106
# Requirements: Windows must have Python3.9.x (NTO 3.10.x) installed and a few packages.
107
import subprocess
108
try:
109
where_python = subprocess.check_output('where.exe python.exe', shell=True, text=True)
110
except subprocess.CalledProcessError:
111
#if where.exe can't find the file it returns a non-zero result which throws this exception
112
where_python = ""
113
if "python.exe" not in where_python:
114
print(self.get_full_wsl2_error_msg("Windows python.exe not found"))
115
return False
116
return True
117
118
def get_full_wsl2_error_msg(self, error_msg):
119
return ("""
120
****************************************
121
****************************************
122
WSL2 firmware uploads use the host's Windows Python.exe so it has access to the COM ports.
123
124
%s
125
Please download Windows Installer 3.9.x (not 3.10) from https://www.python.org/downloads/
126
and make sure to add it to your path during the installation. Once installed, run this
127
command in Powershell or Command Prompt to install some packages:
128
129
pip.exe install empy==3.3.4 pyserial
130
****************************************
131
****************************************
132
""" % error_msg)
133
134
def exec_command(self, cmd, **kw):
135
kw['stdout'] = sys.stdout
136
return super(upload_fw, self).exec_command(cmd, **kw)
137
138
def keyword(self):
139
return "Uploading"
140
141
class set_default_parameters(Task.Task):
142
color='CYAN'
143
always_run = True
144
def keyword(self):
145
return "apj_tool"
146
def run(self):
147
rel_default_parameters = self.env.get_flat('DEFAULT_PARAMETERS').replace("'", "")
148
abs_default_parameters = os.path.join(self.env.SRCROOT, rel_default_parameters)
149
apj_tool = self.env.APJ_TOOL
150
sys.path.append(os.path.dirname(apj_tool))
151
from apj_tool import embedded_defaults
152
defaults = embedded_defaults(self.inputs[0].abspath())
153
if defaults.find():
154
defaults.set_file(abs_default_parameters)
155
defaults.save()
156
157
158
class generate_bin(Task.Task):
159
color='CYAN'
160
# run_str="${OBJCOPY} -O binary ${SRC} ${TGT}"
161
always_run = True
162
EXTF_MEMORY_START = 0x90000000
163
EXTF_MEMORY_END = 0x90FFFFFF
164
INTF_MEMORY_START = 0x08000000
165
INTF_MEMORY_END = 0x08FFFFFF
166
def keyword(self):
167
return "Generating"
168
def run(self):
169
if self.env.HAS_EXTERNAL_FLASH_SECTIONS:
170
ret = self.split_sections()
171
if (ret < 0):
172
return ret
173
return ret
174
else:
175
# use --gap-fill 0xFF so gaps match erased flash, avoiding CRC
176
# mismatch when loading via GDB vs bootloader/DroneCAN
177
cmd = [self.env.get_flat('OBJCOPY'), '-O', 'binary', '--gap-fill', '0xFF',
178
self.inputs[0].relpath(), self.outputs[0].relpath()]
179
self.exec_command(cmd)
180
181
'''list sections and split into two binaries based on section's location in internal, external or in ram'''
182
def split_sections(self):
183
# get a list of sections
184
cmd = "'{}' -A -x {}".format(self.env.get_flat('SIZE'), self.inputs[0].relpath())
185
out = self.generator.bld.cmd_and_log(cmd, quiet=Context.BOTH, cwd=self.env.get_flat('BUILDROOT'))
186
extf_sections = []
187
intf_sections = []
188
is_text_in_extf = False
189
found_text_section = False
190
ramsections = []
191
for line in out.splitlines():
192
section_line = line.split()
193
if (len(section_line) < 3):
194
continue
195
try:
196
if int(section_line[2], 0) == 0:
197
continue
198
else:
199
addr = int(section_line[2], 0)
200
except ValueError:
201
continue
202
if (addr >= self.EXTF_MEMORY_START) and (addr <= self.EXTF_MEMORY_END):
203
extf_sections.append("--only-section=%s" % section_line[0])
204
if section_line[0] == '.text':
205
is_text_in_extf = True
206
found_text_section = True
207
elif (addr >= self.INTF_MEMORY_START) and (addr <= self.INTF_MEMORY_END):
208
intf_sections.append("--only-section=%s" % section_line[0])
209
if section_line[0] == '.text':
210
is_text_in_extf = False
211
found_text_section = True
212
else: # most likely RAM data, we place it in the same bin as text
213
ramsections.append(section_line[0])
214
215
if found_text_section:
216
for section in ramsections:
217
if is_text_in_extf:
218
extf_sections.append("--only-section=%s" % section)
219
else:
220
intf_sections.append("--only-section=%s" % section)
221
else:
222
Logs.error("Couldn't find .text section")
223
# create intf binary
224
# use --gap-fill 0xFF so gaps match erased flash, avoiding CRC
225
# mismatch when loading via GDB vs bootloader/DroneCAN
226
if len(intf_sections):
227
cmd = "'{}' {} --gap-fill 0xFF -O binary {} {}".format(self.env.get_flat('OBJCOPY'),
228
' '.join(intf_sections), self.inputs[0].relpath(), self.outputs[0].relpath())
229
else:
230
cmd = "cp /dev/null {}".format(self.outputs[0].relpath())
231
ret = self.exec_command(cmd)
232
if (ret < 0):
233
return ret
234
# create extf binary
235
cmd = "'{}' {} --gap-fill 0xFF -O binary {} {}".format(self.env.get_flat('OBJCOPY'),
236
' '.join(extf_sections), self.inputs[0].relpath(), self.outputs[1].relpath())
237
return self.exec_command(cmd)
238
239
def __str__(self):
240
return self.outputs[0].path_from(self.generator.bld.bldnode)
241
242
def to_unsigned(i):
243
'''convert a possibly signed integer to unsigned'''
244
if i < 0:
245
i += 2**32
246
return i
247
248
def sign_firmware(image, private_keyfile):
249
'''sign firmware with private key'''
250
try:
251
import monocypher
252
except ImportError:
253
Logs.error("Please install monocypher with: python3 -m pip install pymonocypher==3.1.3.2")
254
return None
255
256
if monocypher.__version__ != "3.1.3.2":
257
Logs.error("must use monocypher 3.1.3.2, please run: python3 -m pip install pymonocypher==3.1.3.2")
258
return None
259
260
try:
261
key = open(private_keyfile, 'r').read()
262
except Exception as ex:
263
Logs.error("Failed to open %s" % private_keyfile)
264
return None
265
keytype = "PRIVATE_KEYV1:"
266
if not key.startswith(keytype):
267
Logs.error("Bad private key file %s" % private_keyfile)
268
return None
269
key = base64.b64decode(key[len(keytype):])
270
sig = monocypher.signature_sign(key, image)
271
sig_len = len(sig)
272
sig_version = 30437
273
return struct.pack("<IQ64s", sig_len+8, sig_version, sig)
274
275
276
class set_app_descriptor(Task.Task):
277
'''setup app descriptor in bin file'''
278
color='BLUE'
279
always_run = True
280
def keyword(self):
281
return "app_descriptor"
282
def run(self):
283
if self.generator.bld.env.AP_SIGNED_FIRMWARE:
284
descriptor = b'\x41\xa3\xe5\xf2\x65\x69\x92\x07'
285
else:
286
descriptor = b'\x40\xa2\xe4\xf1\x64\x68\x91\x06'
287
288
elf_file = self.inputs[0].abspath()
289
bin_file = self.inputs[1].abspath()
290
img = open(bin_file, 'rb').read()
291
offset = img.find(descriptor)
292
if offset == -1:
293
Logs.info("No APP_DESCRIPTOR found")
294
return
295
offset += len(descriptor)
296
# next 8 bytes is 64 bit CRC. We set first 4 bytes to
297
# CRC32 of image before descriptor and 2nd 4 bytes
298
# to CRC32 of image after descriptor. This is very efficient
299
# for bootloader to calculate
300
# after CRC comes image length and 32 bit git hash
301
upload_tools = self.env.get_flat('UPLOAD_TOOLS')
302
sys.path.append(upload_tools)
303
from uploader import crc32
304
if self.generator.bld.env.AP_SIGNED_FIRMWARE:
305
desc_len = 92
306
else:
307
desc_len = 16
308
img1 = bytearray(img[:offset])
309
img2 = bytearray(img[offset+desc_len:])
310
crc1 = to_unsigned(crc32(img1))
311
crc2 = to_unsigned(crc32(img2))
312
githash = to_unsigned(int('0x' + os.environ.get('GIT_VERSION', self.generator.bld.git_head_hash(short=True)),16))
313
if self.generator.bld.env.AP_SIGNED_FIRMWARE:
314
sig = bytearray([0 for i in range(76)])
315
if self.generator.bld.env.PRIVATE_KEY:
316
sig_signed = sign_firmware(img1+img2, self.generator.bld.env.PRIVATE_KEY)
317
if sig_signed:
318
Logs.info("Signed firmware")
319
sig = sig_signed
320
else:
321
self.generator.bld.fatal("Signing failed")
322
desc = struct.pack('<IIII76s', crc1, crc2, len(img), githash, sig)
323
else:
324
desc = struct.pack('<IIII', crc1, crc2, len(img), githash)
325
img = img[:offset] + desc + img[offset+desc_len:]
326
Logs.info("Applying APP_DESCRIPTOR %08x%08x" % (crc1, crc2))
327
open(bin_file, 'wb').write(img)
328
329
elf_img = open(elf_file,'rb').read()
330
zero_descriptor = descriptor + struct.pack("<IIII",0,0,0,0)
331
elf_ofs = elf_img.find(zero_descriptor)
332
if elf_ofs == -1:
333
Logs.info("No APP_DESCRIPTOR found in elf file")
334
return
335
elf_ofs += len(descriptor)
336
elf_img = elf_img[:elf_ofs] + desc + elf_img[elf_ofs+desc_len:]
337
Logs.info("Applying APP_DESCRIPTOR %08x%08x to elf" % (crc1, crc2))
338
open(elf_file, 'wb').write(elf_img)
339
340
341
class generate_apj(Task.Task):
342
'''generate an apj firmware file'''
343
color='CYAN'
344
always_run = True
345
def keyword(self):
346
return "apj_gen"
347
def run(self):
348
import json, time, base64, zlib
349
intf_img = open(self.inputs[0].abspath(),'rb').read()
350
if self.env.HAS_EXTERNAL_FLASH_SECTIONS:
351
extf_img = open(self.inputs[1].abspath(),'rb').read()
352
else:
353
extf_img = b""
354
d = {
355
"board_id": int(self.env.APJ_BOARD_ID),
356
"magic": "APJFWv1",
357
"description": "Firmware for a %s board" % self.env.APJ_BOARD_TYPE,
358
"image": base64.b64encode(zlib.compress(intf_img,9)).decode('utf-8'),
359
"extf_image": base64.b64encode(zlib.compress(extf_img,9)).decode('utf-8'),
360
"summary": self.env.BOARD,
361
"version": "0.1",
362
"image_size": len(intf_img),
363
"extf_image_size": len(extf_img),
364
"flash_total": int(self.env.FLASH_TOTAL),
365
"image_maxsize": int(self.env.FLASH_TOTAL),
366
"flash_free": int(self.env.FLASH_TOTAL) - len(intf_img),
367
"extflash_total": int(self.env.EXT_FLASH_SIZE_MB * 1024 * 1024),
368
"extflash_free": int(self.env.EXT_FLASH_SIZE_MB * 1024 * 1024) - len(extf_img),
369
"git_identity": self.generator.bld.git_head_hash(short=True),
370
"board_revision": 0,
371
"USBID": self.env.USBID
372
}
373
if self.env.MANUFACTURER:
374
d["manufacturer"] = self.env.MANUFACTURER
375
if self.env.BRAND_NAME:
376
d["brand_name"] = self.env.BRAND_NAME
377
if self.env.build_dates:
378
# we omit build_time when we don't have build_dates so that apj
379
# file is identical for same git hash and compiler
380
d["build_time"] = int(time.time())
381
if self.env.AP_SIGNED_FIRMWARE and self.env.PRIVATE_KEY:
382
# The firmware file was signed during the build process, so set the flag
383
d['signed_firmware'] = True
384
apj_file = self.outputs[0].abspath()
385
f = open(apj_file, "w")
386
f.write(json.dumps(d, indent=4))
387
f.close()
388
389
class build_abin(Task.Task):
390
'''build an abin file for skyviper firmware upload via web UI'''
391
color='CYAN'
392
run_str='${TOOLS_SCRIPTS}/make_abin.sh ${SRC} ${TGT}'
393
always_run = True
394
def keyword(self):
395
return "Generating"
396
def __str__(self):
397
return self.outputs[0].path_from(self.generator.bld.bldnode)
398
399
class build_normalized_bins(Task.Task):
400
'''Move external flash binaries to regular location if regular bin is zero length'''
401
color='CYAN'
402
always_run = True
403
def run(self):
404
if self.env.HAS_EXTERNAL_FLASH_SECTIONS and os.path.getsize(self.inputs[0].abspath()) == 0:
405
os.remove(self.inputs[0].abspath())
406
shutil.move(self.inputs[1].abspath(), self.inputs[0].abspath())
407
408
def keyword(self):
409
return "bin cleanup"
410
411
class build_intel_hex(Task.Task):
412
'''build an intel hex file for upload with DFU'''
413
color='CYAN'
414
run_str='${TOOLS_SCRIPTS}/make_intel_hex.py ${SRC} ${FLASH_RESERVE_START_KB}'
415
always_run = True
416
def keyword(self):
417
return "Generating"
418
def __str__(self):
419
return self.outputs[0].path_from(self.generator.bld.bldnode)
420
421
@feature('ch_ap_program')
422
@after_method('process_source')
423
def chibios_firmware(self):
424
self.link_task.always_run = True
425
426
link_output = self.link_task.outputs[0]
427
hex_task = None
428
429
if self.bld.env.HAS_EXTERNAL_FLASH_SECTIONS:
430
bin_target = [self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.bin').name),
431
self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('_extf.bin').name)]
432
else:
433
bin_target = [self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.bin').name)]
434
apj_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.apj').name)
435
436
generate_bin_task = self.create_task('generate_bin', src=link_output, tgt=bin_target)
437
generate_bin_task.set_run_after(self.link_task)
438
439
generate_apj_task = self.create_task('generate_apj', src=bin_target, tgt=apj_target)
440
generate_apj_task.set_run_after(generate_bin_task)
441
442
if self.env.BUILD_ABIN:
443
abin_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.abin').name)
444
abin_task = self.create_task('build_abin', src=bin_target, tgt=abin_target)
445
abin_task.set_run_after(generate_apj_task)
446
447
cleanup_task = self.create_task('build_normalized_bins', src=bin_target)
448
cleanup_task.set_run_after(generate_apj_task)
449
450
bootloader_board = self.env.BOARD
451
if self.bld.env.USE_BOOTLOADER_FROM_BOARD:
452
bootloader_board = self.bld.env.USE_BOOTLOADER_FROM_BOARD
453
bootloader_bin = self.bld.srcnode.make_node("Tools/bootloaders/%s_bl.bin" % bootloader_board)
454
if self.bld.env.HAVE_INTEL_HEX:
455
if os.path.exists(bootloader_bin.abspath()):
456
if int(self.bld.env.FLASH_RESERVE_START_KB) > 0:
457
hex_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('_with_bl.hex').name)
458
else:
459
hex_target = self.bld.bldnode.find_or_declare('bin/' + link_output.change_ext('.hex').name)
460
hex_task = self.create_task('build_intel_hex', src=[bin_target[0], bootloader_bin], tgt=hex_target)
461
hex_task.set_run_after(cleanup_task)
462
else:
463
print("Not embedding bootloader; %s does not exist" % bootloader_bin)
464
465
if self.env.DEFAULT_PARAMETERS:
466
default_params_task = self.create_task('set_default_parameters',
467
src=link_output)
468
default_params_task.set_run_after(self.link_task)
469
generate_bin_task.set_run_after(default_params_task)
470
471
# we need to setup the app descriptor so the bootloader can validate the firmware
472
if not self.bld.env.BOOTLOADER:
473
app_descriptor_task = self.create_task('set_app_descriptor', src=[link_output,bin_target[0]])
474
app_descriptor_task.set_run_after(generate_bin_task)
475
generate_apj_task.set_run_after(app_descriptor_task)
476
if hex_task is not None:
477
hex_task.set_run_after(app_descriptor_task)
478
else:
479
generate_apj_task.set_run_after(generate_bin_task)
480
if hex_task is not None:
481
hex_task.set_run_after(generate_bin_task)
482
483
if self.bld.options.upload:
484
_upload_task = self.create_task('upload_fw', src=apj_target)
485
_upload_task.set_run_after(generate_apj_task)
486
487
if self.bld.options.upload_blueos:
488
_upload_task = self.create_task('upload_fw_blueos', src=link_output)
489
_upload_task.set_run_after(generate_apj_task)
490
491
def setup_canmgr_build(cfg):
492
'''enable CANManager build. By doing this here we can auto-enable CAN in
493
the build based on the presence of CAN pins in hwdef.dat except for AP_Periph builds'''
494
env = cfg.env
495
env.AP_LIBRARIES += [
496
'AP_DroneCAN',
497
'modules/DroneCAN/libcanard/*.c',
498
]
499
env.INCLUDES += [
500
cfg.srcnode.find_dir('modules/DroneCAN/libcanard').abspath(),
501
]
502
env.CFLAGS += ['-DHAL_CAN_IFACES=2']
503
504
if not env.AP_PERIPH:
505
env.DEFINES += [
506
'DRONECAN_CXX_WRAPPERS=1',
507
'USE_USER_HELPERS=1',
508
'CANARD_ENABLE_DEADLINE=1',
509
'CANARD_MULTI_IFACE=1',
510
'CANARD_ALLOCATE_SEM=1'
511
]
512
513
cfg.get_board().with_can = True
514
515
def setup_canperiph_build(cfg):
516
'''enable CAN build for peripherals'''
517
env = cfg.env
518
env.DEFINES += [
519
'CANARD_ENABLE_DEADLINE=1',
520
]
521
522
cfg.get_board().with_can = True
523
524
def setup_optimization(env):
525
'''setup optimization flags for build'''
526
if env.DEBUG:
527
OPTIMIZE = "-Og"
528
elif env.OPTIMIZE:
529
OPTIMIZE = env.OPTIMIZE
530
else:
531
OPTIMIZE = "-Os"
532
env.CFLAGS += [ OPTIMIZE ]
533
env.CXXFLAGS += [ OPTIMIZE ]
534
env.CHIBIOS_BUILD_FLAGS += ' USE_COPT=%s' % OPTIMIZE
535
536
def configure(cfg):
537
cfg.find_program('make', var='MAKE')
538
#cfg.objcopy = cfg.find_program('%s-%s'%(cfg.env.TOOLCHAIN,'objcopy'), var='OBJCOPY', mandatory=True)
539
cfg.find_program('arm-none-eabi-objcopy', var='OBJCOPY')
540
env = cfg.env
541
bldnode = cfg.bldnode.make_node(cfg.variant)
542
def srcpath(path):
543
return cfg.srcnode.make_node(path).abspath()
544
545
def bldpath(path):
546
return bldnode.make_node(path).abspath()
547
env.AP_PROGRAM_FEATURES += ['ch_ap_program']
548
549
kw = env.AP_LIBRARIES_OBJECTS_KW
550
kw['features'] = Utils.to_list(kw.get('features', [])) + ['ch_ap_library']
551
552
env.CH_ROOT = srcpath('modules/ChibiOS')
553
env.CC_ROOT = srcpath('modules/CrashDebug/CrashCatcher')
554
env.AP_HAL_ROOT = srcpath('libraries/AP_HAL_ChibiOS')
555
env.BUILDDIR = bldpath('modules/ChibiOS')
556
env.BUILDROOT = bldpath('')
557
env.SRCROOT = srcpath('')
558
env.PT_DIR = srcpath('Tools/ardupilotwaf/chibios/image')
559
env.MKFW_TOOLS = srcpath('Tools/ardupilotwaf')
560
env.UPLOAD_TOOLS = srcpath('Tools/scripts')
561
env.CHIBIOS_SCRIPTS = srcpath('libraries/AP_HAL_ChibiOS/hwdef/scripts')
562
env.TOOLS_SCRIPTS = srcpath('Tools/scripts')
563
env.APJ_TOOL = srcpath('Tools/scripts/apj_tool.py')
564
env.SERIAL_PORT = srcpath('/dev/serial/by-id/*_STLink*')
565
566
# relative paths to pass to make, relative to directory that make is run from
567
env.CH_ROOT_REL = os.path.relpath(env.CH_ROOT, env.BUILDROOT)
568
env.CC_ROOT_REL = os.path.relpath(env.CC_ROOT, env.BUILDROOT)
569
env.AP_HAL_REL = os.path.relpath(env.AP_HAL_ROOT, env.BUILDROOT)
570
env.BUILDDIR_REL = os.path.relpath(env.BUILDDIR, env.BUILDROOT)
571
572
mk_custom = srcpath('libraries/AP_HAL_ChibiOS/hwdef/%s/chibios_board.mk' % env.BOARD)
573
mk_common = srcpath('libraries/AP_HAL_ChibiOS/hwdef/common/chibios_board.mk')
574
# see if there is a board specific make file
575
if os.path.exists(mk_custom):
576
env.BOARD_MK = mk_custom
577
else:
578
env.BOARD_MK = mk_common
579
580
if cfg.options.default_parameters:
581
cfg.msg('Default parameters', cfg.options.default_parameters, color='YELLOW')
582
env.DEFAULT_PARAMETERS = cfg.options.default_parameters
583
584
try:
585
hwdef_obj = generate_hwdef_h(env)
586
except Exception:
587
traceback.print_exc()
588
cfg.fatal("Failed to process hwdef.dat")
589
hal_common.process_hwdef_results(cfg, hwdef_obj)
590
591
if env.DEBUG or env.DEBUG_SYMBOLS:
592
env.CHIBIOS_BUILD_FLAGS += ' ENABLE_DEBUG_SYMBOLS=yes'
593
if env.ENABLE_ASSERTS:
594
env.CHIBIOS_BUILD_FLAGS += ' ENABLE_ASSERTS=yes'
595
if env.ENABLE_MALLOC_GUARD:
596
env.CHIBIOS_BUILD_FLAGS += ' ENABLE_MALLOC_GUARD=yes'
597
if env.ENABLE_STATS:
598
env.CHIBIOS_BUILD_FLAGS += ' ENABLE_STATS=yes'
599
if env.ENABLE_DFU_BOOT and env.BOOTLOADER:
600
env.CHIBIOS_BUILD_FLAGS += ' USE_ASXOPT=-DCRT0_ENTRY_HOOK=TRUE'
601
if env.AP_BOARD_START_TIME:
602
env.CHIBIOS_BUILD_FLAGS += ' AP_BOARD_START_TIME=0x%x' % env.AP_BOARD_START_TIME
603
604
if env.HAL_NUM_CAN_IFACES and not env.AP_PERIPH:
605
setup_canmgr_build(cfg)
606
if env.HAL_NUM_CAN_IFACES and env.AP_PERIPH and not env.BOOTLOADER:
607
setup_canperiph_build(cfg)
608
if env.HAL_NUM_CAN_IFACES and env.AP_PERIPH and int(env.HAL_NUM_CAN_IFACES)>1 and not env.BOOTLOADER:
609
env.DEFINES += [ 'CANARD_MULTI_IFACE=1' ]
610
setup_optimization(cfg.env)
611
612
def generate_hwdef_h(env):
613
'''run chibios_hwdef.py'''
614
if env.BOOTLOADER:
615
if len(env.HWDEF) == 0:
616
env.HWDEF = os.path.join(env.SRCROOT, 'libraries/AP_HAL_ChibiOS/hwdef/%s/hwdef-bl.dat' % env.BOARD)
617
else:
618
# update to using hwdef-bl.dat
619
env.HWDEF = env.HWDEF.replace('hwdef.dat', 'hwdef-bl.dat')
620
bootloader_flag = True
621
else:
622
if len(env.HWDEF) == 0:
623
env.HWDEF = os.path.join(env.SRCROOT, 'libraries/AP_HAL_ChibiOS/hwdef/%s/hwdef.dat' % env.BOARD)
624
bootloader_flag = False
625
626
hwdef_script = os.path.join(env.SRCROOT, 'libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py')
627
hwdef_out = env.BUILDROOT
628
if not os.path.exists(hwdef_out):
629
os.mkdir(hwdef_out)
630
631
hwdef = [env.HWDEF]
632
if env.HWDEF_EXTRA:
633
hwdef.append(env.HWDEF_EXTRA)
634
635
hwdef_obj = chibios_hwdef.ChibiOSHWDef(
636
outdir=hwdef_out,
637
bootloader=bootloader_flag,
638
signed_fw=bool(env.AP_SIGNED_FIRMWARE),
639
hwdef=hwdef,
640
# stringify like old subprocess based invocation. note that no error is
641
# generated if this path is missing!
642
default_params_filepath=str(env.DEFAULT_PARAMETERS),
643
quiet=False,
644
)
645
hwdef_obj.run()
646
647
return hwdef_obj
648
649
def pre_build(bld):
650
'''pre-build hook to change dynamic sources'''
651
if bld.env.HAL_NUM_CAN_IFACES:
652
bld.get_board().with_can = True
653
if bld.env.WITH_LITTLEFS:
654
bld.get_board().with_littlefs = True
655
setup_optimization(bld.env)
656
657
def build(bld):
658
659
# make ccache effective on ChibiOS builds
660
os.environ['CCACHE_IGNOREOPTIONS'] = '--specs=nano.specs --specs=nosys.specs'
661
662
bld(
663
# create the file modules/ChibiOS/include_dirs
664
rule="touch Makefile && BUILDDIR=${BUILDDIR_REL} BUILDROOT=${BUILDROOT} CRASHCATCHER=${CC_ROOT_REL} CHIBIOS=${CH_ROOT_REL} AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${MAKE} pass -f '${BOARD_MK}'",
665
group='dynamic_sources',
666
target=bld.bldnode.find_or_declare('modules/ChibiOS/include_dirs')
667
)
668
669
bld(
670
# create the file modules/ChibiOS/include_dirs
671
rule="echo // BUILD_FLAGS: ${BUILDDIR_REL} ${BUILDROOT} ${CC_ROOT_REL} ${CH_ROOT_REL} ${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} > chibios_flags.h",
672
group='dynamic_sources',
673
target=bld.bldnode.find_or_declare('chibios_flags.h')
674
)
675
676
common_src = [bld.bldnode.find_or_declare('hwdef.h'),
677
bld.bldnode.find_or_declare('hw.dat'),
678
bld.bldnode.find_or_declare('ldscript.ld'),
679
bld.bldnode.find_or_declare('common.ld'),
680
bld.bldnode.find_or_declare('modules/ChibiOS/include_dirs')]
681
common_src += bld.path.ant_glob('libraries/AP_HAL_ChibiOS/hwdef/common/*.[ch]')
682
common_src += bld.path.ant_glob('libraries/AP_HAL_ChibiOS/hwdef/common/*.mk')
683
common_src += bld.path.ant_glob('modules/ChibiOS/os/hal/**/*.[ch]')
684
common_src += bld.path.ant_glob('modules/ChibiOS/os/hal/**/*.mk')
685
if bld.env.ROMFS_FILES:
686
common_src += [bld.bldnode.find_or_declare('ap_romfs_embedded.h')]
687
688
if bld.env.ENABLE_CRASHDUMP:
689
ch_task = bld(
690
# build libch.a from ChibiOS sources and hwdef.h
691
rule="BUILDDIR='${BUILDDIR_REL}' BUILDROOT='${BUILDROOT}' CRASHCATCHER='${CC_ROOT_REL}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} '${MAKE}' -j%u lib -f '${BOARD_MK}'" % bld.options.jobs,
692
group='dynamic_sources',
693
source=common_src,
694
target=[bld.bldnode.find_or_declare('modules/ChibiOS/libch.a'), bld.bldnode.find_or_declare('modules/ChibiOS/libcc.a')]
695
)
696
else:
697
ch_task = bld(
698
# build libch.a from ChibiOS sources and hwdef.h
699
rule="BUILDDIR='${BUILDDIR_REL}' BUILDROOT='${BUILDROOT}' CHIBIOS='${CH_ROOT_REL}' AP_HAL=${AP_HAL_REL} ${CHIBIOS_BUILD_FLAGS} ${CHIBIOS_BOARD_NAME} ${HAL_MAX_STACK_FRAME_SIZE} '${MAKE}' -j%u lib -f '${BOARD_MK}'" % bld.options.jobs,
700
group='dynamic_sources',
701
source=common_src,
702
target=bld.bldnode.find_or_declare('modules/ChibiOS/libch.a')
703
)
704
ch_task.name = "ChibiOS_lib"
705
DSP_LIBS = {
706
'cortex-m4' : 'libarm_cortexM4lf_math.a',
707
'cortex-m7' : 'libarm_cortexM7lfdp_math.a',
708
}
709
if bld.env.CORTEX in DSP_LIBS:
710
libname = DSP_LIBS[bld.env.CORTEX]
711
# we need to copy the library on cygwin as it doesn't handle linking outside build tree
712
shutil.copyfile(os.path.join(bld.env.SRCROOT,'libraries/AP_GyroFFT/CMSIS_5/lib',libname),
713
os.path.join(bld.env.BUILDROOT,'modules/ChibiOS/libDSP.a'))
714
bld.env.LIB += ['DSP']
715
bld.env.LIB += ['ch']
716
bld.env.LIBPATH += ['modules/ChibiOS/']
717
if bld.env.ENABLE_CRASHDUMP:
718
bld.env.LINKFLAGS += ['-Wl,-whole-archive', 'modules/ChibiOS/libcc.a', '-Wl,-no-whole-archive']
719
# list of functions that will be wrapped to move them out of libc into our
720
# own code
721
wraplist = ['sscanf', 'fprintf', 'snprintf', 'vsnprintf', 'vasprintf', 'asprintf', 'vprintf', 'scanf', 'printf']
722
723
# list of functions that we will give a link error for if they are
724
# used. This is to prevent accidental use of these functions
725
blacklist = ['_sbrk', '_sbrk_r', '_malloc_r', '_calloc_r', '_free_r', 'ftell', 'realloc',
726
'fopen', 'fflush', 'fwrite', 'fread', 'fputs', 'fgets',
727
'clearerr', 'fseek', 'ferror', 'fclose', 'tmpfile', 'getc', 'ungetc', 'feof',
728
'ftell', 'freopen', 'remove', 'vfprintf', 'vfprintf_r', 'fscanf',
729
'_gettimeofday', '_times', '_times_r', '_gettimeofday_r', 'time', 'clock',
730
'setjmp']
731
732
# these functions use global state that is not thread safe
733
blacklist += ['gmtime']
734
735
for w in wraplist + blacklist:
736
bld.env.LINKFLAGS += ['-Wl,--wrap,%s' % w]
737
738