#!/usr/bin/env python # encoding: utf-8 """ Waf tool for ChibiOS build """ from waflib import Errors, Logs, Task, Utils from waflib.TaskGen import after_method, before_method, feature import os import shutil import sys import re import pickle import struct _dynamic_env_data = {} def _load_dynamic_env_data(bld): bldnode = bld.bldnode.make_node('modules/ChibiOS') tmp_str = bldnode.find_node('include_dirs').read() tmp_str = tmp_str.replace(';\n','') tmp_str = tmp_str.replace('-I','') #remove existing -I flags # split, coping with separator idirs = re.split('; ', tmp_str) # create unique list, coping with relative paths idirs2 = [] for d in idirs: if d.startswith('../'): # relative paths from the make build are relative to BUILDROOT d = os.path.join(bld.env.BUILDROOT, d) d = os.path.normpath(d) if not d in idirs2: idirs2.append(d) _dynamic_env_data['include_dirs'] = idirs2 @feature('ch_ap_library', 'ch_ap_program') @before_method('process_source') def ch_dynamic_env(self): # The generated files from configuration possibly don't exist if it's just # a list command (TODO: figure out a better way to address that). if self.bld.cmd == 'list': return if not _dynamic_env_data: _load_dynamic_env_data(self.bld) self.use += ' ch' self.env.append_value('INCLUDES', _dynamic_env_data['include_dirs']) class upload_fw(Task.Task): color='BLUE' always_run = True def run(self): upload_tools = self.env.get_flat('UPLOAD_TOOLS') upload_port = self.generator.bld.options.upload_port src = self.inputs[0] cmd = "{} '{}/uploader.py' '{}'".format(self.env.get_flat('PYTHON'), upload_tools, src) if upload_port is not None: cmd += " '--port' '%s'" % upload_port return self.exec_command(cmd) def exec_command(self, cmd, **kw): kw['stdout'] = sys.stdout return super(upload_fw, self).exec_command(cmd, **kw) def keyword(self): return "Uploading" class set_default_parameters(Task.Task): color='CYAN' always_run = True def keyword(self): return "apj_tool" def run(self): rel_default_parameters = self.env.get_flat('DEFAULT_PARAMETERS').replace("'", "") abs_default_parameters = os.path.join(self.env.SRCROOT, rel_default_parameters) apj_tool = self.env.APJ_TOOL sys.path.append(os.path.dirname(apj_tool)) from apj_tool import embedded_defaults defaults = embedded_defaults(self.inputs[0].abspath()) if defaults.find(): defaults.set_file(abs_default_parameters) defaults.save() class generate_bin(Task.Task): color='CYAN' run_str="${OBJCOPY} -O binary ${SRC} ${TGT}" always_run = True def keyword(self): return "Generating" def __str__(self): return self.outputs[0].path_from(self.generator.bld.bldnode) def to_unsigned(i): '''convert a possibly signed integer to unsigned''' if i < 0: i += 2**32 return i class set_app_descriptor(Task.Task): '''setup app descriptor in bin file''' color='BLUE' always_run = True def keyword(self): return "app_descriptor" def run(self): if not 'APP_DESCRIPTOR' in self.env: return if self.env.APP_DESCRIPTOR == 'MissionPlanner': descriptor = b'\x40\xa2\xe4\xf1\x64\x68\x91\x06' else: Logs.error("Bad APP_DESCRIPTOR %s" % self.env.APP_DESCRIPTOR) return img = open(self.inputs[0].abspath(), 'rb').read() offset = img.find(descriptor) if offset == -1: Logs.error("Failed to find %s APP_DESCRIPTOR" % self.env.APP_DESCRIPTOR) return offset += 8 # next 8 bytes is 64 bit CRC. We set first 4 bytes to # CRC32 of image before descriptor and 2nd 4 bytes # to CRC32 of image after descriptor. This is very efficient # for bootloader to calculate # after CRC comes image length and 32 bit git hash upload_tools = self.env.get_flat('UPLOAD_TOOLS') sys.path.append(upload_tools) from uploader import crc32 desc_len = 16 crc1 = to_unsigned(crc32(bytearray(img[:offset]))) crc2 = to_unsigned(crc32(bytearray(img[offset+desc_len:]))) githash = to_unsigned(int('0x' + self.generator.bld.git_head_hash(short=True),16)) desc = struct.pack('