Select Git revision
mpconfigport_coverage.h
-
Damien George authored
The unix coverage build is now switched fully to the VFS implementation, ie the uos module is the uos_vfs module. For example, one can now sandbox uPy to their home directory via: $ ./micropython_coverage >>> import uos >>> uos.umount('/') # unmount existing root VFS >>> vfs = uos.VfsPosix('/home/user') # create new POSIX VFS >>> uos.mount(vfs, '/') # mount new POSIX VFS at root Some filesystem/OS features may no longer work with the coverage build due to this change, and these need to be gradually fixed. The standard unix port remains unchanged, it still uses the traditional uos module which directly accesses the underlying host filesystem.
Damien George authoredThe unix coverage build is now switched fully to the VFS implementation, ie the uos module is the uos_vfs module. For example, one can now sandbox uPy to their home directory via: $ ./micropython_coverage >>> import uos >>> uos.umount('/') # unmount existing root VFS >>> vfs = uos.VfsPosix('/home/user') # create new POSIX VFS >>> uos.mount(vfs, '/') # mount new POSIX VFS at root Some filesystem/OS features may no longer work with the coverage build due to this change, and these need to be gradually fixed. The standard unix port remains unchanged, it still uses the traditional uos module which directly accesses the underlying host filesystem.
genapi.py 5.33 KiB
import argparse
import contextlib
import os
import re
import subprocess
api_src_fmt = """\
#define API(id, def) __GENERATE_API $ __GEN_ID_##id $ def $
#include "{header}"
"""
"""Generated Client file"""
api_func_start_fmt = """\
/* Autogenerated stub for {id} */
void {cdecl}({cargs})
{{
const int size = {total_size};
void*buffer;
buffer = api_call_start({id}, size);
/* TODO: Check if buffer is no NULL */
"""
serialise_arg_fmt = """ *({type}*)(buffer + {offset}) = {arg};"""
bother_dispatcher_fmt = """
printf("Sending call {id}\\nBUF: ");
for (int i = 0; i < size; i++) {{
printf("0x%02x ", ((char*)buffer)[i]);
}}
printf("\\n");
api_call_bother_dispatcher(buffer);
}}
"""
"""Generated Service file"""
api_dispatch_call_start = """\
void __api_dispatch_call(uint32_t id, void*buffer)
{
switch (id) {"""
dispatch_case_fmt = """\
case {id}:
{cdecl}("""
deserialise_arg_fmt = """\
*({type}*)(buffer + {offset})"""
insert_switch_case_break_str = """
);
break;"""
switch_add_default_fmt = """\
default:
printf("Error: API function %x is unknown!!\\n", {id});
break;
}}
}}"""
def api_func_iter (header:str):
# Parse the header for API definitions
matcher = re.compile(
r"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ void (?P<decl>.+?)\((?P<args>.*?)\) \$",
re.DOTALL | re.MULTILINE,
)
# Run the preprocessor on the header file to get the API definitions.
#
# For this, we first need a source to include the header which contains
# an alternative definition of the `API` macro that marks definitions in
# a way we can find later on.
api_src = api_src_fmt.format(
header=os.path.relpath(header)
)
# Evaluate the preprocessor
source = subprocess.check_output(
["gcc", "-E", "-"], input=api_src.encode()
).decode()
return matcher.finditer(source)
def include_header (header:str, file):
print('#include "{}"\n'.format(
os.path.basename(header)
), file=file)
def destructure_args (api_args:str):
api_args_names = []
api_args_types = []
api_args_sizes = []
args_matcher = re.compile(r"(?P<type>\w+(?:\*+|\s+))(?P<name>\w+),")
# Destructure args
for arg in args_matcher.finditer(api_args + ","):
arg_type = arg.group("type").strip()
arg_name = arg.group("name")
api_args_names.append(arg_name)
api_args_types.append(arg_type)
api_args_sizes.append("sizeof({})".format(arg_type))
return (api_args_names, api_args_types, api_args_sizes)
def serialise_arg (ty:str, api_args_sizes:list, arg_idx:int, arg:str, file):
print(
serialise_arg_fmt.format(
type=ty,
offset=" + ".join(api_args_sizes[:arg_idx]) if arg_idx > 0 else "0",
arg=arg,
),
file=file,
)
def deserialise_arg (ty:str, api_args_sizes:list, arg_idx:int, file):
if arg_idx != 0:
print(",", file=file)
print(
deserialise_arg_fmt.format(
type=ty,
offset=" + ".join(api_args_sizes[:arg_idx]) if arg_idx > 0 else "0",
),
file=file,
end="",
)
def insert_switch_case_break (file):
print(insert_switch_case_break_str,
file=file,
)
def bother_dispatcher (api_id:str, file):
print(bother_dispatcher_fmt.format(
id=api_id
),
file=file,
)
def switch_add_default (api_id:str, file):
print(switch_add_default_fmt.format(
id=api_id,
), file=file)
def main():
parser = argparse.ArgumentParser(
description="Generate the API stubs from a header file."
)
parser.add_argument(
"-H", "--header", required=True, help="The header to base the definitions on."
)
parser.add_argument(
"-c", "--client", required=True, help="The output client-side c source file."
)
parser.add_argument(
"-s", "--server", required=True, help="The output server-side c source file."
)
args = parser.parse_args()
# Open output files
cx = contextlib.ExitStack()
f_client = cx.enter_context(open(args.client, "w"))
f_server = cx.enter_context(open(args.server, "w"))
include_header (args.header, f_client)
include_header (args.header, f_server)
print(api_dispatch_call_start, file=f_server)
for api_func in api_func_iter (args.header):
api_id = api_func.group("id")
api_decl = api_func.group("decl")
api_args = api_func.group("args")
(api_args_names, api_args_types, api_args_sizes) = \
destructure_args (api_args)
print(api_func_start_fmt.format(
id=api_id,
cdecl=api_decl,
cargs=api_args,
total_size=" + ".join(api_args_sizes),
),
file=f_client,
)
print(dispatch_case_fmt.format(id=api_id, cdecl=api_decl),
file=f_server,
)
for i, (arg, ty) in enumerate(zip(api_args_names, api_args_types)):
serialise_arg (ty, api_args_sizes, i, arg, f_client)
deserialise_arg (ty, api_args_sizes, i, f_server)
insert_switch_case_break (f_server)
bother_dispatcher (api_id, f_client)
switch_add_default (api_id, f_server)
if __name__ == "__main__":
main()