Skip to content

Commit

Permalink
fix(wifi_remote): Clenaup
Browse files Browse the repository at this point in the history
  • Loading branch information
david-cermak committed Mar 6, 2024
1 parent 2000a51 commit 091d30a
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
Expand Down Expand Up @@ -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{')
Expand All @@ -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)
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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});')


Expand Down
185 changes: 185 additions & 0 deletions components/esp_wifi_remote/scripts/parse_header.py
Original file line number Diff line number Diff line change
@@ -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():

0 comments on commit 091d30a

Please sign in to comment.