the other jimmy / mbed-sdk-tools

Fork of mbed-sdk-tools by mbed official

Committer:
The Other Jimmy
Date:
Wed Jan 04 11:58:24 2017 -0600
Revision:
31:182518299918
Parent:
30:f12ce67666d0
Update tools to follow mbed-os tools release 5.3.1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:66f3b5499f7f 1 """
screamer 0:66f3b5499f7f 2 mbed SDK
screamer 0:66f3b5499f7f 3 Copyright (c) 2011-2016 ARM Limited
screamer 0:66f3b5499f7f 4
screamer 0:66f3b5499f7f 5 Licensed under the Apache License, Version 2.0 (the "License");
screamer 0:66f3b5499f7f 6 you may not use this file except in compliance with the License.
screamer 0:66f3b5499f7f 7 You may obtain a copy of the License at
screamer 0:66f3b5499f7f 8
screamer 0:66f3b5499f7f 9 http://www.apache.org/licenses/LICENSE-2.0
screamer 0:66f3b5499f7f 10
screamer 0:66f3b5499f7f 11 Unless required by applicable law or agreed to in writing, software
screamer 0:66f3b5499f7f 12 distributed under the License is distributed on an "AS IS" BASIS,
screamer 0:66f3b5499f7f 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
screamer 0:66f3b5499f7f 14 See the License for the specific language governing permissions and
screamer 0:66f3b5499f7f 15 limitations under the License.
screamer 0:66f3b5499f7f 16 """
screamer 0:66f3b5499f7f 17
screamer 29:1210849dba19 18 import os
screamer 29:1210849dba19 19 import binascii
screamer 29:1210849dba19 20 import struct
screamer 29:1210849dba19 21 import shutil
screamer 29:1210849dba19 22 import inspect
screamer 29:1210849dba19 23 import sys
The Other Jimmy 31:182518299918 24 from collections import namedtuple
screamer 29:1210849dba19 25 from tools.patch import patch
screamer 29:1210849dba19 26 from tools.paths import TOOLS_BOOTLOADERS
screamer 29:1210849dba19 27 from tools.utils import json_file_to_dict
screamer 29:1210849dba19 28
The Other Jimmy 31:182518299918 29 __all__ = ["target", "TARGETS", "TARGET_MAP", "TARGET_NAMES", "CORE_LABELS",
The Other Jimmy 31:182518299918 30 "HookError", "generate_py_target", "Target",
The Other Jimmy 31:182518299918 31 "CUMULATIVE_ATTRIBUTES", "get_resolution_order"]
The Other Jimmy 31:182518299918 32
screamer 0:66f3b5499f7f 33 CORE_LABELS = {
screamer 0:66f3b5499f7f 34 "ARM7TDMI-S": ["ARM7", "LIKE_CORTEX_ARM7"],
screamer 0:66f3b5499f7f 35 "Cortex-M0" : ["M0", "CORTEX_M", "LIKE_CORTEX_M0"],
screamer 0:66f3b5499f7f 36 "Cortex-M0+": ["M0P", "CORTEX_M", "LIKE_CORTEX_M0"],
screamer 0:66f3b5499f7f 37 "Cortex-M1" : ["M1", "CORTEX_M", "LIKE_CORTEX_M1"],
screamer 0:66f3b5499f7f 38 "Cortex-M3" : ["M3", "CORTEX_M", "LIKE_CORTEX_M3"],
screamer 0:66f3b5499f7f 39 "Cortex-M4" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"],
screamer 0:66f3b5499f7f 40 "Cortex-M4F" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"],
screamer 0:66f3b5499f7f 41 "Cortex-M7" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
screamer 0:66f3b5499f7f 42 "Cortex-M7F" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
screamer 13:ab47a20b66f0 43 "Cortex-M7FD" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
screamer 0:66f3b5499f7f 44 "Cortex-A9" : ["A9", "CORTEX_A", "LIKE_CORTEX_A9"]
screamer 0:66f3b5499f7f 45 }
screamer 0:66f3b5499f7f 46
screamer 29:1210849dba19 47 ################################################################################
screamer 7:5af61d55adbe 48 # Generic Target class that reads and interprets the data in targets.json
screamer 7:5af61d55adbe 49
screamer 7:5af61d55adbe 50 class HookError(Exception):
screamer 29:1210849dba19 51 """ A simple class that represents all the exceptions associated with
screamer 29:1210849dba19 52 hooking
screamer 29:1210849dba19 53 """
screamer 7:5af61d55adbe 54 pass
screamer 7:5af61d55adbe 55
screamer 29:1210849dba19 56 CACHES = {}
screamer 7:5af61d55adbe 57 def cached(func):
screamer 29:1210849dba19 58 """A simple decorator used for automatically caching data returned by a
screamer 29:1210849dba19 59 function
screamer 29:1210849dba19 60 """
screamer 7:5af61d55adbe 61 def wrapper(*args, **kwargs):
screamer 29:1210849dba19 62 """The wrapped function itself"""
screamer 29:1210849dba19 63 if not CACHES.has_key((func.__name__, args)):
screamer 29:1210849dba19 64 CACHES[(func.__name__, args)] = func(*args, **kwargs)
screamer 29:1210849dba19 65 return CACHES[(func.__name__, args)]
screamer 7:5af61d55adbe 66 return wrapper
screamer 0:66f3b5499f7f 67
The Other Jimmy 31:182518299918 68
The Other Jimmy 31:182518299918 69 # Cumulative attributes can have values appended to them, so they
The Other Jimmy 31:182518299918 70 # need to be computed differently than regular attributes
The Other Jimmy 31:182518299918 71 CUMULATIVE_ATTRIBUTES = ['extra_labels', 'macros', 'device_has', 'features']
The Other Jimmy 31:182518299918 72
The Other Jimmy 31:182518299918 73
The Other Jimmy 31:182518299918 74 def get_resolution_order(json_data, target_name, order, level=0):
The Other Jimmy 31:182518299918 75 """ Return the order in which target descriptions are searched for
The Other Jimmy 31:182518299918 76 attributes. This mimics the Python 2.2 method resolution order, which
The Other Jimmy 31:182518299918 77 is what the old targets.py module used. For more details, check
The Other Jimmy 31:182518299918 78 http://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path
The Other Jimmy 31:182518299918 79 The resolution order contains (name, level) tuples, where "name" is the
The Other Jimmy 31:182518299918 80 name of the class and "level" is the level in the inheritance hierarchy
The Other Jimmy 31:182518299918 81 (the target itself is at level 0, its first parent at level 1, its
The Other Jimmy 31:182518299918 82 parent's parent at level 2 and so on)
The Other Jimmy 31:182518299918 83 """
The Other Jimmy 31:182518299918 84 # the resolution order can't contain duplicate target names
The Other Jimmy 31:182518299918 85 if target_name not in [l[0] for l in order]:
The Other Jimmy 31:182518299918 86 order.append((target_name, level))
The Other Jimmy 31:182518299918 87 parents = json_data[target_name].get("inherits", [])
The Other Jimmy 31:182518299918 88 for par in parents:
The Other Jimmy 31:182518299918 89 order = get_resolution_order(json_data, par, order, level + 1)
The Other Jimmy 31:182518299918 90 return order
The Other Jimmy 31:182518299918 91
The Other Jimmy 31:182518299918 92
The Other Jimmy 31:182518299918 93 def target(name, json_data):
The Other Jimmy 31:182518299918 94 """Construct a target object"""
The Other Jimmy 31:182518299918 95 resolution_order = get_resolution_order(json_data, name, [])
The Other Jimmy 31:182518299918 96 resolution_order_names = [tgt for tgt, _ in resolution_order]
The Other Jimmy 31:182518299918 97 return Target(name=name,
The Other Jimmy 31:182518299918 98 json_data={key: value for key, value in json_data.items()
The Other Jimmy 31:182518299918 99 if key in resolution_order_names},
The Other Jimmy 31:182518299918 100 resolution_order=resolution_order,
The Other Jimmy 31:182518299918 101 resolution_order_names=resolution_order_names)
The Other Jimmy 31:182518299918 102
The Other Jimmy 31:182518299918 103 def generate_py_target(new_targets, name):
The Other Jimmy 31:182518299918 104 """Add one or more new target(s) represented as a Python dictionary
The Other Jimmy 31:182518299918 105 in 'new_targets'. It is an error to add a target with a name that
The Other Jimmy 31:182518299918 106 already exists.
The Other Jimmy 31:182518299918 107 """
The Other Jimmy 31:182518299918 108 base_targets = Target.get_json_target_data()
The Other Jimmy 31:182518299918 109 for new_target in new_targets.keys():
The Other Jimmy 31:182518299918 110 if new_target in base_targets:
The Other Jimmy 31:182518299918 111 raise Exception("Attempt to add target '%s' that already exists"
The Other Jimmy 31:182518299918 112 % new_target)
The Other Jimmy 31:182518299918 113 total_data = {}
The Other Jimmy 31:182518299918 114 total_data.update(new_targets)
The Other Jimmy 31:182518299918 115 total_data.update(base_targets)
The Other Jimmy 31:182518299918 116 return target(name, total_data)
The Other Jimmy 31:182518299918 117
The Other Jimmy 31:182518299918 118 class Target(namedtuple("Target", "name json_data resolution_order resolution_order_names")):
screamer 29:1210849dba19 119 """An object to represent a Target (MCU/Board)"""
screamer 7:5af61d55adbe 120
screamer 29:1210849dba19 121 # Default location of the 'targets.json' file
screamer 29:1210849dba19 122 __targets_json_location_default = os.path.join(
screamer 29:1210849dba19 123 os.path.dirname(os.path.abspath(__file__)), 'latest_targets.json')
screamer 16:a6285a7e5cc6 124
screamer 29:1210849dba19 125 # Current/new location of the 'targets.json' file
screamer 29:1210849dba19 126 __targets_json_location = None
screamer 29:1210849dba19 127
screamer 7:5af61d55adbe 128 @staticmethod
screamer 7:5af61d55adbe 129 @cached
screamer 7:5af61d55adbe 130 def get_json_target_data():
screamer 29:1210849dba19 131 """Load the description of JSON target data"""
screamer 29:1210849dba19 132 return json_file_to_dict(Target.__targets_json_location or
screamer 29:1210849dba19 133 Target.__targets_json_location_default)
screamer 16:a6285a7e5cc6 134
screamer 16:a6285a7e5cc6 135 @staticmethod
screamer 29:1210849dba19 136 def set_targets_json_location(location=None):
screamer 29:1210849dba19 137 """Set the location of the targets.json file"""
screamer 29:1210849dba19 138 Target.__targets_json_location = (location or
screamer 29:1210849dba19 139 Target.__targets_json_location_default)
screamer 16:a6285a7e5cc6 140 # Invalidate caches, since the location of the JSON file changed
screamer 29:1210849dba19 141 CACHES.clear()
screamer 7:5af61d55adbe 142
screamer 7:5af61d55adbe 143 @staticmethod
screamer 7:5af61d55adbe 144 @cached
screamer 7:5af61d55adbe 145 def get_module_data():
screamer 29:1210849dba19 146 """Get the members of this module using Python's "inspect" module"""
screamer 29:1210849dba19 147 return dict([(m[0], m[1]) for m in
screamer 29:1210849dba19 148 inspect.getmembers(sys.modules[__name__])])
screamer 0:66f3b5499f7f 149
screamer 7:5af61d55adbe 150 @staticmethod
screamer 7:5af61d55adbe 151 def __add_paths_to_progen(data):
screamer 29:1210849dba19 152 """Modify the exporter specification ("progen") by changing all
screamer 29:1210849dba19 153 "template" keys to full paths
screamer 29:1210849dba19 154 """
screamer 7:5af61d55adbe 155 out = {}
screamer 29:1210849dba19 156 for key, val in data.items():
screamer 29:1210849dba19 157 if isinstance(val, dict):
screamer 29:1210849dba19 158 out[key] = Target.__add_paths_to_progen(val)
screamer 7:5af61d55adbe 159 elif key == "template":
screamer 29:1210849dba19 160 out[key] = [os.path.join(os.path.dirname(__file__), 'export', v)
screamer 29:1210849dba19 161 for v in val]
screamer 7:5af61d55adbe 162 else:
screamer 29:1210849dba19 163 out[key] = val
screamer 7:5af61d55adbe 164 return out
screamer 0:66f3b5499f7f 165
screamer 29:1210849dba19 166 def __getattr_cumulative(self, attrname):
screamer 29:1210849dba19 167 """Look for the attribute in the class and its parents, as defined by
screamer 29:1210849dba19 168 the resolution order
screamer 29:1210849dba19 169 """
The Other Jimmy 31:182518299918 170 tdata = self.json_data
screamer 29:1210849dba19 171 # For a cumulative attribute, figure out when it was defined the
screamer 29:1210849dba19 172 # last time (in attribute resolution order) then follow the "_add"
screamer 29:1210849dba19 173 # and "_remove" data fields
The Other Jimmy 31:182518299918 174 for idx, tgt in enumerate(self.resolution_order):
screamer 29:1210849dba19 175 # the attribute was defined at this level in the resolution
screamer 29:1210849dba19 176 # order
The Other Jimmy 31:182518299918 177 if attrname in tdata[tgt[0]]:
screamer 29:1210849dba19 178 def_idx = idx
screamer 29:1210849dba19 179 break
screamer 29:1210849dba19 180 else:
screamer 29:1210849dba19 181 raise AttributeError("Attribute '%s' not found in target '%s'"
screamer 29:1210849dba19 182 % (attrname, self.name))
screamer 29:1210849dba19 183 # Get the starting value of the attribute
screamer 29:1210849dba19 184 starting_value = (tdata[self.resolution_order[def_idx][0]][attrname]
screamer 29:1210849dba19 185 or [])[:]
screamer 29:1210849dba19 186 # Traverse the resolution list in high inheritance to low
screamer 29:1210849dba19 187 # inheritance level, left to right order to figure out all the
screamer 29:1210849dba19 188 # other classes that change the definition by adding or removing
screamer 29:1210849dba19 189 # elements
screamer 29:1210849dba19 190 for idx in xrange(self.resolution_order[def_idx][1] - 1, -1, -1):
screamer 29:1210849dba19 191 same_level_targets = [tar[0] for tar in self.resolution_order
screamer 29:1210849dba19 192 if tar[1] == idx]
screamer 29:1210849dba19 193 for tar in same_level_targets:
screamer 29:1210849dba19 194 data = tdata[tar]
screamer 29:1210849dba19 195 # Do we have anything to add ?
screamer 29:1210849dba19 196 if data.has_key(attrname + "_add"):
screamer 29:1210849dba19 197 starting_value.extend(data[attrname + "_add"])
screamer 29:1210849dba19 198 # Do we have anything to remove ?
screamer 29:1210849dba19 199 if data.has_key(attrname + "_remove"):
screamer 29:1210849dba19 200 # Macros can be defined either without a value (MACRO)
screamer 29:1210849dba19 201 # or with a value (MACRO=10). When removing, we specify
screamer 29:1210849dba19 202 # only the name of the macro, without the value. So we
screamer 29:1210849dba19 203 # need to create a mapping between the macro name and
screamer 29:1210849dba19 204 # its value. This will work for extra_labels and other
screamer 29:1210849dba19 205 # type of arrays as well, since they fall into the
screamer 29:1210849dba19 206 # "macros without a value" category (simple definitions
screamer 29:1210849dba19 207 # without a value).
screamer 29:1210849dba19 208 name_def_map = {}
screamer 29:1210849dba19 209 for crtv in starting_value:
screamer 29:1210849dba19 210 if crtv.find('=') != -1:
screamer 29:1210849dba19 211 temp = crtv.split('=')
screamer 29:1210849dba19 212 if len(temp) != 2:
screamer 29:1210849dba19 213 raise ValueError(
screamer 29:1210849dba19 214 "Invalid macro definition '%s'" % crtv)
screamer 29:1210849dba19 215 name_def_map[temp[0]] = crtv
screamer 29:1210849dba19 216 else:
screamer 29:1210849dba19 217 name_def_map[crtv] = crtv
screamer 29:1210849dba19 218 for element in data[attrname + "_remove"]:
screamer 29:1210849dba19 219 if element not in name_def_map:
screamer 29:1210849dba19 220 raise ValueError(
screamer 29:1210849dba19 221 ("Unable to remove '%s' in '%s.%s' since "
screamer 29:1210849dba19 222 % (element, self.name, attrname)) +
screamer 29:1210849dba19 223 "it doesn't exist")
screamer 29:1210849dba19 224 starting_value.remove(name_def_map[element])
screamer 29:1210849dba19 225 return starting_value
screamer 29:1210849dba19 226
screamer 29:1210849dba19 227 def __getattr_helper(self, attrname):
screamer 29:1210849dba19 228 """Compute the value of a given target attribute"""
The Other Jimmy 31:182518299918 229 if attrname in CUMULATIVE_ATTRIBUTES:
screamer 29:1210849dba19 230 return self.__getattr_cumulative(attrname)
screamer 29:1210849dba19 231 else:
The Other Jimmy 31:182518299918 232 tdata = self.json_data
screamer 29:1210849dba19 233 starting_value = None
The Other Jimmy 31:182518299918 234 for tgt in self.resolution_order:
The Other Jimmy 31:182518299918 235 data = tdata[tgt[0]]
screamer 29:1210849dba19 236 if data.has_key(attrname):
screamer 29:1210849dba19 237 starting_value = data[attrname]
screamer 7:5af61d55adbe 238 break
screamer 29:1210849dba19 239 else: # Attribute not found
screamer 29:1210849dba19 240 raise AttributeError(
screamer 29:1210849dba19 241 "Attribute '%s' not found in target '%s'"
screamer 29:1210849dba19 242 % (attrname, self.name))
screamer 29:1210849dba19 243 # 'progen' needs the full path to the template (the path in JSON is
screamer 29:1210849dba19 244 # relative to tools/export)
screamer 29:1210849dba19 245 if attrname == "progen":
screamer 29:1210849dba19 246 return self.__add_paths_to_progen(starting_value)
screamer 7:5af61d55adbe 247 else:
screamer 29:1210849dba19 248 return starting_value
screamer 0:66f3b5499f7f 249
screamer 7:5af61d55adbe 250 def __getattr__(self, attrname):
screamer 29:1210849dba19 251 """ Return the value of an attribute. This function only computes the
screamer 29:1210849dba19 252 attribute's value once, then adds it to the instance attributes (in
screamer 29:1210849dba19 253 __dict__), so the next time it is returned directly
screamer 29:1210849dba19 254 """
screamer 29:1210849dba19 255 result = self.__getattr_helper(attrname)
screamer 29:1210849dba19 256 self.__dict__[attrname] = result
screamer 29:1210849dba19 257 return result
screamer 0:66f3b5499f7f 258
screamer 7:5af61d55adbe 259 @staticmethod
screamer 16:a6285a7e5cc6 260 @cached
screamer 29:1210849dba19 261 def get_target(target_name):
screamer 29:1210849dba19 262 """ Return the target instance starting from the target name """
The Other Jimmy 31:182518299918 263 return target(target_name, Target.get_json_target_data())
screamer 7:5af61d55adbe 264
screamer 0:66f3b5499f7f 265
screamer 13:ab47a20b66f0 266 @property
screamer 0:66f3b5499f7f 267 def program_cycle_s(self):
screamer 29:1210849dba19 268 """Special override for program_cycle_s as it's default value depends
screamer 29:1210849dba19 269 upon is_disk_virtual
screamer 29:1210849dba19 270 """
screamer 7:5af61d55adbe 271 try:
screamer 7:5af61d55adbe 272 return self.__getattr__("program_cycle_s")
screamer 7:5af61d55adbe 273 except AttributeError:
screamer 7:5af61d55adbe 274 return 4 if self.is_disk_virtual else 1.5
screamer 0:66f3b5499f7f 275
The Other Jimmy 31:182518299918 276 @property
The Other Jimmy 31:182518299918 277 def labels(self):
screamer 29:1210849dba19 278 """Get all possible labels for this target"""
screamer 13:ab47a20b66f0 279 labels = [self.name] + CORE_LABELS[self.core] + self.extra_labels
screamer 29:1210849dba19 280 # Automatically define UVISOR_UNSUPPORTED if the target doesn't
screamer 29:1210849dba19 281 # specifically define UVISOR_SUPPORTED
screamer 29:1210849dba19 282 if "UVISOR_SUPPORTED" not in labels:
screamer 13:ab47a20b66f0 283 labels.append("UVISOR_UNSUPPORTED")
screamer 13:ab47a20b66f0 284 return labels
screamer 0:66f3b5499f7f 285
screamer 0:66f3b5499f7f 286 def init_hooks(self, hook, toolchain_name):
screamer 29:1210849dba19 287 """Initialize the post-build hooks for a toolchain. For now, this
screamer 29:1210849dba19 288 function only allows "post binary" hooks (hooks that are executed
screamer 29:1210849dba19 289 after the binary image is extracted from the executable file)
screamer 29:1210849dba19 290 """
screamer 29:1210849dba19 291
screamer 7:5af61d55adbe 292 # If there's no hook, simply return
screamer 7:5af61d55adbe 293 try:
screamer 7:5af61d55adbe 294 hook_data = self.post_binary_hook
screamer 7:5af61d55adbe 295 except AttributeError:
screamer 7:5af61d55adbe 296 return
screamer 29:1210849dba19 297 # A hook was found. The hook's name is in the format
screamer 29:1210849dba19 298 # "classname.functionname"
screamer 7:5af61d55adbe 299 temp = hook_data["function"].split(".")
screamer 7:5af61d55adbe 300 if len(temp) != 2:
screamer 29:1210849dba19 301 raise HookError(
screamer 29:1210849dba19 302 ("Invalid format for hook '%s' in target '%s'"
screamer 29:1210849dba19 303 % (hook_data["function"], self.name)) +
screamer 29:1210849dba19 304 " (must be 'class_name.function_name')")
screamer 7:5af61d55adbe 305 class_name, function_name = temp[0], temp[1]
screamer 29:1210849dba19 306 # "class_name" must refer to a class in this file, so check if the
screamer 29:1210849dba19 307 # class exists
screamer 7:5af61d55adbe 308 mdata = self.get_module_data()
screamer 29:1210849dba19 309 if not mdata.has_key(class_name) or \
screamer 29:1210849dba19 310 not inspect.isclass(mdata[class_name]):
screamer 29:1210849dba19 311 raise HookError(
screamer 29:1210849dba19 312 ("Class '%s' required by '%s' in target '%s'"
screamer 29:1210849dba19 313 % (class_name, hook_data["function"], self.name)) +
screamer 29:1210849dba19 314 " not found in targets.py")
screamer 29:1210849dba19 315 # "function_name" must refer to a static function inside class
screamer 29:1210849dba19 316 # "class_name"
screamer 7:5af61d55adbe 317 cls = mdata[class_name]
screamer 29:1210849dba19 318 if (not hasattr(cls, function_name)) or \
screamer 29:1210849dba19 319 (not inspect.isfunction(getattr(cls, function_name))):
screamer 29:1210849dba19 320 raise HookError(
screamer 29:1210849dba19 321 ("Static function '%s' " % function_name) +
screamer 29:1210849dba19 322 ("required by '%s' " % hook_data["function"]) +
screamer 29:1210849dba19 323 ("in target '%s' " % self.name) +
screamer 29:1210849dba19 324 ("not found in class '%s'" % class_name))
screamer 7:5af61d55adbe 325 # Check if the hook specification also has target restrictions
screamer 7:5af61d55adbe 326 toolchain_restrictions = hook_data.get("toolchains", [])
screamer 29:1210849dba19 327 if toolchain_restrictions and \
screamer 29:1210849dba19 328 (toolchain_name not in toolchain_restrictions):
screamer 7:5af61d55adbe 329 return
screamer 7:5af61d55adbe 330 # Finally, hook the requested function
screamer 7:5af61d55adbe 331 hook.hook_add_binary("post", getattr(cls, function_name))
screamer 0:66f3b5499f7f 332
screamer 29:1210849dba19 333 ################################################################################
screamer 7:5af61d55adbe 334 # Target specific code goes in this section
screamer 29:1210849dba19 335 # This code can be invoked from the target description using the
screamer 29:1210849dba19 336 # "post_binary_hook" key
screamer 0:66f3b5499f7f 337
screamer 29:1210849dba19 338 class LPCTargetCode(object):
screamer 29:1210849dba19 339 """General LPC Target patching code"""
screamer 0:66f3b5499f7f 340 @staticmethod
screamer 0:66f3b5499f7f 341 def lpc_patch(t_self, resources, elf, binf):
screamer 29:1210849dba19 342 """Patch an elf file"""
screamer 0:66f3b5499f7f 343 t_self.debug("LPC Patch: %s" % os.path.split(binf)[1])
screamer 0:66f3b5499f7f 344 patch(binf)
screamer 0:66f3b5499f7f 345
screamer 29:1210849dba19 346 class LPC4088Code(object):
screamer 29:1210849dba19 347 """Code specific to the LPC4088"""
screamer 0:66f3b5499f7f 348 @staticmethod
screamer 0:66f3b5499f7f 349 def binary_hook(t_self, resources, elf, binf):
screamer 29:1210849dba19 350 """Hook to be run after an elf file is built"""
screamer 0:66f3b5499f7f 351 if not os.path.isdir(binf):
screamer 0:66f3b5499f7f 352 # Regular binary file, nothing to do
screamer 7:5af61d55adbe 353 LPCTargetCode.lpc_patch(t_self, resources, elf, binf)
screamer 0:66f3b5499f7f 354 return
screamer 0:66f3b5499f7f 355 outbin = open(binf + ".temp", "wb")
screamer 0:66f3b5499f7f 356 partf = open(os.path.join(binf, "ER_IROM1"), "rb")
screamer 0:66f3b5499f7f 357 # Pad the fist part (internal flash) with 0xFF to 512k
screamer 0:66f3b5499f7f 358 data = partf.read()
screamer 0:66f3b5499f7f 359 outbin.write(data)
screamer 0:66f3b5499f7f 360 outbin.write('\xFF' * (512*1024 - len(data)))
screamer 0:66f3b5499f7f 361 partf.close()
screamer 29:1210849dba19 362 # Read and append the second part (external flash) in chunks of fixed
screamer 29:1210849dba19 363 # size
screamer 0:66f3b5499f7f 364 chunksize = 128 * 1024
screamer 0:66f3b5499f7f 365 partf = open(os.path.join(binf, "ER_IROM2"), "rb")
screamer 0:66f3b5499f7f 366 while True:
screamer 0:66f3b5499f7f 367 data = partf.read(chunksize)
screamer 0:66f3b5499f7f 368 outbin.write(data)
screamer 0:66f3b5499f7f 369 if len(data) < chunksize:
screamer 0:66f3b5499f7f 370 break
screamer 0:66f3b5499f7f 371 partf.close()
screamer 0:66f3b5499f7f 372 outbin.close()
screamer 0:66f3b5499f7f 373 # Remove the directory with the binary parts and rename the temporary
screamer 0:66f3b5499f7f 374 # file to 'binf'
screamer 0:66f3b5499f7f 375 shutil.rmtree(binf, True)
screamer 0:66f3b5499f7f 376 os.rename(binf + '.temp', binf)
screamer 0:66f3b5499f7f 377 t_self.debug("Generated custom binary file (internal flash + SPIFI)")
screamer 7:5af61d55adbe 378 LPCTargetCode.lpc_patch(t_self, resources, elf, binf)
screamer 0:66f3b5499f7f 379
screamer 29:1210849dba19 380 class TEENSY3_1Code(object):
screamer 29:1210849dba19 381 """Hooks for the TEENSY3.1"""
screamer 0:66f3b5499f7f 382 @staticmethod
screamer 0:66f3b5499f7f 383 def binary_hook(t_self, resources, elf, binf):
screamer 29:1210849dba19 384 """Hook that is run after elf is generated"""
screamer 0:66f3b5499f7f 385 from intelhex import IntelHex
screamer 0:66f3b5499f7f 386 binh = IntelHex()
screamer 29:1210849dba19 387 binh.loadbin(binf, offset=0)
screamer 29:1210849dba19 388
screamer 29:1210849dba19 389 with open(binf.replace(".bin", ".hex"), "w") as file_desc:
screamer 29:1210849dba19 390 binh.tofile(file_desc, format='hex')
screamer 0:66f3b5499f7f 391
screamer 29:1210849dba19 392 class MTSCode(object):
screamer 29:1210849dba19 393 """Generic MTS code"""
screamer 0:66f3b5499f7f 394 @staticmethod
screamer 29:1210849dba19 395 def _combine_bins_helper(target_name, binf):
screamer 29:1210849dba19 396 """combine bins with the bootloader for a particular target"""
screamer 7:5af61d55adbe 397 loader = os.path.join(TOOLS_BOOTLOADERS, target_name, "bootloader.bin")
screamer 0:66f3b5499f7f 398 target = binf + ".tmp"
screamer 0:66f3b5499f7f 399 if not os.path.exists(loader):
screamer 0:66f3b5499f7f 400 print "Can't find bootloader binary: " + loader
screamer 0:66f3b5499f7f 401 return
screamer 0:66f3b5499f7f 402 outbin = open(target, 'w+b')
screamer 0:66f3b5499f7f 403 part = open(loader, 'rb')
screamer 0:66f3b5499f7f 404 data = part.read()
screamer 0:66f3b5499f7f 405 outbin.write(data)
screamer 0:66f3b5499f7f 406 outbin.write('\xFF' * (64*1024 - len(data)))
screamer 0:66f3b5499f7f 407 part.close()
screamer 0:66f3b5499f7f 408 part = open(binf, 'rb')
screamer 0:66f3b5499f7f 409 data = part.read()
screamer 0:66f3b5499f7f 410 outbin.write(data)
screamer 0:66f3b5499f7f 411 part.close()
screamer 0:66f3b5499f7f 412 outbin.seek(0, 0)
screamer 0:66f3b5499f7f 413 data = outbin.read()
screamer 0:66f3b5499f7f 414 outbin.seek(0, 1)
screamer 0:66f3b5499f7f 415 crc = struct.pack('<I', binascii.crc32(data) & 0xFFFFFFFF)
screamer 0:66f3b5499f7f 416 outbin.write(crc)
screamer 0:66f3b5499f7f 417 outbin.close()
screamer 0:66f3b5499f7f 418 os.remove(binf)
screamer 0:66f3b5499f7f 419 os.rename(target, binf)
screamer 0:66f3b5499f7f 420
screamer 0:66f3b5499f7f 421 @staticmethod
screamer 7:5af61d55adbe 422 def combine_bins_mts_dot(t_self, resources, elf, binf):
screamer 29:1210849dba19 423 """A hook for the MTS MDOT"""
screamer 29:1210849dba19 424 MTSCode._combine_bins_helper("MTS_MDOT_F411RE", binf)
screamer 0:66f3b5499f7f 425
screamer 7:5af61d55adbe 426 @staticmethod
screamer 7:5af61d55adbe 427 def combine_bins_mts_dragonfly(t_self, resources, elf, binf):
screamer 29:1210849dba19 428 """A hoof for the MTS Dragonfly"""
screamer 29:1210849dba19 429 MTSCode._combine_bins_helper("MTS_DRAGONFLY_F411RE", binf)
screamer 0:66f3b5499f7f 430
screamer 29:1210849dba19 431 class MCU_NRF51Code(object):
screamer 29:1210849dba19 432 """NRF51 Hooks"""
screamer 0:66f3b5499f7f 433 @staticmethod
screamer 29:1210849dba19 434 def binary_hook(t_self, resources, _, binf):
screamer 29:1210849dba19 435 """Hook that merges the soft device with the bin file"""
screamer 0:66f3b5499f7f 436 # Scan to find the actual paths of soft device
screamer 0:66f3b5499f7f 437 sdf = None
screamer 29:1210849dba19 438 for softdevice_and_offset_entry\
screamer 29:1210849dba19 439 in t_self.target.EXPECTED_SOFTDEVICES_WITH_OFFSETS:
screamer 0:66f3b5499f7f 440 for hexf in resources.hex_files:
screamer 29:1210849dba19 441 if hexf.find(softdevice_and_offset_entry['name']) != -1:
screamer 29:1210849dba19 442 t_self.debug("SoftDevice file found %s."
screamer 29:1210849dba19 443 % softdevice_and_offset_entry['name'])
screamer 0:66f3b5499f7f 444 sdf = hexf
screamer 0:66f3b5499f7f 445
screamer 29:1210849dba19 446 if sdf is not None:
screamer 29:1210849dba19 447 break
screamer 29:1210849dba19 448 if sdf is not None:
screamer 29:1210849dba19 449 break
screamer 0:66f3b5499f7f 450
screamer 0:66f3b5499f7f 451 if sdf is None:
screamer 0:66f3b5499f7f 452 t_self.debug("Hex file not found. Aborting.")
screamer 0:66f3b5499f7f 453 return
screamer 0:66f3b5499f7f 454
screamer 29:1210849dba19 455 # Look for bootloader file that matches this soft device or bootloader
screamer 29:1210849dba19 456 # override image
screamer 0:66f3b5499f7f 457 blf = None
screamer 0:66f3b5499f7f 458 if t_self.target.MERGE_BOOTLOADER is True:
screamer 0:66f3b5499f7f 459 for hexf in resources.hex_files:
screamer 0:66f3b5499f7f 460 if hexf.find(t_self.target.OVERRIDE_BOOTLOADER_FILENAME) != -1:
screamer 29:1210849dba19 461 t_self.debug("Bootloader file found %s."
screamer 29:1210849dba19 462 % t_self.target.OVERRIDE_BOOTLOADER_FILENAME)
screamer 0:66f3b5499f7f 463 blf = hexf
screamer 0:66f3b5499f7f 464 break
screamer 29:1210849dba19 465 elif hexf.find(softdevice_and_offset_entry['boot']) != -1:
screamer 29:1210849dba19 466 t_self.debug("Bootloader file found %s."
screamer 29:1210849dba19 467 % softdevice_and_offset_entry['boot'])
screamer 0:66f3b5499f7f 468 blf = hexf
screamer 0:66f3b5499f7f 469 break
screamer 0:66f3b5499f7f 470
screamer 0:66f3b5499f7f 471 # Merge user code with softdevice
screamer 0:66f3b5499f7f 472 from intelhex import IntelHex
screamer 0:66f3b5499f7f 473 binh = IntelHex()
screamer 29:1210849dba19 474 binh.loadbin(binf, offset=softdevice_and_offset_entry['offset'])
screamer 0:66f3b5499f7f 475
screamer 0:66f3b5499f7f 476 if t_self.target.MERGE_SOFT_DEVICE is True:
screamer 29:1210849dba19 477 t_self.debug("Merge SoftDevice file %s"
screamer 29:1210849dba19 478 % softdevice_and_offset_entry['name'])
screamer 0:66f3b5499f7f 479 sdh = IntelHex(sdf)
screamer 0:66f3b5499f7f 480 binh.merge(sdh)
screamer 0:66f3b5499f7f 481
screamer 0:66f3b5499f7f 482 if t_self.target.MERGE_BOOTLOADER is True and blf is not None:
screamer 0:66f3b5499f7f 483 t_self.debug("Merge BootLoader file %s" % blf)
screamer 0:66f3b5499f7f 484 blh = IntelHex(blf)
screamer 0:66f3b5499f7f 485 binh.merge(blh)
screamer 0:66f3b5499f7f 486
screamer 29:1210849dba19 487 with open(binf.replace(".bin", ".hex"), "w") as fileout:
screamer 29:1210849dba19 488 binh.tofile(fileout, format='hex')
screamer 0:66f3b5499f7f 489
The Other Jimmy 31:182518299918 490 class NCS36510TargetCode:
The Other Jimmy 31:182518299918 491 @staticmethod
The Other Jimmy 31:182518299918 492 def ncs36510_addfib(t_self, resources, elf, binf):
The Other Jimmy 31:182518299918 493 from tools.add_fib import add_fib_at_start
The Other Jimmy 31:182518299918 494 print("binf ", binf)
The Other Jimmy 31:182518299918 495 add_fib_at_start(binf[:-4])
screamer 29:1210849dba19 496 ################################################################################
screamer 0:66f3b5499f7f 497
screamer 7:5af61d55adbe 498 # Instantiate all public targets
screamer 29:1210849dba19 499 TARGETS = [Target.get_target(name) for name, value
screamer 29:1210849dba19 500 in Target.get_json_target_data().items()
screamer 29:1210849dba19 501 if value.get("public", True)]
screamer 0:66f3b5499f7f 502
screamer 0:66f3b5499f7f 503 # Map each target name to its unique instance
screamer 7:5af61d55adbe 504 TARGET_MAP = dict([(t.name, t) for t in TARGETS])
screamer 0:66f3b5499f7f 505
screamer 0:66f3b5499f7f 506 TARGET_NAMES = TARGET_MAP.keys()
screamer 0:66f3b5499f7f 507
screamer 0:66f3b5499f7f 508 # Some targets with different name have the same exporters
screamer 7:5af61d55adbe 509 EXPORT_MAP = {}
screamer 0:66f3b5499f7f 510
screamer 0:66f3b5499f7f 511 # Detection APIs
screamer 0:66f3b5499f7f 512 def get_target_detect_codes():
screamer 0:66f3b5499f7f 513 """ Returns dictionary mapping detect_code -> platform_name
screamer 0:66f3b5499f7f 514 """
screamer 0:66f3b5499f7f 515 result = {}
The Other Jimmy 31:182518299918 516 for tgt in TARGETS:
The Other Jimmy 31:182518299918 517 for detect_code in tgt.detect_code:
The Other Jimmy 31:182518299918 518 result[detect_code] = tgt.name
screamer 0:66f3b5499f7f 519 return result
screamer 16:a6285a7e5cc6 520
screamer 29:1210849dba19 521 def set_targets_json_location(location=None):
screamer 29:1210849dba19 522 """Sets the location of the JSON file that contains the targets"""
screamer 16:a6285a7e5cc6 523 # First instruct Target about the new location
screamer 16:a6285a7e5cc6 524 Target.set_targets_json_location(location)
screamer 29:1210849dba19 525 # Then re-initialize TARGETS, TARGET_MAP and TARGET_NAMES. The
screamer 29:1210849dba19 526 # re-initialization does not create new variables, it keeps the old ones
screamer 29:1210849dba19 527 # instead. This ensures compatibility with code that does
screamer 29:1210849dba19 528 # "from tools.targets import TARGET_NAMES"
The Other Jimmy 31:182518299918 529 TARGETS[:] = [Target.get_target(tgt) for tgt, obj
screamer 29:1210849dba19 530 in Target.get_json_target_data().items()
screamer 29:1210849dba19 531 if obj.get("public", True)]
screamer 16:a6285a7e5cc6 532 TARGET_MAP.clear()
The Other Jimmy 31:182518299918 533 TARGET_MAP.update(dict([(tgt.name, tgt) for tgt in TARGETS]))
screamer 16:a6285a7e5cc6 534 TARGET_NAMES[:] = TARGET_MAP.keys()