1425bb815Sopenharmony_ci#!/usr/bin/env python 2425bb815Sopenharmony_ci 3425bb815Sopenharmony_ci# Copyright JS Foundation and other contributors, http://js.foundation 4425bb815Sopenharmony_ci# 5425bb815Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 6425bb815Sopenharmony_ci# you may not use this file except in compliance with the License. 7425bb815Sopenharmony_ci# You may obtain a copy of the License at 8425bb815Sopenharmony_ci# 9425bb815Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 10425bb815Sopenharmony_ci# 11425bb815Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 12425bb815Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS 13425bb815Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14425bb815Sopenharmony_ci# See the License for the specific language governing permissions and 15425bb815Sopenharmony_ci# limitations under the License. 16425bb815Sopenharmony_ci""" 17425bb815Sopenharmony_ciGenerate pins.cpp for a specified target, using target definitions from the 18425bb815Sopenharmony_cimbed OS source tree. 19425bb815Sopenharmony_ci 20425bb815Sopenharmony_ciIt's expecting to be run from the targets/mbedos5 directory. 21425bb815Sopenharmony_ci""" 22425bb815Sopenharmony_ci 23425bb815Sopenharmony_cifrom __future__ import print_function 24425bb815Sopenharmony_ci 25425bb815Sopenharmony_ciimport argparse 26425bb815Sopenharmony_ciimport ast 27425bb815Sopenharmony_ci 28425bb815Sopenharmony_ciimport sys 29425bb815Sopenharmony_ciimport os 30425bb815Sopenharmony_ci 31425bb815Sopenharmony_cifrom pycparserext.ext_c_parser import GnuCParser 32425bb815Sopenharmony_cifrom pycparser import parse_file, c_ast 33425bb815Sopenharmony_ci 34425bb815Sopenharmony_ci# import mbed tools 35425bb815Sopenharmony_cisys.path.append(os.path.join(os.path.dirname(__file__), '..', 'mbed-os')) 36425bb815Sopenharmony_cifrom tools.targets import Target 37425bb815Sopenharmony_ci 38425bb815Sopenharmony_ciLICENSE = '''/* Copyright JS Foundation and other contributors, http://js.foundation 39425bb815Sopenharmony_ci * 40425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the \"License\"); 41425bb815Sopenharmony_ci * you may not use this file except in compliance with the License. 42425bb815Sopenharmony_ci * You may obtain a copy of the License at 43425bb815Sopenharmony_ci * 44425bb815Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 45425bb815Sopenharmony_ci * 46425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 47425bb815Sopenharmony_ci * distributed under the License is distributed on an \"AS IS\" BASIS 48425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49425bb815Sopenharmony_ci * See the License for the specific language governing permissions and 50425bb815Sopenharmony_ci * limitations under the License. 51425bb815Sopenharmony_ci * 52425bb815Sopenharmony_ci * This file is generated by generate_pins.py. Please do not modify. 53425bb815Sopenharmony_ci */ 54425bb815Sopenharmony_ci ''' 55425bb815Sopenharmony_ci 56425bb815Sopenharmony_ci 57425bb815Sopenharmony_cidef find_file(root_dir, directories, name): 58425bb815Sopenharmony_ci """ 59425bb815Sopenharmony_ci Find the first instance of file with name 'name' in the directory tree 60425bb815Sopenharmony_ci starting with 'root_dir'. 61425bb815Sopenharmony_ci 62425bb815Sopenharmony_ci Filter out directories that are not in directories, or do not start with 63425bb815Sopenharmony_ci TARGET_. 64425bb815Sopenharmony_ci 65425bb815Sopenharmony_ci Since this looks in (essentially )the same directories as the compiler would 66425bb815Sopenharmony_ci when compiling mbed OS, we should only find one PinNames.h. 67425bb815Sopenharmony_ci """ 68425bb815Sopenharmony_ci 69425bb815Sopenharmony_ci for root, dirs, files in os.walk(root_dir, topdown=True): 70425bb815Sopenharmony_ci # modify dirs in place 71425bb815Sopenharmony_ci dirs[:] = [directory for directory in dirs if directory in directories or not directory.startswith('TARGET_')] 72425bb815Sopenharmony_ci 73425bb815Sopenharmony_ci if name in files: 74425bb815Sopenharmony_ci return os.path.join(root, name) 75425bb815Sopenharmony_ci 76425bb815Sopenharmony_ci 77425bb815Sopenharmony_cidef enumerate_includes(root_dir, directories): 78425bb815Sopenharmony_ci """ 79425bb815Sopenharmony_ci Walk through the directory tree, starting at root_dir, and enumerate all 80425bb815Sopenharmony_ci valid include directories. 81425bb815Sopenharmony_ci """ 82425bb815Sopenharmony_ci for root, dirs, _ in os.walk(root_dir, topdown=True): 83425bb815Sopenharmony_ci # modify dirs in place 84425bb815Sopenharmony_ci dirs[:] = [dir_label for dir_label in dirs 85425bb815Sopenharmony_ci if dir_label in directories 86425bb815Sopenharmony_ci or (not dir_label.startswith('TARGET_') 87425bb815Sopenharmony_ci and not dir_label.startswith('TOOLCHAIN_'))] 88425bb815Sopenharmony_ci yield root 89425bb815Sopenharmony_ci 90425bb815Sopenharmony_ci 91425bb815Sopenharmony_ciclass TypeDeclVisitor(c_ast.NodeVisitor): 92425bb815Sopenharmony_ci """ 93425bb815Sopenharmony_ci A TypeDecl visitor class that walks the ast and calls a visitor function for every node found. 94425bb815Sopenharmony_ci """ 95425bb815Sopenharmony_ci def __init__(self, filter_names=None): 96425bb815Sopenharmony_ci self.names = filter_names or [] 97425bb815Sopenharmony_ci 98425bb815Sopenharmony_ci def visit(self, node): 99425bb815Sopenharmony_ci value = None 100425bb815Sopenharmony_ci 101425bb815Sopenharmony_ci if node.__class__.__name__ == "TypeDecl": 102425bb815Sopenharmony_ci value = self.visit_typedecl(node) 103425bb815Sopenharmony_ci 104425bb815Sopenharmony_ci if value is None: 105425bb815Sopenharmony_ci for _, child_node in node.children(): 106425bb815Sopenharmony_ci value = value or self.visit(child_node) 107425bb815Sopenharmony_ci 108425bb815Sopenharmony_ci return value 109425bb815Sopenharmony_ci 110425bb815Sopenharmony_ci def visit_typedecl(self, node): 111425bb815Sopenharmony_ci """ 112425bb815Sopenharmony_ci Visit a node. 113425bb815Sopenharmony_ci """ 114425bb815Sopenharmony_ci if node.declname in self.names: 115425bb815Sopenharmony_ci return [pin.name for pin in node.type.values.enumerators] 116425bb815Sopenharmony_ci 117425bb815Sopenharmony_ci 118425bb815Sopenharmony_cidef enumerate_pins(c_source_file, include_dirs, definitions): 119425bb815Sopenharmony_ci """ 120425bb815Sopenharmony_ci Enumerate pins specified in PinNames.h, by looking for a PinName enum 121425bb815Sopenharmony_ci typedef somewhere in the file. 122425bb815Sopenharmony_ci """ 123425bb815Sopenharmony_ci definitions += ['__attribute(x)__=', '__extension__(x)=', 'register=', '__IO=', 'uint32_t=unsigned int'] 124425bb815Sopenharmony_ci 125425bb815Sopenharmony_ci gcc_args = ['-E', '-fmerge-all-constants'] 126425bb815Sopenharmony_ci gcc_args += ['-I' + directory for directory in include_dirs] 127425bb815Sopenharmony_ci 128425bb815Sopenharmony_ci gcc_args += ['-D' + definition for definition in definitions] 129425bb815Sopenharmony_ci parsed_ast = parse_file(c_source_file, 130425bb815Sopenharmony_ci use_cpp=True, 131425bb815Sopenharmony_ci cpp_path='arm-none-eabi-gcc', 132425bb815Sopenharmony_ci cpp_args=gcc_args, 133425bb815Sopenharmony_ci parser=GnuCParser()) 134425bb815Sopenharmony_ci 135425bb815Sopenharmony_ci # now, walk the AST 136425bb815Sopenharmony_ci visitor = TypeDeclVisitor(['PinName']) 137425bb815Sopenharmony_ci return visitor.visit(parsed_ast) 138425bb815Sopenharmony_ci 139425bb815Sopenharmony_ci 140425bb815Sopenharmony_cidef write_pins_to_file(pins, pins_file, out_cpp_file): 141425bb815Sopenharmony_ci """ 142425bb815Sopenharmony_ci Write the generated pins for a specified mbed board into the output C++ file. 143425bb815Sopenharmony_ci """ 144425bb815Sopenharmony_ci 145425bb815Sopenharmony_ci include = '\n#include "../{}"'.format(pins_file) 146425bb815Sopenharmony_ci 147425bb815Sopenharmony_ci count = ''' 148425bb815Sopenharmony_ciunsigned int jsmbed_js_magic_string_count = {}; 149425bb815Sopenharmony_ci '''.format(len(pins)) 150425bb815Sopenharmony_ci 151425bb815Sopenharmony_ci lengths = ',\n '.join(str(len(pin)) for pin in pins) 152425bb815Sopenharmony_ci lenghts_source = ''' 153425bb815Sopenharmony_ciunsigned int jsmbed_js_magic_string_lengths[] = { 154425bb815Sopenharmony_ci %s 155425bb815Sopenharmony_ci}; 156425bb815Sopenharmony_ci ''' % lengths 157425bb815Sopenharmony_ci 158425bb815Sopenharmony_ci magic_values = ',\n '.join(pins) 159425bb815Sopenharmony_ci magic_source = ''' 160425bb815Sopenharmony_ciunsigned int jsmbed_js_magic_string_values[] = { 161425bb815Sopenharmony_ci %s 162425bb815Sopenharmony_ci}; 163425bb815Sopenharmony_ci ''' % magic_values 164425bb815Sopenharmony_ci 165425bb815Sopenharmony_ci magic_strings = ',\n '.join('"' + pin + '"' for pin in pins) 166425bb815Sopenharmony_ci magic_string_source = ''' 167425bb815Sopenharmony_ciconst char * jsmbed_js_magic_strings[] = { 168425bb815Sopenharmony_ci %s 169425bb815Sopenharmony_ci}; 170425bb815Sopenharmony_ci ''' % magic_strings 171425bb815Sopenharmony_ci 172425bb815Sopenharmony_ci out_cpp_file.write(LICENSE + include + count + lenghts_source + magic_source + magic_string_source) 173425bb815Sopenharmony_ci 174425bb815Sopenharmony_ci 175425bb815Sopenharmony_cidef main(): 176425bb815Sopenharmony_ci """ 177425bb815Sopenharmony_ci Perform the main function of this program 178425bb815Sopenharmony_ci """ 179425bb815Sopenharmony_ci if not os.path.exists('./mbed-os'): 180425bb815Sopenharmony_ci print("Fatal: mbed-os directory does not exist.") 181425bb815Sopenharmony_ci print("Try running 'make getlibs'") 182425bb815Sopenharmony_ci sys.exit(1) 183425bb815Sopenharmony_ci 184425bb815Sopenharmony_ci description = """ 185425bb815Sopenharmony_ci Generate pins.cpp for a specified mbed board, using target definitions from the 186425bb815Sopenharmony_ci mbed OS source tree. 187425bb815Sopenharmony_ci """ 188425bb815Sopenharmony_ci 189425bb815Sopenharmony_ci parser = argparse.ArgumentParser(description=description) 190425bb815Sopenharmony_ci 191425bb815Sopenharmony_ci parser.add_argument('board', help='mbed board name') 192425bb815Sopenharmony_ci parser.add_argument('-c', 193425bb815Sopenharmony_ci help='Output C++ file (default: %(default)s)', 194425bb815Sopenharmony_ci default='source/pins.cpp', 195425bb815Sopenharmony_ci type=argparse.FileType('w')) 196425bb815Sopenharmony_ci 197425bb815Sopenharmony_ci args = parser.parse_args() 198425bb815Sopenharmony_ci board_name = args.board.upper() 199425bb815Sopenharmony_ci 200425bb815Sopenharmony_ci target = Target.get_target(board_name) 201425bb815Sopenharmony_ci 202425bb815Sopenharmony_ci directory_labels = ['TARGET_' + label for label in target.labels] + target.macros 203425bb815Sopenharmony_ci 204425bb815Sopenharmony_ci targets_dir = os.path.join('.', 'mbed-os', 'targets') 205425bb815Sopenharmony_ci 206425bb815Sopenharmony_ci pins_file = find_file(targets_dir, directory_labels, 'PinNames.h') 207425bb815Sopenharmony_ci 208425bb815Sopenharmony_ci includes = enumerate_includes(targets_dir, directory_labels) 209425bb815Sopenharmony_ci defines = list(directory_labels) 210425bb815Sopenharmony_ci 211425bb815Sopenharmony_ci # enumerate pins from PinNames.h 212425bb815Sopenharmony_ci pins = enumerate_pins(pins_file, ['./tools'] + list(includes), defines) 213425bb815Sopenharmony_ci 214425bb815Sopenharmony_ci # first sort alphabetically, then by length. 215425bb815Sopenharmony_ci pins = sorted(pins, key=lambda x: (len(x), x.lower())) 216425bb815Sopenharmony_ci 217425bb815Sopenharmony_ci write_pins_to_file(pins, pins_file, args.c) 218425bb815Sopenharmony_ci 219425bb815Sopenharmony_ci 220425bb815Sopenharmony_ciif __name__ == "__main__": 221425bb815Sopenharmony_ci main() 222