Maxim mbed development library

Dependents:   sensomed

Committer:
switches
Date:
Tue Nov 08 18:27:11 2016 +0000
Revision:
0:0e018d759a2a
Initial commit

Who changed what in which revision?

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