mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			535 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			535 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
"""
 | 
						|
mbed SDK
 | 
						|
Copyright (c) 2011-2016 ARM Limited
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
"""
 | 
						|
 | 
						|
import os
 | 
						|
import binascii
 | 
						|
import struct
 | 
						|
import shutil
 | 
						|
import inspect
 | 
						|
import sys
 | 
						|
from collections import namedtuple
 | 
						|
from tools.patch import patch
 | 
						|
from tools.paths import TOOLS_BOOTLOADERS
 | 
						|
from tools.utils import json_file_to_dict
 | 
						|
 | 
						|
__all__ = ["target", "TARGETS", "TARGET_MAP", "TARGET_NAMES", "CORE_LABELS",
 | 
						|
           "HookError", "generate_py_target", "Target",
 | 
						|
           "CUMULATIVE_ATTRIBUTES", "get_resolution_order"]
 | 
						|
 | 
						|
CORE_LABELS = {
 | 
						|
    "ARM7TDMI-S": ["ARM7", "LIKE_CORTEX_ARM7"],
 | 
						|
    "Cortex-M0" : ["M0", "CORTEX_M", "LIKE_CORTEX_M0"],
 | 
						|
    "Cortex-M0+": ["M0P", "CORTEX_M", "LIKE_CORTEX_M0"],
 | 
						|
    "Cortex-M1" : ["M1", "CORTEX_M", "LIKE_CORTEX_M1"],
 | 
						|
    "Cortex-M3" : ["M3", "CORTEX_M", "LIKE_CORTEX_M3"],
 | 
						|
    "Cortex-M4" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"],
 | 
						|
    "Cortex-M4F" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"],
 | 
						|
    "Cortex-M7" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
 | 
						|
    "Cortex-M7F" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
 | 
						|
    "Cortex-M7FD" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
 | 
						|
    "Cortex-A9" : ["A9", "CORTEX_A", "LIKE_CORTEX_A9"]
 | 
						|
}
 | 
						|
 | 
						|
################################################################################
 | 
						|
# Generic Target class that reads and interprets the data in targets.json
 | 
						|
 | 
						|
class HookError(Exception):
 | 
						|
    """ A simple class that represents all the exceptions associated with
 | 
						|
    hooking
 | 
						|
    """
 | 
						|
    pass
 | 
						|
 | 
						|
CACHES = {}
 | 
						|
def cached(func):
 | 
						|
    """A simple decorator used for automatically caching data returned by a
 | 
						|
    function
 | 
						|
    """
 | 
						|
    def wrapper(*args, **kwargs):
 | 
						|
        """The wrapped function itself"""
 | 
						|
        if not CACHES.has_key((func.__name__, args)):
 | 
						|
            CACHES[(func.__name__, args)] = func(*args, **kwargs)
 | 
						|
        return CACHES[(func.__name__, args)]
 | 
						|
    return wrapper
 | 
						|
 | 
						|
 | 
						|
# Cumulative attributes can have values appended to them, so they
 | 
						|
# need to be computed differently than regular attributes
 | 
						|
CUMULATIVE_ATTRIBUTES = ['extra_labels', 'macros', 'device_has', 'features']
 | 
						|
 | 
						|
 | 
						|
def get_resolution_order(json_data, target_name, order, level=0):
 | 
						|
    """ Return the order in which target descriptions are searched for
 | 
						|
    attributes. This mimics the Python 2.2 method resolution order, which
 | 
						|
    is what the old targets.py module used. For more details, check
 | 
						|
    http://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path
 | 
						|
    The resolution order contains (name, level) tuples, where "name" is the
 | 
						|
    name of the class and "level" is the level in the inheritance hierarchy
 | 
						|
    (the target itself is at level 0, its first parent at level 1, its
 | 
						|
    parent's parent at level 2 and so on)
 | 
						|
    """
 | 
						|
    # the resolution order can't contain duplicate target names
 | 
						|
    if target_name not in [l[0] for l in order]:
 | 
						|
        order.append((target_name, level))
 | 
						|
    parents = json_data[target_name].get("inherits", [])
 | 
						|
    for par in parents:
 | 
						|
        order = get_resolution_order(json_data, par, order, level + 1)
 | 
						|
    return order
 | 
						|
 | 
						|
 | 
						|
