Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcozecchini 0:9fca2b23d0ba 1 """A linting utility for targets.json
marcozecchini 0:9fca2b23d0ba 2
marcozecchini 0:9fca2b23d0ba 3 This linting utility may be called as follows:
marcozecchini 0:9fca2b23d0ba 4 python <path-to>/lint.py targets TARGET [TARGET ...]
marcozecchini 0:9fca2b23d0ba 5
marcozecchini 0:9fca2b23d0ba 6 all targets will be linted
marcozecchini 0:9fca2b23d0ba 7 """
marcozecchini 0:9fca2b23d0ba 8
marcozecchini 0:9fca2b23d0ba 9 # mbed SDK
marcozecchini 0:9fca2b23d0ba 10 # Copyright (c) 2017 ARM Limited
marcozecchini 0:9fca2b23d0ba 11 #
marcozecchini 0:9fca2b23d0ba 12 # Licensed under the Apache License, Version 2.0 (the "License");
marcozecchini 0:9fca2b23d0ba 13 # you may not use this file except in compliance with the License.
marcozecchini 0:9fca2b23d0ba 14 # You may obtain a copy of the License at
marcozecchini 0:9fca2b23d0ba 15 #
marcozecchini 0:9fca2b23d0ba 16 # http://www.apache.org/licenses/LICENSE-2.0
marcozecchini 0:9fca2b23d0ba 17 #
marcozecchini 0:9fca2b23d0ba 18 # Unless required by applicable law or agreed to in writing, software
marcozecchini 0:9fca2b23d0ba 19 # distributed under the License is distributed on an "AS IS" BASIS,
marcozecchini 0:9fca2b23d0ba 20 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
marcozecchini 0:9fca2b23d0ba 21 # See the License for the specific language governing permissions and
marcozecchini 0:9fca2b23d0ba 22 # limitations under the License.
marcozecchini 0:9fca2b23d0ba 23
marcozecchini 0:9fca2b23d0ba 24 from os.path import join, abspath, dirname
marcozecchini 0:9fca2b23d0ba 25 if __name__ == "__main__":
marcozecchini 0:9fca2b23d0ba 26 import sys
marcozecchini 0:9fca2b23d0ba 27 ROOT = abspath(join(dirname(__file__), "..", ".."))
marcozecchini 0:9fca2b23d0ba 28 sys.path.insert(0, ROOT)
marcozecchini 0:9fca2b23d0ba 29 from copy import copy
marcozecchini 0:9fca2b23d0ba 30 from yaml import dump_all
marcozecchini 0:9fca2b23d0ba 31 import argparse
marcozecchini 0:9fca2b23d0ba 32
marcozecchini 0:9fca2b23d0ba 33 from tools.targets import Target, set_targets_json_location, TARGET_MAP
marcozecchini 0:9fca2b23d0ba 34
marcozecchini 0:9fca2b23d0ba 35 def must_have_keys(keys, dict):
marcozecchini 0:9fca2b23d0ba 36 """Require keys in an MCU/Board
marcozecchini 0:9fca2b23d0ba 37
marcozecchini 0:9fca2b23d0ba 38 is a generator for errors
marcozecchini 0:9fca2b23d0ba 39 """
marcozecchini 0:9fca2b23d0ba 40 for key in keys:
marcozecchini 0:9fca2b23d0ba 41 if key not in dict:
marcozecchini 0:9fca2b23d0ba 42 yield "%s not found, and is required" % key
marcozecchini 0:9fca2b23d0ba 43
marcozecchini 0:9fca2b23d0ba 44 def may_have_keys(keys, dict):
marcozecchini 0:9fca2b23d0ba 45 """Disable all other keys in an MCU/Board
marcozecchini 0:9fca2b23d0ba 46
marcozecchini 0:9fca2b23d0ba 47 is a generator for errors
marcozecchini 0:9fca2b23d0ba 48 """
marcozecchini 0:9fca2b23d0ba 49 for key in dict.keys():
marcozecchini 0:9fca2b23d0ba 50 if key not in keys:
marcozecchini 0:9fca2b23d0ba 51 yield "%s found, and is not allowed" % key
marcozecchini 0:9fca2b23d0ba 52
marcozecchini 0:9fca2b23d0ba 53 def check_extra_labels(dict):
marcozecchini 0:9fca2b23d0ba 54 """Check that extra_labels does not contain any Target names
marcozecchini 0:9fca2b23d0ba 55
marcozecchini 0:9fca2b23d0ba 56 is a generator for errors
marcozecchini 0:9fca2b23d0ba 57 """
marcozecchini 0:9fca2b23d0ba 58 for label in (dict.get("extra_labels", []) +
marcozecchini 0:9fca2b23d0ba 59 dict.get("extra_labels_add", [])):
marcozecchini 0:9fca2b23d0ba 60 if label in Target.get_json_target_data():
marcozecchini 0:9fca2b23d0ba 61 yield "%s is not allowed in extra_labels" % label
marcozecchini 0:9fca2b23d0ba 62
marcozecchini 0:9fca2b23d0ba 63 def check_release_version(dict):
marcozecchini 0:9fca2b23d0ba 64 """Verify that release version 5 is combined with support for all toolcahins
marcozecchini 0:9fca2b23d0ba 65
marcozecchini 0:9fca2b23d0ba 66 is a generator for errors
marcozecchini 0:9fca2b23d0ba 67 """
marcozecchini 0:9fca2b23d0ba 68 if ("release_versions" in dict and
marcozecchini 0:9fca2b23d0ba 69 "5" in dict["release_versions"] and
marcozecchini 0:9fca2b23d0ba 70 "supported_toolchains" in dict):
marcozecchini 0:9fca2b23d0ba 71 for toolc in ["GCC_ARM", "ARM", "IAR"]:
marcozecchini 0:9fca2b23d0ba 72 if toolc not in dict["supported_toolchains"]:
marcozecchini 0:9fca2b23d0ba 73 yield ("%s not found in supported_toolchains, and is "
marcozecchini 0:9fca2b23d0ba 74 "required by mbed OS 5" % toolc)
marcozecchini 0:9fca2b23d0ba 75
marcozecchini 0:9fca2b23d0ba 76 def check_inherits(dict):
marcozecchini 0:9fca2b23d0ba 77 if ("inherits" in dict and len(dict["inherits"]) > 1):
marcozecchini 0:9fca2b23d0ba 78 yield "multiple inheritance is forbidden"
marcozecchini 0:9fca2b23d0ba 79
marcozecchini 0:9fca2b23d0ba 80 DEVICE_HAS_ALLOWED = ["ANALOGIN", "ANALOGOUT", "CAN", "ETHERNET", "EMAC",
marcozecchini 0:9fca2b23d0ba 81 "FLASH", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN",
marcozecchini 0:9fca2b23d0ba 82 "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT",
marcozecchini 0:9fca2b23d0ba 83 "PWMOUT", "RTC", "TRNG","SERIAL", "SERIAL_ASYNCH",
marcozecchini 0:9fca2b23d0ba 84 "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE",
marcozecchini 0:9fca2b23d0ba 85 "STORAGE", "STCLK_OFF_DURING_SLEEP"]
marcozecchini 0:9fca2b23d0ba 86 def check_device_has(dict):
marcozecchini 0:9fca2b23d0ba 87 for name in dict.get("device_has", []):
marcozecchini 0:9fca2b23d0ba 88 if name not in DEVICE_HAS_ALLOWED:
marcozecchini 0:9fca2b23d0ba 89 yield "%s is not allowed in device_has" % name
marcozecchini 0:9fca2b23d0ba 90
marcozecchini 0:9fca2b23d0ba 91 MCU_REQUIRED_KEYS = ["release_versions", "supported_toolchains",
marcozecchini 0:9fca2b23d0ba 92 "default_lib", "public", "inherits", "device_has"]
marcozecchini 0:9fca2b23d0ba 93 MCU_ALLOWED_KEYS = ["device_has_add", "device_has_remove", "core",
marcozecchini 0:9fca2b23d0ba 94 "extra_labels", "features", "features_add",
marcozecchini 0:9fca2b23d0ba 95 "features_remove", "bootloader_supported", "device_name",
marcozecchini 0:9fca2b23d0ba 96 "post_binary_hook", "default_toolchain", "config",
marcozecchini 0:9fca2b23d0ba 97 "extra_labels_add", "extra_labels_remove",
marcozecchini 0:9fca2b23d0ba 98 "target_overrides"] + MCU_REQUIRED_KEYS
marcozecchini 0:9fca2b23d0ba 99 def check_mcu(mcu_json, strict=False):
marcozecchini 0:9fca2b23d0ba 100 """Generate a list of problems with an MCU
marcozecchini 0:9fca2b23d0ba 101
marcozecchini 0:9fca2b23d0ba 102 :param: mcu_json the MCU's dict to check
marcozecchini 0:9fca2b23d0ba 103 :param: strict enforce required keys
marcozecchini 0:9fca2b23d0ba 104 """
marcozecchini 0:9fca2b23d0ba 105 errors = list(may_have_keys(MCU_ALLOWED_KEYS, mcu_json))
marcozecchini 0:9fca2b23d0ba 106 if strict:
marcozecchini 0:9fca2b23d0ba 107 errors.extend(must_have_keys(MCU_REQUIRED_KEYS, mcu_json))
marcozecchini 0:9fca2b23d0ba 108 errors.extend(check_extra_labels(mcu_json))
marcozecchini 0:9fca2b23d0ba 109 errors.extend(check_release_version(mcu_json))
marcozecchini 0:9fca2b23d0ba 110 errors.extend(check_inherits(mcu_json))
marcozecchini 0:9fca2b23d0ba 111 errors.extend(check_device_has(mcu_json))
marcozecchini 0:9fca2b23d0ba 112 if 'public' in mcu_json and mcu_json['public']:
marcozecchini 0:9fca2b23d0ba 113 errors.append("public must be false")
marcozecchini 0:9fca2b23d0ba 114 return errors
marcozecchini 0:9fca2b23d0ba 115
marcozecchini 0:9fca2b23d0ba 116 BOARD_REQUIRED_KEYS = ["inherits"]
marcozecchini 0:9fca2b23d0ba 117 BOARD_ALLOWED_KEYS = ["supported_form_factors", "is_disk_virtual",
marcozecchini 0:9fca2b23d0ba 118 "detect_code", "extra_labels", "extra_labels_add",
marcozecchini 0:9fca2b23d0ba 119 "extra_labels_remove", "public", "config",
marcozecchini 0:9fca2b23d0ba 120 "forced_reset_timeout", "target_overrides"] + BOARD_REQUIRED_KEYS
marcozecchini 0:9fca2b23d0ba 121 def check_board(board_json, strict=False):
marcozecchini 0:9fca2b23d0ba 122 """Generate a list of problems with an board
marcozecchini 0:9fca2b23d0ba 123
marcozecchini 0:9fca2b23d0ba 124 :param: board_json the mcus dict to check
marcozecchini 0:9fca2b23d0ba 125 :param: strict enforce required keys
marcozecchini 0:9fca2b23d0ba 126 """
marcozecchini 0:9fca2b23d0ba 127 errors = list(may_have_keys(BOARD_ALLOWED_KEYS, board_json))
marcozecchini 0:9fca2b23d0ba 128 if strict:
marcozecchini 0:9fca2b23d0ba 129 errors.extend(must_have_keys(BOARD_REQUIRED_KEYS, board_json))
marcozecchini 0:9fca2b23d0ba 130 errors.extend(check_extra_labels(board_json))
marcozecchini 0:9fca2b23d0ba 131 errors.extend(check_inherits(board_json))
marcozecchini 0:9fca2b23d0ba 132 return errors
marcozecchini 0:9fca2b23d0ba 133
marcozecchini 0:9fca2b23d0ba 134 def add_if(dict, key, val):
marcozecchini 0:9fca2b23d0ba 135 """Add a value to a dict if it's non-empty"""
marcozecchini 0:9fca2b23d0ba 136 if val:
marcozecchini 0:9fca2b23d0ba 137 dict[key] = val
marcozecchini 0:9fca2b23d0ba 138
marcozecchini 0:9fca2b23d0ba 139 def _split_boards(resolution_order, tgt):
marcozecchini 0:9fca2b23d0ba 140 """Split the resolution order between boards and mcus"""
marcozecchini 0:9fca2b23d0ba 141 mcus = []
marcozecchini 0:9fca2b23d0ba 142 boards = []
marcozecchini 0:9fca2b23d0ba 143 iterable = iter(resolution_order)
marcozecchini 0:9fca2b23d0ba 144 for name in iterable:
marcozecchini 0:9fca2b23d0ba 145 mcu_json = tgt.json_data[name]
marcozecchini 0:9fca2b23d0ba 146 if (len(list(check_mcu(mcu_json, True))) >
marcozecchini 0:9fca2b23d0ba 147 len(list(check_board(mcu_json, True)))):
marcozecchini 0:9fca2b23d0ba 148 boards.append(name)
marcozecchini 0:9fca2b23d0ba 149 else:
marcozecchini 0:9fca2b23d0ba 150 mcus.append(name)
marcozecchini 0:9fca2b23d0ba 151 break
marcozecchini 0:9fca2b23d0ba 152 mcus.extend(iterable)
marcozecchini 0:9fca2b23d0ba 153 mcus.reverse()
marcozecchini 0:9fca2b23d0ba 154 boards.reverse()
marcozecchini 0:9fca2b23d0ba 155 return mcus, boards
marcozecchini 0:9fca2b23d0ba 156
marcozecchini 0:9fca2b23d0ba 157
marcozecchini 0:9fca2b23d0ba 158 MCU_FORMAT_STRING = {1: "MCU (%s) ->",
marcozecchini 0:9fca2b23d0ba 159 2: "Family (%s) -> MCU (%s) ->",
marcozecchini 0:9fca2b23d0ba 160 3: "Family (%s) -> SubFamily (%s) -> MCU (%s) ->"}
marcozecchini 0:9fca2b23d0ba 161 BOARD_FORMAT_STRING = {1: "Board (%s)",
marcozecchini 0:9fca2b23d0ba 162 2: "Module (%s) -> Board (%s)"}
marcozecchini 0:9fca2b23d0ba 163 def _generate_hierarchy_string(mcus, boards):
marcozecchini 0:9fca2b23d0ba 164 global_errors = []
marcozecchini 0:9fca2b23d0ba 165 if len(mcus) < 1:
marcozecchini 0:9fca2b23d0ba 166 global_errors.append("No MCUS found in heirarchy")
marcozecchini 0:9fca2b23d0ba 167 mcus_string = "??? ->"
marcozecchini 0:9fca2b23d0ba 168 elif len(mcus) > 3:
marcozecchini 0:9fca2b23d0ba 169 global_errors.append("No name for targets %s" % ", ".join(mcus[3:]))
marcozecchini 0:9fca2b23d0ba 170 mcus_string = MCU_FORMAT_STRING[3] % tuple(mcus[:3])
marcozecchini 0:9fca2b23d0ba 171 for name in mcus[3:]:
marcozecchini 0:9fca2b23d0ba 172 mcus_string += " ??? (%s) ->" % name
marcozecchini 0:9fca2b23d0ba 173 else:
marcozecchini 0:9fca2b23d0ba 174 mcus_string = MCU_FORMAT_STRING[len(mcus)] % tuple(mcus)
marcozecchini 0:9fca2b23d0ba 175
marcozecchini 0:9fca2b23d0ba 176 if len(boards) < 1:
marcozecchini 0:9fca2b23d0ba 177 global_errors.append("no boards found in heirarchy")
marcozecchini 0:9fca2b23d0ba 178 boards_string = "???"
marcozecchini 0:9fca2b23d0ba 179 elif len(boards) > 2:
marcozecchini 0:9fca2b23d0ba 180 global_errors.append("no name for targets %s" % ", ".join(boards[2:]))
marcozecchini 0:9fca2b23d0ba 181 boards_string = BOARD_FORMAT_STRING[2] % tuple(boards[:2])
marcozecchini 0:9fca2b23d0ba 182 for name in boards[2:]:
marcozecchini 0:9fca2b23d0ba 183 boards_string += " -> ??? (%s)" % name
marcozecchini 0:9fca2b23d0ba 184 else:
marcozecchini 0:9fca2b23d0ba 185 boards_string = BOARD_FORMAT_STRING[len(boards)] % tuple(boards)
marcozecchini 0:9fca2b23d0ba 186 return mcus_string + " " + boards_string, global_errors
marcozecchini 0:9fca2b23d0ba 187
marcozecchini 0:9fca2b23d0ba 188
marcozecchini 0:9fca2b23d0ba 189 def check_hierarchy(tgt):
marcozecchini 0:9fca2b23d0ba 190 """Atempts to assign labels to the heirarchy"""
marcozecchini 0:9fca2b23d0ba 191 resolution_order = copy(tgt.resolution_order_names[:-1])
marcozecchini 0:9fca2b23d0ba 192 mcus, boards = _split_boards(resolution_order, tgt)
marcozecchini 0:9fca2b23d0ba 193
marcozecchini 0:9fca2b23d0ba 194 target_errors = {}
marcozecchini 0:9fca2b23d0ba 195 hierachy_string, hierachy_errors = _generate_hierarchy_string(mcus, boards)
marcozecchini 0:9fca2b23d0ba 196 to_ret = {"hierarchy": hierachy_string}
marcozecchini 0:9fca2b23d0ba 197 add_if(to_ret, "hierarchy errors", hierachy_errors)
marcozecchini 0:9fca2b23d0ba 198
marcozecchini 0:9fca2b23d0ba 199 for name in mcus[:-1]:
marcozecchini 0:9fca2b23d0ba 200 add_if(target_errors, name, list(check_mcu(tgt.json_data[name])))
marcozecchini 0:9fca2b23d0ba 201 if len(mcus) >= 1:
marcozecchini 0:9fca2b23d0ba 202 add_if(target_errors, mcus[-1],
marcozecchini 0:9fca2b23d0ba 203 list(check_mcu(tgt.json_data[mcus[-1]], True)))
marcozecchini 0:9fca2b23d0ba 204 for name in boards:
marcozecchini 0:9fca2b23d0ba 205 add_if(target_errors, name, list(check_board(tgt.json_data[name])))
marcozecchini 0:9fca2b23d0ba 206 if len(boards) >= 1:
marcozecchini 0:9fca2b23d0ba 207 add_if(target_errors, boards[-1],
marcozecchini 0:9fca2b23d0ba 208 list(check_board(tgt.json_data[boards[-1]], True)))
marcozecchini 0:9fca2b23d0ba 209 add_if(to_ret, "target errors", target_errors)
marcozecchini 0:9fca2b23d0ba 210 return to_ret
marcozecchini 0:9fca2b23d0ba 211
marcozecchini 0:9fca2b23d0ba 212 PARSER = argparse.ArgumentParser(prog="targets/lint.py")
marcozecchini 0:9fca2b23d0ba 213 SUBPARSERS = PARSER.add_subparsers(title="Commands")
marcozecchini 0:9fca2b23d0ba 214
marcozecchini 0:9fca2b23d0ba 215 def subcommand(name, *args, **kwargs):
marcozecchini 0:9fca2b23d0ba 216 def __subcommand(command):
marcozecchini 0:9fca2b23d0ba 217 kwargs['description'] = command.__doc__
marcozecchini 0:9fca2b23d0ba 218 subparser = SUBPARSERS.add_parser(name, **kwargs)
marcozecchini 0:9fca2b23d0ba 219 for arg in args:
marcozecchini 0:9fca2b23d0ba 220 arg = dict(arg)
marcozecchini 0:9fca2b23d0ba 221 opt = arg['name']
marcozecchini 0:9fca2b23d0ba 222 del arg['name']
marcozecchini 0:9fca2b23d0ba 223
marcozecchini 0:9fca2b23d0ba 224 if isinstance(opt, basestring):
marcozecchini 0:9fca2b23d0ba 225 subparser.add_argument(opt, **arg)
marcozecchini 0:9fca2b23d0ba 226 else:
marcozecchini 0:9fca2b23d0ba 227 subparser.add_argument(*opt, **arg)
marcozecchini 0:9fca2b23d0ba 228
marcozecchini 0:9fca2b23d0ba 229 def _thunk(parsed_args):
marcozecchini 0:9fca2b23d0ba 230 argv = [arg['dest'] if 'dest' in arg else arg['name']
marcozecchini 0:9fca2b23d0ba 231 for arg in args]
marcozecchini 0:9fca2b23d0ba 232 argv = [(arg if isinstance(arg, basestring)
marcozecchini 0:9fca2b23d0ba 233 else arg[-1]).strip('-').replace('-', '_')
marcozecchini 0:9fca2b23d0ba 234 for arg in argv]
marcozecchini 0:9fca2b23d0ba 235 argv = {arg: vars(parsed_args)[arg] for arg in argv
marcozecchini 0:9fca2b23d0ba 236 if vars(parsed_args)[arg] is not None}
marcozecchini 0:9fca2b23d0ba 237
marcozecchini 0:9fca2b23d0ba 238 return command(**argv)
marcozecchini 0:9fca2b23d0ba 239
marcozecchini 0:9fca2b23d0ba 240 subparser.set_defaults(command=_thunk)
marcozecchini 0:9fca2b23d0ba 241 return command
marcozecchini 0:9fca2b23d0ba 242 return __subcommand
marcozecchini 0:9fca2b23d0ba 243
marcozecchini 0:9fca2b23d0ba 244 @subcommand("targets",
marcozecchini 0:9fca2b23d0ba 245 dict(name="mcus", nargs="+", metavar="MCU",
marcozecchini 0:9fca2b23d0ba 246 choices=TARGET_MAP.keys(), type=str.upper))
marcozecchini 0:9fca2b23d0ba 247 def targets_cmd(mcus=[]):
marcozecchini 0:9fca2b23d0ba 248 """Find and print errors about specific targets"""
marcozecchini 0:9fca2b23d0ba 249 print dump_all([check_hierarchy(TARGET_MAP[m]) for m in mcus],
marcozecchini 0:9fca2b23d0ba 250 default_flow_style=False)
marcozecchini 0:9fca2b23d0ba 251
marcozecchini 0:9fca2b23d0ba 252 @subcommand("all-targets")
marcozecchini 0:9fca2b23d0ba 253 def all_targets_cmd():
marcozecchini 0:9fca2b23d0ba 254 """Print all errors about all parts"""
marcozecchini 0:9fca2b23d0ba 255 print dump_all([check_hierarchy(m) for m in TARGET_MAP.values()],
marcozecchini 0:9fca2b23d0ba 256 default_flow_style=False)
marcozecchini 0:9fca2b23d0ba 257
marcozecchini 0:9fca2b23d0ba 258 @subcommand("orphans")
marcozecchini 0:9fca2b23d0ba 259 def orphans_cmd():
marcozecchini 0:9fca2b23d0ba 260 """Find and print all orphan targets"""
marcozecchini 0:9fca2b23d0ba 261 orphans = Target.get_json_target_data().keys()
marcozecchini 0:9fca2b23d0ba 262 for tgt in TARGET_MAP.values():
marcozecchini 0:9fca2b23d0ba 263 for name in tgt.resolution_order_names:
marcozecchini 0:9fca2b23d0ba 264 if name in orphans:
marcozecchini 0:9fca2b23d0ba 265 orphans.remove(name)
marcozecchini 0:9fca2b23d0ba 266 if orphans:
marcozecchini 0:9fca2b23d0ba 267 print dump_all([orphans], default_flow_style=False)
marcozecchini 0:9fca2b23d0ba 268 return len(orphans)
marcozecchini 0:9fca2b23d0ba 269
marcozecchini 0:9fca2b23d0ba 270 def main():
marcozecchini 0:9fca2b23d0ba 271 """entry point"""
marcozecchini 0:9fca2b23d0ba 272 options = PARSER.parse_args()
marcozecchini 0:9fca2b23d0ba 273 return options.command(options)
marcozecchini 0:9fca2b23d0ba 274
marcozecchini 0:9fca2b23d0ba 275 if __name__ == "__main__":
marcozecchini 0:9fca2b23d0ba 276 sys.exit(main())
marcozecchini 0:9fca2b23d0ba 277