1# Copyright (c) 2021, Linaro Limited. 2# Copyright (c) 2022, NXP 3# 4# SPDX-License-Identifier: Apache-2.0 5 6""" 7Implements a configuration file parser for kinetis MCUs, which can generate 8pinctrl definitions for Zephyr 9""" 10 11import xml.etree.ElementTree as ET 12import re 13import os 14import collections 15import logging 16import pathlib 17import __main__ 18 19# layout/index of pins tuple 20PIN = collections.namedtuple('PIN', ['PERIPH', 'NAME_PART', 'SIGNAL', 'PORT', 21 'PIN', 'CH', 'MUX_FUNC']) 22 23NAMESPACES = {'mex': 'http://mcuxpresso.nxp.com/XSD/mex_configuration_14'} 24 25# Pin controller types 26PORT_KINETIS = 1 27PORT_N9X = 2 28PORT_A15X = 3 29 30class MUXOption: 31 """ 32 Internal class representing a mux option on the SOC 33 """ 34 def __init__(self, connection, port_type): 35 """ 36 Initializes a mux option 37 @param connection XML connection option from signal_configuration.xml 38 """ 39 self._name = connection.attrib.get('name_part') 40 logging.debug("\t\t %s", self._name) 41 if self._name is None: 42 self._name = '' 43 return 44 # Get MUX settings 45 self._port = None 46 for periph in connection.iter('peripheral_signal_ref'): 47 self._periph = periph.attrib.get('peripheral') 48 self._signal = periph.attrib.get('signal') 49 self._channel = periph.attrib.get('channel') 50 for assign in connection.iter('assign'): 51 reg = assign.attrib.get('register') 52 val = assign.attrib.get('bit_field_value') 53 logging.debug('\t\t\t [ASSIGN] %s %s', reg, val) 54 # Only process PCR registers 55 if port_type == PORT_KINETIS: 56 match = re.match(r'PORT([A-Z])_PCR(\d+)', reg) 57 elif port_type == PORT_N9X or port_type == PORT_A15X: 58 match = re.match(r'PORT(\d)_PCR(\d+)', reg) 59 if match and (assign.attrib.get('bit_field') == "MUX"): 60 # For muxes like PTC5 (or PIO1_8 on N9X), 61 # do not append peripheral name 62 if port_type == PORT_KINETIS: 63 if re.match(r'PT[A-Z]\d+', self._name) is None: 64 self._name += f"_PT{match.group(1)}{match.group(2)}" 65 elif port_type == PORT_N9X: 66 if re.match(r'PIO\d_\d+', self._name) is None: 67 self._name += f"_PIO{match.group(1)}_{match.group(2)}" 68 elif port_type == PORT_A15X: 69 if re.match(r'P\d_\d+', self._name) is None: 70 self._name += f"_P{match.group(1)}_{match.group(2)}" 71 self._port = match.group(1) 72 self._pin = int(match.group(2)) 73 self._mux = int(val, 16) 74 if self._port is None: 75 # Not a valid port mapping. Clear name 76 self._name = '' 77 78 def __repr__(self): 79 """ 80 String representation of object 81 """ 82 return "MUXOption(%s)" % (self._name) 83 84 def get_name(self): 85 """ 86 Get mux option name 87 """ 88 return self._name 89 90 def get_mux_name(self): 91 """ 92 Get name of the mux option, without pin name 93 """ 94 if self._channel: 95 return f"{self._periph}_{self._signal}, {self._channel}" 96 return f"{self._periph}_{self._signal}" 97 98 def get_port(self): 99 """ 100 Get mux port 101 """ 102 return self._port 103 104 def get_signal(self): 105 """ 106 Get mux signal name 107 """ 108 return self._signal 109 110 def get_pin(self): 111 """ 112 Get mux pin 113 """ 114 return self._pin 115 116 def get_mux(self): 117 """ 118 Get mux register write value 119 """ 120 return self._mux 121 122 def get_periph(self): 123 """ 124 Get peripheral name 125 """ 126 return self._periph 127 128 def get_channel(self): 129 """ 130 Get channel number 131 """ 132 return self._channel 133 134 def __hash__(self): 135 """ 136 Override hash method to return pin name as hash 137 """ 138 return hash(self._name) 139 140 def __eq__(self, obj): 141 """ 142 Like the hash method, we override the eq method to return true if two 143 objects have the same pin name 144 """ 145 return isinstance(obj, SignalPin) and self._name == obj._name 146 147 def __lt__(self, obj): 148 """ 149 Compare objects based on name 150 """ 151 if not isinstance(obj, SignalPin): 152 return True 153 return self._name < obj._name 154 155 156class SignalPin: 157 """ 158 Internal class representing a signal on the SOC 159 """ 160 def __init__(self, pin): 161 """ 162 Initializes a SignalPin object 163 @param pin: pin XML object from signal_configuration.xml 164 """ 165 # Kinetis pin names are formatted as [PT[Port][Pin]], 166 # N9X pin names use the PIO[Port]_[Pin] format. Try both. 167 if re.search(r'PT([A-Z])(\d+)', pin.attrib['name']): 168 # Kinetis part. 169 pin_regex = re.search(r'PT([A-Z])(\d+)', pin.attrib['name']) 170 self._type = PORT_KINETIS 171 elif re.search(r'PIO(\d)_(\d+)', pin.attrib['name']): 172 # This may be an N9X part. Try that pin pattern 173 pin_regex = re.search(r'PIO(\d)_(\d+)', pin.attrib['name']) 174 self._type = PORT_N9X 175 elif re.search(r'P(\d)_(\d+)', pin.attrib['name']): 176 # This may be an A15X part. Try that pin pattern 177 pin_regex = re.search(r'P(\d)_(\d+)', pin.attrib['name']) 178 self._type = PORT_A15X 179 else: 180 logging.debug('Could not match pin name %s', pin.attrib['name']) 181 self._name = '' 182 return 183 self._name = pin.attrib['name'] 184 self._port = pin_regex.group(1) 185 self._pin = pin_regex.group(2) 186 self._properties = self._get_pin_properties(pin.find('functional_properties')) 187 self._mux_options = {} 188 for connections in pin.findall('connections'): 189 mux_opt = MUXOption(connections, self._type) 190 # Only append mux options with a valid name 191 if mux_opt.get_name() != '': 192 self._mux_options[mux_opt.get_mux_name()] = mux_opt 193 194 def __repr__(self): 195 """ 196 String representation of object 197 """ 198 return "SignalPin(%s)" % (self._name) 199 200 def __hash__(self): 201 """ 202 Override hash method to return pin name as hash 203 """ 204 return hash(self._name) 205 206 def __eq__(self, obj): 207 """ 208 Like the hash method, we override the eq method to return true if two 209 objects have the same pin name 210 """ 211 return isinstance(obj, SignalPin) and self._name == obj._name 212 213 def __lt__(self, obj): 214 """ 215 Compare objects based on name 216 """ 217 if not isinstance(obj, SignalPin): 218 return True 219 return self._name < obj._name 220 221 def get_name(self): 222 """ 223 Get name of pin 224 """ 225 return self._name 226 227 def get_port(self): 228 """ 229 Get PORT this signal is defined for 230 """ 231 return self._port 232 233 def get_pin(self): 234 """ 235 Get pin this signal is defined for 236 """ 237 return self._pin 238 239 def get_mux_connection(self, signal): 240 """ 241 Gets an MUXOption object for the relevant signal name 242 @param signal: Signal name on pin to get mux option for 243 """ 244 if signal in self._mux_options: 245 return self._mux_options[signal] 246 return None 247 248 def get_mux_options(self): 249 """ 250 Gets all unique settings for IOMUX on the specific pin 251 """ 252 return set(self._mux_options.values()) 253 254 def get_pin_properties(self): 255 """ 256 Gets array of pin property names 257 """ 258 return self._properties.keys() 259 260 def get_pin_property_default(self, prop): 261 """ 262 Gets name of default pin property 263 @param prop: name of pin property 264 """ 265 return self._properties[prop]['default'] 266 267 def get_pin_defaults(self): 268 """ 269 Gets mapping of all pin property names to default value names 270 """ 271 pin_defaults = {} 272 for prop in self.get_pin_properties(): 273 pin_default = self.get_pin_property_default(prop) 274 pin_defaults[prop] = pin_default 275 return pin_defaults 276 277 def get_pin_property_value(self, prop, selection): 278 """ 279 Gets bit value for pin property 280 @param prop: name of pin property 281 @param selection: name of option selected for property 282 """ 283 return self._properties[prop][selection] 284 285 def _get_pin_properties(self, props): 286 """ 287 Builds dictionary with all pin properties 288 @param props: pin function_properties XML object in signal_configuration.xml 289 """ 290 prop_mapping = {} 291 for prop in props.findall('functional_property'): 292 prop_id = prop.attrib['id'] 293 if not 'default' in prop.attrib: 294 # No default property. Skip 295 continue 296 prop_mapping[prop_id] = {} 297 prop_mapping[prop_id]['default'] = prop.attrib['default'] 298 for state in prop.findall('state'): 299 reg_assign = state.find('configuration/assign') 300 if reg_assign: 301 bit_value = int(reg_assign.attrib['bit_field_value'], 0) 302 else: 303 # Assume writing zero to register will select default 304 bit_value = 0 305 prop_mapping[prop_id][state.attrib['id']] = bit_value 306 return prop_mapping 307 308class PinGroup: 309 """ 310 Internal class representing pin group 311 """ 312 def __init__(self, function, signal_map): 313 """ 314 Creates a pin group 315 @param function: function xml structure from MEX configuration file 316 @param signal_map: Signal mapping, maps signal names to signal pins 317 """ 318 self._name = function.attrib.get('name') 319 pins = function.find('mex:pins', NAMESPACES) 320 description = function.find('mex:description', NAMESPACES) 321 if description is not None and description.text is not None: 322 # Replace <br> html tag with newline 323 self._description = description.text.replace("<br/>", "\n") 324 else: 325 self._description = "" 326 # Build dictionary mapping pin properties to pins. This allows us to 327 # group pins based on shared configuration 328 self._pin_groups = collections.defaultdict(lambda: []) 329 for pin in pins: 330 # find signal defintion for this pin 331 signal_name = pin.attrib.get('pin_signal') 332 signal = signal_map[signal_name] 333 if not signal: 334 logging.warning('Signal name %s not present in mapping', signal_name) 335 # No way to find mux option 336 continue 337 # Get mux option for this signal 338 mux_option = f"{pin.attrib.get('peripheral')}_{pin.attrib.get('signal')}" 339 mux = signal.get_mux_connection(mux_option) 340 if mux is None: 341 logging.warning('Signal name %s has no mux', mux_option) 342 # Do not add pinmux option to group 343 continue 344 # Get pin defaults for this pin 345 defaults = signal.get_pin_defaults() 346 # Get pin overrides 347 features = pin.find('mex:pin_features', NAMESPACES) 348 pin_overrides = {} 349 if features is not None: 350 for feature in pin.find('mex:pin_features', NAMESPACES): 351 pin_overrides[feature.attrib.get('name')] = feature.attrib.get('value') 352 pin_props = self._props_to_dts(pin_overrides, defaults) 353 self._pin_groups[pin_props].append(mux) 354 355 def __repr__(self): 356 """ 357 Get string representation of the object 358 """ 359 return "PinGroup(%s)" % (self._name) 360 361 def __eq__(self, obj): 362 """ 363 return true if two objects have the same pin group name 364 """ 365 return isinstance(obj, PinGroup) and self._name == obj._name 366 367 def __lt__(self, obj): 368 """ 369 Compare objects based on name 370 """ 371 if not isinstance(obj, PinGroup): 372 return True 373 return self._name < obj._name 374 375 def get_pin_props(self): 376 """ 377 Get all unique pin properties 378 """ 379 return self._pin_groups.keys() 380 381 def get_pins(self, props): 382 """ 383 Get all pins with a provided set of properties 384 @param props: property set 385 """ 386 return self._pin_groups[props] 387 388 def get_description(self): 389 """ 390 Get description of the pin group, if present. If no description present, 391 description will be "" 392 """ 393 return self._description 394 395 def get_name(self): 396 """ 397 Get pin group name 398 """ 399 return self._name 400 401 def _props_to_dts(self, props, defaults): 402 """ 403 Remap dictionary of property names from NXP defined values to 404 Zephyr ones 405 @param props: Dictionary of NXP property names and values 406 @param defaults: Dictionary of NXP property names and default pin values 407 @return array of strings suitable for writing to DTS 408 """ 409 zephyr_props = [] 410 prop_mapping = { 411 'fast': 'fast', 412 'slow': 'slow', 413 'low': 'low', 414 'high': 'high', 415 } 416 # Lambda to convert property names to zephyr formatted strings 417 sanitize = lambda x: "\"" + prop_mapping[x] + "\"" if (x in prop_mapping) else "" 418 # Lambda to get property value or fallback on default 419 prop_val = lambda x: props[x] if x in props else defaults[x] 420 # Check pin defaults and overrides to see if the pin will have a pull 421 pull_enable = prop_val('pull_enable') == 'enable' 422 # For each property, append the provided override or the default 423 zephyr_props.append(f"drive-strength = {sanitize(prop_val('drive_strength'))}") 424 if prop_val('open_drain') == 'enable': 425 zephyr_props.append('drive-open-drain') 426 if pull_enable: 427 # If pull is enabled, select pull up or pull down 428 if prop_val('pull_select') == 'up': 429 zephyr_props.append('bias-pull-up') 430 else: 431 zephyr_props.append('bias-pull-down') 432 zephyr_props.append(f"slew-rate = {sanitize(prop_val('slew_rate'))}") 433 if prop_val('passive_filter') == 'enable': 434 zephyr_props.append("nxp,passive-filter") 435 return tuple(zephyr_props) 436 437 438class NXPSdkUtil: 439 """ 440 Class for kinetis configuration file parser 441 """ 442 def __init__(self, cfg_root, copyright_header = "", log_level = logging.ERROR): 443 """ 444 Initialize SDK utilities. 445 Providing a signal file will enable this class to parse MEX files, 446 and generate output DTS 447 @param cfg_root processor configuration folder root 448 @param copyright_header: copyright string to add to any generated file header 449 @param log_level: log level for SDK utility 450 """ 451 # Load the signal XML data 452 453 self._logger = logging.getLogger('') 454 self._logger.setLevel(log_level) 455 self._parse_signal_xml(pathlib.Path(cfg_root)/'signal_configuration.xml') 456 self._copyright = copyright_header 457 logging.info("Loaded %d configurable pin defs", len(self._pins)) 458 459 def _parse_signal_xml(self, signal_fn): 460 """ 461 Parses signal XML configuration file. Builds a list of pins, which can 462 be used to generate soc level DTSI file. 463 @param signal_fn: signal_configuration.xml file to parse 464 """ 465 self._pins = {} 466 try: 467 signal_tree = ET.parse(signal_fn) 468 except ET.ParseError: 469 logging.error("Could not parse provided signal file: %s", signal_fn) 470 return 471 472 signal_root = signal_tree.getroot() 473 474 self._part_num = signal_root.find("./part_information/part_number").get('id') 475 476 logging.info("Loaded XML for %s", self._part_num) 477 478 periphs_node = signal_root.find("peripherals") 479 periphs = [] 480 for pin in periphs_node: 481 pin_id = pin.attrib.get("id") 482 name = pin.attrib.get("name") 483 484 if pin_id != name: 485 logging.warning("id and name don't match") 486 487 periphs.append(pin_id) 488 489 pins_node = signal_root.find("pins") 490 for pin in pins_node: 491 signal = SignalPin(pin) 492 # Only add valid signal pins to list 493 if signal.get_name() != '': 494 self._pins[signal.get_name()] = signal 495 496 def _write_pins(self, which_port, pins, prefix, file): 497 """ 498 Writes all pin mux nodes for a specific pin port to soc pinctrl dtsi 499 file. 500 @param which_port: pin port to define 501 @param pins: list of pin mux options to write 502 @param prefix: prefix to use for pin macros 503 @param file: output file to write to 504 """ 505 port_pins = list(filter(lambda p: (p.get_port().lower() == which_port), pins)) 506 507 if (len(port_pins)) == 0: 508 return 509 510 port_pins.sort(key=lambda p: (p.get_pin(), p.get_mux())) 511 512 seen_nodes = [] 513 514 515 for pin_data in port_pins: 516 label = pin_data.get_name() 517 port = pin_data.get_port() 518 pin = pin_data.get_pin() 519 mux = pin_data.get_mux() 520 521 if label in seen_nodes: 522 continue 523 seen_nodes.append(label) 524 525 file.write(f"#define {label} {prefix}('{port}',{pin},{mux}) /* PT{port}_{pin} */\n") 526 527 def get_part_num(self): 528 """ 529 Return the part number this class is instantiated for 530 """ 531 return self._part_num 532 533 def write_pinctrl_defs(self, outputfile): 534 """ 535 Writes all pin mux options into pinctrl DTSI file. Board level pin groups 536 can include this pinctrl dtsi file to access pin control defintions. 537 @param outputfile: file to write output pinctrl defs to 538 """ 539 # Create list of all pin mux options 540 pinmux_opts = [] 541 # Check pin setting to see if we should write a Kinetis style pinctrl 542 # header, or a N9X style header 543 if list(self._pins.values())[0]._type == PORT_N9X: 544 n9x_mode = True 545 else: 546 n9x_mode = False 547 if list(self._pins.values())[0]._type == PORT_A15X: 548 a15x_mode = True 549 else: 550 a15x_mode = False 551 for pin in self._pins.values(): 552 pinmux_opts.extend(pin.get_mux_options()) 553 pcr_pins = list(filter(lambda p: (p.get_periph() not in ["FB", "EZPORT"]), pinmux_opts)) 554 file_header = ("/*\n" 555 f" * NOTE: Autogenerated file by {os.path.basename(__main__.__file__)}\n" 556 f" * for {self._part_num}/signal_configuration.xml\n" 557 " *\n" 558 f" * {self._copyright}\n" 559 " */\n" 560 "\n") 561 562 # Notes on the below macro: 563 # Port values range from 'A'-'E', so we store them with 4 bits, 564 # with port A being 0, B=1,... 565 # N9X uses Port values between 0-5, and these are stored as integers 566 # Pin values range from 0-31, so we give 6 bits for future expansion 567 # Mux values range from 0-15, so we give 4 bits 568 # shift the port and pin values to the MSBs of the mux value, so they 569 # don't conflict with pin configuration settings 570 # Store the mux value at the offset it will actually be written to the 571 # configuration register 572 if n9x_mode: 573 mux_macro = ("#define N9X_MUX(port, pin, mux)\t\t\\\n" 574 "\t(((((port) - '0') & 0xF) << 28) |\t\\\n" 575 "\t(((pin) & 0x3F) << 22) |\t\t\\\n" 576 "\t(((mux) & 0xF) << 8))\n\n") 577 elif a15x_mode: 578 mux_macro = ("#define A15X_MUX(port, pin, mux)\t\t\\\n" 579 "\t(((((port) - '0') & 0xF) << 28) |\t\\\n" 580 "\t(((pin) & 0x3F) << 22) |\t\t\\\n" 581 "\t(((mux) & 0xF) << 8))\n\n") 582 else: 583 mux_macro = ("#define KINETIS_MUX(port, pin, mux)\t\t\\\n" 584 "\t(((((port) - 'A') & 0xF) << 28) |\t\\\n" 585 "\t(((pin) & 0x3F) << 22) |\t\t\\\n" 586 "\t(((mux) & 0x7) << 8))\n\n") 587 with open(outputfile, "w", encoding="utf8") as file: 588 file.write(file_header) 589 # ifdef guard 590 file.write(f"#ifndef _ZEPHYR_DTS_BINDING_{self._part_num.upper()}_\n") 591 file.write(f"#define _ZEPHYR_DTS_BINDING_{self._part_num.upper()}_\n\n") 592 # Write macro to make port name 593 file.write(mux_macro) 594 if n9x_mode: 595 self._write_pins('0', pcr_pins, 'N9X_MUX', file) 596 self._write_pins('1', pcr_pins, 'N9X_MUX', file) 597 self._write_pins('2', pcr_pins, 'N9X_MUX', file) 598 self._write_pins('3', pcr_pins, 'N9X_MUX', file) 599 self._write_pins('4', pcr_pins, 'N9X_MUX', file) 600 self._write_pins('5', pcr_pins, 'N9X_MUX', file) 601 elif a15x_mode: 602 self._write_pins('0', pcr_pins, 'A15X_MUX', file) 603 self._write_pins('1', pcr_pins, 'A15X_MUX', file) 604 self._write_pins('2', pcr_pins, 'A15X_MUX', file) 605 self._write_pins('3', pcr_pins, 'A15X_MUX', file) 606 self._write_pins('4', pcr_pins, 'A15X_MUX', file) 607 self._write_pins('5', pcr_pins, 'A15X_MUX', file) 608 else: 609 self._write_pins('a', pcr_pins, 'KINETIS_MUX', file) 610 self._write_pins('b', pcr_pins, 'KINETIS_MUX', file) 611 self._write_pins('c', pcr_pins, 'KINETIS_MUX', file) 612 self._write_pins('d', pcr_pins, 'KINETIS_MUX', file) 613 self._write_pins('e', pcr_pins, 'KINETIS_MUX', file) 614 file.write("#endif\n") 615 616 def _parse_mex_cfg(self, mexfile): 617 """ 618 Parses mex configuration into pin groups. 619 @param mexfile: mex configuration file to parse 620 @return parsed pin groups 621 """ 622 pin_groups = {} 623 try: 624 mex_xml = ET.parse(mexfile) 625 for function in mex_xml.findall( 626 'mex:tools/mex:pins/mex:functions_list/mex:function', NAMESPACES): 627 group = PinGroup(function, self._pins) 628 pin_groups[group.get_name()] = group 629 return pin_groups 630 except ET.ParseError: 631 logging.error("Could not parse mex file %s", mex_xml) 632 return None 633 634 def write_pinctrl_groups(self, mexfile, outputfile): 635 """ 636 Write pinctrl groups to disk as a parsed DTS file. Intended for use 637 with the output of @ref write_pinctrl_defs 638 @param mexfile: mex file to parse 639 @param outputfile: DTS pinctrl file to write pin groups to 640 """ 641 file_header = ("/*\n" 642 f" * NOTE: Autogenerated file by {os.path.basename(__main__.__file__)}\n" 643 f" * for {self._part_num}/signal_configuration.xml\n" 644 " *\n" 645 f" * {self._copyright}\n" 646 " */\n" 647 "\n") 648 pin_groups = self._parse_mex_cfg(mexfile) 649 with open(outputfile, "w", encoding="utf8") as file: 650 file.write(file_header) 651 file.write(f"\n#include <nxp/kinetis/{get_package_name(mexfile)}-pinctrl.h>\n\n") 652 file.write("&pinctrl {\n") 653 # Write pin groups back out to disk 654 for group in pin_groups.values(): 655 pin_props = group.get_pin_props() 656 if len(pin_props) == 0: 657 # Do not write to disk 658 continue 659 logging.info("Writing pin group %s to disk", group.get_name()) 660 # Write description as comment if group has one 661 description = group.get_description() 662 if description != "": 663 description_lines = description.split("\n") 664 if len(description_lines) == 1: 665 file.write(f"\t/* {description} */\n") 666 else: 667 file.write("\t/*\n") 668 for line in description_lines: 669 file.write(f"\t * {line}\n") 670 file.write("\t */\n") 671 file.write(f"\t{group.get_name().lower()}: {group.get_name().lower()} {{\n") 672 idx = 0 673 for pin_prop in sorted(pin_props): 674 group_str = f"\t\tgroup{idx} {{\n" 675 # Write all pin names 676 group_str += "\t\t\tpinmux = " 677 for pin in group.get_pins(pin_prop): 678 group_str += f"<{pin.get_name()}>,\n\t\t\t\t" 679 # Strip out last 3 tabs and close pin name list 680 group_str = re.sub(r',\n\t\t\t\t$', ';\n', group_str) 681 idx += 1 682 # Write all pin props 683 for prop in pin_prop: 684 group_str += f"\t\t\t{prop};\n" 685 group_str += "\t\t};\n" 686 file.write(group_str) 687 file.write("\t};\n\n") 688 file.write("};\n") 689 690""" 691Utility functions used to get details about board/processor from MEX file 692""" 693 694def get_board_name(mexfile): 695 """ 696 Extracts board name from a mex file 697 @param mexfile: mex file to parse for board name 698 """ 699 try: 700 config_tree = ET.parse(mexfile) 701 return config_tree.getroot().find('mex:common/mex:board', 702 NAMESPACES).text 703 except ET.ParseError: 704 print(f"Malformed XML tree {mexfile}") 705 return None 706 except IOError: 707 print(f"File {mexfile} could not be opened") 708 return None 709 710def get_processor_name(mexfile): 711 """ 712 Extracts processor name from a mex file 713 @param mexfile: mex file to parse for processor name 714 """ 715 try: 716 config_tree = ET.parse(mexfile) 717 processor = config_tree.getroot().find('mex:common/mex:processor', 718 NAMESPACES) 719 if processor is None: 720 raise RuntimeError("Cannot locate processor name in MEX file. " 721 "Are you using v12 of the MCUXpresso configuration tools?") 722 return processor.text 723 except ET.ParseError: 724 print(f"Malformed XML tree {mexfile}") 725 return None 726 except IOError: 727 print(f"File {mexfile} could not be opened") 728 return None 729 730def get_package_name(mexfile): 731 """ 732 Extracts package name from a mex file 733 @param mexfile: mex file to parse for package name 734 """ 735 try: 736 config_tree = ET.parse(mexfile) 737 return config_tree.getroot().find('mex:common/mex:package', 738 NAMESPACES).text 739 except ET.ParseError: 740 print(f"Malformed XML tree {mexfile}") 741 return None 742 except IOError: 743 print(f"File {mexfile} could not be opened") 744 return None 745