Clone of official tools

Committer:
Anders Blomdell
Date:
Thu Feb 04 17:17:13 2021 +0100
Revision:
47:21ae3e5a7128
Parent:
43:2a7da56ebd24
Add a few normpath calls

Who changed what in which revision?

UserRevisionLine numberNew contents of line
The Other Jimmy 36:96847d42f010 1 """
The Other Jimmy 36:96847d42f010 2 mbed SDK
The Other Jimmy 36:96847d42f010 3 Copyright (c) 2016 ARM Limited
The Other Jimmy 36:96847d42f010 4
The Other Jimmy 36:96847d42f010 5 Licensed under the Apache License, Version 2.0 (the "License");
The Other Jimmy 36:96847d42f010 6 you may not use this file except in compliance with the License.
The Other Jimmy 36:96847d42f010 7 You may obtain a copy of the License at
The Other Jimmy 36:96847d42f010 8
The Other Jimmy 36:96847d42f010 9 http://www.apache.org/licenses/LICENSE-2.0
The Other Jimmy 36:96847d42f010 10
The Other Jimmy 36:96847d42f010 11 Unless required by applicable law or agreed to in writing, software
The Other Jimmy 36:96847d42f010 12 distributed under the License is distributed on an "AS IS" BASIS,
The Other Jimmy 36:96847d42f010 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
The Other Jimmy 36:96847d42f010 14 See the License for the specific language governing permissions and
The Other Jimmy 36:96847d42f010 15 limitations under the License.
The Other Jimmy 36:96847d42f010 16 """
theotherjimmy 43:2a7da56ebd24 17 from __future__ import print_function, division, absolute_import
The Other Jimmy 36:96847d42f010 18
The Other Jimmy 36:96847d42f010 19 from copy import deepcopy
theotherjimmy 43:2a7da56ebd24 20 from six import moves
theotherjimmy 43:2a7da56ebd24 21 import json
theotherjimmy 43:2a7da56ebd24 22 import six
The Other Jimmy 36:96847d42f010 23 import os
theotherjimmy 43:2a7da56ebd24 24 from os.path import dirname, abspath, exists, join, isabs
The Other Jimmy 36:96847d42f010 25 import sys
The Other Jimmy 36:96847d42f010 26 from collections import namedtuple
The Other Jimmy 36:96847d42f010 27 from os.path import splitext, relpath
The Other Jimmy 36:96847d42f010 28 from intelhex import IntelHex
The Other Jimmy 36:96847d42f010 29 from jinja2 import FileSystemLoader, StrictUndefined
The Other Jimmy 36:96847d42f010 30 from jinja2.environment import Environment
theotherjimmy 43:2a7da56ebd24 31 from jsonschema import Draft4Validator, RefResolver
theotherjimmy 43:2a7da56ebd24 32
theotherjimmy 43:2a7da56ebd24 33 from ..resources import FileType
theotherjimmy 43:2a7da56ebd24 34 from ..utils import (json_file_to_dict, intelhex_offset, integer,
theotherjimmy 43:2a7da56ebd24 35 NotSupportedException)
theotherjimmy 43:2a7da56ebd24 36 from ..arm_pack_manager import Cache
theotherjimmy 43:2a7da56ebd24 37 from ..targets import (CUMULATIVE_ATTRIBUTES, TARGET_MAP, generate_py_target,
theotherjimmy 43:2a7da56ebd24 38 get_resolution_order, Target)
theotherjimmy 43:2a7da56ebd24 39
theotherjimmy 43:2a7da56ebd24 40 try:
theotherjimmy 43:2a7da56ebd24 41 unicode
theotherjimmy 43:2a7da56ebd24 42 except NameError:
theotherjimmy 43:2a7da56ebd24 43 unicode = str
theotherjimmy 43:2a7da56ebd24 44 PATH_OVERRIDES = set(["target.bootloader_img"])
theotherjimmy 43:2a7da56ebd24 45 ROM_OVERRIDES = set([
theotherjimmy 43:2a7da56ebd24 46 # managed BL
theotherjimmy 43:2a7da56ebd24 47 "target.bootloader_img", "target.restrict_size",
theotherjimmy 43:2a7da56ebd24 48 "target.header_format", "target.header_offset",
theotherjimmy 43:2a7da56ebd24 49 "target.app_offset",
theotherjimmy 43:2a7da56ebd24 50
theotherjimmy 43:2a7da56ebd24 51 # unmanaged BL
theotherjimmy 43:2a7da56ebd24 52 "target.mbed_app_start", "target.mbed_app_size",
theotherjimmy 43:2a7da56ebd24 53
theotherjimmy 43:2a7da56ebd24 54 # both
theotherjimmy 43:2a7da56ebd24 55 "target.mbed_rom_start", "target.mbed_rom_size",
theotherjimmy 43:2a7da56ebd24 56 ])
theotherjimmy 43:2a7da56ebd24 57 RAM_OVERRIDES = set([
theotherjimmy 43:2a7da56ebd24 58 # both
theotherjimmy 43:2a7da56ebd24 59 "target.mbed_ram_start", "target.mbed_ram_size",
theotherjimmy 43:2a7da56ebd24 60 ])
theotherjimmy 43:2a7da56ebd24 61
theotherjimmy 43:2a7da56ebd24 62 BOOTLOADER_OVERRIDES = ROM_OVERRIDES | RAM_OVERRIDES
theotherjimmy 43:2a7da56ebd24 63
theotherjimmy 43:2a7da56ebd24 64
theotherjimmy 43:2a7da56ebd24 65 ALLOWED_FEATURES = [
theotherjimmy 43:2a7da56ebd24 66 "BOOTLOADER","UVISOR", "BLE", "CLIENT", "IPV4", "LWIP", "COMMON_PAL", "STORAGE",
theotherjimmy 43:2a7da56ebd24 67 "NANOSTACK","CRYPTOCELL310",
theotherjimmy 43:2a7da56ebd24 68 # Nanostack configurations
theotherjimmy 43:2a7da56ebd24 69 "LOWPAN_BORDER_ROUTER", "LOWPAN_HOST", "LOWPAN_ROUTER", "NANOSTACK_FULL",
theotherjimmy 43:2a7da56ebd24 70 "THREAD_BORDER_ROUTER", "THREAD_END_DEVICE", "THREAD_ROUTER",
theotherjimmy 43:2a7da56ebd24 71 "ETHERNET_HOST",
theotherjimmy 43:2a7da56ebd24 72 ]
The Other Jimmy 36:96847d42f010 73
The Other Jimmy 36:96847d42f010 74 # Base class for all configuration exceptions
The Other Jimmy 36:96847d42f010 75 class ConfigException(Exception):
The Other Jimmy 36:96847d42f010 76 """Config system only exception. Makes it easier to distinguish config
The Other Jimmy 36:96847d42f010 77 errors"""
The Other Jimmy 36:96847d42f010 78 pass
The Other Jimmy 36:96847d42f010 79
theotherjimmy 43:2a7da56ebd24 80 class UndefinedParameter(ConfigException):
theotherjimmy 43:2a7da56ebd24 81 def __init__(self, param, name, kind, label):
theotherjimmy 43:2a7da56ebd24 82 self.param = param
theotherjimmy 43:2a7da56ebd24 83 self.name = name
theotherjimmy 43:2a7da56ebd24 84 self.kind = kind
theotherjimmy 43:2a7da56ebd24 85 self.label = label
theotherjimmy 43:2a7da56ebd24 86
theotherjimmy 43:2a7da56ebd24 87 def __str__(self):
theotherjimmy 43:2a7da56ebd24 88 return "Attempt to override undefined parameter '{}' in '{}'".format(
theotherjimmy 43:2a7da56ebd24 89 self.param,
theotherjimmy 43:2a7da56ebd24 90 ConfigParameter.get_display_name(self.name, self.kind, self.label),
theotherjimmy 43:2a7da56ebd24 91 )
theotherjimmy 43:2a7da56ebd24 92
The Other Jimmy 36:96847d42f010 93 class ConfigParameter(object):
The Other Jimmy 36:96847d42f010 94 """This class keeps information about a single configuration parameter"""
The Other Jimmy 36:96847d42f010 95
The Other Jimmy 36:96847d42f010 96 def __init__(self, name, data, unit_name, unit_kind):
The Other Jimmy 36:96847d42f010 97 """Construct a ConfigParameter
The Other Jimmy 36:96847d42f010 98
The Other Jimmy 36:96847d42f010 99 Positional arguments:
The Other Jimmy 36:96847d42f010 100 name - the name of the configuration parameter
The Other Jimmy 36:96847d42f010 101 data - the data associated with the configuration parameter
The Other Jimmy 36:96847d42f010 102 unit_name - the unit (target/library/application) that defines this
The Other Jimmy 36:96847d42f010 103 parameter
The Other Jimmy 36:96847d42f010 104 unit_ kind - the kind of the unit ("target", "library" or "application")
The Other Jimmy 36:96847d42f010 105 """
The Other Jimmy 36:96847d42f010 106 self.name = self.get_full_name(name, unit_name, unit_kind,
The Other Jimmy 36:96847d42f010 107 allow_prefix=False)
The Other Jimmy 36:96847d42f010 108 self.defined_by = self.get_display_name(unit_name, unit_kind)
The Other Jimmy 36:96847d42f010 109 self.set_value(data.get("value", None), unit_name, unit_kind)
The Other Jimmy 36:96847d42f010 110 self.help_text = data.get("help", None)
The Other Jimmy 36:96847d42f010 111 self.required = data.get("required", False)
The Other Jimmy 36:96847d42f010 112 self.macro_name = data.get("macro_name", "MBED_CONF_%s" %
The Other Jimmy 36:96847d42f010 113 self.sanitize(self.name.upper()))
The Other Jimmy 36:96847d42f010 114 self.config_errors = []
The Other Jimmy 36:96847d42f010 115
The Other Jimmy 36:96847d42f010 116 @staticmethod
The Other Jimmy 36:96847d42f010 117 def get_full_name(name, unit_name, unit_kind, label=None,
The Other Jimmy 36:96847d42f010 118 allow_prefix=True):
The Other Jimmy 36:96847d42f010 119 """Return the full (prefixed) name of a parameter. If the parameter
The Other Jimmy 36:96847d42f010 120 already has a prefix, check if it is valid
The Other Jimmy 36:96847d42f010 121
The Other Jimmy 36:96847d42f010 122 Positional arguments:
The Other Jimmy 36:96847d42f010 123 name - the simple (unqualified) name of the parameter
The Other Jimmy 36:96847d42f010 124 unit_name - the unit (target/library/application) that defines this
The Other Jimmy 36:96847d42f010 125 parameter
The Other Jimmy 36:96847d42f010 126 unit_kind - the kind of the unit ("target", "library" or "application")
The Other Jimmy 36:96847d42f010 127
The Other Jimmy 36:96847d42f010 128 Keyword arguments:
The Other Jimmy 36:96847d42f010 129 label - the name of the label in the 'target_config_overrides' section
The Other Jimmy 36:96847d42f010 130 allow_prefix - True to allow the original name to have a prefix, False
The Other Jimmy 36:96847d42f010 131 otherwise
The Other Jimmy 36:96847d42f010 132 """
The Other Jimmy 36:96847d42f010 133 if name.find('.') == -1: # the name is not prefixed
The Other Jimmy 36:96847d42f010 134 if unit_kind == "target":
The Other Jimmy 36:96847d42f010 135 prefix = "target."
The Other Jimmy 36:96847d42f010 136 elif unit_kind == "application":
The Other Jimmy 36:96847d42f010 137 prefix = "app."
The Other Jimmy 36:96847d42f010 138 else:
The Other Jimmy 36:96847d42f010 139 prefix = unit_name + '.'
The Other Jimmy 36:96847d42f010 140 return prefix + name
theotherjimmy 43:2a7da56ebd24 141 if name in BOOTLOADER_OVERRIDES:
theotherjimmy 43:2a7da56ebd24 142 return name
The Other Jimmy 36:96847d42f010 143 # The name has a prefix, so check if it is valid
The Other Jimmy 36:96847d42f010 144 if not allow_prefix:
The Other Jimmy 36:96847d42f010 145 raise ConfigException("Invalid parameter name '%s' in '%s'" %
The Other Jimmy 36:96847d42f010 146 (name, ConfigParameter.get_display_name(
The Other Jimmy 36:96847d42f010 147 unit_name, unit_kind, label)))
The Other Jimmy 36:96847d42f010 148 temp = name.split(".")
The Other Jimmy 36:96847d42f010 149 # Check if the parameter syntax is correct (must be
The Other Jimmy 36:96847d42f010 150 # unit_name.parameter_name)
The Other Jimmy 36:96847d42f010 151 if len(temp) != 2:
The Other Jimmy 36:96847d42f010 152 raise ConfigException("Invalid parameter name '%s' in '%s'" %
The Other Jimmy 36:96847d42f010 153 (name, ConfigParameter.get_display_name(
The Other Jimmy 36:96847d42f010 154 unit_name, unit_kind, label)))
The Other Jimmy 36:96847d42f010 155 prefix = temp[0]
The Other Jimmy 36:96847d42f010 156 # Check if the given parameter prefix matches the expected prefix
theotherjimmy 43:2a7da56ebd24 157 if (unit_kind == "library" and prefix not in [unit_name, "target"]) or \
The Other Jimmy 36:96847d42f010 158 (unit_kind == "target" and prefix != "target"):
The Other Jimmy 36:96847d42f010 159 raise ConfigException(
The Other Jimmy 36:96847d42f010 160 "Invalid prefix '%s' for parameter name '%s' in '%s'" %
The Other Jimmy 36:96847d42f010 161 (prefix, name, ConfigParameter.get_display_name(
The Other Jimmy 36:96847d42f010 162 unit_name, unit_kind, label)))
The Other Jimmy 36:96847d42f010 163 return name
The Other Jimmy 36:96847d42f010 164
The Other Jimmy 36:96847d42f010 165 @staticmethod
The Other Jimmy 36:96847d42f010 166 def get_display_name(unit_name, unit_kind, label=None):
The Other Jimmy 36:96847d42f010 167 """Return the name displayed for a unit when interrogating the origin
The Other Jimmy 36:96847d42f010 168 and the last set place of a parameter
The Other Jimmy 36:96847d42f010 169
The Other Jimmy 36:96847d42f010 170 Positional arguments:
The Other Jimmy 36:96847d42f010 171 unit_name - the unit (target/library/application) that defines this
The Other Jimmy 36:96847d42f010 172 parameter
The Other Jimmy 36:96847d42f010 173 unit_kind - the kind of the unit ("target", "library" or "application")
The Other Jimmy 36:96847d42f010 174
The Other Jimmy 36:96847d42f010 175 Keyword arguments:
The Other Jimmy 36:96847d42f010 176 label - the name of the label in the 'target_config_overrides' section
The Other Jimmy 36:96847d42f010 177 """
The Other Jimmy 36:96847d42f010 178 if unit_kind == "target":
The Other Jimmy 36:96847d42f010 179 return "target:" + unit_name
The Other Jimmy 36:96847d42f010 180 elif unit_kind == "application":
The Other Jimmy 36:96847d42f010 181 return "application%s" % ("[%s]" % label if label else "")
The Other Jimmy 36:96847d42f010 182 else: # library
The Other Jimmy 36:96847d42f010 183 return "library:%s%s" % (unit_name, "[%s]" % label if label else "")
The Other Jimmy 36:96847d42f010 184
The Other Jimmy 36:96847d42f010 185 @staticmethod
The Other Jimmy 36:96847d42f010 186 def sanitize(name):
The Other Jimmy 36:96847d42f010 187 """ "Sanitize" a name so that it is a valid C macro name. Currently it
The Other Jimmy 36:96847d42f010 188 simply replaces '.' and '-' with '_'.
The Other Jimmy 36:96847d42f010 189
The Other Jimmy 36:96847d42f010 190 Positional arguments:
The Other Jimmy 36:96847d42f010 191 name - the name to make into a valid C macro
The Other Jimmy 36:96847d42f010 192 """
The Other Jimmy 36:96847d42f010 193 return name.replace('.', '_').replace('-', '_')
The Other Jimmy 36:96847d42f010 194
The Other Jimmy 36:96847d42f010 195 def set_value(self, value, unit_name, unit_kind, label=None):
The Other Jimmy 36:96847d42f010 196 """ Sets a value for this parameter, remember the place where it was
The Other Jimmy 36:96847d42f010 197 set. If the value is a Boolean, it is converted to 1 (for True) or
The Other Jimmy 36:96847d42f010 198 to 0 (for False).
The Other Jimmy 36:96847d42f010 199
The Other Jimmy 36:96847d42f010 200 Positional arguments:
The Other Jimmy 36:96847d42f010 201 value - the value of the parameter
The Other Jimmy 36:96847d42f010 202 unit_name - the unit (target/library/application) that defines this
The Other Jimmy 36:96847d42f010 203 parameter
The Other Jimmy 36:96847d42f010 204 unit_kind - the kind of the unit ("target", "library" or "application")
The Other Jimmy 36:96847d42f010 205
The Other Jimmy 36:96847d42f010 206 Keyword arguments:
The Other Jimmy 36:96847d42f010 207 label - the name of the label in the 'target_config_overrides' section
The Other Jimmy 36:96847d42f010 208 (optional)
The Other Jimmy 36:96847d42f010 209 """
The Other Jimmy 36:96847d42f010 210 self.value = int(value) if isinstance(value, bool) else value
The Other Jimmy 36:96847d42f010 211 self.set_by = self.get_display_name(unit_name, unit_kind, label)
The Other Jimmy 36:96847d42f010 212
The Other Jimmy 36:96847d42f010 213 def __str__(self):
The Other Jimmy 36:96847d42f010 214 """Return the string representation of this configuration parameter
The Other Jimmy 36:96847d42f010 215
The Other Jimmy 36:96847d42f010 216 Arguments: None
The Other Jimmy 36:96847d42f010 217 """
The Other Jimmy 36:96847d42f010 218 if self.value is not None:
The Other Jimmy 36:96847d42f010 219 return '%s = %s (macro name: "%s")' % \
The Other Jimmy 36:96847d42f010 220 (self.name, self.value, self.macro_name)
The Other Jimmy 36:96847d42f010 221 else:
The Other Jimmy 36:96847d42f010 222 return '%s has no value' % self.name
The Other Jimmy 36:96847d42f010 223
The Other Jimmy 36:96847d42f010 224 def get_verbose_description(self):
The Other Jimmy 36:96847d42f010 225 """Return a verbose description of this configuration parameter as a
The Other Jimmy 36:96847d42f010 226 string
The Other Jimmy 36:96847d42f010 227
The Other Jimmy 36:96847d42f010 228 Arguments: None
The Other Jimmy 36:96847d42f010 229 """
The Other Jimmy 36:96847d42f010 230 desc = "Name: %s%s\n" % \
The Other Jimmy 36:96847d42f010 231 (self.name, " (required parameter)" if self.required else "")
The Other Jimmy 36:96847d42f010 232 if self.help_text:
The Other Jimmy 36:96847d42f010 233 desc += " Description: %s\n" % self.help_text
The Other Jimmy 36:96847d42f010 234 desc += " Defined by: %s\n" % self.defined_by
The Other Jimmy 36:96847d42f010 235 if not self.value:
The Other Jimmy 36:96847d42f010 236 return desc + " No value set"
The Other Jimmy 36:96847d42f010 237 desc += " Macro name: %s\n" % self.macro_name
The Other Jimmy 36:96847d42f010 238 desc += " Value: %s (set by %s)" % (self.value, self.set_by)
The Other Jimmy 36:96847d42f010 239 return desc
The Other Jimmy 36:96847d42f010 240
The Other Jimmy 36:96847d42f010 241 class ConfigMacro(object):
The Other Jimmy 36:96847d42f010 242 """ A representation of a configuration macro. It handles both macros
The Other Jimmy 36:96847d42f010 243 without a value (MACRO) and with a value (MACRO=VALUE)
The Other Jimmy 36:96847d42f010 244 """
The Other Jimmy 36:96847d42f010 245 def __init__(self, name, unit_name, unit_kind):
The Other Jimmy 36:96847d42f010 246 """Construct a ConfigMacro object
The Other Jimmy 36:96847d42f010 247
The Other Jimmy 36:96847d42f010 248 Positional arguments:
The Other Jimmy 36:96847d42f010 249 name - the macro's name
The Other Jimmy 36:96847d42f010 250 unit_name - the location where the macro was defined
The Other Jimmy 36:96847d42f010 251 unit_kind - the type of macro this is
The Other Jimmy 36:96847d42f010 252 """
The Other Jimmy 36:96847d42f010 253 self.name = name
The Other Jimmy 36:96847d42f010 254 self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind)
The Other Jimmy 36:96847d42f010 255 if name.find("=") != -1:
The Other Jimmy 36:96847d42f010 256 tmp = name.split("=")
The Other Jimmy 36:96847d42f010 257 if len(tmp) != 2:
The Other Jimmy 36:96847d42f010 258 raise ValueError("Invalid macro definition '%s' in '%s'" %
The Other Jimmy 36:96847d42f010 259 (name, self.defined_by))
The Other Jimmy 36:96847d42f010 260 self.macro_name = tmp[0]
The Other Jimmy 36:96847d42f010 261 self.macro_value = tmp[1]
The Other Jimmy 36:96847d42f010 262 else:
The Other Jimmy 36:96847d42f010 263 self.macro_name = name
The Other Jimmy 36:96847d42f010 264 self.macro_value = None
The Other Jimmy 36:96847d42f010 265
The Other Jimmy 36:96847d42f010 266 class ConfigCumulativeOverride(object):
The Other Jimmy 36:96847d42f010 267 """Representation of overrides for cumulative attributes"""
The Other Jimmy 36:96847d42f010 268 def __init__(self, name, additions=None, removals=None, strict=False):
The Other Jimmy 36:96847d42f010 269 """Construct a ConfigCumulativeOverride object
The Other Jimmy 36:96847d42f010 270
The Other Jimmy 36:96847d42f010 271 Positional arguments:
The Other Jimmy 36:96847d42f010 272 name - the name of the config file this came from ?
The Other Jimmy 36:96847d42f010 273
The Other Jimmy 36:96847d42f010 274 Keyword arguments:
The Other Jimmy 36:96847d42f010 275 additions - macros to add to the overrides
The Other Jimmy 36:96847d42f010 276 removals - macros to remove from the overrides
The Other Jimmy 36:96847d42f010 277 strict - Boolean indicating that attempting to remove from an override
The Other Jimmy 36:96847d42f010 278 that does not exist should error
The Other Jimmy 36:96847d42f010 279 """
The Other Jimmy 36:96847d42f010 280 self.name = name
The Other Jimmy 36:96847d42f010 281 if additions:
The Other Jimmy 36:96847d42f010 282 self.additions = set(additions)
The Other Jimmy 36:96847d42f010 283 else:
The Other Jimmy 36:96847d42f010 284 self.additions = set()
The Other Jimmy 36:96847d42f010 285 if removals:
The Other Jimmy 36:96847d42f010 286 self.removals = set(removals)
The Other Jimmy 36:96847d42f010 287 else:
The Other Jimmy 36:96847d42f010 288 self.removals = set()
The Other Jimmy 36:96847d42f010 289 self.strict = strict
The Other Jimmy 36:96847d42f010 290
The Other Jimmy 36:96847d42f010 291 def remove_cumulative_overrides(self, overrides):
The Other Jimmy 36:96847d42f010 292 """Extend the list of override removals.
The Other Jimmy 36:96847d42f010 293
The Other Jimmy 36:96847d42f010 294 Positional arguments:
The Other Jimmy 36:96847d42f010 295 overrides - a list of names that, when the override is evaluated, will
The Other Jimmy 36:96847d42f010 296 be removed
The Other Jimmy 36:96847d42f010 297 """
The Other Jimmy 36:96847d42f010 298 for override in overrides:
The Other Jimmy 36:96847d42f010 299 if override in self.additions:
The Other Jimmy 36:96847d42f010 300 raise ConfigException(
The Other Jimmy 36:96847d42f010 301 "Configuration conflict. The %s %s both added and removed."
The Other Jimmy 36:96847d42f010 302 % (self.name[:-1], override))
The Other Jimmy 36:96847d42f010 303
The Other Jimmy 36:96847d42f010 304 self.removals |= set(overrides)
The Other Jimmy 36:96847d42f010 305
The Other Jimmy 36:96847d42f010 306 def add_cumulative_overrides(self, overrides):
The Other Jimmy 36:96847d42f010 307 """Extend the list of override additions.
The Other Jimmy 36:96847d42f010 308
The Other Jimmy 36:96847d42f010 309 Positional arguments:
The Other Jimmy 36:96847d42f010 310 overrides - a list of a names that, when the override is evaluated, will
The Other Jimmy 36:96847d42f010 311 be added to the list
The Other Jimmy 36:96847d42f010 312 """
The Other Jimmy 36:96847d42f010 313 for override in overrides:
The Other Jimmy 36:96847d42f010 314 if override in self.removals or \
The Other Jimmy 36:96847d42f010 315 (self.strict and override not in self.additions):
The Other Jimmy 36:96847d42f010 316 raise ConfigException(
The Other Jimmy 36:96847d42f010 317 "Configuration conflict. The %s %s both added and removed."
The Other Jimmy 36:96847d42f010 318 % (self.name[:-1], override))
The Other Jimmy 36:96847d42f010 319
The Other Jimmy 36:96847d42f010 320 self.additions |= set(overrides)
The Other Jimmy 36:96847d42f010 321
The Other Jimmy 36:96847d42f010 322 def strict_cumulative_overrides(self, overrides):
The Other Jimmy 36:96847d42f010 323 """Remove all overrides that are not the specified ones
The Other Jimmy 36:96847d42f010 324
The Other Jimmy 36:96847d42f010 325 Positional arguments:
The Other Jimmy 36:96847d42f010 326 overrides - a list of names that will replace the entire attribute when
The Other Jimmy 36:96847d42f010 327 this override is evaluated.
The Other Jimmy 36:96847d42f010 328 """
The Other Jimmy 36:96847d42f010 329 self.remove_cumulative_overrides(self.additions - set(overrides))
The Other Jimmy 36:96847d42f010 330 self.add_cumulative_overrides(overrides)
The Other Jimmy 36:96847d42f010 331 self.strict = True
The Other Jimmy 36:96847d42f010 332
The Other Jimmy 36:96847d42f010 333 def update_target(self, target):
The Other Jimmy 36:96847d42f010 334 """Update the attributes of a target based on this override"""
The Other Jimmy 36:96847d42f010 335 setattr(target, self.name,
The Other Jimmy 36:96847d42f010 336 list((set(getattr(target, self.name, []))
The Other Jimmy 36:96847d42f010 337 | self.additions) - self.removals))
The Other Jimmy 36:96847d42f010 338
The Other Jimmy 36:96847d42f010 339
The Other Jimmy 36:96847d42f010 340 def _process_config_parameters(data, params, unit_name, unit_kind):
The Other Jimmy 36:96847d42f010 341 """Process a "config_parameters" section in either a target, a library,
The Other Jimmy 36:96847d42f010 342 or the application.
The Other Jimmy 36:96847d42f010 343
The Other Jimmy 36:96847d42f010 344 Positional arguments:
The Other Jimmy 36:96847d42f010 345 data - a dictionary with the configuration parameters
The Other Jimmy 36:96847d42f010 346 params - storage for the discovered configuration parameters
The Other Jimmy 36:96847d42f010 347 unit_name - the unit (target/library/application) that defines this
The Other Jimmy 36:96847d42f010 348 parameter
The Other Jimmy 36:96847d42f010 349 unit_kind - the kind of the unit ("target", "library" or "application")
The Other Jimmy 36:96847d42f010 350 """
The Other Jimmy 36:96847d42f010 351 for name, val in data.items():
The Other Jimmy 36:96847d42f010 352 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
The Other Jimmy 36:96847d42f010 353 # If the parameter was already defined, raise an error
The Other Jimmy 36:96847d42f010 354 if full_name in params:
The Other Jimmy 36:96847d42f010 355 raise ConfigException(
The Other Jimmy 36:96847d42f010 356 "Parameter name '%s' defined in both '%s' and '%s'" %
The Other Jimmy 36:96847d42f010 357 (name, ConfigParameter.get_display_name(unit_name, unit_kind),
The Other Jimmy 36:96847d42f010 358 params[full_name].defined_by))
The Other Jimmy 36:96847d42f010 359 # Otherwise add it to the list of known parameters
The Other Jimmy 36:96847d42f010 360 # If "val" is not a dictionary, this is a shortcut definition,
The Other Jimmy 36:96847d42f010 361 # otherwise it is a full definition
The Other Jimmy 36:96847d42f010 362 params[full_name] = ConfigParameter(name, val if isinstance(val, dict)
The Other Jimmy 36:96847d42f010 363 else {"value": val}, unit_name,
The Other Jimmy 36:96847d42f010 364 unit_kind)
The Other Jimmy 36:96847d42f010 365 return params
The Other Jimmy 36:96847d42f010 366
The Other Jimmy 36:96847d42f010 367
The Other Jimmy 36:96847d42f010 368 def _process_macros(mlist, macros, unit_name, unit_kind):
The Other Jimmy 36:96847d42f010 369 """Process a macro definition and check for incompatible duplicate
The Other Jimmy 36:96847d42f010 370 definitions.
The Other Jimmy 36:96847d42f010 371
The Other Jimmy 36:96847d42f010 372 Positional arguments:
The Other Jimmy 36:96847d42f010 373 mlist - list of macro names to process
The Other Jimmy 36:96847d42f010 374 macros - dictionary with currently discovered macros
The Other Jimmy 36:96847d42f010 375 unit_name - the unit (library/application) that defines this macro
The Other Jimmy 36:96847d42f010 376 unit_kind - the kind of the unit ("library" or "application")
The Other Jimmy 36:96847d42f010 377 """
The Other Jimmy 36:96847d42f010 378 for mname in mlist:
The Other Jimmy 36:96847d42f010 379 macro = ConfigMacro(mname, unit_name, unit_kind)
The Other Jimmy 36:96847d42f010 380 if (macro.macro_name in macros) and \
The Other Jimmy 36:96847d42f010 381 (macros[macro.macro_name].name != mname):
The Other Jimmy 36:96847d42f010 382 # Found an incompatible definition of the macro in another module,
The Other Jimmy 36:96847d42f010 383 # so raise an error
The Other Jimmy 36:96847d42f010 384 full_unit_name = ConfigParameter.get_display_name(unit_name,
The Other Jimmy 36:96847d42f010 385 unit_kind)
The Other Jimmy 36:96847d42f010 386 raise ConfigException(
The Other Jimmy 36:96847d42f010 387 ("Macro '%s' defined in both '%s' and '%s'"
The Other Jimmy 36:96847d42f010 388 % (macro.macro_name, macros[macro.macro_name].defined_by,
The Other Jimmy 36:96847d42f010 389 full_unit_name)) +
The Other Jimmy 36:96847d42f010 390 " with incompatible values")
The Other Jimmy 36:96847d42f010 391 macros[macro.macro_name] = macro
The Other Jimmy 36:96847d42f010 392
The Other Jimmy 36:96847d42f010 393
The Other Jimmy 36:96847d42f010 394 Region = namedtuple("Region", "name start size active filename")
theotherjimmy 43:2a7da56ebd24 395 RamRegion = namedtuple("RamRegion", "name start size active")
The Other Jimmy 36:96847d42f010 396
The Other Jimmy 36:96847d42f010 397 class Config(object):
The Other Jimmy 36:96847d42f010 398 """'Config' implements the mbed configuration mechanism"""
The Other Jimmy 36:96847d42f010 399
The Other Jimmy 36:96847d42f010 400 # Libraries and applications have different names for their configuration
The Other Jimmy 36:96847d42f010 401 # files
The Other Jimmy 36:96847d42f010 402 __mbed_app_config_name = "mbed_app.json"
The Other Jimmy 36:96847d42f010 403 __mbed_lib_config_name = "mbed_lib.json"
The Other Jimmy 36:96847d42f010 404
The Other Jimmy 36:96847d42f010 405 __unused_overrides = set(["target.bootloader_img", "target.restrict_size",
The Other Jimmy 36:96847d42f010 406 "target.mbed_app_start", "target.mbed_app_size"])
The Other Jimmy 36:96847d42f010 407
theotherjimmy 43:2a7da56ebd24 408 @classmethod
theotherjimmy 43:2a7da56ebd24 409 def find_app_config(cls, top_level_dirs):
theotherjimmy 43:2a7da56ebd24 410 app_config_location = None
theotherjimmy 43:2a7da56ebd24 411 for directory in top_level_dirs:
theotherjimmy 43:2a7da56ebd24 412 full_path = os.path.join(directory, cls.__mbed_app_config_name)
theotherjimmy 43:2a7da56ebd24 413 if os.path.isfile(full_path):
theotherjimmy 43:2a7da56ebd24 414 if app_config_location is not None:
theotherjimmy 43:2a7da56ebd24 415 raise ConfigException("Duplicate '%s' file in '%s' and '%s'"
theotherjimmy 43:2a7da56ebd24 416 % (cls.__mbed_app_config_name,
theotherjimmy 43:2a7da56ebd24 417 cls.app_config_location, full_path))
theotherjimmy 43:2a7da56ebd24 418 else:
theotherjimmy 43:2a7da56ebd24 419 app_config_location = full_path
theotherjimmy 43:2a7da56ebd24 420 return app_config_location
theotherjimmy 43:2a7da56ebd24 421
theotherjimmy 43:2a7da56ebd24 422 def format_validation_error(self, error, path):
theotherjimmy 43:2a7da56ebd24 423 if error.context:
theotherjimmy 43:2a7da56ebd24 424 return self.format_validation_error(error.context[0], path)
theotherjimmy 43:2a7da56ebd24 425 else:
theotherjimmy 43:2a7da56ebd24 426 return "in {} element {}: {}".format(
theotherjimmy 43:2a7da56ebd24 427 path, ".".join(p for p in error.absolute_path),
theotherjimmy 43:2a7da56ebd24 428 error.message.replace('u\'','\''))
The Other Jimmy 36:96847d42f010 429
The Other Jimmy 36:96847d42f010 430 def __init__(self, tgt, top_level_dirs=None, app_config=None):
The Other Jimmy 36:96847d42f010 431 """Construct a mbed configuration
The Other Jimmy 36:96847d42f010 432
The Other Jimmy 36:96847d42f010 433 Positional arguments:
The Other Jimmy 36:96847d42f010 434 target - the name of the mbed target used for this configuration
The Other Jimmy 36:96847d42f010 435 instance
The Other Jimmy 36:96847d42f010 436
The Other Jimmy 36:96847d42f010 437 Keyword argumets:
The Other Jimmy 36:96847d42f010 438 top_level_dirs - a list of top level source directories (where
The Other Jimmy 36:96847d42f010 439 mbed_app_config.json could be found)
The Other Jimmy 36:96847d42f010 440 app_config - location of a chosen mbed_app.json file
The Other Jimmy 36:96847d42f010 441
The Other Jimmy 36:96847d42f010 442 NOTE: Construction of a Config object will look for the application
The Other Jimmy 36:96847d42f010 443 configuration file in top_level_dirs. If found once, it'll parse it.
The Other Jimmy 36:96847d42f010 444 top_level_dirs may be None (in this case, the constructor will not
The Other Jimmy 36:96847d42f010 445 search for a configuration file).
The Other Jimmy 36:96847d42f010 446 """
The Other Jimmy 36:96847d42f010 447 config_errors = []
theotherjimmy 43:2a7da56ebd24 448 self.config_errors = []
The Other Jimmy 36:96847d42f010 449 self.app_config_location = app_config
theotherjimmy 43:2a7da56ebd24 450 if self.app_config_location is None and top_level_dirs:
theotherjimmy 43:2a7da56ebd24 451 self.app_config_location = self.find_app_config(top_level_dirs)
The Other Jimmy 36:96847d42f010 452 try:
The Other Jimmy 36:96847d42f010 453 self.app_config_data = json_file_to_dict(self.app_config_location) \
The Other Jimmy 36:96847d42f010 454 if self.app_config_location else {}
The Other Jimmy 36:96847d42f010 455 except ValueError as exc:
The Other Jimmy 36:96847d42f010 456 self.app_config_data = {}
The Other Jimmy 36:96847d42f010 457 config_errors.append(
The Other Jimmy 36:96847d42f010 458 ConfigException("Could not parse mbed app configuration from %s"
The Other Jimmy 36:96847d42f010 459 % self.app_config_location))
The Other Jimmy 36:96847d42f010 460
theotherjimmy 43:2a7da56ebd24 461
theotherjimmy 43:2a7da56ebd24 462 if self.app_config_location is not None:
theotherjimmy 43:2a7da56ebd24 463 # Validate the format of the JSON file based on schema_app.json
theotherjimmy 43:2a7da56ebd24 464 schema_root = os.path.dirname(os.path.abspath(__file__))
theotherjimmy 43:2a7da56ebd24 465 schema_path = os.path.join(schema_root, "schema_app.json")
theotherjimmy 43:2a7da56ebd24 466 schema = json_file_to_dict(schema_path)
theotherjimmy 43:2a7da56ebd24 467
theotherjimmy 43:2a7da56ebd24 468 url = moves.urllib.request.pathname2url(schema_path)
theotherjimmy 43:2a7da56ebd24 469 uri = moves.urllib_parse.urljoin("file://", url)
theotherjimmy 43:2a7da56ebd24 470
theotherjimmy 43:2a7da56ebd24 471 resolver = RefResolver(uri, schema)
theotherjimmy 43:2a7da56ebd24 472 validator = Draft4Validator(schema, resolver=resolver)
theotherjimmy 43:2a7da56ebd24 473
theotherjimmy 43:2a7da56ebd24 474 errors = sorted(validator.iter_errors(self.app_config_data))
theotherjimmy 43:2a7da56ebd24 475
theotherjimmy 43:2a7da56ebd24 476 if errors:
theotherjimmy 43:2a7da56ebd24 477 raise ConfigException("; ".join(
theotherjimmy 43:2a7da56ebd24 478 self.format_validation_error(x, self.app_config_location)
theotherjimmy 43:2a7da56ebd24 479 for x in errors))
theotherjimmy 43:2a7da56ebd24 480
The Other Jimmy 36:96847d42f010 481 # Update the list of targets with the ones defined in the application
The Other Jimmy 36:96847d42f010 482 # config, if applicable
The Other Jimmy 36:96847d42f010 483 self.lib_config_data = {}
The Other Jimmy 36:96847d42f010 484 # Make sure that each config is processed only once
The Other Jimmy 36:96847d42f010 485 self.processed_configs = {}
theotherjimmy 43:2a7da56ebd24 486 if isinstance(tgt, Target):
theotherjimmy 43:2a7da56ebd24 487 self.target = tgt
theotherjimmy 43:2a7da56ebd24 488 else:
The Other Jimmy 36:96847d42f010 489 if tgt in TARGET_MAP:
The Other Jimmy 36:96847d42f010 490 self.target = TARGET_MAP[tgt]
The Other Jimmy 36:96847d42f010 491 else:
The Other Jimmy 36:96847d42f010 492 self.target = generate_py_target(
The Other Jimmy 36:96847d42f010 493 self.app_config_data.get("custom_targets", {}), tgt)
The Other Jimmy 36:96847d42f010 494 self.target = deepcopy(self.target)
The Other Jimmy 36:96847d42f010 495 self.target_labels = self.target.labels
theotherjimmy 43:2a7da56ebd24 496 for override in BOOTLOADER_OVERRIDES:
theotherjimmy 43:2a7da56ebd24 497 _, attr = override.split(".")
theotherjimmy 43:2a7da56ebd24 498 setattr(self.target, attr, None)
The Other Jimmy 36:96847d42f010 499
The Other Jimmy 36:96847d42f010 500 self.cumulative_overrides = {key: ConfigCumulativeOverride(key)
The Other Jimmy 36:96847d42f010 501 for key in CUMULATIVE_ATTRIBUTES}
The Other Jimmy 36:96847d42f010 502
The Other Jimmy 36:96847d42f010 503 self._process_config_and_overrides(self.app_config_data, {}, "app",
The Other Jimmy 36:96847d42f010 504 "application")
The Other Jimmy 36:96847d42f010 505 self.config_errors = config_errors
The Other Jimmy 36:96847d42f010 506
The Other Jimmy 36:96847d42f010 507 def add_config_files(self, flist):
The Other Jimmy 36:96847d42f010 508 """Add configuration files
The Other Jimmy 36:96847d42f010 509
The Other Jimmy 36:96847d42f010 510 Positional arguments:
The Other Jimmy 36:96847d42f010 511 flist - a list of files to add to this configuration
The Other Jimmy 36:96847d42f010 512 """
The Other Jimmy 36:96847d42f010 513 for config_file in flist:
The Other Jimmy 36:96847d42f010 514 if not config_file.endswith(self.__mbed_lib_config_name):
The Other Jimmy 36:96847d42f010 515 continue
The Other Jimmy 36:96847d42f010 516 full_path = os.path.normpath(os.path.abspath(config_file))
The Other Jimmy 36:96847d42f010 517 # Check that we didn't already process this file
theotherjimmy 43:2a7da56ebd24 518 if full_path in self.processed_configs:
The Other Jimmy 36:96847d42f010 519 continue
The Other Jimmy 36:96847d42f010 520 self.processed_configs[full_path] = True
The Other Jimmy 36:96847d42f010 521 # Read the library configuration and add a "__full_config_path"
The Other Jimmy 36:96847d42f010 522 # attribute to it
The Other Jimmy 36:96847d42f010 523 try:
The Other Jimmy 36:96847d42f010 524 cfg = json_file_to_dict(config_file)
The Other Jimmy 36:96847d42f010 525 except ValueError as exc:
theotherjimmy 43:2a7da56ebd24 526 raise ConfigException(str(exc))
theotherjimmy 43:2a7da56ebd24 527
theotherjimmy 43:2a7da56ebd24 528 # Validate the format of the JSON file based on the schema_lib.json
theotherjimmy 43:2a7da56ebd24 529 schema_root = os.path.dirname(os.path.abspath(__file__))
theotherjimmy 43:2a7da56ebd24 530 schema_path = os.path.join(schema_root, "schema_lib.json")
theotherjimmy 43:2a7da56ebd24 531 schema_file = json_file_to_dict(schema_path)
theotherjimmy 43:2a7da56ebd24 532
theotherjimmy 43:2a7da56ebd24 533 url = moves.urllib.request.pathname2url(schema_path)
theotherjimmy 43:2a7da56ebd24 534 uri = moves.urllib_parse.urljoin("file://", url)
theotherjimmy 43:2a7da56ebd24 535
theotherjimmy 43:2a7da56ebd24 536 resolver = RefResolver(uri, schema_file)
theotherjimmy 43:2a7da56ebd24 537 validator = Draft4Validator(schema_file, resolver=resolver)
theotherjimmy 43:2a7da56ebd24 538
theotherjimmy 43:2a7da56ebd24 539 errors = sorted(validator.iter_errors(cfg))
theotherjimmy 43:2a7da56ebd24 540
theotherjimmy 43:2a7da56ebd24 541 if errors:
theotherjimmy 43:2a7da56ebd24 542 raise ConfigException("; ".join(
theotherjimmy 43:2a7da56ebd24 543 self.format_validation_error(x, config_file)
theotherjimmy 43:2a7da56ebd24 544 for x in errors))
The Other Jimmy 36:96847d42f010 545
The Other Jimmy 36:96847d42f010 546 cfg["__config_path"] = full_path
The Other Jimmy 36:96847d42f010 547
The Other Jimmy 36:96847d42f010 548 # If there's already a configuration for a module with the same
The Other Jimmy 36:96847d42f010 549 # name, exit with error
theotherjimmy 43:2a7da56ebd24 550 if cfg["name"] in self.lib_config_data:
The Other Jimmy 36:96847d42f010 551 raise ConfigException(
The Other Jimmy 36:96847d42f010 552 "Library name '%s' is not unique (defined in '%s' and '%s')"
The Other Jimmy 36:96847d42f010 553 % (cfg["name"], full_path,
The Other Jimmy 36:96847d42f010 554 self.lib_config_data[cfg["name"]]["__config_path"]))
The Other Jimmy 36:96847d42f010 555 self.lib_config_data[cfg["name"]] = cfg
The Other Jimmy 36:96847d42f010 556
The Other Jimmy 36:96847d42f010 557 @property
The Other Jimmy 36:96847d42f010 558 def has_regions(self):
The Other Jimmy 36:96847d42f010 559 """Does this config have regions defined?"""
theotherjimmy 43:2a7da56ebd24 560 for override in ROM_OVERRIDES:
theotherjimmy 43:2a7da56ebd24 561 _, attr = override.split(".")
theotherjimmy 43:2a7da56ebd24 562 if getattr(self.target, attr, None):
theotherjimmy 43:2a7da56ebd24 563 return True
theotherjimmy 43:2a7da56ebd24 564 return False
theotherjimmy 43:2a7da56ebd24 565
theotherjimmy 43:2a7da56ebd24 566 @property
theotherjimmy 43:2a7da56ebd24 567 def has_ram_regions(self):
theotherjimmy 43:2a7da56ebd24 568 """Does this config have regions defined?"""
theotherjimmy 43:2a7da56ebd24 569 for override in RAM_OVERRIDES:
theotherjimmy 43:2a7da56ebd24 570 _, attr = override.split(".")
theotherjimmy 43:2a7da56ebd24 571 if getattr(self.target, attr, None):
theotherjimmy 43:2a7da56ebd24 572 return True
theotherjimmy 43:2a7da56ebd24 573 return False
The Other Jimmy 36:96847d42f010 574
The Other Jimmy 36:96847d42f010 575 @property
theotherjimmy 43:2a7da56ebd24 576 def sectors(self):
theotherjimmy 43:2a7da56ebd24 577 """Return a list of tuples of sector start,size"""
theotherjimmy 43:2a7da56ebd24 578 cache = Cache(False, False)
theotherjimmy 43:2a7da56ebd24 579 if self.target.device_name not in cache.index:
theotherjimmy 43:2a7da56ebd24 580 raise ConfigException("Bootloader not supported on this target: "
theotherjimmy 43:2a7da56ebd24 581 "targets.json `device_name` not found in "
theotherjimmy 43:2a7da56ebd24 582 "arm_pack_manager index.")
theotherjimmy 43:2a7da56ebd24 583 cmsis_part = cache.index[self.target.device_name]
theotherjimmy 43:2a7da56ebd24 584 sectors = cmsis_part['sectors']
theotherjimmy 43:2a7da56ebd24 585 if sectors:
theotherjimmy 43:2a7da56ebd24 586 return sectors
theotherjimmy 43:2a7da56ebd24 587 raise ConfigException("No sector info available")
theotherjimmy 43:2a7da56ebd24 588
theotherjimmy 43:2a7da56ebd24 589 def _get_cmsis_part(self):
theotherjimmy 43:2a7da56ebd24 590 if not getattr(self.target, "bootloader_supported", False):
The Other Jimmy 36:96847d42f010 591 raise ConfigException("Bootloader not supported on this target.")
The Other Jimmy 36:96847d42f010 592 if not hasattr(self.target, "device_name"):
The Other Jimmy 36:96847d42f010 593 raise ConfigException("Bootloader not supported on this target: "
The Other Jimmy 36:96847d42f010 594 "targets.json `device_name` not specified.")
The Other Jimmy 36:96847d42f010 595 cache = Cache(False, False)
The Other Jimmy 36:96847d42f010 596 if self.target.device_name not in cache.index:
The Other Jimmy 36:96847d42f010 597 raise ConfigException("Bootloader not supported on this target: "
The Other Jimmy 36:96847d42f010 598 "targets.json `device_name` not found in "
The Other Jimmy 36:96847d42f010 599 "arm_pack_manager index.")
theotherjimmy 43:2a7da56ebd24 600 return cache.index[self.target.device_name]
theotherjimmy 43:2a7da56ebd24 601
theotherjimmy 43:2a7da56ebd24 602 def _get_mem_specs(self, memories, cmsis_part, exception_text):
theotherjimmy 43:2a7da56ebd24 603 for memory in memories:
theotherjimmy 43:2a7da56ebd24 604 try:
theotherjimmy 43:2a7da56ebd24 605 size = cmsis_part['memory'][memory]['size']
theotherjimmy 43:2a7da56ebd24 606 start = cmsis_part['memory'][memory]['start']
theotherjimmy 43:2a7da56ebd24 607 return (start, size)
theotherjimmy 43:2a7da56ebd24 608 except KeyError:
theotherjimmy 43:2a7da56ebd24 609 continue
theotherjimmy 43:2a7da56ebd24 610 raise ConfigException(exception_text)
theotherjimmy 43:2a7da56ebd24 611
theotherjimmy 43:2a7da56ebd24 612 @property
theotherjimmy 43:2a7da56ebd24 613 def rom(self):
theotherjimmy 43:2a7da56ebd24 614 """Get rom information as a pair of start_addr, size"""
theotherjimmy 43:2a7da56ebd24 615 # Override rom_start/rom_size
theotherjimmy 43:2a7da56ebd24 616 #
theotherjimmy 43:2a7da56ebd24 617 # This is usually done for a target which:
theotherjimmy 43:2a7da56ebd24 618 # 1. Doesn't support CMSIS pack, or
theotherjimmy 43:2a7da56ebd24 619 # 2. Supports TrustZone and user needs to change its flash partition
theotherjimmy 43:2a7da56ebd24 620 cmsis_part = self._get_cmsis_part()
theotherjimmy 43:2a7da56ebd24 621 rom_start, rom_size = self._get_mem_specs(
theotherjimmy 43:2a7da56ebd24 622 ["IROM1", "PROGRAM_FLASH"],
theotherjimmy 43:2a7da56ebd24 623 cmsis_part,
theotherjimmy 43:2a7da56ebd24 624 "Not enough information in CMSIS packs to build a bootloader "
theotherjimmy 43:2a7da56ebd24 625 "project"
theotherjimmy 43:2a7da56ebd24 626 )
theotherjimmy 43:2a7da56ebd24 627 rom_start = int(getattr(self.target, "mbed_rom_start", False) or rom_start, 0)
theotherjimmy 43:2a7da56ebd24 628 rom_size = int(getattr(self.target, "mbed_rom_size", False) or rom_size, 0)
theotherjimmy 43:2a7da56ebd24 629 return (rom_start, rom_size)
theotherjimmy 43:2a7da56ebd24 630
theotherjimmy 43:2a7da56ebd24 631 @property
theotherjimmy 43:2a7da56ebd24 632 def ram_regions(self):
theotherjimmy 43:2a7da56ebd24 633 """Generate a list of ram regions from the config"""
theotherjimmy 43:2a7da56ebd24 634 cmsis_part = self._get_cmsis_part()
theotherjimmy 43:2a7da56ebd24 635 ram_start, ram_size = self._get_mem_specs(
theotherjimmy 43:2a7da56ebd24 636 ["IRAM1", "SRAM0"],
theotherjimmy 43:2a7da56ebd24 637 cmsis_part,
theotherjimmy 43:2a7da56ebd24 638 "Not enough information in CMSIS packs to build a ram sharing project"
theotherjimmy 43:2a7da56ebd24 639 )
theotherjimmy 43:2a7da56ebd24 640 # Override ram_start/ram_size
theotherjimmy 43:2a7da56ebd24 641 #
theotherjimmy 43:2a7da56ebd24 642 # This is usually done for a target which:
theotherjimmy 43:2a7da56ebd24 643 # 1. Doesn't support CMSIS pack, or
theotherjimmy 43:2a7da56ebd24 644 # 2. Supports TrustZone and user needs to change its flash partition
theotherjimmy 43:2a7da56ebd24 645 ram_start = getattr(self.target, "mbed_ram_start", False) or ram_start
theotherjimmy 43:2a7da56ebd24 646 ram_size = getattr(self.target, "mbed_ram_size", False) or ram_size
theotherjimmy 43:2a7da56ebd24 647 return [RamRegion("application_ram", int(ram_start, 0), int(ram_size, 0), True)]
theotherjimmy 43:2a7da56ebd24 648
theotherjimmy 43:2a7da56ebd24 649 @property
theotherjimmy 43:2a7da56ebd24 650 def regions(self):
theotherjimmy 43:2a7da56ebd24 651 """Generate a list of regions from the config"""
theotherjimmy 43:2a7da56ebd24 652 if ((self.target.bootloader_img or self.target.restrict_size) and
theotherjimmy 43:2a7da56ebd24 653 (self.target.mbed_app_start or self.target.mbed_app_size)):
The Other Jimmy 36:96847d42f010 654 raise ConfigException(
The Other Jimmy 36:96847d42f010 655 "target.bootloader_img and target.restirct_size are "
The Other Jimmy 36:96847d42f010 656 "incompatible with target.mbed_app_start and "
The Other Jimmy 36:96847d42f010 657 "target.mbed_app_size")
theotherjimmy 43:2a7da56ebd24 658 if self.target.bootloader_img or self.target.restrict_size:
theotherjimmy 43:2a7da56ebd24 659 return self._generate_bootloader_build(*self.rom)
theotherjimmy 43:2a7da56ebd24 660 else:
theotherjimmy 43:2a7da56ebd24 661 return self._generate_linker_overrides(*self.rom)
theotherjimmy 43:2a7da56ebd24 662
theotherjimmy 43:2a7da56ebd24 663 @staticmethod
theotherjimmy 43:2a7da56ebd24 664 def header_member_size(member):
theotherjimmy 43:2a7da56ebd24 665 _, _, subtype, _ = member
The Other Jimmy 36:96847d42f010 666 try:
theotherjimmy 43:2a7da56ebd24 667 return int(subtype[:-2]) // 8
theotherjimmy 43:2a7da56ebd24 668 except:
theotherjimmy 43:2a7da56ebd24 669 if subtype.startswith("CRCITT32"):
theotherjimmy 43:2a7da56ebd24 670 return 32 // 8
theotherjimmy 43:2a7da56ebd24 671 elif subtype == "SHA256":
theotherjimmy 43:2a7da56ebd24 672 return 256 // 8
theotherjimmy 43:2a7da56ebd24 673 elif subtype == "SHA512":
theotherjimmy 43:2a7da56ebd24 674 return 512 // 8
theotherjimmy 43:2a7da56ebd24 675 else:
theotherjimmy 43:2a7da56ebd24 676 raise ValueError("target.header_format: subtype %s is not "
theotherjimmy 43:2a7da56ebd24 677 "understood" % subtype)
theotherjimmy 43:2a7da56ebd24 678
theotherjimmy 43:2a7da56ebd24 679 @staticmethod
theotherjimmy 43:2a7da56ebd24 680 def _header_size(format):
theotherjimmy 43:2a7da56ebd24 681 return sum(Config.header_member_size(m) for m in format)
theotherjimmy 43:2a7da56ebd24 682
theotherjimmy 43:2a7da56ebd24 683 def _make_header_region(self, start, header_format, offset=None):
theotherjimmy 43:2a7da56ebd24 684 size = self._header_size(header_format)
theotherjimmy 43:2a7da56ebd24 685 region = Region("header", start, size, False, None)
theotherjimmy 43:2a7da56ebd24 686 start += size
theotherjimmy 43:2a7da56ebd24 687 start = ((start + 7) // 8) * 8
theotherjimmy 43:2a7da56ebd24 688 return (start, region)
theotherjimmy 43:2a7da56ebd24 689
theotherjimmy 43:2a7da56ebd24 690 @staticmethod
theotherjimmy 43:2a7da56ebd24 691 def _assign_new_offset(rom_start, start, new_offset, region_name):
theotherjimmy 43:2a7da56ebd24 692 newstart = rom_start + integer(new_offset, 0)
theotherjimmy 43:2a7da56ebd24 693 if newstart < start:
The Other Jimmy 36:96847d42f010 694 raise ConfigException(
theotherjimmy 43:2a7da56ebd24 695 "Can not place % region inside previous region" % region_name)
theotherjimmy 43:2a7da56ebd24 696 return newstart
The Other Jimmy 36:96847d42f010 697
theotherjimmy 43:2a7da56ebd24 698 def _generate_bootloader_build(self, rom_start, rom_size):
theotherjimmy 43:2a7da56ebd24 699 start = rom_start
theotherjimmy 43:2a7da56ebd24 700 rom_end = rom_start + rom_size
theotherjimmy 43:2a7da56ebd24 701 if self.target.bootloader_img:
theotherjimmy 43:2a7da56ebd24 702 if isabs(self.target.bootloader_img):
theotherjimmy 43:2a7da56ebd24 703 filename = self.target.bootloader_img
theotherjimmy 43:2a7da56ebd24 704 else:
theotherjimmy 43:2a7da56ebd24 705 basedir = abspath(dirname(self.app_config_location))
theotherjimmy 43:2a7da56ebd24 706 filename = join(basedir, self.target.bootloader_img)
The Other Jimmy 36:96847d42f010 707 if not exists(filename):
The Other Jimmy 36:96847d42f010 708 raise ConfigException("Bootloader %s not found" % filename)
The Other Jimmy 36:96847d42f010 709 part = intelhex_offset(filename, offset=rom_start)
The Other Jimmy 36:96847d42f010 710 if part.minaddr() != rom_start:
The Other Jimmy 36:96847d42f010 711 raise ConfigException("bootloader executable does not "
The Other Jimmy 36:96847d42f010 712 "start at 0x%x" % rom_start)
The Other Jimmy 36:96847d42f010 713 part_size = (part.maxaddr() - part.minaddr()) + 1
theotherjimmy 43:2a7da56ebd24 714 part_size = Config._align_ceiling(rom_start + part_size, self.sectors) - rom_start
theotherjimmy 43:2a7da56ebd24 715 yield Region("bootloader", rom_start, part_size, False,
The Other Jimmy 36:96847d42f010 716 filename)
theotherjimmy 43:2a7da56ebd24 717 start = rom_start + part_size
theotherjimmy 43:2a7da56ebd24 718 if self.target.header_format:
theotherjimmy 43:2a7da56ebd24 719 if self.target.header_offset:
theotherjimmy 43:2a7da56ebd24 720 start = self._assign_new_offset(
theotherjimmy 43:2a7da56ebd24 721 rom_start, start, self.target.header_offset, "header")
theotherjimmy 43:2a7da56ebd24 722 start, region = self._make_header_region(
theotherjimmy 43:2a7da56ebd24 723 start, self.target.header_format)
theotherjimmy 43:2a7da56ebd24 724 yield region._replace(filename=self.target.header_format)
theotherjimmy 43:2a7da56ebd24 725 if self.target.restrict_size is not None:
theotherjimmy 43:2a7da56ebd24 726 new_size = int(self.target.restrict_size, 0)
theotherjimmy 43:2a7da56ebd24 727 new_size = Config._align_floor(start + new_size, self.sectors) - start
theotherjimmy 43:2a7da56ebd24 728 yield Region("application", start, new_size, True, None)
The Other Jimmy 36:96847d42f010 729 start += new_size
theotherjimmy 43:2a7da56ebd24 730 if self.target.header_format and not self.target.bootloader_img:
theotherjimmy 43:2a7da56ebd24 731 if self.target.header_offset:
theotherjimmy 43:2a7da56ebd24 732 start = self._assign_new_offset(
theotherjimmy 43:2a7da56ebd24 733 rom_start, start, self.target.header_offset, "header")
theotherjimmy 43:2a7da56ebd24 734 start, region = self._make_header_region(
theotherjimmy 43:2a7da56ebd24 735 start, self.target.header_format)
theotherjimmy 43:2a7da56ebd24 736 yield region
theotherjimmy 43:2a7da56ebd24 737 if self.target.app_offset:
theotherjimmy 43:2a7da56ebd24 738 start = self._assign_new_offset(
theotherjimmy 43:2a7da56ebd24 739 rom_start, start, self.target.app_offset, "application")
theotherjimmy 43:2a7da56ebd24 740 yield Region("post_application", start, rom_end - start,
The Other Jimmy 36:96847d42f010 741 False, None)
The Other Jimmy 36:96847d42f010 742 else:
theotherjimmy 43:2a7da56ebd24 743 if self.target.app_offset:
theotherjimmy 43:2a7da56ebd24 744 start = self._assign_new_offset(
theotherjimmy 43:2a7da56ebd24 745 rom_start, start, self.target.app_offset, "application")
theotherjimmy 43:2a7da56ebd24 746 yield Region("application", start, rom_end - start,
The Other Jimmy 36:96847d42f010 747 True, None)
theotherjimmy 43:2a7da56ebd24 748 if start > rom_start + rom_size:
The Other Jimmy 36:96847d42f010 749 raise ConfigException("Not enough memory on device to fit all "
The Other Jimmy 36:96847d42f010 750 "application regions")
theotherjimmy 43:2a7da56ebd24 751
theotherjimmy 43:2a7da56ebd24 752 @staticmethod
theotherjimmy 43:2a7da56ebd24 753 def _find_sector(address, sectors):
theotherjimmy 43:2a7da56ebd24 754 target_size = -1
theotherjimmy 43:2a7da56ebd24 755 target_start = -1
theotherjimmy 43:2a7da56ebd24 756 for (start, size) in sectors:
theotherjimmy 43:2a7da56ebd24 757 if address < start:
theotherjimmy 43:2a7da56ebd24 758 break
theotherjimmy 43:2a7da56ebd24 759 target_start = start
theotherjimmy 43:2a7da56ebd24 760 target_size = size
theotherjimmy 43:2a7da56ebd24 761 if (target_size < 0):
theotherjimmy 43:2a7da56ebd24 762 raise ConfigException("No valid sector found")
theotherjimmy 43:2a7da56ebd24 763 return target_start, target_size
theotherjimmy 43:2a7da56ebd24 764
theotherjimmy 43:2a7da56ebd24 765 @staticmethod
theotherjimmy 43:2a7da56ebd24 766 def _align_floor(address, sectors):
theotherjimmy 43:2a7da56ebd24 767 target_start, target_size = Config._find_sector(address, sectors)
theotherjimmy 43:2a7da56ebd24 768 sector_num = (address - target_start) // target_size
theotherjimmy 43:2a7da56ebd24 769 return target_start + (sector_num * target_size)
theotherjimmy 43:2a7da56ebd24 770
theotherjimmy 43:2a7da56ebd24 771 @staticmethod
theotherjimmy 43:2a7da56ebd24 772 def _align_ceiling(address, sectors):
theotherjimmy 43:2a7da56ebd24 773 target_start, target_size = Config._find_sector(address, sectors)
theotherjimmy 43:2a7da56ebd24 774 sector_num = ((address - target_start) + target_size - 1) // target_size
theotherjimmy 43:2a7da56ebd24 775 return target_start + (sector_num * target_size)
The Other Jimmy 36:96847d42f010 776
The Other Jimmy 36:96847d42f010 777 @property
The Other Jimmy 36:96847d42f010 778 def report(self):
The Other Jimmy 36:96847d42f010 779 return {'app_config': self.app_config_location,
The Other Jimmy 36:96847d42f010 780 'library_configs': map(relpath, self.processed_configs.keys())}
The Other Jimmy 36:96847d42f010 781
theotherjimmy 43:2a7da56ebd24 782 def _generate_linker_overrides(self, rom_start, rom_size):
theotherjimmy 43:2a7da56ebd24 783 if self.target.mbed_app_start is not None:
theotherjimmy 43:2a7da56ebd24 784 start = int(self.target.mbed_app_start, 0)
The Other Jimmy 36:96847d42f010 785 else:
The Other Jimmy 36:96847d42f010 786 start = rom_start
theotherjimmy 43:2a7da56ebd24 787 if self.target.mbed_app_size is not None:
theotherjimmy 43:2a7da56ebd24 788 size = int(self.target.mbed_app_size, 0)
The Other Jimmy 36:96847d42f010 789 else:
The Other Jimmy 36:96847d42f010 790 size = (rom_size + rom_start) - start
The Other Jimmy 36:96847d42f010 791 if start < rom_start:
The Other Jimmy 36:96847d42f010 792 raise ConfigException("Application starts before ROM")
The Other Jimmy 36:96847d42f010 793 if size + start > rom_size + rom_start:
The Other Jimmy 36:96847d42f010 794 raise ConfigException("Application ends after ROM")
The Other Jimmy 36:96847d42f010 795 yield Region("application", start, size, True, None)
The Other Jimmy 36:96847d42f010 796
The Other Jimmy 36:96847d42f010 797 def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
The Other Jimmy 36:96847d42f010 798 """Process "config_parameters" and "target_config_overrides" into a
The Other Jimmy 36:96847d42f010 799 given dictionary
The Other Jimmy 36:96847d42f010 800
The Other Jimmy 36:96847d42f010 801 Positional arguments:
The Other Jimmy 36:96847d42f010 802 data - the configuration data of the library/appliation
The Other Jimmy 36:96847d42f010 803 params - storage for the discovered configuration parameters
The Other Jimmy 36:96847d42f010 804 unit_name - the unit (library/application) that defines this parameter
The Other Jimmy 36:96847d42f010 805 unit_kind - the kind of the unit ("library" or "application")
The Other Jimmy 36:96847d42f010 806 """
The Other Jimmy 36:96847d42f010 807 _process_config_parameters(data.get("config", {}), params, unit_name,
The Other Jimmy 36:96847d42f010 808 unit_kind)
The Other Jimmy 36:96847d42f010 809 for label, overrides in data.get("target_overrides", {}).items():
The Other Jimmy 36:96847d42f010 810 # If the label is defined by the target or it has the special value
The Other Jimmy 36:96847d42f010 811 # "*", process the overrides
The Other Jimmy 36:96847d42f010 812 if (label == '*') or (label in self.target_labels):
The Other Jimmy 36:96847d42f010 813 # Check for invalid cumulative overrides in libraries
The Other Jimmy 36:96847d42f010 814 if (unit_kind == 'library' and
The Other Jimmy 36:96847d42f010 815 any(attr.startswith('target.extra_labels') for attr
theotherjimmy 43:2a7da56ebd24 816 in overrides.keys())):
The Other Jimmy 36:96847d42f010 817 raise ConfigException(
The Other Jimmy 36:96847d42f010 818 "Target override 'target.extra_labels' in " +
The Other Jimmy 36:96847d42f010 819 ConfigParameter.get_display_name(unit_name, unit_kind,
The Other Jimmy 36:96847d42f010 820 label) +
The Other Jimmy 36:96847d42f010 821 " is only allowed at the application level")
The Other Jimmy 36:96847d42f010 822
The Other Jimmy 36:96847d42f010 823 # Parse out cumulative overrides
theotherjimmy 43:2a7da56ebd24 824 for attr, cumulatives in self.cumulative_overrides.items():
The Other Jimmy 36:96847d42f010 825 if 'target.'+attr in overrides:
The Other Jimmy 36:96847d42f010 826 key = 'target.' + attr
The Other Jimmy 36:96847d42f010 827 if not isinstance(overrides[key], list):
The Other Jimmy 36:96847d42f010 828 raise ConfigException(
The Other Jimmy 36:96847d42f010 829 "The value of %s.%s is not of type %s" %
The Other Jimmy 36:96847d42f010 830 (unit_name, "target_overrides." + key,
The Other Jimmy 36:96847d42f010 831 "list"))
The Other Jimmy 36:96847d42f010 832 cumulatives.strict_cumulative_overrides(overrides[key])
The Other Jimmy 36:96847d42f010 833 del overrides[key]
The Other Jimmy 36:96847d42f010 834
The Other Jimmy 36:96847d42f010 835 if 'target.'+attr+'_add' in overrides:
The Other Jimmy 36:96847d42f010 836 key = 'target.' + attr + "_add"
The Other Jimmy 36:96847d42f010 837 if not isinstance(overrides[key], list):
The Other Jimmy 36:96847d42f010 838 raise ConfigException(
The Other Jimmy 36:96847d42f010 839 "The value of %s.%s is not of type %s" %
The Other Jimmy 36:96847d42f010 840 (unit_name, "target_overrides." + key,
The Other Jimmy 36:96847d42f010 841 "list"))
The Other Jimmy 36:96847d42f010 842 cumulatives.add_cumulative_overrides(overrides[key])
The Other Jimmy 36:96847d42f010 843 del overrides[key]
The Other Jimmy 36:96847d42f010 844
The Other Jimmy 36:96847d42f010 845 if 'target.'+attr+'_remove' in overrides:
The Other Jimmy 36:96847d42f010 846 key = 'target.' + attr + "_remove"
The Other Jimmy 36:96847d42f010 847 if not isinstance(overrides[key], list):
The Other Jimmy 36:96847d42f010 848 raise ConfigException(
The Other Jimmy 36:96847d42f010 849 "The value of %s.%s is not of type %s" %
The Other Jimmy 36:96847d42f010 850 (unit_name, "target_overrides." + key,
The Other Jimmy 36:96847d42f010 851 "list"))
The Other Jimmy 36:96847d42f010 852 cumulatives.remove_cumulative_overrides(overrides[key])
The Other Jimmy 36:96847d42f010 853 del overrides[key]
The Other Jimmy 36:96847d42f010 854
The Other Jimmy 36:96847d42f010 855 # Consider the others as overrides
The Other Jimmy 36:96847d42f010 856 for name, val in overrides.items():
theotherjimmy 43:2a7da56ebd24 857 if (name in PATH_OVERRIDES and "__config_path" in data):
theotherjimmy 43:2a7da56ebd24 858 val = os.path.join(
theotherjimmy 43:2a7da56ebd24 859 os.path.dirname(data["__config_path"]), val)
theotherjimmy 43:2a7da56ebd24 860
The Other Jimmy 36:96847d42f010 861 # Get the full name of the parameter
The Other Jimmy 36:96847d42f010 862 full_name = ConfigParameter.get_full_name(name, unit_name,
The Other Jimmy 36:96847d42f010 863 unit_kind, label)
The Other Jimmy 36:96847d42f010 864 if full_name in params:
The Other Jimmy 36:96847d42f010 865 params[full_name].set_value(val, unit_name, unit_kind,
The Other Jimmy 36:96847d42f010 866 label)
The Other Jimmy 36:96847d42f010 867 elif (name.startswith("target.") and
theotherjimmy 43:2a7da56ebd24 868 (unit_kind is "application" or
theotherjimmy 43:2a7da56ebd24 869 name in BOOTLOADER_OVERRIDES)):
The Other Jimmy 36:96847d42f010 870 _, attribute = name.split(".")
The Other Jimmy 36:96847d42f010 871 setattr(self.target, attribute, val)
theotherjimmy 43:2a7da56ebd24 872 continue
The Other Jimmy 36:96847d42f010 873 else:
The Other Jimmy 36:96847d42f010 874 self.config_errors.append(
theotherjimmy 43:2a7da56ebd24 875 UndefinedParameter(
theotherjimmy 43:2a7da56ebd24 876 full_name, unit_name, unit_kind, label))
The Other Jimmy 36:96847d42f010 877
theotherjimmy 43:2a7da56ebd24 878 for cumulatives in self.cumulative_overrides.values():
The Other Jimmy 36:96847d42f010 879 cumulatives.update_target(self.target)
The Other Jimmy 36:96847d42f010 880
The Other Jimmy 36:96847d42f010 881 return params
The Other Jimmy 36:96847d42f010 882
The Other Jimmy 36:96847d42f010 883 def get_target_config_data(self):
The Other Jimmy 36:96847d42f010 884 """Read and interpret configuration data defined by targets.
The Other Jimmy 36:96847d42f010 885
The Other Jimmy 36:96847d42f010 886 We consider the resolution order for our target and sort it by level
The Other Jimmy 36:96847d42f010 887 reversed, so that we first look at the top level target (the parent),
The Other Jimmy 36:96847d42f010 888 then its direct children, then the children of those children and so on,
The Other Jimmy 36:96847d42f010 889 until we reach self.target
The Other Jimmy 36:96847d42f010 890 TODO: this might not work so well in some multiple inheritance scenarios
The Other Jimmy 36:96847d42f010 891 At each step, look at two keys of the target data:
The Other Jimmy 36:96847d42f010 892 - config_parameters: used to define new configuration parameters
The Other Jimmy 36:96847d42f010 893 - config_overrides: used to override already defined configuration
The Other Jimmy 36:96847d42f010 894 parameters
The Other Jimmy 36:96847d42f010 895
The Other Jimmy 36:96847d42f010 896 Arguments: None
The Other Jimmy 36:96847d42f010 897 """
The Other Jimmy 36:96847d42f010 898 params, json_data = {}, self.target.json_data
The Other Jimmy 36:96847d42f010 899 resolution_order = [e[0] for e
The Other Jimmy 36:96847d42f010 900 in sorted(
The Other Jimmy 36:96847d42f010 901 self.target.resolution_order,
The Other Jimmy 36:96847d42f010 902 key=lambda e: e[1], reverse=True)]
The Other Jimmy 36:96847d42f010 903 for tname in resolution_order:
The Other Jimmy 36:96847d42f010 904 # Read the target data directly from its description
The Other Jimmy 36:96847d42f010 905 target_data = json_data[tname]
The Other Jimmy 36:96847d42f010 906 # Process definitions first
The Other Jimmy 36:96847d42f010 907 _process_config_parameters(target_data.get("config", {}), params,
The Other Jimmy 36:96847d42f010 908 tname, "target")
The Other Jimmy 36:96847d42f010 909 # Then process overrides
The Other Jimmy 36:96847d42f010 910 for name, val in target_data.get("overrides", {}).items():
The Other Jimmy 36:96847d42f010 911 full_name = ConfigParameter.get_full_name(name, tname, "target")
The Other Jimmy 36:96847d42f010 912 # If the parameter name is not defined or if there isn't a path
The Other Jimmy 36:96847d42f010 913 # from this target to the target where the parameter was defined
The Other Jimmy 36:96847d42f010 914 # in the target inheritance tree, raise an error We need to use
The Other Jimmy 36:96847d42f010 915 # 'defined_by[7:]' to remove the "target:" prefix from
The Other Jimmy 36:96847d42f010 916 # defined_by
The Other Jimmy 36:96847d42f010 917 rel_names = [tgt for tgt, _ in
The Other Jimmy 36:96847d42f010 918 get_resolution_order(self.target.json_data, tname,
The Other Jimmy 36:96847d42f010 919 [])]
theotherjimmy 43:2a7da56ebd24 920 if full_name in BOOTLOADER_OVERRIDES:
The Other Jimmy 36:96847d42f010 921 continue
The Other Jimmy 36:96847d42f010 922 if (full_name not in params) or \
The Other Jimmy 36:96847d42f010 923 (params[full_name].defined_by[7:] not in rel_names):
theotherjimmy 43:2a7da56ebd24 924 raise UndefinedParameter(name, tname, "target", "")
The Other Jimmy 36:96847d42f010 925 # Otherwise update the value of the parameter
The Other Jimmy 36:96847d42f010 926 params[full_name].set_value(val, tname, "target")
The Other Jimmy 36:96847d42f010 927 return params
The Other Jimmy 36:96847d42f010 928
theotherjimmy 43:2a7da56ebd24 929 def get_lib_config_data(self, target_data):
The Other Jimmy 36:96847d42f010 930 """ Read and interpret configuration data defined by libraries. It is
The Other Jimmy 36:96847d42f010 931 assumed that "add_config_files" above was already called and the library
The Other Jimmy 36:96847d42f010 932 configuration data exists in self.lib_config_data
The Other Jimmy 36:96847d42f010 933
The Other Jimmy 36:96847d42f010 934 Arguments: None
The Other Jimmy 36:96847d42f010 935 """
theotherjimmy 43:2a7da56ebd24 936 macros = {}
The Other Jimmy 36:96847d42f010 937 for lib_name, lib_data in self.lib_config_data.items():
theotherjimmy 43:2a7da56ebd24 938 self._process_config_and_overrides(
theotherjimmy 43:2a7da56ebd24 939 lib_data, target_data, lib_name, "library")
The Other Jimmy 36:96847d42f010 940 _process_macros(lib_data.get("macros", []), macros, lib_name,
The Other Jimmy 36:96847d42f010 941 "library")
theotherjimmy 43:2a7da56ebd24 942 return target_data, macros
The Other Jimmy 36:96847d42f010 943
The Other Jimmy 36:96847d42f010 944 def get_app_config_data(self, params, macros):
The Other Jimmy 36:96847d42f010 945 """ Read and interpret the configuration data defined by the target. The
The Other Jimmy 36:96847d42f010 946 target can override any configuration parameter, as well as define its
The Other Jimmy 36:96847d42f010 947 own configuration data.
The Other Jimmy 36:96847d42f010 948
The Other Jimmy 36:96847d42f010 949 Positional arguments.
The Other Jimmy 36:96847d42f010 950 params - the dictionary with configuration parameters found so far (in
The Other Jimmy 36:96847d42f010 951 the target and in libraries)
The Other Jimmy 36:96847d42f010 952 macros - the list of macros defined in the configuration
The Other Jimmy 36:96847d42f010 953 """
The Other Jimmy 36:96847d42f010 954 app_cfg = self.app_config_data
The Other Jimmy 36:96847d42f010 955 # The application can have a "config_parameters" and a
The Other Jimmy 36:96847d42f010 956 # "target_config_overrides" section just like a library
The Other Jimmy 36:96847d42f010 957 self._process_config_and_overrides(app_cfg, params, "app",
The Other Jimmy 36:96847d42f010 958 "application")
The Other Jimmy 36:96847d42f010 959 # The application can also defined macros
The Other Jimmy 36:96847d42f010 960 _process_macros(app_cfg.get("macros", []), macros, "app",
The Other Jimmy 36:96847d42f010 961 "application")
The Other Jimmy 36:96847d42f010 962
The Other Jimmy 36:96847d42f010 963 def get_config_data(self):
The Other Jimmy 36:96847d42f010 964 """ Return the configuration data in two parts: (params, macros)
The Other Jimmy 36:96847d42f010 965 params - a dictionary with mapping a name to a ConfigParam
The Other Jimmy 36:96847d42f010 966 macros - the list of macros defined with "macros" in libraries and in
The Other Jimmy 36:96847d42f010 967 the application (as ConfigMacro instances)
The Other Jimmy 36:96847d42f010 968
The Other Jimmy 36:96847d42f010 969 Arguments: None
The Other Jimmy 36:96847d42f010 970 """
The Other Jimmy 36:96847d42f010 971 all_params = self.get_target_config_data()
theotherjimmy 43:2a7da56ebd24 972 lib_params, macros = self.get_lib_config_data(all_params)
theotherjimmy 43:2a7da56ebd24 973 self.get_app_config_data(lib_params, macros)
theotherjimmy 43:2a7da56ebd24 974 return lib_params, macros
The Other Jimmy 36:96847d42f010 975
The Other Jimmy 36:96847d42f010 976 @staticmethod
The Other Jimmy 36:96847d42f010 977 def _check_required_parameters(params):
The Other Jimmy 36:96847d42f010 978 """Check that there are no required parameters without a value
The Other Jimmy 36:96847d42f010 979
The Other Jimmy 36:96847d42f010 980 Positional arguments:
The Other Jimmy 36:96847d42f010 981 params - the list of parameters to check
The Other Jimmy 36:96847d42f010 982
The Other Jimmy 36:96847d42f010 983 NOTE: This function does not return. Instead, it throws a
The Other Jimmy 36:96847d42f010 984 ConfigException when any of the required parameters are missing values
The Other Jimmy 36:96847d42f010 985 """
The Other Jimmy 36:96847d42f010 986 for param in params.values():
The Other Jimmy 36:96847d42f010 987 if param.required and (param.value is None):
The Other Jimmy 36:96847d42f010 988 raise ConfigException("Required parameter '" + param.name +
The Other Jimmy 36:96847d42f010 989 "' defined by '" + param.defined_by +
The Other Jimmy 36:96847d42f010 990 "' doesn't have a value")
The Other Jimmy 36:96847d42f010 991
The Other Jimmy 36:96847d42f010 992 @staticmethod
The Other Jimmy 36:96847d42f010 993 def parameters_to_macros(params):
The Other Jimmy 36:96847d42f010 994 """ Encode the configuration parameters as C macro definitions.
The Other Jimmy 36:96847d42f010 995
The Other Jimmy 36:96847d42f010 996 Positional arguments:
The Other Jimmy 36:96847d42f010 997 params - a dictionary mapping a name to a ConfigParameter
The Other Jimmy 36:96847d42f010 998
The Other Jimmy 36:96847d42f010 999 Return: a list of strings that encode the configuration parameters as
The Other Jimmy 36:96847d42f010 1000 C pre-processor macros
The Other Jimmy 36:96847d42f010 1001 """
The Other Jimmy 36:96847d42f010 1002 return ['%s=%s' % (m.macro_name, m.value) for m in params.values()
The Other Jimmy 36:96847d42f010 1003 if m.value is not None]
The Other Jimmy 36:96847d42f010 1004
The Other Jimmy 36:96847d42f010 1005 @staticmethod
The Other Jimmy 36:96847d42f010 1006 def config_macros_to_macros(macros):
The Other Jimmy 36:96847d42f010 1007 """ Return the macro definitions generated for a dictionary of
The Other Jimmy 36:96847d42f010 1008 ConfigMacros (as returned by get_config_data).
The Other Jimmy 36:96847d42f010 1009
The Other Jimmy 36:96847d42f010 1010 Positional arguments:
The Other Jimmy 36:96847d42f010 1011 params - a dictionary mapping a name to a ConfigMacro instance
The Other Jimmy 36:96847d42f010 1012
The Other Jimmy 36:96847d42f010 1013 Return: a list of strings that are the C pre-processor macros
The Other Jimmy 36:96847d42f010 1014 """
The Other Jimmy 36:96847d42f010 1015 return [m.name for m in macros.values()]
The Other Jimmy 36:96847d42f010 1016
The Other Jimmy 36:96847d42f010 1017 @staticmethod
The Other Jimmy 36:96847d42f010 1018 def config_to_macros(config):
The Other Jimmy 36:96847d42f010 1019 """Convert the configuration data to a list of C macros
The Other Jimmy 36:96847d42f010 1020
The Other Jimmy 36:96847d42f010 1021 Positional arguments:
The Other Jimmy 36:96847d42f010 1022 config - configuration data as (ConfigParam instances, ConfigMacro
The Other Jimmy 36:96847d42f010 1023 instances) tuple (as returned by get_config_data())
The Other Jimmy 36:96847d42f010 1024 """
The Other Jimmy 36:96847d42f010 1025 params, macros = config[0], config[1]
The Other Jimmy 36:96847d42f010 1026 Config._check_required_parameters(params)
The Other Jimmy 36:96847d42f010 1027 return Config.config_macros_to_macros(macros) + \
The Other Jimmy 36:96847d42f010 1028 Config.parameters_to_macros(params)
The Other Jimmy 36:96847d42f010 1029
The Other Jimmy 36:96847d42f010 1030 def get_config_data_macros(self):
The Other Jimmy 36:96847d42f010 1031 """ Convert a Config object to a list of C macros
The Other Jimmy 36:96847d42f010 1032
The Other Jimmy 36:96847d42f010 1033 Arguments: None
The Other Jimmy 36:96847d42f010 1034 """
The Other Jimmy 36:96847d42f010 1035 return self.config_to_macros(self.get_config_data())
The Other Jimmy 36:96847d42f010 1036
The Other Jimmy 36:96847d42f010 1037 def get_features(self):
The Other Jimmy 36:96847d42f010 1038 """ Extract any features from the configuration data
The Other Jimmy 36:96847d42f010 1039
The Other Jimmy 36:96847d42f010 1040 Arguments: None
The Other Jimmy 36:96847d42f010 1041 """
The Other Jimmy 36:96847d42f010 1042 params, _ = self.get_config_data()
The Other Jimmy 36:96847d42f010 1043 self._check_required_parameters(params)
The Other Jimmy 36:96847d42f010 1044 self.cumulative_overrides['features']\
The Other Jimmy 36:96847d42f010 1045 .update_target(self.target)
The Other Jimmy 36:96847d42f010 1046
The Other Jimmy 36:96847d42f010 1047 return self.target.features
The Other Jimmy 36:96847d42f010 1048
The Other Jimmy 36:96847d42f010 1049 def validate_config(self):
The Other Jimmy 36:96847d42f010 1050 """ Validate configuration settings. This either returns True or
The Other Jimmy 36:96847d42f010 1051 raises an exception
The Other Jimmy 36:96847d42f010 1052
The Other Jimmy 36:96847d42f010 1053 Arguments: None
The Other Jimmy 36:96847d42f010 1054 """
theotherjimmy 43:2a7da56ebd24 1055 params, _ = self.get_config_data()
theotherjimmy 43:2a7da56ebd24 1056 for error in self.config_errors:
theotherjimmy 43:2a7da56ebd24 1057 if (isinstance(error, UndefinedParameter) and
theotherjimmy 43:2a7da56ebd24 1058 error.param in params):
theotherjimmy 43:2a7da56ebd24 1059 continue
theotherjimmy 43:2a7da56ebd24 1060 else:
theotherjimmy 43:2a7da56ebd24 1061 raise error
The Other Jimmy 36:96847d42f010 1062 return True
The Other Jimmy 36:96847d42f010 1063
The Other Jimmy 36:96847d42f010 1064
The Other Jimmy 36:96847d42f010 1065 @property
The Other Jimmy 36:96847d42f010 1066 def name(self):
The Other Jimmy 36:96847d42f010 1067 if "artifact_name" in self.app_config_data:
The Other Jimmy 36:96847d42f010 1068 return self.app_config_data["artifact_name"]
The Other Jimmy 36:96847d42f010 1069 else:
The Other Jimmy 36:96847d42f010 1070 return None
The Other Jimmy 36:96847d42f010 1071
The Other Jimmy 36:96847d42f010 1072 def load_resources(self, resources):
The Other Jimmy 36:96847d42f010 1073 """ Load configuration data from a Resources instance and expand it
The Other Jimmy 36:96847d42f010 1074 based on defined features.
The Other Jimmy 36:96847d42f010 1075
The Other Jimmy 36:96847d42f010 1076 Positional arguments:
The Other Jimmy 36:96847d42f010 1077 resources - the resources object to load from and expand
The Other Jimmy 36:96847d42f010 1078 """
The Other Jimmy 36:96847d42f010 1079 # Update configuration files until added features creates no changes
The Other Jimmy 36:96847d42f010 1080 prev_features = set()
The Other Jimmy 36:96847d42f010 1081 while True:
The Other Jimmy 36:96847d42f010 1082 # Add/update the configuration with any .json files found while
The Other Jimmy 36:96847d42f010 1083 # scanning
theotherjimmy 43:2a7da56ebd24 1084 self.add_config_files(
theotherjimmy 43:2a7da56ebd24 1085 f.path for f in resources.get_file_refs(FileType.JSON)
theotherjimmy 43:2a7da56ebd24 1086 )
The Other Jimmy 36:96847d42f010 1087
The Other Jimmy 36:96847d42f010 1088 # Add features while we find new ones
The Other Jimmy 36:96847d42f010 1089 features = set(self.get_features())
The Other Jimmy 36:96847d42f010 1090 if features == prev_features:
The Other Jimmy 36:96847d42f010 1091 break
The Other Jimmy 36:96847d42f010 1092
theotherjimmy 43:2a7da56ebd24 1093 resources.add_features(features)
The Other Jimmy 36:96847d42f010 1094
The Other Jimmy 36:96847d42f010 1095 prev_features = features
The Other Jimmy 36:96847d42f010 1096 self.validate_config()
The Other Jimmy 36:96847d42f010 1097
theotherjimmy 43:2a7da56ebd24 1098 if (hasattr(self.target, "release_versions") and
theotherjimmy 43:2a7da56ebd24 1099 "5" not in self.target.release_versions and
theotherjimmy 43:2a7da56ebd24 1100 "rtos" in self.lib_config_data):
theotherjimmy 43:2a7da56ebd24 1101 raise NotSupportedException("Target does not support mbed OS 5")
The Other Jimmy 36:96847d42f010 1102
The Other Jimmy 36:96847d42f010 1103 @staticmethod
The Other Jimmy 36:96847d42f010 1104 def config_to_header(config, fname=None):
The Other Jimmy 36:96847d42f010 1105 """ Convert the configuration data to the content of a C header file,
The Other Jimmy 36:96847d42f010 1106 meant to be included to a C/C++ file. The content is returned as a
The Other Jimmy 36:96847d42f010 1107 string.
The Other Jimmy 36:96847d42f010 1108
The Other Jimmy 36:96847d42f010 1109 Positional arguments:
The Other Jimmy 36:96847d42f010 1110 config - configuration data as (ConfigParam instances, ConfigMacro
The Other Jimmy 36:96847d42f010 1111 instances) tuple (as returned by get_config_data())
The Other Jimmy 36:96847d42f010 1112
The Other Jimmy 36:96847d42f010 1113 Keyword arguments:
The Other Jimmy 36:96847d42f010 1114 fname - also write the content is to the file called "fname".
The Other Jimmy 36:96847d42f010 1115 WARNING: if 'fname' names an existing file, it will be
The Other Jimmy 36:96847d42f010 1116 overwritten!
The Other Jimmy 36:96847d42f010 1117 """
The Other Jimmy 36:96847d42f010 1118 params, macros = config[0] or {}, config[1] or {}
The Other Jimmy 36:96847d42f010 1119 Config._check_required_parameters(params)
The Other Jimmy 36:96847d42f010 1120 params_with_values = [p for p in params.values() if p.value is not None]
The Other Jimmy 36:96847d42f010 1121 ctx = {
theotherjimmy 43:2a7da56ebd24 1122 "cfg_params": sorted([
theotherjimmy 43:2a7da56ebd24 1123 (p.macro_name, str(p.value), p.set_by)
theotherjimmy 43:2a7da56ebd24 1124 for p in params_with_values
theotherjimmy 43:2a7da56ebd24 1125 ]),
theotherjimmy 43:2a7da56ebd24 1126 "macros": sorted([
theotherjimmy 43:2a7da56ebd24 1127 (m.macro_name, str(m.macro_value or ""), m.defined_by)
theotherjimmy 43:2a7da56ebd24 1128 for m in macros.values()
theotherjimmy 43:2a7da56ebd24 1129 ]),
The Other Jimmy 36:96847d42f010 1130 "name_len": max([len(m.macro_name) for m in macros.values()] +
The Other Jimmy 36:96847d42f010 1131 [len(m.macro_name) for m in params_with_values]
The Other Jimmy 36:96847d42f010 1132 + [0]),
The Other Jimmy 36:96847d42f010 1133 "val_len" : max([len(str(m.value)) for m in params_with_values] +
The Other Jimmy 36:96847d42f010 1134 [len(m.macro_value or "") for m in macros.values()]
The Other Jimmy 36:96847d42f010 1135 + [0]),
The Other Jimmy 36:96847d42f010 1136 }
The Other Jimmy 36:96847d42f010 1137 jinja_loader = FileSystemLoader(dirname(abspath(__file__)))
The Other Jimmy 36:96847d42f010 1138 jinja_environment = Environment(loader=jinja_loader,
The Other Jimmy 36:96847d42f010 1139 undefined=StrictUndefined)
The Other Jimmy 36:96847d42f010 1140 header_data = jinja_environment.get_template("header.tmpl").render(ctx)
The Other Jimmy 36:96847d42f010 1141 # If fname is given, write "header_data" to it
The Other Jimmy 36:96847d42f010 1142 if fname:
The Other Jimmy 36:96847d42f010 1143 with open(fname, "w+") as file_desc:
The Other Jimmy 36:96847d42f010 1144 file_desc.write(header_data)
The Other Jimmy 36:96847d42f010 1145 return header_data
The Other Jimmy 36:96847d42f010 1146
The Other Jimmy 36:96847d42f010 1147 def get_config_data_header(self, fname=None):
The Other Jimmy 36:96847d42f010 1148 """ Convert a Config instance to the content of a C header file, meant
The Other Jimmy 36:96847d42f010 1149 to be included to a C/C++ file. The content is returned as a string.
The Other Jimmy 36:96847d42f010 1150
The Other Jimmy 36:96847d42f010 1151 Keyword arguments:
The Other Jimmy 36:96847d42f010 1152 fname - also write the content to the file called "fname".
The Other Jimmy 36:96847d42f010 1153 WARNING: if 'fname' names an existing file, it will be
The Other Jimmy 36:96847d42f010 1154 overwritten!
The Other Jimmy 36:96847d42f010 1155 """
The Other Jimmy 36:96847d42f010 1156 return self.config_to_header(self.get_config_data(), fname)