mbed-os for GR-LYCHEE

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Committer:
dkato
Date:
Fri Feb 02 05:42:23 2018 +0000
Revision:
0:f782d9c66c49
mbed-os for GR-LYCHEE

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dkato 0:f782d9c66c49 1 """
dkato 0:f782d9c66c49 2 mbed SDK
dkato 0:f782d9c66c49 3 Copyright (c) 2016 ARM Limited
dkato 0:f782d9c66c49 4
dkato 0:f782d9c66c49 5 Licensed under the Apache License, Version 2.0 (the "License");
dkato 0:f782d9c66c49 6 you may not use this file except in compliance with the License.
dkato 0:f782d9c66c49 7 You may obtain a copy of the License at
dkato 0:f782d9c66c49 8
dkato 0:f782d9c66c49 9 http://www.apache.org/licenses/LICENSE-2.0
dkato 0:f782d9c66c49 10
dkato 0:f782d9c66c49 11 Unless required by applicable law or agreed to in writing, software
dkato 0:f782d9c66c49 12 distributed under the License is distributed on an "AS IS" BASIS,
dkato 0:f782d9c66c49 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dkato 0:f782d9c66c49 14 See the License for the specific language governing permissions and
dkato 0:f782d9c66c49 15 limitations under the License.
dkato 0:f782d9c66c49 16 """
dkato 0:f782d9c66c49 17
dkato 0:f782d9c66c49 18 from copy import deepcopy
dkato 0:f782d9c66c49 19 import os
dkato 0:f782d9c66c49 20 import sys
dkato 0:f782d9c66c49 21 from collections import namedtuple
dkato 0:f782d9c66c49 22 from os.path import splitext
dkato 0:f782d9c66c49 23 from intelhex import IntelHex
dkato 0:f782d9c66c49 24 # Implementation of mbed configuration mechanism
dkato 0:f782d9c66c49 25 from tools.utils import json_file_to_dict, intelhex_offset
dkato 0:f782d9c66c49 26 from tools.arm_pack_manager import Cache
dkato 0:f782d9c66c49 27 from tools.targets import CUMULATIVE_ATTRIBUTES, TARGET_MAP, \
dkato 0:f782d9c66c49 28 generate_py_target, get_resolution_order
dkato 0:f782d9c66c49 29
dkato 0:f782d9c66c49 30 # Base class for all configuration exceptions
dkato 0:f782d9c66c49 31 class ConfigException(Exception):
dkato 0:f782d9c66c49 32 """Config system only exception. Makes it easier to distinguish config
dkato 0:f782d9c66c49 33 errors"""
dkato 0:f782d9c66c49 34 pass
dkato 0:f782d9c66c49 35
dkato 0:f782d9c66c49 36 class ConfigParameter(object):
dkato 0:f782d9c66c49 37 """This class keeps information about a single configuration parameter"""
dkato 0:f782d9c66c49 38
dkato 0:f782d9c66c49 39 def __init__(self, name, data, unit_name, unit_kind):
dkato 0:f782d9c66c49 40 """Construct a ConfigParameter
dkato 0:f782d9c66c49 41
dkato 0:f782d9c66c49 42 Positional arguments:
dkato 0:f782d9c66c49 43 name - the name of the configuration parameter
dkato 0:f782d9c66c49 44 data - the data associated with the configuration parameter
dkato 0:f782d9c66c49 45 unit_name - the unit (target/library/application) that defines this
dkato 0:f782d9c66c49 46 parameter
dkato 0:f782d9c66c49 47 unit_ kind - the kind of the unit ("target", "library" or "application")
dkato 0:f782d9c66c49 48 """
dkato 0:f782d9c66c49 49 self.name = self.get_full_name(name, unit_name, unit_kind,
dkato 0:f782d9c66c49 50 allow_prefix=False)
dkato 0:f782d9c66c49 51 self.defined_by = self.get_display_name(unit_name, unit_kind)
dkato 0:f782d9c66c49 52 self.set_value(data.get("value", None), unit_name, unit_kind)
dkato 0:f782d9c66c49 53 self.help_text = data.get("help", None)
dkato 0:f782d9c66c49 54 self.required = data.get("required", False)
dkato 0:f782d9c66c49 55 self.macro_name = data.get("macro_name", "MBED_CONF_%s" %
dkato 0:f782d9c66c49 56 self.sanitize(self.name.upper()))
dkato 0:f782d9c66c49 57 self.config_errors = []
dkato 0:f782d9c66c49 58
dkato 0:f782d9c66c49 59 @staticmethod
dkato 0:f782d9c66c49 60 def get_full_name(name, unit_name, unit_kind, label=None,
dkato 0:f782d9c66c49 61 allow_prefix=True):
dkato 0:f782d9c66c49 62 """Return the full (prefixed) name of a parameter. If the parameter
dkato 0:f782d9c66c49 63 already has a prefix, check if it is valid
dkato 0:f782d9c66c49 64
dkato 0:f782d9c66c49 65 Positional arguments:
dkato 0:f782d9c66c49 66 name - the simple (unqualified) name of the parameter
dkato 0:f782d9c66c49 67 unit_name - the unit (target/library/application) that defines this
dkato 0:f782d9c66c49 68 parameter
dkato 0:f782d9c66c49 69 unit_kind - the kind of the unit ("target", "library" or "application")
dkato 0:f782d9c66c49 70
dkato 0:f782d9c66c49 71 Keyword arguments:
dkato 0:f782d9c66c49 72 label - the name of the label in the 'target_config_overrides' section
dkato 0:f782d9c66c49 73 allow_prefix - True to allow the original name to have a prefix, False
dkato 0:f782d9c66c49 74 otherwise
dkato 0:f782d9c66c49 75 """
dkato 0:f782d9c66c49 76 if name.find('.') == -1: # the name is not prefixed
dkato 0:f782d9c66c49 77 if unit_kind == "target":
dkato 0:f782d9c66c49 78 prefix = "target."
dkato 0:f782d9c66c49 79 elif unit_kind == "application":
dkato 0:f782d9c66c49 80 prefix = "app."
dkato 0:f782d9c66c49 81 else:
dkato 0:f782d9c66c49 82 prefix = unit_name + '.'
dkato 0:f782d9c66c49 83 return prefix + name
dkato 0:f782d9c66c49 84 # The name has a prefix, so check if it is valid
dkato 0:f782d9c66c49 85 if not allow_prefix:
dkato 0:f782d9c66c49 86 raise ConfigException("Invalid parameter name '%s' in '%s'" %
dkato 0:f782d9c66c49 87 (name, ConfigParameter.get_display_name(
dkato 0:f782d9c66c49 88 unit_name, unit_kind, label)))
dkato 0:f782d9c66c49 89 temp = name.split(".")
dkato 0:f782d9c66c49 90 # Check if the parameter syntax is correct (must be
dkato 0:f782d9c66c49 91 # unit_name.parameter_name)
dkato 0:f782d9c66c49 92 if len(temp) != 2:
dkato 0:f782d9c66c49 93 raise ConfigException("Invalid parameter name '%s' in '%s'" %
dkato 0:f782d9c66c49 94 (name, ConfigParameter.get_display_name(
dkato 0:f782d9c66c49 95 unit_name, unit_kind, label)))
dkato 0:f782d9c66c49 96 prefix = temp[0]
dkato 0:f782d9c66c49 97 # Check if the given parameter prefix matches the expected prefix
dkato 0:f782d9c66c49 98 if (unit_kind == "library" and prefix != unit_name) or \
dkato 0:f782d9c66c49 99 (unit_kind == "target" and prefix != "target"):
dkato 0:f782d9c66c49 100 raise ConfigException(
dkato 0:f782d9c66c49 101 "Invalid prefix '%s' for parameter name '%s' in '%s'" %
dkato 0:f782d9c66c49 102 (prefix, name, ConfigParameter.get_display_name(
dkato 0:f782d9c66c49 103 unit_name, unit_kind, label)))
dkato 0:f782d9c66c49 104 return name
dkato 0:f782d9c66c49 105
dkato 0:f782d9c66c49 106 @staticmethod
dkato 0:f782d9c66c49 107 def get_display_name(unit_name, unit_kind, label=None):
dkato 0:f782d9c66c49 108 """Return the name displayed for a unit when interrogating the origin
dkato 0:f782d9c66c49 109 and the last set place of a parameter
dkato 0:f782d9c66c49 110
dkato 0:f782d9c66c49 111 Positional arguments:
dkato 0:f782d9c66c49 112 unit_name - the unit (target/library/application) that defines this
dkato 0:f782d9c66c49 113 parameter
dkato 0:f782d9c66c49 114 unit_kind - the kind of the unit ("target", "library" or "application")
dkato 0:f782d9c66c49 115
dkato 0:f782d9c66c49 116 Keyword arguments:
dkato 0:f782d9c66c49 117 label - the name of the label in the 'target_config_overrides' section
dkato 0:f782d9c66c49 118 """
dkato 0:f782d9c66c49 119 if unit_kind == "target":
dkato 0:f782d9c66c49 120 return "target:" + unit_name
dkato 0:f782d9c66c49 121 elif unit_kind == "application":
dkato 0:f782d9c66c49 122 return "application%s" % ("[%s]" % label if label else "")
dkato 0:f782d9c66c49 123 else: # library
dkato 0:f782d9c66c49 124 return "library:%s%s" % (unit_name, "[%s]" % label if label else "")
dkato 0:f782d9c66c49 125
dkato 0:f782d9c66c49 126 @staticmethod
dkato 0:f782d9c66c49 127 def sanitize(name):
dkato 0:f782d9c66c49 128 """ "Sanitize" a name so that it is a valid C macro name. Currently it
dkato 0:f782d9c66c49 129 simply replaces '.' and '-' with '_'.
dkato 0:f782d9c66c49 130
dkato 0:f782d9c66c49 131 Positional arguments:
dkato 0:f782d9c66c49 132 name - the name to make into a valid C macro
dkato 0:f782d9c66c49 133 """
dkato 0:f782d9c66c49 134 return name.replace('.', '_').replace('-', '_')
dkato 0:f782d9c66c49 135
dkato 0:f782d9c66c49 136 def set_value(self, value, unit_name, unit_kind, label=None):
dkato 0:f782d9c66c49 137 """ Sets a value for this parameter, remember the place where it was
dkato 0:f782d9c66c49 138 set. If the value is a Boolean, it is converted to 1 (for True) or
dkato 0:f782d9c66c49 139 to 0 (for False).
dkato 0:f782d9c66c49 140
dkato 0:f782d9c66c49 141 Positional arguments:
dkato 0:f782d9c66c49 142 value - the value of the parameter
dkato 0:f782d9c66c49 143 unit_name - the unit (target/library/application) that defines this
dkato 0:f782d9c66c49 144 parameter
dkato 0:f782d9c66c49 145 unit_kind - the kind of the unit ("target", "library" or "application")
dkato 0:f782d9c66c49 146
dkato 0:f782d9c66c49 147 Keyword arguments:
dkato 0:f782d9c66c49 148 label - the name of the label in the 'target_config_overrides' section
dkato 0:f782d9c66c49 149 (optional)
dkato 0:f782d9c66c49 150 """
dkato 0:f782d9c66c49 151 self.value = int(value) if isinstance(value, bool) else value
dkato 0:f782d9c66c49 152 self.set_by = self.get_display_name(unit_name, unit_kind, label)
dkato 0:f782d9c66c49 153
dkato 0:f782d9c66c49 154 def __str__(self):
dkato 0:f782d9c66c49 155 """Return the string representation of this configuration parameter
dkato 0:f782d9c66c49 156
dkato 0:f782d9c66c49 157 Arguments: None
dkato 0:f782d9c66c49 158 """
dkato 0:f782d9c66c49 159 if self.value is not None:
dkato 0:f782d9c66c49 160 return '%s = %s (macro name: "%s")' % \
dkato 0:f782d9c66c49 161 (self.name, self.value, self.macro_name)
dkato 0:f782d9c66c49 162 else:
dkato 0:f782d9c66c49 163 return '%s has no value' % self.name
dkato 0:f782d9c66c49 164
dkato 0:f782d9c66c49 165 def get_verbose_description(self):
dkato 0:f782d9c66c49 166 """Return a verbose description of this configuration parameter as a
dkato 0:f782d9c66c49 167 string
dkato 0:f782d9c66c49 168
dkato 0:f782d9c66c49 169 Arguments: None
dkato 0:f782d9c66c49 170 """
dkato 0:f782d9c66c49 171 desc = "Name: %s%s\n" % \
dkato 0:f782d9c66c49 172 (self.name, " (required parameter)" if self.required else "")
dkato 0:f782d9c66c49 173 if self.help_text:
dkato 0:f782d9c66c49 174 desc += " Description: %s\n" % self.help_text
dkato 0:f782d9c66c49 175 desc += " Defined by: %s\n" % self.defined_by
dkato 0:f782d9c66c49 176 if not self.value:
dkato 0:f782d9c66c49 177 return desc + " No value set"
dkato 0:f782d9c66c49 178 desc += " Macro name: %s\n" % self.macro_name
dkato 0:f782d9c66c49 179 desc += " Value: %s (set by %s)" % (self.value, self.set_by)
dkato 0:f782d9c66c49 180 return desc
dkato 0:f782d9c66c49 181
dkato 0:f782d9c66c49 182 class ConfigMacro(object):
dkato 0:f782d9c66c49 183 """ A representation of a configuration macro. It handles both macros
dkato 0:f782d9c66c49 184 without a value (MACRO) and with a value (MACRO=VALUE)
dkato 0:f782d9c66c49 185 """
dkato 0:f782d9c66c49 186 def __init__(self, name, unit_name, unit_kind):
dkato 0:f782d9c66c49 187 """Construct a ConfigMacro object
dkato 0:f782d9c66c49 188
dkato 0:f782d9c66c49 189 Positional arguments:
dkato 0:f782d9c66c49 190 name - the macro's name
dkato 0:f782d9c66c49 191 unit_name - the location where the macro was defined
dkato 0:f782d9c66c49 192 unit_kind - the type of macro this is
dkato 0:f782d9c66c49 193 """
dkato 0:f782d9c66c49 194 self.name = name
dkato 0:f782d9c66c49 195 self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind)
dkato 0:f782d9c66c49 196 if name.find("=") != -1:
dkato 0:f782d9c66c49 197 tmp = name.split("=")
dkato 0:f782d9c66c49 198 if len(tmp) != 2:
dkato 0:f782d9c66c49 199 raise ValueError("Invalid macro definition '%s' in '%s'" %
dkato 0:f782d9c66c49 200 (name, self.defined_by))
dkato 0:f782d9c66c49 201 self.macro_name = tmp[0]
dkato 0:f782d9c66c49 202 self.macro_value = tmp[1]
dkato 0:f782d9c66c49 203 else:
dkato 0:f782d9c66c49 204 self.macro_name = name
dkato 0:f782d9c66c49 205 self.macro_value = None
dkato 0:f782d9c66c49 206
dkato 0:f782d9c66c49 207 class ConfigCumulativeOverride(object):
dkato 0:f782d9c66c49 208 """Representation of overrides for cumulative attributes"""
dkato 0:f782d9c66c49 209 def __init__(self, name, additions=None, removals=None, strict=False):
dkato 0:f782d9c66c49 210 """Construct a ConfigCumulativeOverride object
dkato 0:f782d9c66c49 211
dkato 0:f782d9c66c49 212 Positional arguments:
dkato 0:f782d9c66c49 213 name - the name of the config file this came from ?
dkato 0:f782d9c66c49 214
dkato 0:f782d9c66c49 215 Keyword arguments:
dkato 0:f782d9c66c49 216 additions - macros to add to the overrides
dkato 0:f782d9c66c49 217 removals - macros to remove from the overrides
dkato 0:f782d9c66c49 218 strict - Boolean indicating that attempting to remove from an override
dkato 0:f782d9c66c49 219 that does not exist should error
dkato 0:f782d9c66c49 220 """
dkato 0:f782d9c66c49 221 self.name = name
dkato 0:f782d9c66c49 222 if additions:
dkato 0:f782d9c66c49 223 self.additions = set(additions)
dkato 0:f782d9c66c49 224 else:
dkato 0:f782d9c66c49 225 self.additions = set()
dkato 0:f782d9c66c49 226 if removals:
dkato 0:f782d9c66c49 227 self.removals = set(removals)
dkato 0:f782d9c66c49 228 else:
dkato 0:f782d9c66c49 229 self.removals = set()
dkato 0:f782d9c66c49 230 self.strict = strict
dkato 0:f782d9c66c49 231
dkato 0:f782d9c66c49 232 def remove_cumulative_overrides(self, overrides):
dkato 0:f782d9c66c49 233 """Extend the list of override removals.
dkato 0:f782d9c66c49 234
dkato 0:f782d9c66c49 235 Positional arguments:
dkato 0:f782d9c66c49 236 overrides - a list of names that, when the override is evaluated, will
dkato 0:f782d9c66c49 237 be removed
dkato 0:f782d9c66c49 238 """
dkato 0:f782d9c66c49 239 for override in overrides:
dkato 0:f782d9c66c49 240 if override in self.additions:
dkato 0:f782d9c66c49 241 raise ConfigException(
dkato 0:f782d9c66c49 242 "Configuration conflict. The %s %s both added and removed."
dkato 0:f782d9c66c49 243 % (self.name[:-1], override))
dkato 0:f782d9c66c49 244
dkato 0:f782d9c66c49 245 self.removals |= set(overrides)
dkato 0:f782d9c66c49 246
dkato 0:f782d9c66c49 247 def add_cumulative_overrides(self, overrides):
dkato 0:f782d9c66c49 248 """Extend the list of override additions.
dkato 0:f782d9c66c49 249
dkato 0:f782d9c66c49 250 Positional arguments:
dkato 0:f782d9c66c49 251 overrides - a list of a names that, when the override is evaluated, will
dkato 0:f782d9c66c49 252 be added to the list
dkato 0:f782d9c66c49 253 """
dkato 0:f782d9c66c49 254 for override in overrides:
dkato 0:f782d9c66c49 255 if override in self.removals or \
dkato 0:f782d9c66c49 256 (self.strict and override not in self.additions):
dkato 0:f782d9c66c49 257 raise ConfigException(
dkato 0:f782d9c66c49 258 "Configuration conflict. The %s %s both added and removed."
dkato 0:f782d9c66c49 259 % (self.name[:-1], override))
dkato 0:f782d9c66c49 260
dkato 0:f782d9c66c49 261 self.additions |= set(overrides)
dkato 0:f782d9c66c49 262
dkato 0:f782d9c66c49 263 def strict_cumulative_overrides(self, overrides):
dkato 0:f782d9c66c49 264 """Remove all overrides that are not the specified ones
dkato 0:f782d9c66c49 265
dkato 0:f782d9c66c49 266 Positional arguments:
dkato 0:f782d9c66c49 267 overrides - a list of names that will replace the entire attribute when
dkato 0:f782d9c66c49 268 this override is evaluated.
dkato 0:f782d9c66c49 269 """
dkato 0:f782d9c66c49 270 self.remove_cumulative_overrides(self.additions - set(overrides))
dkato 0:f782d9c66c49 271 self.add_cumulative_overrides(overrides)
dkato 0:f782d9c66c49 272 self.strict = True
dkato 0:f782d9c66c49 273
dkato 0:f782d9c66c49 274 def update_target(self, target):
dkato 0:f782d9c66c49 275 """Update the attributes of a target based on this override"""
dkato 0:f782d9c66c49 276 setattr(target, self.name,
dkato 0:f782d9c66c49 277 list((set(getattr(target, self.name, []))
dkato 0:f782d9c66c49 278 | self.additions) - self.removals))
dkato 0:f782d9c66c49 279
dkato 0:f782d9c66c49 280
dkato 0:f782d9c66c49 281 def _process_config_parameters(data, params, unit_name, unit_kind):
dkato 0:f782d9c66c49 282 """Process a "config_parameters" section in either a target, a library,
dkato 0:f782d9c66c49 283 or the application.
dkato 0:f782d9c66c49 284
dkato 0:f782d9c66c49 285 Positional arguments:
dkato 0:f782d9c66c49 286 data - a dictionary with the configuration parameters
dkato 0:f782d9c66c49 287 params - storage for the discovered configuration parameters
dkato 0:f782d9c66c49 288 unit_name - the unit (target/library/application) that defines this
dkato 0:f782d9c66c49 289 parameter
dkato 0:f782d9c66c49 290 unit_kind - the kind of the unit ("target", "library" or "application")
dkato 0:f782d9c66c49 291 """
dkato 0:f782d9c66c49 292 for name, val in data.items():
dkato 0:f782d9c66c49 293 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
dkato 0:f782d9c66c49 294 # If the parameter was already defined, raise an error
dkato 0:f782d9c66c49 295 if full_name in params:
dkato 0:f782d9c66c49 296 raise ConfigException(
dkato 0:f782d9c66c49 297 "Parameter name '%s' defined in both '%s' and '%s'" %
dkato 0:f782d9c66c49 298 (name, ConfigParameter.get_display_name(unit_name, unit_kind),
dkato 0:f782d9c66c49 299 params[full_name].defined_by))
dkato 0:f782d9c66c49 300 # Otherwise add it to the list of known parameters
dkato 0:f782d9c66c49 301 # If "val" is not a dictionary, this is a shortcut definition,
dkato 0:f782d9c66c49 302 # otherwise it is a full definition
dkato 0:f782d9c66c49 303 params[full_name] = ConfigParameter(name, val if isinstance(val, dict)
dkato 0:f782d9c66c49 304 else {"value": val}, unit_name,
dkato 0:f782d9c66c49 305 unit_kind)
dkato 0:f782d9c66c49 306 return params
dkato 0:f782d9c66c49 307
dkato 0:f782d9c66c49 308
dkato 0:f782d9c66c49 309 def _process_macros(mlist, macros, unit_name, unit_kind):
dkato 0:f782d9c66c49 310 """Process a macro definition and check for incompatible duplicate
dkato 0:f782d9c66c49 311 definitions.
dkato 0:f782d9c66c49 312
dkato 0:f782d9c66c49 313 Positional arguments:
dkato 0:f782d9c66c49 314 mlist - list of macro names to process
dkato 0:f782d9c66c49 315 macros - dictionary with currently discovered macros
dkato 0:f782d9c66c49 316 unit_name - the unit (library/application) that defines this macro
dkato 0:f782d9c66c49 317 unit_kind - the kind of the unit ("library" or "application")
dkato 0:f782d9c66c49 318 """
dkato 0:f782d9c66c49 319 for mname in mlist:
dkato 0:f782d9c66c49 320 macro = ConfigMacro(mname, unit_name, unit_kind)
dkato 0:f782d9c66c49 321 if (macro.macro_name in macros) and \
dkato 0:f782d9c66c49 322 (macros[macro.macro_name].name != mname):
dkato 0:f782d9c66c49 323 # Found an incompatible definition of the macro in another module,
dkato 0:f782d9c66c49 324 # so raise an error
dkato 0:f782d9c66c49 325 full_unit_name = ConfigParameter.get_display_name(unit_name,
dkato 0:f782d9c66c49 326 unit_kind)
dkato 0:f782d9c66c49 327 raise ConfigException(
dkato 0:f782d9c66c49 328 ("Macro '%s' defined in both '%s' and '%s'"
dkato 0:f782d9c66c49 329 % (macro.macro_name, macros[macro.macro_name].defined_by,
dkato 0:f782d9c66c49 330 full_unit_name)) +
dkato 0:f782d9c66c49 331 " with incompatible values")
dkato 0:f782d9c66c49 332 macros[macro.macro_name] = macro
dkato 0:f782d9c66c49 333
dkato 0:f782d9c66c49 334
dkato 0:f782d9c66c49 335 Region = namedtuple("Region", "name start size active filename")
dkato 0:f782d9c66c49 336
dkato 0:f782d9c66c49 337 class Config(object):
dkato 0:f782d9c66c49 338 """'Config' implements the mbed configuration mechanism"""
dkato 0:f782d9c66c49 339
dkato 0:f782d9c66c49 340 # Libraries and applications have different names for their configuration
dkato 0:f782d9c66c49 341 # files
dkato 0:f782d9c66c49 342 __mbed_app_config_name = "mbed_app.json"
dkato 0:f782d9c66c49 343 __mbed_lib_config_name = "mbed_lib.json"
dkato 0:f782d9c66c49 344
dkato 0:f782d9c66c49 345 # Allowed keys in configuration dictionaries
dkato 0:f782d9c66c49 346 # (targets can have any kind of keys, so this validation is not applicable
dkato 0:f782d9c66c49 347 # to them)
dkato 0:f782d9c66c49 348 __allowed_keys = {
dkato 0:f782d9c66c49 349 "library": set(["name", "config", "target_overrides", "macros",
dkato 0:f782d9c66c49 350 "__config_path"]),
dkato 0:f782d9c66c49 351 "application": set(["config", "target_overrides",
dkato 0:f782d9c66c49 352 "macros", "__config_path"])
dkato 0:f782d9c66c49 353 }
dkato 0:f782d9c66c49 354
dkato 0:f782d9c66c49 355 __unused_overrides = set(["target.bootloader_img", "target.restrict_size"])
dkato 0:f782d9c66c49 356
dkato 0:f782d9c66c49 357 # Allowed features in configurations
dkato 0:f782d9c66c49 358 __allowed_features = [
dkato 0:f782d9c66c49 359 "UVISOR", "BLE", "CLIENT", "IPV4", "LWIP", "COMMON_PAL", "STORAGE", "NANOSTACK",
dkato 0:f782d9c66c49 360 # Nanostack configurations
dkato 0:f782d9c66c49 361 "LOWPAN_BORDER_ROUTER", "LOWPAN_HOST", "LOWPAN_ROUTER", "NANOSTACK_FULL", "THREAD_BORDER_ROUTER", "THREAD_END_DEVICE", "THREAD_ROUTER", "ETHERNET_HOST"
dkato 0:f782d9c66c49 362 ]
dkato 0:f782d9c66c49 363
dkato 0:f782d9c66c49 364 def __init__(self, tgt, top_level_dirs=None, app_config=None):
dkato 0:f782d9c66c49 365 """Construct a mbed configuration
dkato 0:f782d9c66c49 366
dkato 0:f782d9c66c49 367 Positional arguments:
dkato 0:f782d9c66c49 368 target - the name of the mbed target used for this configuration
dkato 0:f782d9c66c49 369 instance
dkato 0:f782d9c66c49 370
dkato 0:f782d9c66c49 371 Keyword argumets:
dkato 0:f782d9c66c49 372 top_level_dirs - a list of top level source directories (where
dkato 0:f782d9c66c49 373 mbed_app_config.json could be found)
dkato 0:f782d9c66c49 374 app_config - location of a chosen mbed_app.json file
dkato 0:f782d9c66c49 375
dkato 0:f782d9c66c49 376 NOTE: Construction of a Config object will look for the application
dkato 0:f782d9c66c49 377 configuration file in top_level_dirs. If found once, it'll parse it.
dkato 0:f782d9c66c49 378 top_level_dirs may be None (in this case, the constructor will not
dkato 0:f782d9c66c49 379 search for a configuration file).
dkato 0:f782d9c66c49 380 """
dkato 0:f782d9c66c49 381 app_config_location = app_config
dkato 0:f782d9c66c49 382 if app_config_location is None:
dkato 0:f782d9c66c49 383 for directory in top_level_dirs or []:
dkato 0:f782d9c66c49 384 full_path = os.path.join(directory, self.__mbed_app_config_name)
dkato 0:f782d9c66c49 385 if os.path.isfile(full_path):
dkato 0:f782d9c66c49 386 if app_config_location is not None:
dkato 0:f782d9c66c49 387 raise ConfigException("Duplicate '%s' file in '%s' and '%s'"
dkato 0:f782d9c66c49 388 % (self.__mbed_app_config_name,
dkato 0:f782d9c66c49 389 app_config_location, full_path))
dkato 0:f782d9c66c49 390 else:
dkato 0:f782d9c66c49 391 app_config_location = full_path
dkato 0:f782d9c66c49 392 try:
dkato 0:f782d9c66c49 393 self.app_config_data = json_file_to_dict(app_config_location) \
dkato 0:f782d9c66c49 394 if app_config_location else {}
dkato 0:f782d9c66c49 395 except ValueError as exc:
dkato 0:f782d9c66c49 396 sys.stderr.write(str(exc) + "\n")
dkato 0:f782d9c66c49 397 self.app_config_data = {}
dkato 0:f782d9c66c49 398
dkato 0:f782d9c66c49 399 # Check the keys in the application configuration data
dkato 0:f782d9c66c49 400 unknown_keys = set(self.app_config_data.keys()) - \
dkato 0:f782d9c66c49 401 self.__allowed_keys["application"]
dkato 0:f782d9c66c49 402 if unknown_keys:
dkato 0:f782d9c66c49 403 raise ConfigException("Unknown key(s) '%s' in %s" %
dkato 0:f782d9c66c49 404 (",".join(unknown_keys),
dkato 0:f782d9c66c49 405 self.__mbed_app_config_name))
dkato 0:f782d9c66c49 406 # Update the list of targets with the ones defined in the application
dkato 0:f782d9c66c49 407 # config, if applicable
dkato 0:f782d9c66c49 408 self.lib_config_data = {}
dkato 0:f782d9c66c49 409 # Make sure that each config is processed only once
dkato 0:f782d9c66c49 410 self.processed_configs = {}
dkato 0:f782d9c66c49 411 if isinstance(tgt, basestring):
dkato 0:f782d9c66c49 412 if tgt in TARGET_MAP:
dkato 0:f782d9c66c49 413 self.target = TARGET_MAP[tgt]
dkato 0:f782d9c66c49 414 else:
dkato 0:f782d9c66c49 415 self.target = generate_py_target(
dkato 0:f782d9c66c49 416 self.app_config_data.get("custom_targets", {}), tgt)
dkato 0:f782d9c66c49 417
dkato 0:f782d9c66c49 418 else:
dkato 0:f782d9c66c49 419 self.target = tgt
dkato 0:f782d9c66c49 420 self.target = deepcopy(self.target)
dkato 0:f782d9c66c49 421 self.target_labels = self.target.labels
dkato 0:f782d9c66c49 422
dkato 0:f782d9c66c49 423 self.cumulative_overrides = {key: ConfigCumulativeOverride(key)
dkato 0:f782d9c66c49 424 for key in CUMULATIVE_ATTRIBUTES}
dkato 0:f782d9c66c49 425
dkato 0:f782d9c66c49 426 self._process_config_and_overrides(self.app_config_data, {}, "app",
dkato 0:f782d9c66c49 427 "application")
dkato 0:f782d9c66c49 428 self.config_errors = None
dkato 0:f782d9c66c49 429
dkato 0:f782d9c66c49 430 def add_config_files(self, flist):
dkato 0:f782d9c66c49 431 """Add configuration files
dkato 0:f782d9c66c49 432
dkato 0:f782d9c66c49 433 Positional arguments:
dkato 0:f782d9c66c49 434 flist - a list of files to add to this configuration
dkato 0:f782d9c66c49 435 """
dkato 0:f782d9c66c49 436 for config_file in flist:
dkato 0:f782d9c66c49 437 if not config_file.endswith(self.__mbed_lib_config_name):
dkato 0:f782d9c66c49 438 continue
dkato 0:f782d9c66c49 439 full_path = os.path.normpath(os.path.abspath(config_file))
dkato 0:f782d9c66c49 440 # Check that we didn't already process this file
dkato 0:f782d9c66c49 441 if self.processed_configs.has_key(full_path):
dkato 0:f782d9c66c49 442 continue
dkato 0:f782d9c66c49 443 self.processed_configs[full_path] = True
dkato 0:f782d9c66c49 444 # Read the library configuration and add a "__full_config_path"
dkato 0:f782d9c66c49 445 # attribute to it
dkato 0:f782d9c66c49 446 try:
dkato 0:f782d9c66c49 447 cfg = json_file_to_dict(config_file)
dkato 0:f782d9c66c49 448 except ValueError as exc:
dkato 0:f782d9c66c49 449 sys.stderr.write(str(exc) + "\n")
dkato 0:f782d9c66c49 450 continue
dkato 0:f782d9c66c49 451
dkato 0:f782d9c66c49 452 cfg["__config_path"] = full_path
dkato 0:f782d9c66c49 453
dkato 0:f782d9c66c49 454 if "name" not in cfg:
dkato 0:f782d9c66c49 455 raise ConfigException(
dkato 0:f782d9c66c49 456 "Library configured at %s has no name field." % full_path)
dkato 0:f782d9c66c49 457 # If there's already a configuration for a module with the same
dkato 0:f782d9c66c49 458 # name, exit with error
dkato 0:f782d9c66c49 459 if self.lib_config_data.has_key(cfg["name"]):
dkato 0:f782d9c66c49 460 raise ConfigException(
dkato 0:f782d9c66c49 461 "Library name '%s' is not unique (defined in '%s' and '%s')"
dkato 0:f782d9c66c49 462 % (cfg["name"], full_path,
dkato 0:f782d9c66c49 463 self.lib_config_data[cfg["name"]]["__config_path"]))
dkato 0:f782d9c66c49 464 self.lib_config_data[cfg["name"]] = cfg
dkato 0:f782d9c66c49 465
dkato 0:f782d9c66c49 466 @property
dkato 0:f782d9c66c49 467 def has_regions(self):
dkato 0:f782d9c66c49 468 """Does this config have regions defined?"""
dkato 0:f782d9c66c49 469 if 'target_overrides' in self.app_config_data:
dkato 0:f782d9c66c49 470 target_overrides = self.app_config_data['target_overrides'].get(
dkato 0:f782d9c66c49 471 self.target.name, {})
dkato 0:f782d9c66c49 472 return ('target.bootloader_img' in target_overrides or
dkato 0:f782d9c66c49 473 'target.restrict_size' in target_overrides)
dkato 0:f782d9c66c49 474 else:
dkato 0:f782d9c66c49 475 return False
dkato 0:f782d9c66c49 476
dkato 0:f782d9c66c49 477 @property
dkato 0:f782d9c66c49 478 def regions(self):
dkato 0:f782d9c66c49 479 """Generate a list of regions from the config"""
dkato 0:f782d9c66c49 480 if not self.target.bootloader_supported:
dkato 0:f782d9c66c49 481 raise ConfigException("Bootloader not supported on this target.")
dkato 0:f782d9c66c49 482 cmsis_part = Cache(False, False).index[self.target.device_name]
dkato 0:f782d9c66c49 483 start = 0
dkato 0:f782d9c66c49 484 target_overrides = self.app_config_data['target_overrides'].get(
dkato 0:f782d9c66c49 485 self.target.name, {})
dkato 0:f782d9c66c49 486 try:
dkato 0:f782d9c66c49 487 rom_size = int(cmsis_part['memory']['IROM1']['size'], 0)
dkato 0:f782d9c66c49 488 rom_start = int(cmsis_part['memory']['IROM1']['start'], 0)
dkato 0:f782d9c66c49 489 except KeyError:
dkato 0:f782d9c66c49 490 raise ConfigException("Not enough information in CMSIS packs to "
dkato 0:f782d9c66c49 491 "build a bootloader project")
dkato 0:f782d9c66c49 492 if 'target.bootloader_img' in target_overrides:
dkato 0:f782d9c66c49 493 filename = target_overrides['target.bootloader_img']
dkato 0:f782d9c66c49 494 part = intelhex_offset(filename, offset=rom_start)
dkato 0:f782d9c66c49 495 if part.minaddr() != rom_start:
dkato 0:f782d9c66c49 496 raise ConfigException("bootloader executable does not "
dkato 0:f782d9c66c49 497 "start at 0x%x" % rom_start)
dkato 0:f782d9c66c49 498 part_size = (part.maxaddr() - part.minaddr()) + 1
dkato 0:f782d9c66c49 499 yield Region("bootloader", rom_start + start, part_size, False,
dkato 0:f782d9c66c49 500 filename)
dkato 0:f782d9c66c49 501 start += part_size
dkato 0:f782d9c66c49 502 if 'target.restrict_size' in target_overrides:
dkato 0:f782d9c66c49 503 new_size = int(target_overrides['target.restrict_size'], 0)
dkato 0:f782d9c66c49 504 yield Region("application", rom_start + start, new_size, True, None)
dkato 0:f782d9c66c49 505 start += new_size
dkato 0:f782d9c66c49 506 yield Region("post_application", rom_start +start, rom_size - start,
dkato 0:f782d9c66c49 507 False, None)
dkato 0:f782d9c66c49 508 else:
dkato 0:f782d9c66c49 509 yield Region("application", rom_start + start, rom_size - start,
dkato 0:f782d9c66c49 510 True, None)
dkato 0:f782d9c66c49 511 if start > rom_size:
dkato 0:f782d9c66c49 512 raise ConfigException("Not enough memory on device to fit all "
dkato 0:f782d9c66c49 513 "application regions")
dkato 0:f782d9c66c49 514
dkato 0:f782d9c66c49 515 def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
dkato 0:f782d9c66c49 516 """Process "config_parameters" and "target_config_overrides" into a
dkato 0:f782d9c66c49 517 given dictionary
dkato 0:f782d9c66c49 518
dkato 0:f782d9c66c49 519 Positional arguments:
dkato 0:f782d9c66c49 520 data - the configuration data of the library/appliation
dkato 0:f782d9c66c49 521 params - storage for the discovered configuration parameters
dkato 0:f782d9c66c49 522 unit_name - the unit (library/application) that defines this parameter
dkato 0:f782d9c66c49 523 unit_kind - the kind of the unit ("library" or "application")
dkato 0:f782d9c66c49 524 """
dkato 0:f782d9c66c49 525 self.config_errors = []
dkato 0:f782d9c66c49 526 _process_config_parameters(data.get("config", {}), params, unit_name,
dkato 0:f782d9c66c49 527 unit_kind)
dkato 0:f782d9c66c49 528 for label, overrides in data.get("target_overrides", {}).items():
dkato 0:f782d9c66c49 529 # If the label is defined by the target or it has the special value
dkato 0:f782d9c66c49 530 # "*", process the overrides
dkato 0:f782d9c66c49 531 if (label == '*') or (label in self.target_labels):
dkato 0:f782d9c66c49 532 # Check for invalid cumulative overrides in libraries
dkato 0:f782d9c66c49 533 if (unit_kind == 'library' and
dkato 0:f782d9c66c49 534 any(attr.startswith('target.extra_labels') for attr
dkato 0:f782d9c66c49 535 in overrides.iterkeys())):
dkato 0:f782d9c66c49 536 raise ConfigException(
dkato 0:f782d9c66c49 537 "Target override 'target.extra_labels' in " +
dkato 0:f782d9c66c49 538 ConfigParameter.get_display_name(unit_name, unit_kind,
dkato 0:f782d9c66c49 539 label) +
dkato 0:f782d9c66c49 540 " is only allowed at the application level")
dkato 0:f782d9c66c49 541
dkato 0:f782d9c66c49 542 # Parse out cumulative overrides
dkato 0:f782d9c66c49 543 for attr, cumulatives in self.cumulative_overrides.iteritems():
dkato 0:f782d9c66c49 544 if 'target.'+attr in overrides:
dkato 0:f782d9c66c49 545 cumulatives.strict_cumulative_overrides(
dkato 0:f782d9c66c49 546 overrides['target.'+attr])
dkato 0:f782d9c66c49 547 del overrides['target.'+attr]
dkato 0:f782d9c66c49 548
dkato 0:f782d9c66c49 549 if 'target.'+attr+'_add' in overrides:
dkato 0:f782d9c66c49 550 cumulatives.add_cumulative_overrides(
dkato 0:f782d9c66c49 551 overrides['target.'+attr+'_add'])
dkato 0:f782d9c66c49 552 del overrides['target.'+attr+'_add']
dkato 0:f782d9c66c49 553
dkato 0:f782d9c66c49 554 if 'target.'+attr+'_remove' in overrides:
dkato 0:f782d9c66c49 555 cumulatives.remove_cumulative_overrides(
dkato 0:f782d9c66c49 556 overrides['target.'+attr+'_remove'])
dkato 0:f782d9c66c49 557 del overrides['target.'+attr+'_remove']
dkato 0:f782d9c66c49 558
dkato 0:f782d9c66c49 559 # Consider the others as overrides
dkato 0:f782d9c66c49 560 for name, val in overrides.items():
dkato 0:f782d9c66c49 561 # Get the full name of the parameter
dkato 0:f782d9c66c49 562 full_name = ConfigParameter.get_full_name(name, unit_name,
dkato 0:f782d9c66c49 563 unit_kind, label)
dkato 0:f782d9c66c49 564 if full_name in params:
dkato 0:f782d9c66c49 565 params[full_name].set_value(val, unit_name, unit_kind,
dkato 0:f782d9c66c49 566 label)
dkato 0:f782d9c66c49 567 elif name in self.__unused_overrides:
dkato 0:f782d9c66c49 568 pass
dkato 0:f782d9c66c49 569 else:
dkato 0:f782d9c66c49 570 self.config_errors.append(
dkato 0:f782d9c66c49 571 ConfigException(
dkato 0:f782d9c66c49 572 "Attempt to override undefined parameter" +
dkato 0:f782d9c66c49 573 (" '%s' in '%s'"
dkato 0:f782d9c66c49 574 % (full_name,
dkato 0:f782d9c66c49 575 ConfigParameter.get_display_name(unit_name,
dkato 0:f782d9c66c49 576 unit_kind,
dkato 0:f782d9c66c49 577 label)))))
dkato 0:f782d9c66c49 578
dkato 0:f782d9c66c49 579 for cumulatives in self.cumulative_overrides.itervalues():
dkato 0:f782d9c66c49 580 cumulatives.update_target(self.target)
dkato 0:f782d9c66c49 581
dkato 0:f782d9c66c49 582 return params
dkato 0:f782d9c66c49 583
dkato 0:f782d9c66c49 584 def get_target_config_data(self):
dkato 0:f782d9c66c49 585 """Read and interpret configuration data defined by targets.
dkato 0:f782d9c66c49 586
dkato 0:f782d9c66c49 587 We consider the resolution order for our target and sort it by level
dkato 0:f782d9c66c49 588 reversed, so that we first look at the top level target (the parent),
dkato 0:f782d9c66c49 589 then its direct children, then the children of those children and so on,
dkato 0:f782d9c66c49 590 until we reach self.target
dkato 0:f782d9c66c49 591 TODO: this might not work so well in some multiple inheritance scenarios
dkato 0:f782d9c66c49 592 At each step, look at two keys of the target data:
dkato 0:f782d9c66c49 593 - config_parameters: used to define new configuration parameters
dkato 0:f782d9c66c49 594 - config_overrides: used to override already defined configuration
dkato 0:f782d9c66c49 595 parameters
dkato 0:f782d9c66c49 596
dkato 0:f782d9c66c49 597 Arguments: None
dkato 0:f782d9c66c49 598 """
dkato 0:f782d9c66c49 599 params, json_data = {}, self.target.json_data
dkato 0:f782d9c66c49 600 resolution_order = [e[0] for e
dkato 0:f782d9c66c49 601 in sorted(
dkato 0:f782d9c66c49 602 self.target.resolution_order,
dkato 0:f782d9c66c49 603 key=lambda e: e[1], reverse=True)]
dkato 0:f782d9c66c49 604 for tname in resolution_order:
dkato 0:f782d9c66c49 605 # Read the target data directly from its description
dkato 0:f782d9c66c49 606 target_data = json_data[tname]
dkato 0:f782d9c66c49 607 # Process definitions first
dkato 0:f782d9c66c49 608 _process_config_parameters(target_data.get("config", {}), params,
dkato 0:f782d9c66c49 609 tname, "target")
dkato 0:f782d9c66c49 610 # Then process overrides
dkato 0:f782d9c66c49 611 for name, val in target_data.get("overrides", {}).items():
dkato 0:f782d9c66c49 612 full_name = ConfigParameter.get_full_name(name, tname, "target")
dkato 0:f782d9c66c49 613 # If the parameter name is not defined or if there isn't a path
dkato 0:f782d9c66c49 614 # from this target to the target where the parameter was defined
dkato 0:f782d9c66c49 615 # in the target inheritance tree, raise an error We need to use
dkato 0:f782d9c66c49 616 # 'defined_by[7:]' to remove the "target:" prefix from
dkato 0:f782d9c66c49 617 # defined_by
dkato 0:f782d9c66c49 618 rel_names = [tgt for tgt, _ in
dkato 0:f782d9c66c49 619 get_resolution_order(self.target.json_data, tname,
dkato 0:f782d9c66c49 620 [])]
dkato 0:f782d9c66c49 621 if full_name in self.__unused_overrides:
dkato 0:f782d9c66c49 622 continue
dkato 0:f782d9c66c49 623 if (full_name not in params) or \
dkato 0:f782d9c66c49 624 (params[full_name].defined_by[7:] not in rel_names):
dkato 0:f782d9c66c49 625 raise ConfigException(
dkato 0:f782d9c66c49 626 "Attempt to override undefined parameter '%s' in '%s'"
dkato 0:f782d9c66c49 627 % (name,
dkato 0:f782d9c66c49 628 ConfigParameter.get_display_name(tname, "target")))
dkato 0:f782d9c66c49 629 # Otherwise update the value of the parameter
dkato 0:f782d9c66c49 630 params[full_name].set_value(val, tname, "target")
dkato 0:f782d9c66c49 631 return params
dkato 0:f782d9c66c49 632
dkato 0:f782d9c66c49 633 def get_lib_config_data(self):
dkato 0:f782d9c66c49 634 """ Read and interpret configuration data defined by libraries. It is
dkato 0:f782d9c66c49 635 assumed that "add_config_files" above was already called and the library
dkato 0:f782d9c66c49 636 configuration data exists in self.lib_config_data
dkato 0:f782d9c66c49 637
dkato 0:f782d9c66c49 638 Arguments: None
dkato 0:f782d9c66c49 639 """
dkato 0:f782d9c66c49 640 all_params, macros = {}, {}
dkato 0:f782d9c66c49 641 for lib_name, lib_data in self.lib_config_data.items():
dkato 0:f782d9c66c49 642 unknown_keys = set(lib_data.keys()) - self.__allowed_keys["library"]
dkato 0:f782d9c66c49 643 if unknown_keys:
dkato 0:f782d9c66c49 644 raise ConfigException("Unknown key(s) '%s' in %s" %
dkato 0:f782d9c66c49 645 (",".join(unknown_keys), lib_name))
dkato 0:f782d9c66c49 646 all_params.update(self._process_config_and_overrides(lib_data, {},
dkato 0:f782d9c66c49 647 lib_name,
dkato 0:f782d9c66c49 648 "library"))
dkato 0:f782d9c66c49 649 _process_macros(lib_data.get("macros", []), macros, lib_name,
dkato 0:f782d9c66c49 650 "library")
dkato 0:f782d9c66c49 651 return all_params, macros
dkato 0:f782d9c66c49 652
dkato 0:f782d9c66c49 653 def get_app_config_data(self, params, macros):
dkato 0:f782d9c66c49 654 """ Read and interpret the configuration data defined by the target. The
dkato 0:f782d9c66c49 655 target can override any configuration parameter, as well as define its
dkato 0:f782d9c66c49 656 own configuration data.
dkato 0:f782d9c66c49 657
dkato 0:f782d9c66c49 658 Positional arguments.
dkato 0:f782d9c66c49 659 params - the dictionary with configuration parameters found so far (in
dkato 0:f782d9c66c49 660 the target and in libraries)
dkato 0:f782d9c66c49 661 macros - the list of macros defined in the configuration
dkato 0:f782d9c66c49 662 """
dkato 0:f782d9c66c49 663 app_cfg = self.app_config_data
dkato 0:f782d9c66c49 664 # The application can have a "config_parameters" and a
dkato 0:f782d9c66c49 665 # "target_config_overrides" section just like a library
dkato 0:f782d9c66c49 666 self._process_config_and_overrides(app_cfg, params, "app",
dkato 0:f782d9c66c49 667 "application")
dkato 0:f782d9c66c49 668 # The application can also defined macros
dkato 0:f782d9c66c49 669 _process_macros(app_cfg.get("macros", []), macros, "app",
dkato 0:f782d9c66c49 670 "application")
dkato 0:f782d9c66c49 671
dkato 0:f782d9c66c49 672 def get_config_data(self):
dkato 0:f782d9c66c49 673 """ Return the configuration data in two parts: (params, macros)
dkato 0:f782d9c66c49 674 params - a dictionary with mapping a name to a ConfigParam
dkato 0:f782d9c66c49 675 macros - the list of macros defined with "macros" in libraries and in
dkato 0:f782d9c66c49 676 the application (as ConfigMacro instances)
dkato 0:f782d9c66c49 677
dkato 0:f782d9c66c49 678 Arguments: None
dkato 0:f782d9c66c49 679 """
dkato 0:f782d9c66c49 680 all_params = self.get_target_config_data()
dkato 0:f782d9c66c49 681 lib_params, macros = self.get_lib_config_data()
dkato 0:f782d9c66c49 682 all_params.update(lib_params)
dkato 0:f782d9c66c49 683 self.get_app_config_data(all_params, macros)
dkato 0:f782d9c66c49 684 return all_params, macros
dkato 0:f782d9c66c49 685
dkato 0:f782d9c66c49 686 @staticmethod
dkato 0:f782d9c66c49 687 def _check_required_parameters(params):
dkato 0:f782d9c66c49 688 """Check that there are no required parameters without a value
dkato 0:f782d9c66c49 689
dkato 0:f782d9c66c49 690 Positional arguments:
dkato 0:f782d9c66c49 691 params - the list of parameters to check
dkato 0:f782d9c66c49 692
dkato 0:f782d9c66c49 693 NOTE: This function does not return. Instead, it throws a
dkato 0:f782d9c66c49 694 ConfigException when any of the required parameters are missing values
dkato 0:f782d9c66c49 695 """
dkato 0:f782d9c66c49 696 for param in params.values():
dkato 0:f782d9c66c49 697 if param.required and (param.value is None):
dkato 0:f782d9c66c49 698 raise ConfigException("Required parameter '" + param.name +
dkato 0:f782d9c66c49 699 "' defined by '" + param.defined_by +
dkato 0:f782d9c66c49 700 "' doesn't have a value")
dkato 0:f782d9c66c49 701
dkato 0:f782d9c66c49 702 @staticmethod
dkato 0:f782d9c66c49 703 def parameters_to_macros(params):
dkato 0:f782d9c66c49 704 """ Encode the configuration parameters as C macro definitions.
dkato 0:f782d9c66c49 705
dkato 0:f782d9c66c49 706 Positional arguments:
dkato 0:f782d9c66c49 707 params - a dictionary mapping a name to a ConfigParameter
dkato 0:f782d9c66c49 708
dkato 0:f782d9c66c49 709 Return: a list of strings that encode the configuration parameters as
dkato 0:f782d9c66c49 710 C pre-processor macros
dkato 0:f782d9c66c49 711 """
dkato 0:f782d9c66c49 712 return ['%s=%s' % (m.macro_name, m.value) for m in params.values()
dkato 0:f782d9c66c49 713 if m.value is not None]
dkato 0:f782d9c66c49 714
dkato 0:f782d9c66c49 715 @staticmethod
dkato 0:f782d9c66c49 716 def config_macros_to_macros(macros):
dkato 0:f782d9c66c49 717 """ Return the macro definitions generated for a dictionary of
dkato 0:f782d9c66c49 718 ConfigMacros (as returned by get_config_data).
dkato 0:f782d9c66c49 719
dkato 0:f782d9c66c49 720 Positional arguments:
dkato 0:f782d9c66c49 721 params - a dictionary mapping a name to a ConfigMacro instance
dkato 0:f782d9c66c49 722
dkato 0:f782d9c66c49 723 Return: a list of strings that are the C pre-processor macros
dkato 0:f782d9c66c49 724 """
dkato 0:f782d9c66c49 725 return [m.name for m in macros.values()]
dkato 0:f782d9c66c49 726
dkato 0:f782d9c66c49 727 @staticmethod
dkato 0:f782d9c66c49 728 def config_to_macros(config):
dkato 0:f782d9c66c49 729 """Convert the configuration data to a list of C macros
dkato 0:f782d9c66c49 730
dkato 0:f782d9c66c49 731 Positional arguments:
dkato 0:f782d9c66c49 732 config - configuration data as (ConfigParam instances, ConfigMacro
dkato 0:f782d9c66c49 733 instances) tuple (as returned by get_config_data())
dkato 0:f782d9c66c49 734 """
dkato 0:f782d9c66c49 735 params, macros = config[0], config[1]
dkato 0:f782d9c66c49 736 Config._check_required_parameters(params)
dkato 0:f782d9c66c49 737 return Config.config_macros_to_macros(macros) + \
dkato 0:f782d9c66c49 738 Config.parameters_to_macros(params)
dkato 0:f782d9c66c49 739
dkato 0:f782d9c66c49 740 def get_config_data_macros(self):
dkato 0:f782d9c66c49 741 """ Convert a Config object to a list of C macros
dkato 0:f782d9c66c49 742
dkato 0:f782d9c66c49 743 Arguments: None
dkato 0:f782d9c66c49 744 """
dkato 0:f782d9c66c49 745 return self.config_to_macros(self.get_config_data())
dkato 0:f782d9c66c49 746
dkato 0:f782d9c66c49 747 def get_features(self):
dkato 0:f782d9c66c49 748 """ Extract any features from the configuration data
dkato 0:f782d9c66c49 749
dkato 0:f782d9c66c49 750 Arguments: None
dkato 0:f782d9c66c49 751 """
dkato 0:f782d9c66c49 752 params, _ = self.get_config_data()
dkato 0:f782d9c66c49 753 self._check_required_parameters(params)
dkato 0:f782d9c66c49 754 self.cumulative_overrides['features']\
dkato 0:f782d9c66c49 755 .update_target(self.target)
dkato 0:f782d9c66c49 756
dkato 0:f782d9c66c49 757 for feature in self.target.features:
dkato 0:f782d9c66c49 758 if feature not in self.__allowed_features:
dkato 0:f782d9c66c49 759 raise ConfigException(
dkato 0:f782d9c66c49 760 "Feature '%s' is not a supported features" % feature)
dkato 0:f782d9c66c49 761
dkato 0:f782d9c66c49 762 return self.target.features
dkato 0:f782d9c66c49 763
dkato 0:f782d9c66c49 764 def validate_config(self):
dkato 0:f782d9c66c49 765 """ Validate configuration settings. This either returns True or
dkato 0:f782d9c66c49 766 raises an exception
dkato 0:f782d9c66c49 767
dkato 0:f782d9c66c49 768 Arguments: None
dkato 0:f782d9c66c49 769 """
dkato 0:f782d9c66c49 770 if self.config_errors:
dkato 0:f782d9c66c49 771 raise self.config_errors[0]
dkato 0:f782d9c66c49 772 return True
dkato 0:f782d9c66c49 773
dkato 0:f782d9c66c49 774
dkato 0:f782d9c66c49 775 def load_resources(self, resources):
dkato 0:f782d9c66c49 776 """ Load configuration data from a Resources instance and expand it
dkato 0:f782d9c66c49 777 based on defined features.
dkato 0:f782d9c66c49 778
dkato 0:f782d9c66c49 779 Positional arguments:
dkato 0:f782d9c66c49 780 resources - the resources object to load from and expand
dkato 0:f782d9c66c49 781 """
dkato 0:f782d9c66c49 782 # Update configuration files until added features creates no changes
dkato 0:f782d9c66c49 783 prev_features = set()
dkato 0:f782d9c66c49 784 while True:
dkato 0:f782d9c66c49 785 # Add/update the configuration with any .json files found while
dkato 0:f782d9c66c49 786 # scanning
dkato 0:f782d9c66c49 787 self.add_config_files(resources.json_files)
dkato 0:f782d9c66c49 788
dkato 0:f782d9c66c49 789 # Add features while we find new ones
dkato 0:f782d9c66c49 790 features = set(self.get_features())
dkato 0:f782d9c66c49 791 if features == prev_features:
dkato 0:f782d9c66c49 792 break
dkato 0:f782d9c66c49 793
dkato 0:f782d9c66c49 794 for feature in features:
dkato 0:f782d9c66c49 795 if feature in resources.features:
dkato 0:f782d9c66c49 796 resources.add(resources.features[feature])
dkato 0:f782d9c66c49 797
dkato 0:f782d9c66c49 798 prev_features = features
dkato 0:f782d9c66c49 799 self.validate_config()
dkato 0:f782d9c66c49 800
dkato 0:f782d9c66c49 801 return resources
dkato 0:f782d9c66c49 802
dkato 0:f782d9c66c49 803 @staticmethod
dkato 0:f782d9c66c49 804 def config_to_header(config, fname=None):
dkato 0:f782d9c66c49 805 """ Convert the configuration data to the content of a C header file,
dkato 0:f782d9c66c49 806 meant to be included to a C/C++ file. The content is returned as a
dkato 0:f782d9c66c49 807 string.
dkato 0:f782d9c66c49 808
dkato 0:f782d9c66c49 809 Positional arguments:
dkato 0:f782d9c66c49 810 config - configuration data as (ConfigParam instances, ConfigMacro
dkato 0:f782d9c66c49 811 instances) tuple (as returned by get_config_data())
dkato 0:f782d9c66c49 812
dkato 0:f782d9c66c49 813 Keyword arguments:
dkato 0:f782d9c66c49 814 fname - also write the content is to the file called "fname".
dkato 0:f782d9c66c49 815 WARNING: if 'fname' names an existing file, it will be
dkato 0:f782d9c66c49 816 overwritten!
dkato 0:f782d9c66c49 817 """
dkato 0:f782d9c66c49 818 params, macros = config[0], config[1]
dkato 0:f782d9c66c49 819 Config._check_required_parameters(params)
dkato 0:f782d9c66c49 820 header_data = "// Automatically generated configuration file.\n"
dkato 0:f782d9c66c49 821 header_data += "// DO NOT EDIT, content will be overwritten.\n\n"
dkato 0:f782d9c66c49 822 header_data += "#ifndef __MBED_CONFIG_DATA__\n"
dkato 0:f782d9c66c49 823 header_data += "#define __MBED_CONFIG_DATA__\n\n"
dkato 0:f782d9c66c49 824 # Compute maximum length of macro names for proper alignment
dkato 0:f782d9c66c49 825 max_param_macro_name_len = (max([len(m.macro_name) for m
dkato 0:f782d9c66c49 826 in params.values()
dkato 0:f782d9c66c49 827 if m.value is not None])
dkato 0:f782d9c66c49 828 if params else 0)
dkato 0:f782d9c66c49 829 max_direct_macro_name_len = (max([len(m.macro_name) for m
dkato 0:f782d9c66c49 830 in macros.values()])
dkato 0:f782d9c66c49 831 if macros else 0)
dkato 0:f782d9c66c49 832 max_macro_name_len = max(max_param_macro_name_len,
dkato 0:f782d9c66c49 833 max_direct_macro_name_len)
dkato 0:f782d9c66c49 834 # Compute maximum length of macro values for proper alignment
dkato 0:f782d9c66c49 835 max_param_macro_val_len = (max([len(str(m.value)) for m
dkato 0:f782d9c66c49 836 in params.values()
dkato 0:f782d9c66c49 837 if m.value is not None])
dkato 0:f782d9c66c49 838 if params else 0)
dkato 0:f782d9c66c49 839 max_direct_macro_val_len = max([len(m.macro_value or "") for m
dkato 0:f782d9c66c49 840 in macros.values()]) if macros else 0
dkato 0:f782d9c66c49 841 max_macro_val_len = max(max_param_macro_val_len,
dkato 0:f782d9c66c49 842 max_direct_macro_val_len)
dkato 0:f782d9c66c49 843 # Generate config parameters first
dkato 0:f782d9c66c49 844 if params:
dkato 0:f782d9c66c49 845 header_data += "// Configuration parameters\n"
dkato 0:f782d9c66c49 846 for macro in params.values():
dkato 0:f782d9c66c49 847 if macro.value is not None:
dkato 0:f782d9c66c49 848 header_data += ("#define {0:<{1}} {2!s:<{3}} " +
dkato 0:f782d9c66c49 849 "// set by {4}\n")\
dkato 0:f782d9c66c49 850 .format(macro.macro_name, max_macro_name_len,
dkato 0:f782d9c66c49 851 macro.value, max_macro_val_len, macro.set_by)
dkato 0:f782d9c66c49 852 # Then macros
dkato 0:f782d9c66c49 853 if macros:
dkato 0:f782d9c66c49 854 header_data += "// Macros\n"
dkato 0:f782d9c66c49 855 for macro in macros.values():
dkato 0:f782d9c66c49 856 if macro.macro_value:
dkato 0:f782d9c66c49 857 header_data += ("#define {0:<{1}} {2!s:<{3}}" +
dkato 0:f782d9c66c49 858 " // defined by {4}\n")\
dkato 0:f782d9c66c49 859 .format(macro.macro_name, max_macro_name_len,
dkato 0:f782d9c66c49 860 macro.macro_value, max_macro_val_len,
dkato 0:f782d9c66c49 861 macro.defined_by)
dkato 0:f782d9c66c49 862 else:
dkato 0:f782d9c66c49 863 header_data += ("#define {0:<{1}}" +
dkato 0:f782d9c66c49 864 " // defined by {2}\n")\
dkato 0:f782d9c66c49 865 .format(macro.macro_name,
dkato 0:f782d9c66c49 866 max_macro_name_len + max_macro_val_len + 1,
dkato 0:f782d9c66c49 867 macro.defined_by)
dkato 0:f782d9c66c49 868 header_data += "\n#endif\n"
dkato 0:f782d9c66c49 869 # If fname is given, write "header_data" to it
dkato 0:f782d9c66c49 870 if fname:
dkato 0:f782d9c66c49 871 with open(fname, "w+") as file_desc:
dkato 0:f782d9c66c49 872 file_desc.write(header_data)
dkato 0:f782d9c66c49 873 return header_data
dkato 0:f782d9c66c49 874
dkato 0:f782d9c66c49 875 def get_config_data_header(self, fname=None):
dkato 0:f782d9c66c49 876 """ Convert a Config instance to the content of a C header file, meant
dkato 0:f782d9c66c49 877 to be included to a C/C++ file. The content is returned as a string.
dkato 0:f782d9c66c49 878
dkato 0:f782d9c66c49 879 Keyword arguments:
dkato 0:f782d9c66c49 880 fname - also write the content to the file called "fname".
dkato 0:f782d9c66c49 881 WARNING: if 'fname' names an existing file, it will be
dkato 0:f782d9c66c49 882 overwritten!
dkato 0:f782d9c66c49 883 """
dkato 0:f782d9c66c49 884 return self.config_to_header(self.get_config_data(), fname)