mirror of
https://github.com/bluekitchen/btstack.git
synced 2024-12-28 15:20:39 +00:00
423 lines
14 KiB
Python
Executable File
423 lines
14 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import os, sys, getopt, re, pickle
|
|
|
|
copyright = """/*
|
|
* Copyright (C) 2016 BlueKitchen GmbH
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holders nor the names of
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
* 4. Any redistribution, use, or modification is done solely for
|
|
* personal benefit and not for any commercial purpose or for
|
|
* monetary gain.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
|
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* Please inquire about commercial licensing options at
|
|
* contact@bluekitchen-gmbh.com
|
|
*
|
|
*/
|
|
"""
|
|
|
|
single_hfile_header_begin = """
|
|
|
|
/*
|
|
* btstack_rtos.h
|
|
*
|
|
* @brief BTstack Wrapper for use with Real-Time OS
|
|
* Wraps each public BTstack function into a thread-safe version
|
|
*
|
|
* @note Don't edit - generated by tool/btstack_rtos_generator.py
|
|
*
|
|
*/
|
|
|
|
#ifndef BTSTACK_RTOS_H
|
|
#define BTSTACK_RTOS_H
|
|
|
|
#if defined __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "btstack_config.h"
|
|
|
|
#ifndef BTSTACK_RTOS_ENTER
|
|
#error Please define BTSTACK_RTOS_ENTER that locks a recursive mutex when using the RTOS wrapper btstack_rtos.h
|
|
#endif
|
|
|
|
#ifndef BTSTACK_RTOS_EXIT
|
|
#error Please define BTSTACK_RTOS_EXIT that releases a recursive mutex when using the RTOS wrapper btstack_rtos.h
|
|
#endif
|
|
|
|
/* API_START */
|
|
|
|
|
|
"""
|
|
|
|
single_hfile_api_header = """
|
|
#include "API_NAME"
|
|
"""
|
|
|
|
single_hfile_header_end = """
|
|
|
|
/* API_END */
|
|
|
|
#if defined __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // BTSTACK_RTOS_H
|
|
"""
|
|
|
|
multiple_header_begin = """
|
|
|
|
/*
|
|
* FILENAME
|
|
*
|
|
* @brief BTstack Wrapper for use with Real-Time OS
|
|
* Wraps each public BTstack function into a thread-safe version
|
|
*
|
|
* @note Don't edit - generated by tool/btstack_rtos_generator.py
|
|
*
|
|
*/
|
|
|
|
#ifndef GUARD
|
|
#define GUARD
|
|
|
|
#if defined __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "btstack_config.h"
|
|
#include "HEADER"
|
|
|
|
#ifndef BTSTACK_RTOS_ENTER
|
|
#error Please define BTSTACK_RTOS_ENTER that locks a recursive mutex when using the RTOS wrapper btstack_rtos.h
|
|
#endif
|
|
|
|
#ifndef BTSTACK_RTOS_EXIT
|
|
#error Please define BTSTACK_RTOS_EXIT that releases a recursive mutex when using the RTOS wrapper btstack_rtos.h
|
|
#endif
|
|
|
|
/* API_START */
|
|
|
|
|
|
"""
|
|
|
|
multiple_header_end = """
|
|
|
|
/* API_END */
|
|
|
|
#if defined __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // GUARD
|
|
"""
|
|
|
|
class State:
|
|
SearchStartAPI = 0
|
|
SearchEndAPI = 1
|
|
DoneAPI = 2
|
|
|
|
|
|
num_functions = 0
|
|
|
|
# [file_name, api_title, api_label]
|
|
apis = [
|
|
["src/ble/gatt-service/ancs_client.h", "BLE ANCS Client", "ancsClient", True],
|
|
["src/ble/att_db_util.h", "BLE ATT Database", "attDb", True],
|
|
["src/ble/att_server.h", "BLE ATT Server", "attServer", True],
|
|
["src/ble/gatt_client.h", "BLE GATT Client", "gattClient", True],
|
|
["src/ble/le_device_db.h", "BLE Device Database", "leDeviceDb", True],
|
|
["src/ble/sm.h", "BLE Security Manager", "sm", True],
|
|
|
|
["src/classic/bnep.h", "BNEP", "bnep", True],
|
|
["src/classic/btstack_link_key_db.h","Link Key DB","lkDb", True],
|
|
["src/classic/hsp_hs.h","HSP Headset","hspHS", True],
|
|
["src/classic/hsp_ag.h","HSP Audio Gateway","hspAG", True],
|
|
["src/classic/hfp_hf.h","HFP Hands-Free","hfpHF", True],
|
|
["src/classic/hfp_ag.h","HFP Audio Gateway","hfpAG", True],
|
|
["src/classic/pan.h", "PAN", "pan", True],
|
|
["src/classic/rfcomm.h", "RFCOMM", "rfcomm", True],
|
|
["src/classic/sdp_client.h", "SDP Client", "sdpClient", True],
|
|
["src/classic/sdp_client_rfcomm.h", "SDP RFCOMM Query", "sdpQueries", True],
|
|
["src/classic/sdp_server.h", "SDP Server", "sdpSrv", True],
|
|
["src/classic/sdp_util.h","SDP Utils", "sdpUtil", True],
|
|
|
|
["src/ad_parser.h", "BLE Advertisements Parser", "advParser", False],
|
|
# ["src/btstack_chipset.h","BTstack Chipset","btMemory", True],
|
|
# ["src/btstack_control.h","BTstack Hardware Control","btControl", True],
|
|
["src/btstack_event.h","HCI Event Getter","btEvent", False],
|
|
# ["src/btstack_memory.h","BTstack Memory Management","btMemory", True],
|
|
["src/btstack_linked_list.h","BTstack Linked List","btList", False],
|
|
["src/btstack_run_loop.h", "Run Loop", "runLoop", True],
|
|
["src/btstack_util.h", "Common Utils", "btUtil", False],
|
|
["src/gap.h", "GAP", "gap", True],
|
|
["src/hci.h", "HCI", "hci", True],
|
|
["src/hci_dump.h","HCI Logging","hciTrace", True],
|
|
# ["src/hci_transport.h","HCI Transport","hciTransport", True],
|
|
["src/l2cap.h", "L2CAP", "l2cap", True],
|
|
]
|
|
|
|
def split_arguments(args_string):
|
|
args = []
|
|
brace_level = 0
|
|
arg = ''
|
|
for c in args_string:
|
|
if c == '(':
|
|
brace_level += 1
|
|
if c == ')':
|
|
brace_level -= 1
|
|
if c == ',' and brace_level == 0:
|
|
args.append(arg)
|
|
arg = ''
|
|
continue
|
|
arg = arg + c
|
|
if len(arg):
|
|
args.append(arg)
|
|
return args
|
|
|
|
def argument_name(parameter):
|
|
function_pointer = re.match(r'[\w\s\*]*\(\s*\*(\w*)\s*\)\(.*\)', parameter)
|
|
if function_pointer:
|
|
return function_pointer.group(1)
|
|
parts = parameter.split(' ')
|
|
filtered_parts = [part for part in parts if part not in ['']]
|
|
arg = filtered_parts[len(filtered_parts)-1].replace('*','').replace('[]','')
|
|
# le_device_db_encryption_set(index, ediv, rand[8], ltk, key_size, authenticated, authorized);
|
|
if arg == 'rand[8]':
|
|
arg = 'rand'
|
|
return arg
|
|
|
|
def create_wrapper(fout, type_and_name, arg_string, need_lock):
|
|
global num_functions
|
|
|
|
parts = type_and_name.split(' ')
|
|
filtered_parts = [part for part in parts if part not in ['static','inline','']]
|
|
name = filtered_parts[len(filtered_parts)-1]
|
|
return_type = ' '.join(filtered_parts[:-1])
|
|
# handle *function_name
|
|
if name.startswith('*'):
|
|
name = name[1:]
|
|
return_type = return_type + ' *'
|
|
rtos_name = "rtos_" + name
|
|
is_void_function = len(filtered_parts) == 2 and filtered_parts[0] == "void"
|
|
args = split_arguments(arg_string)
|
|
call = []
|
|
is_ellipse_function = False
|
|
if len(args)!= 1 or args[0] != 'void':
|
|
for arg in args:
|
|
call_arg = argument_name(arg)
|
|
if call_arg == '...':
|
|
is_ellipse_function = True
|
|
call.append('argptr')
|
|
name += '_va_arg'
|
|
else:
|
|
call.append(argument_name(arg))
|
|
call_args = ', '.join(call)
|
|
fout.write('static inline ' + return_type + ' ' + rtos_name + '(' + ", ".join(args) + '){\n')
|
|
orig_call = name + '(' + call_args + ')'
|
|
if need_lock:
|
|
fout.write(' BTSTACK_RTOS_ENTER();\n')
|
|
if is_ellipse_function:
|
|
fout.write(' va_list argptr;\n')
|
|
fout.write(' va_start(argptr, %s);\n' % call[-2])
|
|
if is_void_function:
|
|
fout.write(' ' + orig_call+';\n')
|
|
else:
|
|
fout.write(' ' + return_type + ' res = ' + orig_call + ';\n')
|
|
if is_ellipse_function:
|
|
fout.write(' va_end(argptr);\n')
|
|
fout.write(' BTSTACK_RTOS_EXIT();\n')
|
|
if not is_void_function:
|
|
fout.write(' return res;\n')
|
|
else:
|
|
if is_void_function:
|
|
fout.write(' ' + orig_call+';\n')
|
|
else:
|
|
fout.write(' return ' + orig_call + ';\n')
|
|
fout.write('}\n')
|
|
fout.write('\n')
|
|
num_functions += 1
|
|
|
|
def write_wrappers_for_file(fout, file, header_name, need_lock):
|
|
with open(file, 'r') as fin:
|
|
typedefFound = 0
|
|
multiline_function_def = 0
|
|
multiline = ''
|
|
multiline_comment = 0
|
|
inline_function = 0
|
|
state = State.SearchStartAPI
|
|
|
|
for line in fin:
|
|
if state == State.DoneAPI:
|
|
continue
|
|
|
|
if state == State.SearchStartAPI:
|
|
parts = re.match(r'.*API_START.*',line)
|
|
if parts:
|
|
state = State.SearchEndAPI
|
|
continue
|
|
|
|
if state == State.SearchEndAPI:
|
|
parts = re.match(r'.*API_END.*',line)
|
|
if parts:
|
|
state = State.DoneAPI
|
|
continue
|
|
|
|
if inline_function:
|
|
function_end = re.match(r'.*}.*', line)
|
|
if function_end:
|
|
inline_function = 0
|
|
continue
|
|
|
|
if multiline_function_def:
|
|
multiline += line
|
|
function_end = re.match(r'.*\)', line)
|
|
if function_end:
|
|
multiline_function_def = 0
|
|
function = re.match(r'([\w\s\*]*)\(([\w\s,\*]*)\).*', multiline)
|
|
if function:
|
|
type_and_name = function.group(1)
|
|
arg_string = function.group(2)
|
|
create_wrapper(fout, type_and_name, arg_string, need_lock)
|
|
continue
|
|
|
|
if multiline_comment:
|
|
comment_end = re.match(r'.*\*/.*', line)
|
|
if comment_end:
|
|
multiline_comment = 0
|
|
fout.write(line)
|
|
continue
|
|
|
|
# search typedef struct end
|
|
if typedefFound:
|
|
typedef = re.match(r'}\s*(.*);\n', line)
|
|
if typedef:
|
|
typedefFound = 0
|
|
continue
|
|
|
|
# search comment line
|
|
comment = re.match(r'.*/\*.*\*/.*', line)
|
|
if comment:
|
|
fout.write(line)
|
|
continue
|
|
|
|
# search start of multi line comment
|
|
comment = re.match(r'.*/\*', line)
|
|
if comment:
|
|
fout.write(line)
|
|
multiline_comment = 1
|
|
continue
|
|
|
|
# ignore __attribute__ for hci_dump_log in src/hci_dump.h
|
|
param = re.match(r'.*__attribute__', line)
|
|
if param:
|
|
continue
|
|
|
|
# search typedef struct begin
|
|
typedef = re.match(r'.*typedef\s+struct.*', line)
|
|
if typedef:
|
|
typedefFound = 1
|
|
|
|
# complete function declaration
|
|
function = re.match(r'([\w\s\*]*)\((.*)\).*', line)
|
|
if function:
|
|
if "return" in line:
|
|
continue
|
|
type_and_name = function.group(1)
|
|
arg_string = function.group(2)
|
|
create_wrapper(fout, type_and_name, arg_string, need_lock)
|
|
inline_function = 'inline' in line;
|
|
continue
|
|
|
|
# multi-line function declaration
|
|
function = re.match(r'([\w\s\*]*)\((.*).*', line)
|
|
if function:
|
|
multiline = line
|
|
multiline_function_def = 1
|
|
continue
|
|
|
|
# fout.write(single_hfile_header_begin)
|
|
|
|
|
|
def create_wrapper_file(btstack_root, apis, wrapper_file):
|
|
with open(wrapper_file, 'w') as fout:
|
|
fout.write(copyright)
|
|
fout.write(single_hfile_header_begin)
|
|
|
|
for api_tuple in apis:
|
|
api_filename = btstack_root + "/" + api_tuple[0]
|
|
need_lock = api_tuple[3]
|
|
header_file = api_tuple[0].replace('src/','')
|
|
fout.write(single_hfile_api_header.replace("API_NAME", header_file))
|
|
write_wrappers_for_file(fout, api_filename, header_file, need_lock)
|
|
# fout.write(single_hfile_header_begin)
|
|
fout.write(single_hfile_header_end)
|
|
|
|
def create_wrapper_files(btstack_root, rtos_folder, apis):
|
|
for api_tuple in apis:
|
|
api_filename = btstack_root + "/" + api_tuple[0]
|
|
need_lock = api_tuple[3]
|
|
header_file = api_tuple[0].replace('src/','')
|
|
path_parts = header_file.split('/')
|
|
path_parts[-1] = 'rtos_' + path_parts[-1]
|
|
rtos_file = '/'.join(path_parts)
|
|
wrapper_file = rtos_folder + '/' + rtos_file
|
|
# print('- %s' % wrapper_file)
|
|
with open(wrapper_file, 'w') as fout:
|
|
guard = '__' + rtos_file.replace('.','_').upper()
|
|
fout.write(copyright)
|
|
fout.write(multiple_header_begin.replace('FILENAME',rtos_file).replace('GUARD',guard).replace('HEADER',header_file))
|
|
write_wrappers_for_file(fout, api_filename, header_file, need_lock)
|
|
fout.write(multiple_header_end.replace('GUARD',guard))
|
|
|
|
def assert_dir_exists(path):
|
|
if not os.path.exists(path):
|
|
os.makedirs(path)
|
|
|
|
def main(argv):
|
|
btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..')
|
|
print ('BTstack folder is: %s' % btstack_root)
|
|
|
|
# single file
|
|
# gen_path = btstack_root + '/src/btstack_rtos.h'
|
|
# print ('Generating RTOS wrapper %s' % gen_path)
|
|
# create_wrapper_file(btstack_root, apis, gen_path)
|
|
|
|
# individual files in platform/rtos
|
|
print ('Generating RTOS wrappers...')
|
|
rtos_folder = btstack_root + '/platform/rtos'
|
|
assert_dir_exists(rtos_folder)
|
|
assert_dir_exists(rtos_folder+'/ble')
|
|
assert_dir_exists(rtos_folder+'/ble/gatt-service')
|
|
assert_dir_exists(rtos_folder+'/classic')
|
|
create_wrapper_files(btstack_root, rtos_folder, apis)
|
|
|
|
# summary
|
|
print ('Number wrapped headers: %u' % len(apis))
|
|
print ('Number wrapped functions: %u' % num_functions)
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|