Development mbed library for MAX32630FTHR

Dependents:   blinky_max32630fthr

Committer:
switches
Date:
Fri Nov 11 20:59:50 2016 +0000
Revision:
0:5c4d7b2438d3
Initial commit

Who changed what in which revision?

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