def target(name, json_data):
 | 
						|
    """Construct a target object"""
 | 
						|
    resolution_order = get_resolution_order(json_data, name, [])
 | 
						|
    resolution_order_names = [tgt for tgt, _ in resolution_order]
 | 
						|
    return Target(name=name,
 | 
						|
                  json_data={key: value for key, value in json_data.items()
 | 
						|
                             if key in resolution_order_names},
 | 
						|
                  resolution_order=resolution_order,
 | 
						|
                  resolution_order_names=resolution_order_names)
 | 
						|
 | 
						|
def generate_py_target(new_targets, name):
 | 
						|
    """Add one or more new target(s) represented as a Python dictionary
 | 
						|
    in 'new_targets'. It is an error to add a target with a name that
 | 
						|
    already exists.
 | 
						|
    """
 | 
						|
    base_targets = Target.get_json_target_data()
 | 
						|
    for new_target in new_targets.keys():
 | 
						|
        if new_target in base_targets:
 | 
						|
            raise Exception("Attempt to add target '%s' that already exists"
 | 
						|
                            % new_target)
 | 
						|
    total_data = {}
 | 
						|
    total_data.update(new_targets)
 | 
						|
    total_data.update(base_targets)
 | 
						|
    return target(name, total_data)
 | 
						|
 | 
						|
