Clone of official tools
targets.py@14:ee1b877e6839, 2016-07-14 (annotated)
- Committer:
- screamer
- Date:
- Thu Jul 14 20:37:27 2016 +0100
- Revision:
- 14:ee1b877e6839
- Parent:
- 13:ab47a20b66f0
- Child:
- 16:a6285a7e5cc6
Apply legacy build system profiles
Who changed what in which revision?
User | Revision | Line number | New 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 | 0:66f3b5499f7f | 18 | CORE_LABELS = { |
screamer | 0:66f3b5499f7f | 19 | "ARM7TDMI-S": ["ARM7", "LIKE_CORTEX_ARM7"], |
screamer | 0:66f3b5499f7f | 20 | "Cortex-M0" : ["M0", "CORTEX_M", "LIKE_CORTEX_M0"], |
screamer | 0:66f3b5499f7f | 21 | "Cortex-M0+": ["M0P", "CORTEX_M", "LIKE_CORTEX_M0"], |
screamer | 0:66f3b5499f7f | 22 | "Cortex-M1" : ["M1", "CORTEX_M", "LIKE_CORTEX_M1"], |
screamer | 0:66f3b5499f7f | 23 | "Cortex-M3" : ["M3", "CORTEX_M", "LIKE_CORTEX_M3"], |
screamer | 0:66f3b5499f7f | 24 | "Cortex-M4" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"], |
screamer | 0:66f3b5499f7f | 25 | "Cortex-M4F" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"], |
screamer | 0:66f3b5499f7f | 26 | "Cortex-M7" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"], |
screamer | 0:66f3b5499f7f | 27 | "Cortex-M7F" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"], |
screamer | 13:ab47a20b66f0 | 28 | "Cortex-M7FD" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"], |
screamer | 0:66f3b5499f7f | 29 | "Cortex-A9" : ["A9", "CORTEX_A", "LIKE_CORTEX_A9"] |
screamer | 0:66f3b5499f7f | 30 | } |
screamer | 0:66f3b5499f7f | 31 | |
screamer | 0:66f3b5499f7f | 32 | import os |
screamer | 0:66f3b5499f7f | 33 | import binascii |
screamer | 0:66f3b5499f7f | 34 | import struct |
screamer | 0:66f3b5499f7f | 35 | import shutil |
screamer | 0:66f3b5499f7f | 36 | from tools.patch import patch |
screamer | 0:66f3b5499f7f | 37 | from paths import TOOLS_BOOTLOADERS |
screamer | 7:5af61d55adbe | 38 | import json |
screamer | 7:5af61d55adbe | 39 | import inspect |
screamer | 7:5af61d55adbe | 40 | import sys |
screamer | 7:5af61d55adbe | 41 | from tools.utils import json_file_to_dict |
screamer | 7:5af61d55adbe | 42 | |
screamer | 7:5af61d55adbe | 43 | ######################################################################################################################## |
screamer | 7:5af61d55adbe | 44 | # Generic Target class that reads and interprets the data in targets.json |
screamer | 7:5af61d55adbe | 45 | |
screamer | 7:5af61d55adbe | 46 | # A simple class that represents all the exceptions associated with hooking |
screamer | 7:5af61d55adbe | 47 | class HookError(Exception): |
screamer | 7:5af61d55adbe | 48 | pass |
screamer | 7:5af61d55adbe | 49 | |
screamer | 7:5af61d55adbe | 50 | # A simple decorator used for automatically caching data returned by a function |
screamer | 7:5af61d55adbe | 51 | caches = {} |
screamer | 7:5af61d55adbe | 52 | def cached(func): |
screamer | 7:5af61d55adbe | 53 | def wrapper(*args, **kwargs): |
screamer | 14:ee1b877e6839 | 54 | if not caches.has_key(func): |
screamer | 14:ee1b877e6839 | 55 | caches[func] = func(*args, **kwargs) |
screamer | 14:ee1b877e6839 | 56 | return caches[func] |
screamer | 7:5af61d55adbe | 57 | return wrapper |
screamer | 0:66f3b5499f7f | 58 | |
screamer | 0:66f3b5499f7f | 59 | class Target: |
screamer | 7:5af61d55adbe | 60 | # Cumulative attributes can have values appended to them, so they |
screamer | 7:5af61d55adbe | 61 | # need to be computed differently than regular attributes |
screamer | 13:ab47a20b66f0 | 62 | __cumulative_attributes = ['extra_labels', 'macros', 'device_has', 'features'] |
screamer | 7:5af61d55adbe | 63 | |
screamer | 14:ee1b877e6839 | 64 | # {target_name: target_instance} map for all the targets in the system |
screamer | 14:ee1b877e6839 | 65 | __target_map = {} |
screamer | 14:ee1b877e6839 | 66 | |
screamer | 7:5af61d55adbe | 67 | # List of targets that were added dynamically using "add_py_targets" (see below) |
screamer | 7:5af61d55adbe | 68 | __py_targets = set() |
screamer | 7:5af61d55adbe | 69 | |
screamer | 7:5af61d55adbe | 70 | # Load the description of JSON target data |
screamer | 7:5af61d55adbe | 71 | @staticmethod |
screamer | 7:5af61d55adbe | 72 | @cached |
screamer | 7:5af61d55adbe | 73 | def get_json_target_data(): |
screamer | 14:ee1b877e6839 | 74 | return json_file_to_dict(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'targets.json')) |
screamer | 7:5af61d55adbe | 75 | |
screamer | 7:5af61d55adbe | 76 | # Get the members of this module using Python's "inspect" module |
screamer | 7:5af61d55adbe | 77 | @staticmethod |
screamer | 7:5af61d55adbe | 78 | @cached |
screamer | 7:5af61d55adbe | 79 | def get_module_data(): |
screamer | 7:5af61d55adbe | 80 | return dict([(m[0], m[1]) for m in inspect.getmembers(sys.modules[__name__])]) |
screamer | 0:66f3b5499f7f | 81 | |
screamer | 7:5af61d55adbe | 82 | # Return the order in which target descriptions are searched for attributes |
screamer | 7:5af61d55adbe | 83 | # This mimics the Python 2.2 method resolution order, which is what the old targets.py module used |
screamer | 7:5af61d55adbe | 84 | # For more details, check http://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path |
screamer | 7:5af61d55adbe | 85 | # The resolution order contains (name, level) tuples, where "name" is the name of the class and "level" |
screamer | 7:5af61d55adbe | 86 | # is the level in the inheritance hierarchy (the target itself is at level 0, its first parent at level 1, |
screamer | 7:5af61d55adbe | 87 | # its parent's parent at level 1 and so on) |
screamer | 7:5af61d55adbe | 88 | def __get_resolution_order(self, target_name, order, level = 0): |
screamer | 7:5af61d55adbe | 89 | if not target_name in [l[0] for l in order]: # the resolution order can't contain duplicate target names |
screamer | 7:5af61d55adbe | 90 | order.append((target_name, level)) |
screamer | 7:5af61d55adbe | 91 | parents = self.get_json_target_data()[target_name].get("inherits", []) |
screamer | 7:5af61d55adbe | 92 | for p in parents: |
screamer | 7:5af61d55adbe | 93 | order = self.__get_resolution_order(p, order, level + 1) |
screamer | 7:5af61d55adbe | 94 | return order |
screamer | 0:66f3b5499f7f | 95 | |
screamer | 7:5af61d55adbe | 96 | # Modify the exporter specification ("progen") by changing all "template" keys to full paths |
screamer | 7:5af61d55adbe | 97 | @staticmethod |
screamer | 7:5af61d55adbe | 98 | def __add_paths_to_progen(data): |
screamer | 7:5af61d55adbe | 99 | out = {} |
screamer | 7:5af61d55adbe | 100 | for key, value in data.items(): |
screamer | 7:5af61d55adbe | 101 | if isinstance(value, dict): |
screamer | 7:5af61d55adbe | 102 | out[key] = Target.__add_paths_to_progen(value) |
screamer | 7:5af61d55adbe | 103 | elif key == "template": |
screamer | 7:5af61d55adbe | 104 | out[key] = [os.path.join(os.path.dirname(__file__), 'export', v) for v in value] |
screamer | 7:5af61d55adbe | 105 | else: |
screamer | 7:5af61d55adbe | 106 | out[key] = value |
screamer | 7:5af61d55adbe | 107 | return out |
screamer | 0:66f3b5499f7f | 108 | |
screamer | 7:5af61d55adbe | 109 | # Comute the value of a given target attribute |
screamer | 7:5af61d55adbe | 110 | def __getattr_helper(self, attrname): |
screamer | 7:5af61d55adbe | 111 | tdata = self.get_json_target_data() |
screamer | 7:5af61d55adbe | 112 | if attrname in self.__cumulative_attributes: |
screamer | 7:5af61d55adbe | 113 | # For a cumulative attribute, figure out when it was defined the last time (in attribute |
screamer | 7:5af61d55adbe | 114 | # resolution order) then follow the "_add" and "_remove" data fields |
screamer | 7:5af61d55adbe | 115 | for idx, t in enumerate(self.resolution_order): |
screamer | 7:5af61d55adbe | 116 | if attrname in tdata[t[0]]: # the attribute was defined at this level in the resolution order |
screamer | 7:5af61d55adbe | 117 | def_idx = idx |
screamer | 7:5af61d55adbe | 118 | break |
screamer | 7:5af61d55adbe | 119 | else: |
screamer | 7:5af61d55adbe | 120 | raise AttributeError("Attribute '%s' not found in target '%s'" % (attrname, self.name)) |
screamer | 7:5af61d55adbe | 121 | # Get the starting value of the attribute |
screamer | 7:5af61d55adbe | 122 | v = (tdata[self.resolution_order[def_idx][0]][attrname] or [])[:] |
screamer | 7:5af61d55adbe | 123 | # Traverse the resolution list in high inheritance to low inheritance level, left to right order |
screamer | 7:5af61d55adbe | 124 | # to figure out all the other classes that change the definition by adding or removing elements |
screamer | 7:5af61d55adbe | 125 | for idx in xrange(self.resolution_order[def_idx][1] - 1, -1, -1): |
screamer | 7:5af61d55adbe | 126 | same_level_targets = [t[0] for t in self.resolution_order if t[1] == idx] |
screamer | 7:5af61d55adbe | 127 | for t in same_level_targets: |
screamer | 7:5af61d55adbe | 128 | data = tdata[t] |
screamer | 7:5af61d55adbe | 129 | # Do we have anything to add ? |
screamer | 7:5af61d55adbe | 130 | if data.has_key(attrname + "_add"): |
screamer | 7:5af61d55adbe | 131 | v.extend(data[attrname + "_add"]) |
screamer | 7:5af61d55adbe | 132 | # Do we have anything to remove ? |
screamer | 7:5af61d55adbe | 133 | if data.has_key(attrname + "_remove"): |
screamer | 7:5af61d55adbe | 134 | # Macros can be defined either without a value (MACRO) or with a value (MACRO=10). |
screamer | 7:5af61d55adbe | 135 | # When removing, we specify only the name of the macro, without the value. So we need |
screamer | 7:5af61d55adbe | 136 | # to create a mapping between the macro name and its value. This will work for |
screamer | 7:5af61d55adbe | 137 | # extra_labels and other type of arrays as well, since they fall into the "macros |
screamer | 7:5af61d55adbe | 138 | # without a value" category (simple definitions without a value). |
screamer | 7:5af61d55adbe | 139 | name_def_map = {} |
screamer | 7:5af61d55adbe | 140 | for crtv in v: |
screamer | 7:5af61d55adbe | 141 | if crtv.find('=') != -1: |
screamer | 7:5af61d55adbe | 142 | temp = crtv.split('=') |
screamer | 7:5af61d55adbe | 143 | if len(temp) != 2: |
screamer | 7:5af61d55adbe | 144 | raise ValueError("Invalid macro definition '%s'" % crtv) |
screamer | 7:5af61d55adbe | 145 | name_def_map[temp[0]] = crtv |
screamer | 7:5af61d55adbe | 146 | else: |
screamer | 7:5af61d55adbe | 147 | name_def_map[crtv] = crtv |
screamer | 7:5af61d55adbe | 148 | for e in data[attrname + "_remove"]: |
screamer | 7:5af61d55adbe | 149 | if not e in name_def_map: |
screamer | 7:5af61d55adbe | 150 | raise ValueError("Unable to remove '%s' in '%s.%s' since it doesn't exist" % (e, self.name, attrname)) |
screamer | 7:5af61d55adbe | 151 | v.remove(name_def_map[e]) |
screamer | 7:5af61d55adbe | 152 | return v |
screamer | 7:5af61d55adbe | 153 | # Look for the attribute in the class and its parents, as defined by the resolution order |
screamer | 7:5af61d55adbe | 154 | v = None |
screamer | 7:5af61d55adbe | 155 | for t in self.resolution_order: |
screamer | 7:5af61d55adbe | 156 | data = tdata[t[0]] |
screamer | 7:5af61d55adbe | 157 | if data.has_key(attrname): |
screamer | 7:5af61d55adbe | 158 | v = data[attrname] |
screamer | 7:5af61d55adbe | 159 | break |
screamer | 7:5af61d55adbe | 160 | else: # Attribute not found |
screamer | 7:5af61d55adbe | 161 | raise AttributeError("Attribute '%s' not found in target '%s'" % (attrname, self.name)) |
screamer | 7:5af61d55adbe | 162 | # 'progen' needs the full path to the template (the path in JSON is relative to tools/export) |
screamer | 7:5af61d55adbe | 163 | return v if attrname != "progen" else self.__add_paths_to_progen(v) |
screamer | 0:66f3b5499f7f | 164 | |
screamer | 7:5af61d55adbe | 165 | # Return the value of an attribute |
screamer | 7:5af61d55adbe | 166 | # This function only computes the attribute's value once, then adds it to the instance attributes |
screamer | 7:5af61d55adbe | 167 | # (in __dict__), so the next time it is returned directly |
screamer | 7:5af61d55adbe | 168 | def __getattr__(self, attrname): |
screamer | 7:5af61d55adbe | 169 | v = self.__getattr_helper(attrname) |
screamer | 7:5af61d55adbe | 170 | self.__dict__[attrname] = v |
screamer | 7:5af61d55adbe | 171 | return v |
screamer | 0:66f3b5499f7f | 172 | |
screamer | 7:5af61d55adbe | 173 | # Add one or more new target(s) represented as a Python dictionary in 'new_targets' |
screamer | 7:5af61d55adbe | 174 | # It it an error to add a target with a name that exists in "targets.json" |
screamer | 7:5af61d55adbe | 175 | # However, it is OK to add a target that was previously added via "add_py_targets" |
screamer | 7:5af61d55adbe | 176 | # (this makes testing easier without changing the regular semantics) |
screamer | 7:5af61d55adbe | 177 | @staticmethod |
screamer | 7:5af61d55adbe | 178 | def add_py_targets(new_targets): |
screamer | 7:5af61d55adbe | 179 | crt_data = Target.get_json_target_data() |
screamer | 7:5af61d55adbe | 180 | # First add all elemnts to the internal dictionary |
screamer | 7:5af61d55adbe | 181 | for tk, tv in new_targets.items(): |
screamer | 7:5af61d55adbe | 182 | if crt_data.has_key(tk) and (not tk in Target.__py_targets): |
screamer | 7:5af61d55adbe | 183 | raise Exception("Attempt to add target '%s' that already exists" % tk) |
screamer | 7:5af61d55adbe | 184 | crt_data[tk] = tv |
screamer | 7:5af61d55adbe | 185 | Target.__py_targets.add(tk) |
screamer | 7:5af61d55adbe | 186 | # Then create the new instances and update global variables if needed |
screamer | 7:5af61d55adbe | 187 | for tk, tv in new_targets.items(): |
screamer | 7:5af61d55adbe | 188 | # Is the target already created? |
screamer | 7:5af61d55adbe | 189 | old_target = Target.__target_map.get(tk, None) |
screamer | 7:5af61d55adbe | 190 | # Instantiate this target. If it is public, update the data in |
screamer | 7:5af61d55adbe | 191 | # in TARGETS, TARGET_MAP, TARGET_NAMES |
screamer | 7:5af61d55adbe | 192 | new_target = Target(tk) |
screamer | 7:5af61d55adbe | 193 | if tv.get("public", True): |
screamer | 7:5af61d55adbe | 194 | if old_target: # remove the old target from TARGETS and TARGET_NAMES |
screamer | 7:5af61d55adbe | 195 | TARGETS.remove(old_target) |
screamer | 7:5af61d55adbe | 196 | TARGET_NAMES.remove(tk) |
screamer | 7:5af61d55adbe | 197 | # Add the new target |
screamer | 7:5af61d55adbe | 198 | TARGETS.append(new_target) |
screamer | 7:5af61d55adbe | 199 | TARGET_MAP[tk] = new_target |
screamer | 7:5af61d55adbe | 200 | TARGET_NAMES.append(tk) |
screamer | 7:5af61d55adbe | 201 | # Update the target cache |
screamer | 7:5af61d55adbe | 202 | Target.__target_map[tk] = new_target |
screamer | 0:66f3b5499f7f | 203 | |
screamer | 7:5af61d55adbe | 204 | # Return the target instance starting from the target name |
screamer | 7:5af61d55adbe | 205 | @staticmethod |
screamer | 7:5af61d55adbe | 206 | def get_target(name): |
screamer | 14:ee1b877e6839 | 207 | if not Target.__target_map.has_key(name): |
screamer | 14:ee1b877e6839 | 208 | Target.__target_map[name] = Target(name) |
screamer | 14:ee1b877e6839 | 209 | return Target.__target_map[name] |
screamer | 7:5af61d55adbe | 210 | |
screamer | 7:5af61d55adbe | 211 | def __init__(self, name): |
screamer | 7:5af61d55adbe | 212 | self.name = name |
screamer | 7:5af61d55adbe | 213 | |
screamer | 7:5af61d55adbe | 214 | # Compute resolution order once (it will be used later in __getattr__) |
screamer | 7:5af61d55adbe | 215 | self.resolution_order = self.__get_resolution_order(self.name, []) |
screamer | 7:5af61d55adbe | 216 | # Create also a list with only the names of the targets in the resolution order |
screamer | 7:5af61d55adbe | 217 | self.resolution_order_names = [t[0] for t in self.resolution_order] |
screamer | 0:66f3b5499f7f | 218 | |
screamer | 13:ab47a20b66f0 | 219 | @property |
screamer | 0:66f3b5499f7f | 220 | def program_cycle_s(self): |
screamer | 7:5af61d55adbe | 221 | try: |
screamer | 7:5af61d55adbe | 222 | return self.__getattr__("program_cycle_s") |
screamer | 7:5af61d55adbe | 223 | except AttributeError: |
screamer | 7:5af61d55adbe | 224 | return 4 if self.is_disk_virtual else 1.5 |
screamer | 0:66f3b5499f7f | 225 | |
screamer | 0:66f3b5499f7f | 226 | def get_labels(self): |
screamer | 13:ab47a20b66f0 | 227 | labels = [self.name] + CORE_LABELS[self.core] + self.extra_labels |
screamer | 13:ab47a20b66f0 | 228 | # Automatically define UVISOR_UNSUPPORTED if the target doesn't specifically |
screamer | 13:ab47a20b66f0 | 229 | # define UVISOR_SUPPORTED |
screamer | 13:ab47a20b66f0 | 230 | if not "UVISOR_SUPPORTED" in labels: |
screamer | 13:ab47a20b66f0 | 231 | labels.append("UVISOR_UNSUPPORTED") |
screamer | 13:ab47a20b66f0 | 232 | return labels |
screamer | 0:66f3b5499f7f | 233 | |
screamer | 7:5af61d55adbe | 234 | # For now, this function only allows "post binary" hooks (hooks that are executed after |
screamer | 7:5af61d55adbe | 235 | # the binary image is extracted from the executable file) |
screamer | 0:66f3b5499f7f | 236 | def init_hooks(self, hook, toolchain_name): |
screamer | 7:5af61d55adbe | 237 | # If there's no hook, simply return |
screamer | 7:5af61d55adbe | 238 | try: |
screamer | 7:5af61d55adbe | 239 | hook_data = self.post_binary_hook |
screamer | 7:5af61d55adbe | 240 | except AttributeError: |
screamer | 7:5af61d55adbe | 241 | return |
screamer | 7:5af61d55adbe | 242 | # A hook was found. The hook's name is in the format "classname.functionname" |
screamer | 7:5af61d55adbe | 243 | temp = hook_data["function"].split(".") |
screamer | 7:5af61d55adbe | 244 | if len(temp) != 2: |
screamer | 7:5af61d55adbe | 245 | raise HookError("Invalid format for hook '%s' in target '%s' (must be 'class_name.function_name')" % (hook_data["function"], self.name)) |
screamer | 7:5af61d55adbe | 246 | class_name, function_name = temp[0], temp[1] |
screamer | 7:5af61d55adbe | 247 | # "class_name" must refer to a class in this file, so check if the class exists |
screamer | 7:5af61d55adbe | 248 | mdata = self.get_module_data() |
screamer | 7:5af61d55adbe | 249 | if not mdata.has_key(class_name) or not inspect.isclass(mdata[class_name]): |
screamer | 7:5af61d55adbe | 250 | raise HookError("Class '%s' required by '%s' in target '%s' not found in targets.py" % (class_name, hook_data["function"], self.name)) |
screamer | 7:5af61d55adbe | 251 | # "function_name" must refer to a static function inside class "class_name" |
screamer | 7:5af61d55adbe | 252 | cls = mdata[class_name] |
screamer | 7:5af61d55adbe | 253 | if (not hasattr(cls, function_name)) or (not inspect.isfunction(getattr(cls, function_name))): |
screamer | 7:5af61d55adbe | 254 | raise HookError("Static function '%s' required by '%s' in target '%s' not found in class '%s'" % (function_name, hook_data["function"], self.name, class_name)) |
screamer | 7:5af61d55adbe | 255 | # Check if the hook specification also has target restrictions |
screamer | 7:5af61d55adbe | 256 | toolchain_restrictions = hook_data.get("toolchains", []) |
screamer | 7:5af61d55adbe | 257 | if toolchain_restrictions and (toolchain_name not in toolchain_restrictions): |
screamer | 7:5af61d55adbe | 258 | return |
screamer | 7:5af61d55adbe | 259 | # Finally, hook the requested function |
screamer | 7:5af61d55adbe | 260 | hook.hook_add_binary("post", getattr(cls, function_name)) |
screamer | 0:66f3b5499f7f | 261 | |
screamer | 7:5af61d55adbe | 262 | ######################################################################################################################## |
screamer | 7:5af61d55adbe | 263 | # Target specific code goes in this section |
screamer | 7:5af61d55adbe | 264 | # This code can be invoked from the target description using the "post_binary_hook" key |
screamer | 0:66f3b5499f7f | 265 | |
screamer | 7:5af61d55adbe | 266 | class LPCTargetCode: |
screamer | 0:66f3b5499f7f | 267 | @staticmethod |
screamer | 0:66f3b5499f7f | 268 | def lpc_patch(t_self, resources, elf, binf): |
screamer | 0:66f3b5499f7f | 269 | t_self.debug("LPC Patch: %s" % os.path.split(binf)[1]) |
screamer | 0:66f3b5499f7f | 270 | patch(binf) |
screamer | 0:66f3b5499f7f | 271 | |
screamer | 7:5af61d55adbe | 272 | class LPC4088Code: |
screamer | 0:66f3b5499f7f | 273 | @staticmethod |
screamer | 0:66f3b5499f7f | 274 | def binary_hook(t_self, resources, elf, binf): |
screamer | 0:66f3b5499f7f | 275 | if not os.path.isdir(binf): |
screamer | 0:66f3b5499f7f | 276 | # Regular binary file, nothing to do |
screamer | 7:5af61d55adbe | 277 | LPCTargetCode.lpc_patch(t_self, resources, elf, binf) |
screamer | 0:66f3b5499f7f | 278 | return |
screamer | 0:66f3b5499f7f | 279 | outbin = open(binf + ".temp", "wb") |
screamer | 0:66f3b5499f7f | 280 | partf = open(os.path.join(binf, "ER_IROM1"), "rb") |
screamer | 0:66f3b5499f7f | 281 | # Pad the fist part (internal flash) with 0xFF to 512k |
screamer | 0:66f3b5499f7f | 282 | data = partf.read() |
screamer | 0:66f3b5499f7f | 283 | outbin.write(data) |
screamer | 0:66f3b5499f7f | 284 | outbin.write('\xFF' * (512*1024 - len(data))) |
screamer | 0:66f3b5499f7f | 285 | partf.close() |
screamer | 0:66f3b5499f7f | 286 | # Read and append the second part (external flash) in chunks of fixed size |
screamer | 0:66f3b5499f7f | 287 | chunksize = 128 * 1024 |
screamer | 0:66f3b5499f7f | 288 | partf = open(os.path.join(binf, "ER_IROM2"), "rb") |
screamer | 0:66f3b5499f7f | 289 | while True: |
screamer | 0:66f3b5499f7f | 290 | data = partf.read(chunksize) |
screamer | 0:66f3b5499f7f | 291 | outbin.write(data) |
screamer | 0:66f3b5499f7f | 292 | if len(data) < chunksize: |
screamer | 0:66f3b5499f7f | 293 | break |
screamer | 0:66f3b5499f7f | 294 | partf.close() |
screamer | 0:66f3b5499f7f | 295 | outbin.close() |
screamer | 0:66f3b5499f7f | 296 | # Remove the directory with the binary parts and rename the temporary |
screamer | 0:66f3b5499f7f | 297 | # file to 'binf' |
screamer | 0:66f3b5499f7f | 298 | shutil.rmtree(binf, True) |
screamer | 0:66f3b5499f7f | 299 | os.rename(binf + '.temp', binf) |
screamer | 0:66f3b5499f7f | 300 | t_self.debug("Generated custom binary file (internal flash + SPIFI)") |
screamer | 7:5af61d55adbe | 301 | LPCTargetCode.lpc_patch(t_self, resources, elf, binf) |
screamer | 0:66f3b5499f7f | 302 | |
screamer | 7:5af61d55adbe | 303 | class TEENSY3_1Code: |
screamer | 0:66f3b5499f7f | 304 | @staticmethod |
screamer | 0:66f3b5499f7f | 305 | def binary_hook(t_self, resources, elf, binf): |
screamer | 0:66f3b5499f7f | 306 | from intelhex import IntelHex |
screamer | 0:66f3b5499f7f | 307 | binh = IntelHex() |
screamer | 0:66f3b5499f7f | 308 | binh.loadbin(binf, offset = 0) |
screamer | 0:66f3b5499f7f | 309 | |
screamer | 0:66f3b5499f7f | 310 | with open(binf.replace(".bin", ".hex"), "w") as f: |
screamer | 0:66f3b5499f7f | 311 | binh.tofile(f, format='hex') |
screamer | 0:66f3b5499f7f | 312 | |
screamer | 7:5af61d55adbe | 313 | class MTSCode: |
screamer | 0:66f3b5499f7f | 314 | @staticmethod |
screamer | 7:5af61d55adbe | 315 | def _combine_bins_helper(target_name, t_self, resources, elf, binf): |
screamer | 7:5af61d55adbe | 316 | loader = os.path.join(TOOLS_BOOTLOADERS, target_name, "bootloader.bin") |
screamer | 0:66f3b5499f7f | 317 | target = binf + ".tmp" |
screamer | 0:66f3b5499f7f | 318 | if not os.path.exists(loader): |
screamer | 0:66f3b5499f7f | 319 | print "Can't find bootloader binary: " + loader |
screamer | 0:66f3b5499f7f | 320 | return |
screamer | 0:66f3b5499f7f | 321 | outbin = open(target, 'w+b') |
screamer | 0:66f3b5499f7f | 322 | part = open(loader, 'rb') |
screamer | 0:66f3b5499f7f | 323 | data = part.read() |
screamer | 0:66f3b5499f7f | 324 | outbin.write(data) |
screamer | 0:66f3b5499f7f | 325 | outbin.write('\xFF' * (64*1024 - len(data))) |
screamer | 0:66f3b5499f7f | 326 | part.close() |
screamer | 0:66f3b5499f7f | 327 | part = open(binf, 'rb') |
screamer | 0:66f3b5499f7f | 328 | data = part.read() |
screamer | 0:66f3b5499f7f | 329 | outbin.write(data) |
screamer | 0:66f3b5499f7f | 330 | part.close() |
screamer | 0:66f3b5499f7f | 331 | outbin.seek(0, 0) |
screamer | 0:66f3b5499f7f | 332 | data = outbin.read() |
screamer | 0:66f3b5499f7f | 333 | outbin.seek(0, 1) |
screamer | 0:66f3b5499f7f | 334 | crc = struct.pack('<I', binascii.crc32(data) & 0xFFFFFFFF) |
screamer | 0:66f3b5499f7f | 335 | outbin.write(crc) |
screamer | 0:66f3b5499f7f | 336 | outbin.close() |
screamer | 0:66f3b5499f7f | 337 | os.remove(binf) |
screamer | 0:66f3b5499f7f | 338 | os.rename(target, binf) |
screamer | 0:66f3b5499f7f | 339 | |
screamer | 0:66f3b5499f7f | 340 | @staticmethod |
screamer | 7:5af61d55adbe | 341 | def combine_bins_mts_dot(t_self, resources, elf, binf): |
screamer | 7:5af61d55adbe | 342 | MTSCode._combine_bins_helper("MTS_MDOT_F411RE", t_self, resources, elf, binf) |
screamer | 0:66f3b5499f7f | 343 | |
screamer | 7:5af61d55adbe | 344 | @staticmethod |
screamer | 7:5af61d55adbe | 345 | def combine_bins_mts_dragonfly(t_self, resources, elf, binf): |
screamer | 7:5af61d55adbe | 346 | MTSCode._combine_bins_helper("MTS_DRAGONFLY_F411RE", t_self, resources, elf, binf) |
screamer | 0:66f3b5499f7f | 347 | |
screamer | 7:5af61d55adbe | 348 | class MCU_NRF51Code: |
screamer | 0:66f3b5499f7f | 349 | @staticmethod |
screamer | 0:66f3b5499f7f | 350 | def binary_hook(t_self, resources, elf, binf): |
screamer | 0:66f3b5499f7f | 351 | |
screamer | 0:66f3b5499f7f | 352 | # Scan to find the actual paths of soft device |
screamer | 0:66f3b5499f7f | 353 | sdf = None |
screamer | 0:66f3b5499f7f | 354 | for softdeviceAndOffsetEntry in t_self.target.EXPECTED_SOFTDEVICES_WITH_OFFSETS: |
screamer | 0:66f3b5499f7f | 355 | for hexf in resources.hex_files: |
screamer | 0:66f3b5499f7f | 356 | if hexf.find(softdeviceAndOffsetEntry['name']) != -1: |
screamer | 0:66f3b5499f7f | 357 | t_self.debug("SoftDevice file found %s." % softdeviceAndOffsetEntry['name']) |
screamer | 0:66f3b5499f7f | 358 | sdf = hexf |
screamer | 0:66f3b5499f7f | 359 | |
screamer | 0:66f3b5499f7f | 360 | if sdf is not None: break |
screamer | 0:66f3b5499f7f | 361 | if sdf is not None: break |
screamer | 0:66f3b5499f7f | 362 | |
screamer | 0:66f3b5499f7f | 363 | if sdf is None: |
screamer | 0:66f3b5499f7f | 364 | t_self.debug("Hex file not found. Aborting.") |
screamer | 0:66f3b5499f7f | 365 | return |
screamer | 0:66f3b5499f7f | 366 | |
screamer | 0:66f3b5499f7f | 367 | # Look for bootloader file that matches this soft device or bootloader override image |
screamer | 0:66f3b5499f7f | 368 | blf = None |
screamer | 0:66f3b5499f7f | 369 | if t_self.target.MERGE_BOOTLOADER is True: |
screamer | 0:66f3b5499f7f | 370 | for hexf in resources.hex_files: |
screamer | 0:66f3b5499f7f | 371 | if hexf.find(t_self.target.OVERRIDE_BOOTLOADER_FILENAME) != -1: |
screamer | 0:66f3b5499f7f | 372 | t_self.debug("Bootloader file found %s." % t_self.target.OVERRIDE_BOOTLOADER_FILENAME) |
screamer | 0:66f3b5499f7f | 373 | blf = hexf |
screamer | 0:66f3b5499f7f | 374 | break |
screamer | 0:66f3b5499f7f | 375 | elif hexf.find(softdeviceAndOffsetEntry['boot']) != -1: |
screamer | 0:66f3b5499f7f | 376 | t_self.debug("Bootloader file found %s." % softdeviceAndOffsetEntry['boot']) |
screamer | 0:66f3b5499f7f | 377 | blf = hexf |
screamer | 0:66f3b5499f7f | 378 | break |
screamer | 0:66f3b5499f7f | 379 | |
screamer | 0:66f3b5499f7f | 380 | # Merge user code with softdevice |
screamer | 0:66f3b5499f7f | 381 | from intelhex import IntelHex |
screamer | 0:66f3b5499f7f | 382 | binh = IntelHex() |
screamer | 0:66f3b5499f7f | 383 | binh.loadbin(binf, offset=softdeviceAndOffsetEntry['offset']) |
screamer | 0:66f3b5499f7f | 384 | |
screamer | 0:66f3b5499f7f | 385 | if t_self.target.MERGE_SOFT_DEVICE is True: |
screamer | 0:66f3b5499f7f | 386 | t_self.debug("Merge SoftDevice file %s" % softdeviceAndOffsetEntry['name']) |
screamer | 0:66f3b5499f7f | 387 | sdh = IntelHex(sdf) |
screamer | 0:66f3b5499f7f | 388 | binh.merge(sdh) |
screamer | 0:66f3b5499f7f | 389 | |
screamer | 0:66f3b5499f7f | 390 | if t_self.target.MERGE_BOOTLOADER is True and blf is not None: |
screamer | 0:66f3b5499f7f | 391 | t_self.debug("Merge BootLoader file %s" % blf) |
screamer | 0:66f3b5499f7f | 392 | blh = IntelHex(blf) |
screamer | 0:66f3b5499f7f | 393 | binh.merge(blh) |
screamer | 0:66f3b5499f7f | 394 | |
screamer | 0:66f3b5499f7f | 395 | with open(binf.replace(".bin", ".hex"), "w") as f: |
screamer | 0:66f3b5499f7f | 396 | binh.tofile(f, format='hex') |
screamer | 0:66f3b5499f7f | 397 | |
screamer | 7:5af61d55adbe | 398 | ######################################################################################################################## |
screamer | 0:66f3b5499f7f | 399 | |
screamer | 7:5af61d55adbe | 400 | # Instantiate all public targets |
screamer | 7:5af61d55adbe | 401 | TARGETS = [Target.get_target(name) for name, value in Target.get_json_target_data().items() if value.get("public", True)] |
screamer | 0:66f3b5499f7f | 402 | |
screamer | 0:66f3b5499f7f | 403 | # Map each target name to its unique instance |
screamer | 7:5af61d55adbe | 404 | TARGET_MAP = dict([(t.name, t) for t in TARGETS]) |
screamer | 0:66f3b5499f7f | 405 | |
screamer | 0:66f3b5499f7f | 406 | TARGET_NAMES = TARGET_MAP.keys() |
screamer | 0:66f3b5499f7f | 407 | |
screamer | 0:66f3b5499f7f | 408 | # Some targets with different name have the same exporters |
screamer | 7:5af61d55adbe | 409 | EXPORT_MAP = {} |
screamer | 0:66f3b5499f7f | 410 | |
screamer | 0:66f3b5499f7f | 411 | # Detection APIs |
screamer | 0:66f3b5499f7f | 412 | def get_target_detect_codes(): |
screamer | 0:66f3b5499f7f | 413 | """ Returns dictionary mapping detect_code -> platform_name |
screamer | 0:66f3b5499f7f | 414 | """ |
screamer | 0:66f3b5499f7f | 415 | result = {} |
screamer | 0:66f3b5499f7f | 416 | for target in TARGETS: |
screamer | 0:66f3b5499f7f | 417 | for detect_code in target.detect_code: |
screamer | 0:66f3b5499f7f | 418 | result[detect_code] = target.name |
screamer | 0:66f3b5499f7f | 419 | return result |