mbed os with nrf51 internal bandgap enabled to read battery level

Dependents:   BLE_file_test BLE_Blink ExternalEncoder

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

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