class Target(namedtuple("Target", "name json_data resolution_order resolution_order_names")):
 | 
						|
    """An object to represent a Target (MCU/Board)"""
 | 
						|
 | 
						|
    # Default location of the 'targets.json' file
 | 
						|
    __targets_json_location_default = os.path.join(
 | 
						|
        os.path.dirname(os.path.abspath(__file__)), '..', 'targets', 'targets.json')
 | 
						|
 | 
						|
    # Current/new location of the 'targets.json' file
 | 
						|
    __targets_json_location = None
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    @cached
 | 
						|
    def get_json_target_data():
 | 
						|
        """Load the description of JSON target data"""
 | 
						|
        return json_file_to_dict(Target.__targets_json_location or
 | 
						|
                                 Target.__targets_json_location_default)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def set_targets_json_location(location=None):
 | 
						|
        """Set the location of the targets.json file"""
 | 
						|
        Target.__targets_json_location = (location or
 | 
						|
                                          Target.__targets_json_location_default)
 | 
						|
        # Invalidate caches, since the location of the JSON file changed
 | 
						|
        CACHES.clear()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    @cached
 | 
						|
    def get_module_data():
 | 
						|
        """Get the members of this module using Python's "inspect" module"""
 | 
						|
        return dict([(m[0], m[1]) for m in
 | 
						|
                     inspect.getmembers(sys.modules[__name__])])
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def __add_paths_to_progen(data):
 | 
						|
        """Modify the exporter specification ("progen") by changing all
 | 
						|
        "template" keys to full paths
 | 
						|
        """
 | 
						|
        out = {}
 | 
						|
        for key, val in data.items():
 | 
						|
            if isinstance(val, dict):
 | 
						|
                out[key] = Target.__add_paths_to_progen(val)
 | 
						|
            elif key == "template":
 | 
						|
                out[key] = [os.path.join(os.path.dirname(__file__), 'export', v)
 | 
						|
                            for v in val]
 | 
						|
            else:
 | 
						|
                out[key] = val
 | 
						|
        return out
 | 
						|
 | 
						|
    def __getattr_cumulative(self, attrname):
 | 
						|
        """Look for the attribute in the class and its parents, as defined by
 | 
						|
        the resolution order
 | 
						|
        """
 | 
						|
        tdata = self.json_data
 | 
						|
        # For a cumulative attribute, figure out when it was defined the
 | 
						|
        # last time (in attribute resolution order) then follow the "_add"
 | 
						|
        # and "_remove" data fields
 | 
						|
        for idx, tgt in enumerate(self.resolution_order):
 | 
						|
            # the attribute was defined at this level in the resolution
 | 
						|
            # order
 | 
						|
            if attrname in tdata[tgt[0]]:
 | 
						|
                def_idx = idx
 | 
						|
                break
 | 
						|
        else:
 | 
						|
            raise AttributeError("Attribute '%s' not found in target '%s'"
 | 
						|
                                 % (attrname, self.name))
 | 
						|
        # Get the starting value of the attribute
 | 
						|
        starting_value = (tdata[self.resolution_order[def_idx][0]][attrname]
 | 
						|
                          or [])[:]
 | 
						|
        # Traverse the resolution list in high inheritance to low
 | 
						|
        # inheritance level, left to right order to figure out all the
 | 
						|
        # other classes that change the definition by adding or removing
 | 
						|
        # elements
 | 
						|
        for idx in xrange(self.resolution_order[def_idx][1] - 1, -1, -1):
 | 
						|
            same_level_targets = [tar[0] for tar in self.resolution_order
 | 
						|
                                  if tar[1] == idx]
 | 
						|
            for tar in same_level_targets:
 | 
						|
                data = tdata[tar]
 | 
						|
                # Do we have anything to add ?
 | 
						|
                if data.has_key(attrname + "_add"):
 | 
						|
                    starting_value.extend(data[attrname + "_add"])
 | 
						|
                # Do we have anything to remove ?
 | 
						|
                if data.has_key(attrname + "_remove"):
 | 
						|
                    # Macros can be defined either without a value (MACRO)
 | 
						|
                    # or with a value (MACRO=10). When removing, we specify
 | 
						|
                    # only the name of the macro, without the value. So we
 | 
						|
                    # need to create a mapping between the macro name and
 | 
						|
                    # its value. This will work for extra_labels and other
 | 
						|
                    # type of arrays as well, since they fall into the
 | 
						|
                    # "macros without a value" category (simple definitions
 | 
						|
                    # without a value).
 | 
						|
                    name_def_map = {}
 | 
						|
                    for crtv in starting_value:
 | 
						|
                        if crtv.find('=') != -1:
 | 
						|
                            temp = crtv.split('=')
 | 
						|
                            if len(temp) != 2:
 | 
						|
                                raise ValueError(
 | 
						|
                                    "Invalid macro definition '%s'" % crtv)
 | 
						|
                            name_def_map[temp[0]] = crtv
 | 
						|
                        else:
 | 
						|
                            name_def_map[crtv] = crtv
 | 
						|
                    for element in data[attrname + "_remove"]:
 | 
						|
                        if element not in name_def_map:
 | 
						|
                            raise ValueError(
 | 
						|
                                ("Unable to remove '%s' in '%s.%s' since "
 | 
						|
                                 % (element, self.name, attrname)) +
 | 
						|
                                "it doesn't exist")
 | 
						|
                        starting_value.remove(name_def_map[element])
 | 
						|
        return starting_value
 | 
						|
 | 
						|
    def __getattr_helper(self, attrname):
 | 
						|
        """Compute the value of a given target attribute"""
 | 
						|
        if attrname in CUMULATIVE_ATTRIBUTES:
 | 
						|
            return self.__getattr_cumulative(attrname)
 | 
						|
        else:
 | 
						|
            tdata = self.json_data
 | 
						|
            starting_value = None
 | 
						|
            for tgt in self.resolution_order:
 | 
						|
                data = tdata[tgt[0]]
 | 
						|
                if data.has_key(attrname):
 | 
						|
                    starting_value = data[attrname]
 | 
						|
                    break
 | 
						|
            else: # Attribute not found
 | 
						|
                raise AttributeError(
 | 
						|
                    "Attribute '%s' not found in target '%s'"
 | 
						|
                    % (attrname, self.name))
 | 
						|
            # 'progen' needs the full path to the template (the path in JSON is
 | 
						|
            # relative to tools/export)
 | 
						|
            if attrname == "progen":
 | 
						|
                return self.__add_paths_to_progen(starting_value)
 | 
						|
            else:
 | 
						|
                return starting_value
 | 
						|
 | 
						|
    def __getattr__(self, attrname):
 | 
						|
        """ Return the value of an attribute. This function only computes the
 | 
						|
        attribute's value once, then adds it to the instance attributes (in
 | 
						|
        __dict__), so the next time it is returned directly
 | 
						|
        """
 | 
						|
        result = self.__getattr_helper(attrname)
 | 
						|
        self.__dict__[attrname] = result
 | 
						|
        return result
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    @cached
 | 
						|
    def get_target(target_name):
 | 
						|
        """ Return the target instance starting from the target name """
 | 
						|
        return target(target_name, Target.get_json_target_data())
 | 
						|
 | 
						|
 | 
						|
    @property
 | 
						|
    def program_cycle_s(self):
 | 
						|
        """Special override for program_cycle_s as it's default value depends
 | 
						|
        upon is_disk_virtual
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            return self.__getattr__("program_cycle_s")
 | 
						|
        except AttributeError:
 | 
						|
            return 4 if self.is_disk_virtual else 1.5
 | 
						|
 | 
						|
    @property
 | 
						|
    def labels(self):
 | 
						|
        """Get all possible labels for this target"""
 | 
						|
        labels = [self.name] + CORE_LABELS[self.core] + self.extra_labels
 | 
						|
        # Automatically define UVISOR_UNSUPPORTED if the target doesn't
 | 
						|
        # specifically define UVISOR_SUPPORTED
 | 
						|
        if "UVISOR_SUPPORTED" not in labels:
 | 
						|
            labels.append("UVISOR_UNSUPPORTED")
 | 
						|
        return labels
 | 
						|
 | 
						|
    def init_hooks(self, hook, toolchain_name):
 | 
						|
        """Initialize the post-build hooks for a toolchain. For now, this
 | 
						|
        function only allows "post binary" hooks (hooks that are executed
 | 
						|
        after the binary image is extracted from the executable file)
 | 
						|
        """
 | 
						|
 | 
						|
        # If there's no hook, simply return
 | 
						|
        try:
 | 
						|
            hook_data = self.post_binary_hook
 | 
						|
        except AttributeError:
 | 
						|
            return
 | 
						|
        # A hook was found. The hook's name is in the format
 | 
						|
        # "classname.functionname"
 | 
						|
        temp = hook_data["function"].split(".")
 | 
						|
        if len(temp) != 2:
 | 
						|
            raise HookError(
 | 
						|
                ("Invalid format for hook '%s' in target '%s'"
 | 
						|
                 % (hook_data["function"], self.name)) +
 | 
						|
                " (must be 'class_name.function_name')")
 | 
						|
        class_name, function_name = temp[0], temp[1]
 | 
						|
        # "class_name" must refer to a class in this file, so check if the
 | 
						|
        # class exists
 | 
						|
        mdata = self.get_module_data()
 | 
						|
        if not mdata.has_key(class_name) or \
 | 
						|
           not inspect.isclass(mdata[class_name]):
 | 
						|
            raise HookError(
 | 
						|
                ("Class '%s' required by '%s' in target '%s'"
 | 
						|
                 % (class_name, hook_data["function"], self.name)) +
 | 
						|
                " not found in targets.py")
 | 
						|
        # "function_name" must refer to a static function inside class
 | 
						|
        # "class_name"
 | 
						|
        cls = mdata[class_name]
 | 
						|
        if (not hasattr(cls, function_name)) or \
 | 
						|
           (not inspect.isfunction(getattr(cls, function_name))):
 | 
						|
            raise HookError(
 | 
						|
                ("Static function '%s' " % function_name) +
 | 
						|
                ("required by '%s' " % hook_data["function"]) +
 | 
						|
                ("in target '%s' " % self.name) +
 | 
						|
                ("not found in class '%s'" %  class_name))
 | 
						|
        # Check if the hook specification also has target restrictions
 | 
						|
        toolchain_restrictions = hook_data.get("toolchains", [])
 | 
						|
        if toolchain_restrictions and \
 | 
						|
           (toolchain_name not in toolchain_restrictions):
 | 
						|
            return
 | 
						|
        # Finally, hook the requested function
 | 
						|
        hook.hook_add_binary("post", getattr(cls, function_name))
 | 
						|
 | 
						|
################################################################################
 | 
						|
# Target specific code goes in this section
 | 
						|
# This code can be invoked from the target description using the
 | 
						|
# "post_binary_hook" key
 | 
						|
 | 
						|
class LPCTargetCode(object):
 | 
						|
    """General LPC Target patching code"""
 | 
						|
    @staticmethod
 | 
						|
    def lpc_patch(t_self, resources, elf, binf):
 | 
						|
        """Patch an elf file"""
 | 
						|
        t_self.debug("LPC Patch: %s" % os.path.split(binf)[1])
 | 
						|
        patch(binf)
 | 
						|
 | 
						|
class LPC4088Code(object):
 | 
						|
    """Code specific to the LPC4088"""
 | 
						|
    @staticmethod
 | 
						|
    def binary_hook(t_self, resources, elf, binf):
 | 
						|
        """Hook to be run after an elf file is built"""
 | 
						|
        if not os.path.isdir(binf):
 | 
						|
            # Regular binary file, nothing to do
 | 
						|
            LPCTargetCode.lpc_patch(t_self, resources, elf, binf)
 | 
						|
            return
 | 
						|
        outbin = open(binf + ".temp", "wb")
 | 
						|
        partf = open(os.path.join(binf, "ER_IROM1"), "rb")
 | 
						|
        # Pad the fist part (internal flash) with 0xFF to 512k
 | 
						|
        data = partf.read()
 | 
						|
        outbin.write(data)
 | 
						|
        outbin.write('\xFF' * (512*1024 - len(data)))
 | 
						|
        partf.close()
 | 
						|
        # Read and append the second part (external flash) in chunks of fixed
 | 
						|
        # size
 | 
						|
        chunksize = 128 * 1024
 | 
						|
        partf = open(os.path.join(binf, "ER_IROM2"), "rb")
 | 
						|
        while True:
 | 
						|
            data = partf.read(chunksize)
 | 
						|
            outbin.write(data)
 | 
						|
            if len(data) < chunksize:
 | 
						|
                break
 | 
						|
        partf.close()
 | 
						|
        outbin.close()
 | 
						|
        # Remove the directory with the binary parts and rename the temporary
 | 
						|
        # file to 'binf'
 | 
						|
        shutil.rmtree(binf, True)
 | 
						|
        os.rename(binf + '.temp', binf)
 | 
						|
        t_self.debug("Generated custom binary file (internal flash + SPIFI)")
 | 
						|
        LPCTargetCode.lpc_patch(t_self, resources, elf, binf)
 | 
						|
 | 
						|
class TEENSY3_1Code(object):
 | 
						|
    """Hooks for the TEENSY3.1"""
 | 
						|
    @staticmethod
 | 
						|
    def binary_hook(t_self, resources, elf, binf):
 | 
						|
        """Hook that is run after elf is generated"""
 | 
						|
        from intelhex import IntelHex
 | 
						|
        binh = IntelHex()
 | 
						|
        binh.loadbin(binf, offset=0)
 | 
						|
 | 
						|
        with open(binf.replace(".bin", ".hex"), "w") as file_desc:
 | 
						|
            binh.tofile(file_desc, format='hex')
 | 
						|
 | 
						|
class MTSCode(object):
 | 
						|
    """Generic MTS code"""
 | 
						|
    @staticmethod
 | 
						|
    def _combine_bins_helper(target_name, binf):
 | 
						|
        """combine bins with the bootloader for a particular target"""
 | 
						|
        loader = os.path.join(TOOLS_BOOTLOADERS, target_name, "bootloader.bin")
 | 
						|
        target = binf + ".tmp"
 | 
						|
        if not os.path.exists(loader):
 | 
						|
            print "Can't find bootloader binary: " + loader
 | 
						|
            return
 | 
						|
        outbin = open(target, 'w+b')
 | 
						|
        part = open(loader, 'rb')
 | 
						|
        data = part.read()
 | 
						|
        outbin.write(data)
 | 
						|
        outbin.write('\xFF' * (64*1024 - len(data)))
 | 
						|
        part.close()
 | 
						|
        part = open(binf, 'rb')
 | 
						|
        data = part.read()
 | 
						|
        outbin.write(data)
 | 
						|
        part.close()
 | 
						|
        outbin.seek(0, 0)
 | 
						|
        data = outbin.read()
 | 
						|
        outbin.seek(0, 1)
 | 
						|
        crc = struct.pack('<I', binascii.crc32(data) & 0xFFFFFFFF)
 | 
						|
        outbin.write(crc)
 | 
						|
        outbin.close()
 | 
						|
        os.remove(binf)
 | 
						|
        os.rename(target, binf)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def combine_bins_mts_dot(t_self, resources, elf, binf):
 | 
						|
        """A hook for the MTS MDOT"""
 | 
						|
        MTSCode._combine_bins_helper("MTS_MDOT_F411RE", binf)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def combine_bins_mts_dragonfly(t_self, resources, elf, binf):
 | 
						|
        """A hoof for the MTS Dragonfly"""
 | 
						|
        MTSCode._combine_bins_helper("MTS_DRAGONFLY_F411RE", binf)
 | 
						|
 | 
						|
class MCU_NRF51Code(object):
 | 
						|
    """NRF51 Hooks"""
 | 
						|
    @staticmethod
 | 
						|
    def binary_hook(t_self, resources, _, binf):
 | 
						|
        """Hook that merges the soft device with the bin file"""
 | 
						|
        # Scan to find the actual paths of soft device
 | 
						|
        sdf = None
 | 
						|
        for softdevice_and_offset_entry\
 | 
						|
            in t_self.target.EXPECTED_SOFTDEVICES_WITH_OFFSETS:
 | 
						|
            for hexf in resources.hex_files:
 | 
						|
                if hexf.find(softdevice_and_offset_entry['name']) != -1:
 | 
						|
                    t_self.debug("SoftDevice file found %s."
 | 
						|
                                 % softdevice_and_offset_entry['name'])
 | 
						|
                    sdf = hexf
 | 
						|
 | 
						|
                if sdf is not None:
 | 
						|
                    break
 | 
						|
            if sdf is not None:
 | 
						|
                break
 | 
						|
 | 
						|
        if sdf is None:
 | 
						|
            t_self.debug("Hex file not found. Aborting.")
 | 
						|
            return
 | 
						|
 | 
						|
        # Look for bootloader file that matches this soft device or bootloader
 | 
						|
        # override image
 | 
						|
        blf = None
 | 
						|
        if t_self.target.MERGE_BOOTLOADER is True:
 | 
						|
            for hexf in resources.hex_files:
 | 
						|
                if hexf.find(t_self.target.OVERRIDE_BOOTLOADER_FILENAME) != -1:
 | 
						|
                    t_self.debug("Bootloader file found %s."
 | 
						|
                                 % t_self.target.OVERRIDE_BOOTLOADER_FILENAME)
 | 
						|
                    blf = hexf
 | 
						|
                    break
 | 
						|
                elif hexf.find(softdevice_and_offset_entry['boot']) != -1:
 | 
						|
                    t_self.debug("Bootloader file found %s."
 | 
						|
                                 % softdevice_and_offset_entry['boot'])
 | 
						|
                    blf = hexf
 | 
						|
                    break
 | 
						|
 | 
						|
        # Merge user code with softdevice
 | 
						|
        from intelhex import IntelHex
 | 
						|
        binh = IntelHex()
 | 
						|
        binh.loadbin(binf, offset=softdevice_and_offset_entry['offset'])
 | 
						|
 | 
						|
        if t_self.target.MERGE_SOFT_DEVICE is True:
 | 
						|
            t_self.debug("Merge SoftDevice file %s"
 | 
						|
                         % softdevice_and_offset_entry['name'])
 | 
						|
            sdh = IntelHex(sdf)
 | 
						|
            binh.merge(sdh)
 | 
						|
 | 
						|
        if t_self.target.MERGE_BOOTLOADER is True and blf is not None:
 | 
						|
            t_self.debug("Merge BootLoader file %s" % blf)
 | 
						|
            blh = IntelHex(blf)
 | 
						|
            binh.merge(blh)
 | 
						|
 | 
						|
        with open(binf.replace(".bin", ".hex"), "w") as fileout:
 | 
						|
            binh.tofile(fileout, format='hex')
 | 
						|
 | 
						|
class NCS36510TargetCode:
 | 
						|
    @staticmethod
 | 
						|
    def ncs36510_addfib(t_self, resources, elf, binf):
 | 
						|
        from tools.add_fib import add_fib_at_start
 | 
						|
        print("binf ", binf)
 | 
						|
        add_fib_at_start(binf[:-4])
 | 
						|
################################################################################
 | 
						|
 | 
						|
# Instantiate all public targets
 | 
						|
TARGETS = [Target.get_target(name) for name, value
 | 
						|
           in Target.get_json_target_data().items()
 | 
						|
           if value.get("public", True)]
 | 
						|
 | 
						|
# Map each target name to its unique instance
 | 
						|
TARGET_MAP = dict([(t.name, t) for t in TARGETS])
 | 
						|
 | 
						|
TARGET_NAMES = TARGET_MAP.keys()
 | 
						|
 | 
						|
# Some targets with different name have the same exporters
 | 
						|
EXPORT_MAP = {}
 | 
						|
 | 
						|
# Detection APIs
 | 
						|
def get_target_detect_codes():
 | 
						|
    """ Returns dictionary mapping detect_code -> platform_name
 | 
						|
    """
 | 
						|
    result = {}
 | 
						|
    for tgt in TARGETS:
 | 
						|
        for detect_code in tgt.detect_code:
 | 
						|
            result[detect_code] = tgt.name
 | 
						|
    return result
 | 
						|
 | 
						|
def set_targets_json_location(location=None):
 | 
						|
    """Sets the location of the JSON file that contains the targets"""
 | 
						|
    # First instruct Target about the new location
 | 
						|
    Target.set_targets_json_location(location)
 | 
						|
    # Then re-initialize TARGETS, TARGET_MAP and TARGET_NAMES. The
 | 
						|
    # re-initialization does not create new variables, it keeps the old ones
 | 
						|
    # instead. This ensures compatibility with code that does
 | 
						|
    # "from tools.targets import TARGET_NAMES"
 | 
						|
    TARGETS[:] = [Target.get_target(tgt) for tgt, obj
 | 
						|
                  in Target.get_json_target_data().items()
 | 
						|
                  if obj.get("public", True)]
 | 
						|
    TARGET_MAP.clear()
 | 
						|
    TARGET_MAP.update(dict([(tgt.name, tgt) for tgt in TARGETS]))
 | 
						|
    TARGET_NAMES[:] = TARGET_MAP.keys()
 |