mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

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