Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
__init__.py
00001 """ 00002 mbed SDK 00003 Copyright (c) 2011-2016 ARM Limited 00004 00005 Licensed under the Apache License, Version 2.0 (the "License"); 00006 you may not use this file except in compliance with the License. 00007 You may obtain a copy of the License at 00008 00009 http://www.apache.org/licenses/LICENSE-2.0 00010 00011 Unless required by applicable law or agreed to in writing, software 00012 distributed under the License is distributed on an "AS IS" BASIS, 00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 See the License for the specific language governing permissions and 00015 limitations under the License. 00016 """ 00017 00018 import os 00019 import binascii 00020 import struct 00021 import shutil 00022 import inspect 00023 import sys 00024 from copy import copy 00025 from inspect import getmro 00026 from collections import namedtuple, Mapping 00027 from tools.targets.LPC import patch 00028 from tools.paths import TOOLS_BOOTLOADERS 00029 from tools.utils import json_file_to_dict 00030 00031 __all__ = ["target", "TARGETS", "TARGET_MAP", "TARGET_NAMES", "CORE_LABELS", 00032 "HookError", "generate_py_target", "Target", 00033 "CUMULATIVE_ATTRIBUTES", "get_resolution_order"] 00034 00035 CORE_LABELS = { 00036 "Cortex-M0" : ["M0", "CORTEX_M", "LIKE_CORTEX_M0", "CORTEX"], 00037 "Cortex-M0+": ["M0P", "CORTEX_M", "LIKE_CORTEX_M0", "CORTEX"], 00038 "Cortex-M1" : ["M1", "CORTEX_M", "LIKE_CORTEX_M1", "CORTEX"], 00039 "Cortex-M3" : ["M3", "CORTEX_M", "LIKE_CORTEX_M3", "CORTEX"], 00040 "Cortex-M4" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4", "CORTEX"], 00041 "Cortex-M4F" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4", "CORTEX"], 00042 "Cortex-M7" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7", "CORTEX"], 00043 "Cortex-M7F" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7", "CORTEX"], 00044 "Cortex-M7FD" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7", "CORTEX"], 00045 "Cortex-A9" : ["A9", "CORTEX_A", "LIKE_CORTEX_A9", "CORTEX"], 00046 "Cortex-M23": ["M23", "CORTEX_M", "LIKE_CORTEX_M23", "CORTEX"], 00047 "Cortex-M23-NS": ["M23", "CORTEX_M", "LIKE_CORTEX_M23", "CORTEX"], 00048 "Cortex-M33": ["M33", "CORTEX_M", "LIKE_CORTEX_M33", "CORTEX"], 00049 "Cortex-M33-NS": ["M33", "CORTEX_M", "LIKE_CORTEX_M33", "CORTEX"] 00050 } 00051 00052 ################################################################################ 00053 # Generic Target class that reads and interprets the data in targets.json 00054 00055 class HookError(Exception): 00056 """ A simple class that represents all the exceptions associated with 00057 hooking 00058 """ 00059 pass 00060 00061 CACHES = {} 00062 def cached (func): 00063 """A simple decorator used for automatically caching data returned by a 00064 function 00065 """ 00066 def wrapper(*args, **kwargs): 00067 """The wrapped function itself""" 00068 if not CACHES.has_key((func.__name__, args)): 00069 CACHES[(func.__name__, args)] = func(*args, **kwargs) 00070 return CACHES[(func.__name__, args)] 00071 return wrapper 00072 00073 00074 # Cumulative attributes can have values appended to them, so they 00075 # need to be computed differently than regular attributes 00076 CUMULATIVE_ATTRIBUTES = ['extra_labels', 'macros', 'device_has', 'features'] 00077 00078 00079 def get_resolution_order (json_data, target_name, order, level=0): 00080 """ Return the order in which target descriptions are searched for 00081 attributes. This mimics the Python 2.2 method resolution order, which 00082 is what the old targets.py module used. For more details, check 00083 http://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path 00084 The resolution order contains (name, level) tuples, where "name" is the 00085 name of the class and "level" is the level in the inheritance hierarchy 00086 (the target itself is at level 0, its first parent at level 1, its 00087 parent's parent at level 2 and so on) 00088 """ 00089 # the resolution order can't contain duplicate target names 00090 if target_name not in [l[0] for l in order]: 00091 order.append((target_name, level)) 00092 parents = json_data[target_name].get("inherits", []) 00093 for par in parents: 00094 order = get_resolution_order(json_data, par, order, level + 1) 00095 return order 00096 00097 00098 def target (name, json_data): 00099 """Construct a target object""" 00100 resolution_order = get_resolution_order(json_data, name, []) 00101 resolution_order_names = [tgt for tgt, _ in resolution_order] 00102 return Target(name=name, 00103 json_data={key: value for key, value in json_data.items() 00104 if key in resolution_order_names}, 00105 resolution_order=resolution_order, 00106 resolution_order_names=resolution_order_names) 00107 00108 def generate_py_target (new_targets, name): 00109 """Add one or more new target(s) represented as a Python dictionary 00110 in 'new_targets'. It is an error to add a target with a name that 00111 already exists. 00112 """ 00113 base_targets = Target.get_json_target_data() 00114 for new_target in new_targets.keys(): 00115 if new_target in base_targets: 00116 raise Exception("Attempt to add target '%s' that already exists" 00117 % new_target) 00118 total_data = {} 00119 total_data.update(new_targets) 00120 total_data.update(base_targets) 00121 return target(name, total_data) 00122 00123 class Target (namedtuple("Target", "name json_data resolution_order resolution_order_names")): 00124 """An object to represent a Target (MCU/Board)""" 00125 00126 # Default location of the 'targets.json' file 00127 __targets_json_location_default = os.path.join( 00128 os.path.dirname(os.path.abspath(__file__)), '..', '..', 'targets', 'targets.json') 00129 00130 # Current/new location of the 'targets.json' file 00131 __targets_json_location = None 00132 00133 # Extra custom targets files 00134 __extra_target_json_files = [] 00135 00136 @staticmethod 00137 @cached 00138 def get_json_target_data (): 00139 """Load the description of JSON target data""" 00140 targets = json_file_to_dict(Target.__targets_json_location or 00141 Target.__targets_json_location_default) 00142 00143 for extra_target in Target.__extra_target_json_files: 00144 for k, v in json_file_to_dict(extra_target).iteritems(): 00145 if k in targets: 00146 print 'WARNING: Custom target "%s" cannot replace existing target.' % k 00147 else: 00148 targets[k] = v 00149 00150 return targets 00151 00152 @staticmethod 00153 def add_extra_targets(source_dir): 00154 extra_targets_file = os.path.join(source_dir, "custom_targets.json") 00155 if os.path.exists(extra_targets_file): 00156 Target.__extra_target_json_files.append(extra_targets_file) 00157 CACHES.clear() 00158 00159 @staticmethod 00160 def set_targets_json_location (location=None): 00161 """Set the location of the targets.json file""" 00162 Target.__targets_json_location = (location or 00163 Target.__targets_json_location_default) 00164 Target.__extra_target_json_files = [] 00165 # Invalidate caches, since the location of the JSON file changed 00166 CACHES.clear() 00167 00168 @staticmethod 00169 @cached 00170 def get_module_data (): 00171 """Get the members of this module using Python's "inspect" module""" 00172 return dict([(m[0], m[1]) for m in 00173 inspect.getmembers(sys.modules[__name__])]) 00174 00175 @staticmethod 00176 def __add_paths_to_progen(data): 00177 """Modify the exporter specification ("progen") by changing all 00178 "template" keys to full paths 00179 """ 00180 out = {} 00181 for key, val in data.items(): 00182 if isinstance(val, dict): 00183 out[key] = Target.__add_paths_to_progen(val) 00184 elif key == "template": 00185 out[key] = [os.path.join(os.path.dirname(__file__), 'export', v) 00186 for v in val] 00187 else: 00188 out[key] = val 00189 return out 00190 00191 def __getattr_cumulative(self, attrname): 00192 """Look for the attribute in the class and its parents, as defined by 00193 the resolution order 00194 """ 00195 tdata = self.json_data 00196 # For a cumulative attribute, figure out when it was defined the 00197 # last time (in attribute resolution order) then follow the "_add" 00198 # and "_remove" data fields 00199 for idx, tgt in enumerate(self.resolution_order): 00200 # the attribute was defined at this level in the resolution 00201 # order 00202 if attrname in tdata[tgt[0]]: 00203 def_idx = idx 00204 break 00205 else: 00206 raise AttributeError("Attribute '%s' not found in target '%s'" 00207 % (attrname, self.name)) 00208 # Get the starting value of the attribute 00209 starting_value = (tdata[self.resolution_order[def_idx][0]][attrname] 00210 or [])[:] 00211 # Traverse the resolution list in high inheritance to low 00212 # inheritance level, left to right order to figure out all the 00213 # other classes that change the definition by adding or removing 00214 # elements 00215 for idx in xrange(self.resolution_order[def_idx][1] - 1, -1, -1): 00216 same_level_targets = [tar[0] for tar in self.resolution_order 00217 if tar[1] == idx] 00218 for tar in same_level_targets: 00219 data = tdata[tar] 00220 # Do we have anything to add ? 00221 if data.has_key(attrname + "_add"): 00222 starting_value.extend(data[attrname + "_add"]) 00223 # Do we have anything to remove ? 00224 if data.has_key(attrname + "_remove"): 00225 # Macros can be defined either without a value (MACRO) 00226 # or with a value (MACRO=10). When removing, we specify 00227 # only the name of the macro, without the value. So we 00228 # need to create a mapping between the macro name and 00229 # its value. This will work for extra_labels and other 00230 # type of arrays as well, since they fall into the 00231 # "macros without a value" category (simple definitions 00232 # without a value). 00233 name_def_map = {} 00234 for crtv in starting_value: 00235 if crtv.find('=') != -1: 00236 temp = crtv.split('=') 00237 if len(temp) != 2: 00238 raise ValueError( 00239 "Invalid macro definition '%s'" % crtv) 00240 name_def_map[temp[0]] = crtv 00241 else: 00242 name_def_map[crtv] = crtv 00243 for element in data[attrname + "_remove"]: 00244 if element not in name_def_map: 00245 raise ValueError( 00246 ("Unable to remove '%s' in '%s.%s' since " 00247 % (element, self.name, attrname)) + 00248 "it doesn't exist") 00249 starting_value.remove(name_def_map[element]) 00250 return starting_value 00251 00252 def __getattr_helper(self, attrname): 00253 """Compute the value of a given target attribute""" 00254 if attrname in CUMULATIVE_ATTRIBUTES: 00255 return self.__getattr_cumulative (attrname) 00256 else: 00257 tdata = self.json_data 00258 starting_value = None 00259 for tgt in self.resolution_order: 00260 data = tdata[tgt[0]] 00261 if data.has_key(attrname): 00262 starting_value = data[attrname] 00263 break 00264 else: # Attribute not found 00265 raise AttributeError( 00266 "Attribute '%s' not found in target '%s'" 00267 % (attrname, self.name)) 00268 # 'progen' needs the full path to the template (the path in JSON is 00269 # relative to tools/export) 00270 if attrname == "progen": 00271 return self.__add_paths_to_progen (starting_value) 00272 else: 00273 return starting_value 00274 00275 def __getattr__ (self, attrname): 00276 """ Return the value of an attribute. This function only computes the 00277 attribute's value once, then adds it to the instance attributes (in 00278 __dict__), so the next time it is returned directly 00279 """ 00280 result = self.__getattr_helper (attrname) 00281 self.__dict__[attrname] = result 00282 return result 00283 00284 @staticmethod 00285 @cached 00286 def get_target (target_name): 00287 """ Return the target instance starting from the target name """ 00288 return target(target_name, Target.get_json_target_data()) 00289 00290 00291 @property 00292 def program_cycle_s (self): 00293 """Special override for program_cycle_s as it's default value depends 00294 upon is_disk_virtual 00295 """ 00296 try: 00297 return self.__getattr__ ("program_cycle_s") 00298 except AttributeError: 00299 return 4 if self.is_disk_virtual else 1.5 00300 00301 @property 00302 def labels (self): 00303 """Get all possible labels for this target""" 00304 names = copy(self.resolution_order_names) 00305 if "Target" in names: 00306 names.remove("Target") 00307 labels = (names + CORE_LABELS[self.core] + self.extra_labels) 00308 # Automatically define UVISOR_UNSUPPORTED if the target doesn't 00309 # specifically define UVISOR_SUPPORTED 00310 if "UVISOR_SUPPORTED" not in labels: 00311 labels.append("UVISOR_UNSUPPORTED") 00312 return labels 00313 00314 def init_hooks (self, hook, toolchain): 00315 """Initialize the post-build hooks for a toolchain. For now, this 00316 function only allows "post binary" hooks (hooks that are executed 00317 after the binary image is extracted from the executable file) 00318 00319 Positional Arguments: 00320 hook - the hook object to add post-binary-hooks to 00321 toolchain - the toolchain object for inspection 00322 """ 00323 00324 # If there's no hook, simply return 00325 try: 00326 hook_data = self.post_binary_hook 00327 except AttributeError: 00328 return 00329 # A hook was found. The hook's name is in the format 00330 # "classname.functionname" 00331 temp = hook_data["function"].split(".") 00332 if len(temp) != 2: 00333 raise HookError( 00334 ("Invalid format for hook '%s' in target '%s'" 00335 % (hook_data["function"], self.name)) + 00336 " (must be 'class_name.function_name')") 00337 class_name, function_name = temp 00338 # "class_name" must refer to a class in this file, so check if the 00339 # class exists 00340 mdata = self.get_module_data () 00341 if not mdata.has_key(class_name) or \ 00342 not inspect.isclass(mdata[class_name]): 00343 raise HookError( 00344 ("Class '%s' required by '%s' in target '%s'" 00345 % (class_name, hook_data["function"], self.name)) + 00346 " not found in targets.py") 00347 # "function_name" must refer to a static function inside class 00348 # "class_name" 00349 cls = mdata[class_name] 00350 if (not hasattr(cls, function_name)) or \ 00351 (not inspect.isfunction(getattr(cls, function_name))): 00352 raise HookError( 00353 ("Static function '%s' " % function_name) + 00354 ("required by '%s' " % hook_data["function"]) + 00355 ("in target '%s' " % self.name) + 00356 ("not found in class '%s'" % class_name)) 00357 # Check if the hook specification also has toolchain restrictions 00358 toolchain_restrictions = set(hook_data.get("toolchains", [])) 00359 toolchain_labels = set(c.__name__ for c in getmro(toolchain.__class__)) 00360 if toolchain_restrictions and \ 00361 not toolchain_labels.intersection(toolchain_restrictions): 00362 return 00363 # Finally, hook the requested function 00364 hook.hook_add_binary("post", getattr(cls, function_name)) 00365 00366 ################################################################################ 00367 # Target specific code goes in this section 00368 # This code can be invoked from the target description using the 00369 # "post_binary_hook" key 00370 00371 class LPCTargetCode (object): 00372 """General LPC Target patching code""" 00373 @staticmethod 00374 def lpc_patch (t_self, resources, elf, binf): 00375 """Patch an elf file""" 00376 t_self.debug("LPC Patch: %s" % os.path.split(binf)[1]) 00377 patch(binf) 00378 00379 class LPC4088Code (object): 00380 """Code specific to the LPC4088""" 00381 @staticmethod 00382 def binary_hook (t_self, resources, elf, binf): 00383 """Hook to be run after an elf file is built""" 00384 if not os.path.isdir(binf): 00385 # Regular binary file, nothing to do 00386 LPCTargetCode.lpc_patch(t_self, resources, elf, binf) 00387 return 00388 outbin = open(binf + ".temp", "wb") 00389 partf = open(os.path.join(binf, "ER_IROM1"), "rb") 00390 # Pad the fist part (internal flash) with 0xFF to 512k 00391 data = partf.read() 00392 outbin.write(data) 00393 outbin.write('\xFF' * (512*1024 - len(data))) 00394 partf.close() 00395 # Read and append the second part (external flash) in chunks of fixed 00396 # size 00397 chunksize = 128 * 1024 00398 partf = open(os.path.join(binf, "ER_IROM2"), "rb") 00399 while True: 00400 data = partf.read(chunksize) 00401 outbin.write(data) 00402 if len(data) < chunksize: 00403 break 00404 partf.close() 00405 outbin.close() 00406 # Remove the directory with the binary parts and rename the temporary 00407 # file to 'binf' 00408 shutil.rmtree(binf, True) 00409 os.rename(binf + '.temp', binf) 00410 t_self.debug("Generated custom binary file (internal flash + SPIFI)") 00411 LPCTargetCode.lpc_patch(t_self, resources, elf, binf) 00412 00413 class TEENSY3_1Code (object): 00414 """Hooks for the TEENSY3.1""" 00415 @staticmethod 00416 def binary_hook (t_self, resources, elf, binf): 00417 """Hook that is run after elf is generated""" 00418 # This function is referenced by old versions of targets.json and should 00419 # be kept for backwards compatibility. 00420 pass 00421 00422 class MTSCode(object): 00423 """Generic MTS code""" 00424 @staticmethod 00425 def _combine_bins_helper(target_name, binf): 00426 """combine bins with the bootloader for a particular target""" 00427 loader = os.path.join(TOOLS_BOOTLOADERS, target_name, "bootloader.bin") 00428 target = binf + ".tmp" 00429 if not os.path.exists(loader): 00430 print "Can't find bootloader binary: " + loader 00431 return 00432 outbin = open(target, 'w+b') 00433 part = open(loader, 'rb') 00434 data = part.read() 00435 outbin.write(data) 00436 outbin.write('\xFF' * (64*1024 - len(data))) 00437 part.close() 00438 part = open(binf, 'rb') 00439 data = part.read() 00440 outbin.write(data) 00441 part.close() 00442 outbin.seek(0, 0) 00443 data = outbin.read() 00444 outbin.seek(0, 1) 00445 crc = struct.pack('<I', binascii.crc32(data) & 0xFFFFFFFF) 00446 outbin.write(crc) 00447 outbin.close() 00448 os.remove(binf) 00449 os.rename(target, binf) 00450 00451 @staticmethod 00452 def combine_bins_mts_dot (t_self, resources, elf, binf): 00453 """A hook for the MTS MDOT""" 00454 MTSCode._combine_bins_helper("MTS_MDOT_F411RE", binf) 00455 00456 @staticmethod 00457 def combine_bins_mts_dragonfly (t_self, resources, elf, binf): 00458 """A hoof for the MTS Dragonfly""" 00459 MTSCode._combine_bins_helper("MTS_DRAGONFLY_F411RE", binf) 00460 00461 class MCU_NRF51Code (object): 00462 """NRF51 Hooks""" 00463 @staticmethod 00464 def binary_hook (t_self, resources, _, binf): 00465 """Hook that merges the soft device with the bin file""" 00466 # Scan to find the actual paths of soft device 00467 sdf = None 00468 for softdevice_and_offset_entry\ 00469 in t_self.target.EXPECTED_SOFTDEVICES_WITH_OFFSETS: 00470 for hexf in resources.hex_files: 00471 if hexf.find(softdevice_and_offset_entry['name']) != -1: 00472 t_self.debug("SoftDevice file found %s." 00473 % softdevice_and_offset_entry['name']) 00474 sdf = hexf 00475 00476 if sdf is not None: 00477 break 00478 if sdf is not None: 00479 break 00480 00481 if sdf is None: 00482 t_self.debug("Hex file not found. Aborting.") 00483 return 00484 00485 # Look for bootloader file that matches this soft device or bootloader 00486 # override image 00487 blf = None 00488 if t_self.target.MERGE_BOOTLOADER is True: 00489 for hexf in resources.hex_files: 00490 if hexf.find(t_self.target.OVERRIDE_BOOTLOADER_FILENAME) != -1: 00491 t_self.debug("Bootloader file found %s." 00492 % t_self.target.OVERRIDE_BOOTLOADER_FILENAME) 00493 blf = hexf 00494 break 00495 elif hexf.find(softdevice_and_offset_entry['boot']) != -1: 00496 t_self.debug("Bootloader file found %s." 00497 % softdevice_and_offset_entry['boot']) 00498 blf = hexf 00499 break 00500 00501 # Merge user code with softdevice 00502 from intelhex import IntelHex 00503 binh = IntelHex() 00504 _, ext = os.path.splitext(binf) 00505 if ext == ".hex": 00506 binh.loadhex(binf) 00507 elif ext == ".bin": 00508 binh.loadbin(binf, softdevice_and_offset_entry['offset']) 00509 00510 if t_self.target.MERGE_SOFT_DEVICE is True: 00511 t_self.debug("Merge SoftDevice file %s" 00512 % softdevice_and_offset_entry['name']) 00513 sdh = IntelHex(sdf) 00514 binh.merge(sdh) 00515 00516 if t_self.target.MERGE_BOOTLOADER is True and blf is not None: 00517 t_self.debug("Merge BootLoader file %s" % blf) 00518 blh = IntelHex(blf) 00519 binh.merge(blh) 00520 00521 with open(binf.replace(".bin", ".hex"), "w") as fileout: 00522 binh.write_hex_file(fileout, write_start_addr=False) 00523 00524 class NCS36510TargetCode: 00525 @staticmethod 00526 def ncs36510_addfib(t_self, resources, elf, binf): 00527 from tools.targets.NCS import add_fib_at_start 00528 print("binf ", binf) 00529 add_fib_at_start(binf[:-4]) 00530 00531 class RTL8195ACode : 00532 """RTL8195A Hooks""" 00533 @staticmethod 00534 def binary_hook(t_self, resources, elf, binf): 00535 from tools.targets.REALTEK_RTL8195AM import rtl8195a_elf2bin 00536 rtl8195a_elf2bin(t_self, elf, binf) 00537 ################################################################################ 00538 00539 # Instantiate all public targets 00540 def update_target_data(): 00541 TARGETS[:] = [Target.get_target(tgt) for tgt, obj 00542 in Target.get_json_target_data().items() 00543 if obj.get("public", True)] 00544 # Map each target name to its unique instance 00545 TARGET_MAP.clear() 00546 TARGET_MAP.update(dict([(tgt.name, tgt) for tgt in TARGETS])) 00547 TARGET_NAMES[:] = TARGET_MAP.keys() 00548 00549 TARGETS = [] 00550 TARGET_MAP = dict() 00551 TARGET_NAMES = [] 00552 00553 update_target_data() 00554 00555 # Some targets with different name have the same exporters 00556 EXPORT_MAP = {} 00557 00558 # Detection APIs 00559 def get_target_detect_codes (): 00560 """ Returns dictionary mapping detect_code -> platform_name 00561 """ 00562 result = {} 00563 for tgt in TARGETS: 00564 for detect_code in tgt.detect_code: 00565 result[detect_code] = tgt.name 00566 return result 00567 00568 def set_targets_json_location (location=None): 00569 """Sets the location of the JSON file that contains the targets""" 00570 # First instruct Target about the new location 00571 Target.set_targets_json_location(location) 00572 # Then re-initialize TARGETS, TARGET_MAP and TARGET_NAMES. The 00573 # re-initialization does not create new variables, it keeps the old ones 00574 # instead. This ensures compatibility with code that does 00575 # "from tools.targets import TARGET_NAMES" 00576 update_target_data() 00577
Generated on Sun Jul 17 2022 08:25:18 by 1.7.2