From 091d30a5db0a140a8195ab1bd014357320cbb5e5 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 6 Mar 2024 09:27:58 +0100 Subject: [PATCH] fix(wifi_remote): Clenaup --- .../{test => scripts}/generate.py | 16 +- .../{test => scripts}/ignore_extensions.h | 0 .../esp_wifi_remote/scripts/parse_header.py | 185 ++++++++++++++++++ 3 files changed, 189 insertions(+), 12 deletions(-) rename components/esp_wifi_remote/{test => scripts}/generate.py (94%) rename components/esp_wifi_remote/{test => scripts}/ignore_extensions.h (100%) create mode 100644 components/esp_wifi_remote/scripts/parse_header.py diff --git a/components/esp_wifi_remote/test/generate.py b/components/esp_wifi_remote/scripts/generate.py similarity index 94% rename from components/esp_wifi_remote/test/generate.py rename to components/esp_wifi_remote/scripts/generate.py index 1b58ed51fc5..a8cea4faa2e 100644 --- a/components/esp_wifi_remote/test/generate.py +++ b/components/esp_wifi_remote/scripts/generate.py @@ -6,12 +6,13 @@ import re import subprocess import tempfile -from typing import List, Optional, Set, Tuple, Union from collections import namedtuple +from typing import List, Optional, Set, Tuple, Union + +from pycparser import c_ast, c_parser, preprocess_file # Define a named tuple for the simplified AST -from pycparser import c_ast, c_parser, preprocess_file # Function prototypes dictionary to store extracted prototypes function_prototypes = {} @@ -74,7 +75,6 @@ def visit_FuncDecl(self, node): if func_name.startswith('esp_wifi') and func_name in self.content: # for line in self.content.split('\n'): # if func_name in line: - # print(line) ret = node.type.type.names[0] args = [] print('\n{') @@ -83,9 +83,6 @@ def visit_FuncDecl(self, node): param = Param(ptr=self.ptr, array=self.array, qual=quals, type=type, name=name) args.append(param) # if name is not None: - # args.append(name+'_param') - # params = ', '.join(args) - # print('{} ret = {}({});'.format(ret, func_name, params)) print('(void)ret;') print('}\n') self.function_prototypes[func_name] = (ret, args) @@ -167,7 +164,6 @@ def exec_cmd(what: List, out_file: Union['tempfile._TemporaryFileWrapper[bytes]' def preprocess(idf_path, header): project_dir = os.path.join(idf_path, 'examples', 'get-started', 'blink') - # build_dir = '/tmp/tmpnk1dvbfo' #tempfile.mkdtemp() build_dir = os.path.join(project_dir, 'build') print(build_dir) sdkconfig = os.path.join(build_dir, 'sdkconfig') @@ -208,7 +204,6 @@ def preprocess(idf_path, header): f.write('#define __volatile__\n') with open('example.h', 'a') as f: rc, out, err, cmd = exec_cmd(['xtensa-esp32-elf-gcc', '-w', '-P', '-include', 'ignore_extensions.h', '-E', header] + include_dir_flags, f) - # rc, out, err, cmd = exec_cmd(['riscv32-esp-elf-gcc', '-w', '-P', '-include', 'ignore_extensions.h', '-E', header] + include_dir_flags, f) print(err) # with open('example.h', 'w') as f: # riscv32-esp-elf-gcc @@ -219,13 +214,11 @@ def preprocess(idf_path, header): raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.") header = os.path.join(idf_path, 'components', 'esp_wifi', 'include', 'esp_wifi.h') preprocess(idf_path, header) - # exit() header_file = 'example.h' preprocessed_code = preprocess_header(header_file) print('Extracted function prototypes:') function_prototypes = extract_function_prototypes(preprocessed_code, header) for func_name, args in function_prototypes.items(): - #print(f'{func_name}: {args}') params = [] for param in args[1]: typename=param.type @@ -241,8 +234,7 @@ def preprocess(idf_path, header): declname += f'[{param.array}]' params.append(f'{typename} {declname}') arguments = ', '.join(params) - # print(params.ptr, params.array, params.qual, params.type, params.name) - # + # print(f'\n{args[0]} {func_name}({arguments});') diff --git a/components/esp_wifi_remote/test/ignore_extensions.h b/components/esp_wifi_remote/scripts/ignore_extensions.h similarity index 100% rename from components/esp_wifi_remote/test/ignore_extensions.h rename to components/esp_wifi_remote/scripts/ignore_extensions.h diff --git a/components/esp_wifi_remote/scripts/parse_header.py b/components/esp_wifi_remote/scripts/parse_header.py new file mode 100644 index 00000000000..8eae1f8c29c --- /dev/null +++ b/components/esp_wifi_remote/scripts/parse_header.py @@ -0,0 +1,185 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import json +import os +import re +import subprocess +from collections import namedtuple + +from pycparser import c_ast, c_parser, preprocess_file + +Param = namedtuple('Param', ['ptr', 'array', 'qual', 'type', 'name']) + +class FunctionVisitor(c_ast.NodeVisitor): + def __init__(self, header): + self.function_prototypes = {} + self.ptr = 0 + self.array = 0 + self.content = open(header, 'r').read() + + def get_type(self, node, suffix='param'): + if suffix == 'param': + self.ptr = 0 + self.array = 0 + + if isinstance(node.type, c_ast.TypeDecl): + typename = node.type.declname + quals = '' + if node.type.quals: + quals = ' '.join(node.type.quals) + if node.type.type.names: + type = node.type.type.names[0] + return quals, type, typename + if isinstance(node.type, c_ast.PtrDecl): + quals, type, name = self.get_type(node.type, 'ptr') + self.ptr += 1 + return quals, type, name + + if isinstance(node.type, c_ast.ArrayDecl): + quals, type, name = self.get_type(node.type, 'array') + self.array = int(node.type.dim.value) + return quals, type, name + + def visit_FuncDecl(self, node): + if isinstance(node.type, c_ast.TypeDecl): + func_name = node.type.declname + if func_name.startswith('esp_wifi') and func_name in self.content: + ret = node.type.type.names[0] + args = [] + for param in node.args.params: + quals, type, name = self.get_type(param) + param = Param(ptr=self.ptr, array=self.array, qual=quals, type=type, name=name) + args.append(param) + self.function_prototypes[func_name] = (ret, args) + +# Parse the header file and extract function prototypes +def extract_function_prototypes(header_code, header): + parser = c_parser.CParser() # Set debug parameter to False + ast = parser.parse(header_code) + visitor = FunctionVisitor(header) + visitor.visit(ast) + return visitor.function_prototypes + +def preprocess_header(header_file): + with open(header_file, 'r') as file: + preprocessed_code = preprocess_file(header_file) + return preprocessed_code + +# # Parse the preprocessed header file and extract function prototypes +# def extract_function_prototypes(header_code): + +# Generate test cases for each function +def generate_test_cases(): + test_cases = {} + for func_name, args in function_prototypes.items(): + test_args = [] + for arg_info in args: + if isinstance(arg_info, c_ast.TypeDecl): + print(arg_info.type.names[0]) + arg_name = arg_info.declname + arg_type = 'int' # Default to int type if type is missing + else: + arg_name, arg_type = arg_info + test_args.append((arg_name, generate_test_argument(arg_type))) + test_cases[func_name] = test_args + return test_cases + +# Generate test argument based on type +def generate_test_argument(arg_type): + if isinstance(arg_type, c_ast.TypeDecl): + return generate_test_argument(arg_type.type) + elif isinstance(arg_type, c_ast.PtrDecl): + return None # Placeholder for pointer argument handling + elif isinstance(arg_type, c_ast.IdentifierType): + if 'int' in arg_type.names: + return 1 # Example integer argument + elif 'float' in arg_type.names: + return 1.0 # Example float argument + # Add more cases as needed for other data types + return None # Unknown type + +def generate_forwarding_c_file(prefix): + with open('forwarding.c', 'w') as file: + # Write includes and any other necessary declarations + file.write('#include "example.h"\n\n') + + # Write forwarding function definitions + for func_name, args in function_prototypes.items(): + # Write the forwarding function declaration + file.write(f'{function_prototypes[func_name][0]} {prefix}_{func_name}(') + file.write(') {\n') + + # Write the forwarding call + file.write(f' return {func_name}(') + file.write(');\n}\n\n') + +def exec_cmd(what, out_file): + p = subprocess.Popen(what, stdin=subprocess.PIPE, stdout=out_file, stderr=subprocess.PIPE) + output_b, err_b = p.communicate() + rc = p.returncode + output: str = output_b.decode('utf-8') if output_b is not None else '' + err: str = err_b.decode('utf-8') if err_b is not None else '' + return rc, output, err, ' '.join(what) + + +def preprocess(idf_path, header): + project_dir = os.path.join(idf_path, 'examples', 'get-started', 'blink') + build_dir = os.path.join(project_dir, 'build') + build_commands_json = os.path.join(build_dir, 'compile_commands.json') + with open(build_commands_json, 'r', encoding='utf-8') as f: + build_command = json.load(f)[0]['command'].split() + include_dir_flags = [] + include_dirs = [] + # process compilation flags (includes and defines) + for item in build_command: + if item.startswith('-I'): + include_dir_flags.append(item) + if 'components' in item: + include_dirs.append(item[2:]) # Removing the leading "-I" + if item.startswith('-D'): + include_dir_flags.append(item.replace('\\','')) # removes escaped quotes, eg: -DMBEDTLS_CONFIG_FILE=\\\"mbedtls/esp_config.h\\\" + include_dir_flags.append('-I' + os.path.join(build_dir, 'config')) + temp_file = 'esp_wifi_preprocessed.h' + with open(temp_file, 'w') as f: + f.write('#define asm\n') + f.write('#define volatile\n') + f.write('#define __asm__\n') + f.write('#define __volatile__\n') + with open(temp_file, 'a') as f: + rc, out, err, cmd = exec_cmd(['xtensa-esp32-elf-gcc', '-w', '-P', '-include', 'ignore_extensions.h', '-E', header] + include_dir_flags, f) + print(err) + preprocessed_code = preprocess_file(temp_file) + return preprocessed_code + + # with open('example.h', 'w') as f: + # riscv32-esp-elf-gcc + +if __name__ == '__main__': + idf_path = os.getenv('IDF_PATH') + if idf_path is None: + raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.") + header = os.path.join(idf_path, 'components', 'esp_wifi', 'include', 'esp_wifi.h') + function_prototypes = extract_function_prototypes(preprocess(idf_path, header), header) + + for func_name, args in function_prototypes.items(): + params = [] + for param in args[1]: + typename=param.type + if typename == 'void': + params.append(f'{typename}') + continue + if param.qual != '': + typename = f'{param.qual} '+ typename + declname = param.name + if param.ptr > 0: + declname = '*'*param.ptr + declname + if param.array > 0: + declname += f'[{param.array}]' + params.append(f'{typename} {declname}') + arguments = ', '.join(params) + print(f'{args[0]} {func_name}({arguments});') + + + # for func_name, args in test_cases.items(): + + # for func_name, args in test_cases.items():