1#!/usr/bin/env python 2import os, sys, getopt, re, pickle 3 4copyright = """/* 5 * Copyright (C) 2016 BlueKitchen GmbH 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the copyright holders nor the names of 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 4. Any redistribution, use, or modification is done solely for 20 * personal benefit and not for any commercial purpose or for 21 * monetary gain. 22 * 23 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 27 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 33 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * Please inquire about commercial licensing options at 37 * [email protected] 38 * 39 */ 40""" 41 42hfile_header_begin = """ 43 44/* 45 * btstack_rtos.h 46 * 47 * @brief BTstack Wrapper for use with Real-Time OS 48 * Wraps each public BTstack function into a thread-safe version 49 * 50 * @note Don't edit - generated by tool/btstack_rtos_generator.py 51 * 52 */ 53 54#ifndef __BTSTACK_RTOS_H 55#define __BTSTACK_RTOS_H 56 57#if defined __cplusplus 58extern "C" { 59#endif 60 61#include "btstack_config.h" 62 63#ifndef BTSTACK_RTOS_ENTER 64#error Please define BTSTACK_RTOS_ENTER that locks a recursive mutex when using the RTOS wrapper btstack_rtos.h 65#endif 66 67#ifndef BTSTACK_RTOS_EXIT 68#error Please define BTSTACK_RTOS_EXIT that releases a recursive mutex when using the RTOS wrapper btstack_rtos.h 69#endif 70 71/* API_START */ 72 73 74""" 75 76hfile_api_header = """ 77#include "API_NAME" 78""" 79 80hfile_header_end = """ 81 82/* API_END */ 83 84#if defined __cplusplus 85} 86#endif 87 88#endif // __BTSTACK_RTOS_H 89""" 90 91class State: 92 SearchStartAPI = 0 93 SearchEndAPI = 1 94 DoneAPI = 2 95 96 97num_functions = 0 98 99# [file_name, api_title, api_label] 100apis = [ 101 ["src/ble/ancs_client.h", "BLE ANCS Client", "ancsClient", True], 102 ["src/ble/att_db_util.h", "BLE ATT Database", "attDb", True], 103 ["src/ble/att_server.h", "BLE ATT Server", "attServer", True], 104 ["src/ble/gatt_client.h", "BLE GATT Client", "gattClient", True], 105 ["src/ble/le_device_db.h", "BLE Device Database", "leDeviceDb", True], 106 ["src/ble/sm.h", "BLE Security Manager", "sm", True], 107 108 ["src/classic/bnep.h", "BNEP", "bnep", True], 109 ["src/classic/btstack_link_key_db.h","Link Key DB","lkDb", True], 110 ["src/classic/hsp_hs.h","HSP Headset","hspHS", True], 111 ["src/classic/hsp_ag.h","HSP Audio Gateway","hspAG", True], 112 ["src/classic/hfp_hf.h","HFP Hands-Free","hfpHF", True], 113 ["src/classic/hfp_ag.h","HFP Audio Gateway","hfpAG", True], 114 ["src/classic/pan.h", "PAN", "pan", True], 115 ["src/classic/rfcomm.h", "RFCOMM", "rfcomm", True], 116 ["src/classic/sdp_client.h", "SDP Client", "sdpClient", True], 117 ["src/classic/sdp_client_rfcomm.h", "SDP RFCOMM Query", "sdpQueries", True], 118 ["src/classic/sdp_server.h", "SDP Server", "sdpSrv", True], 119 ["src/classic/sdp_util.h","SDP Utils", "sdpUtil", True], 120 121 ["src/ad_parser.h", "BLE Advertisements Parser", "advParser", True], 122 ["src/btstack_chipset.h","BTstack Chipset","btMemory", True], 123 ["src/btstack_control.h","BTstack Hardware Control","btControl", True], 124 ["src/btstack_event.h","HCI Event Getter","btEvent", False], 125 ["src/btstack_memory.h","BTstack Memory Management","btMemory", True], 126 ["src/btstack_linked_list.h","BTstack Linked List","btList", True], 127 ["src/btstack_run_loop.h", "Run Loop", "runLoop", True], 128 ["src/btstack_util.h", "Common Utils", "btUtil", True], 129 ["src/gap.h", "GAP", "gap", True], 130 ["src/hci.h", "HCI", "hci", True], 131 ["src/hci_dump.h","HCI Logging","hciTrace", True], 132 ["src/hci_transport.h","HCI Transport","hciTransport", True], 133 ["src/l2cap.h", "L2CAP", "l2cap", True], 134] 135 136 137def codeReference(fname, filepath, linenr): 138 return fname 139 140def split_arguments(args_string): 141 args = [] 142 brace_level = 0 143 arg = '' 144 for c in args_string: 145 if c == '(': 146 brace_level += 1 147 if c == ')': 148 brace_level -= 1 149 if c == ',' and brace_level == 0: 150 args.append(arg) 151 arg = '' 152 continue 153 arg = arg + c 154 if len(arg): 155 args.append(arg) 156 return args 157 158def argument_name(parameter): 159 function_pointer = re.match('[\w\s\*]*\(\s*\*(\w*)\s*\)\(.*\)', parameter) 160 if function_pointer: 161 return function_pointer.group(1) 162 parts = parameter.split(' ') 163 filtered_parts = [part for part in parts if part not in ['']] 164 arg = filtered_parts[len(filtered_parts)-1].replace('*','').replace('[]','') 165 # le_device_db_encryption_set(index, ediv, rand[8], ltk, key_size, authenticated, authorized); 166 if arg == 'rand[8]': 167 arg = 'rand' 168 return arg 169 170def create_wrapper(fout, type_and_name, arg_string, need_lock): 171 global num_functions 172 173 parts = type_and_name.split(' ') 174 filtered_parts = [part for part in parts if part not in ['static','inline','']] 175 name = filtered_parts[len(filtered_parts)-1] 176 return_type = ' '.join(filtered_parts[:-1]) 177 # handle *function_name 178 if name.startswith('*'): 179 name = name[1:] 180 return_type = return_type + ' *' 181 rtos_name = "rtos_" + name 182 is_void_function = len(filtered_parts) == 2 and filtered_parts[0] == "void" 183 args = split_arguments(arg_string) 184 call = [] 185 is_ellipse_function = False 186 if len(args)!= 1 or args[0] != 'void': 187 for arg in args: 188 call_arg = argument_name(arg) 189 if call_arg == '...': 190 is_ellipse_function = True 191 call.append('argptr') 192 name += '_va_arg' 193 else: 194 call.append(argument_name(arg)) 195 call_args = ', '.join(call) 196 fout.write('static inline ' + return_type + ' ' + rtos_name + '(' + ", ".join(args) + '){\n') 197 orig_call = name + '(' + call_args + ')' 198 if need_lock: 199 fout.write(' BTSTACK_RTOS_ENTER();\n') 200 if is_ellipse_function: 201 fout.write(' va_list argptr;\n') 202 fout.write(' va_start(argptr, %s);\n' % call[-2]) 203 if is_void_function: 204 fout.write(' ' + orig_call+';\n') 205 else: 206 fout.write(' ' + return_type + ' res = ' + orig_call + ';\n') 207 if is_ellipse_function: 208 fout.write(' va_end(argptr);\n') 209 fout.write(' BTSTACK_RTOS_EXIT();\n') 210 if not is_void_function: 211 fout.write(' return res;\n') 212 else: 213 if is_void_function: 214 fout.write(' ' + orig_call+';\n') 215 else: 216 fout.write(' return ' + orig_call + ';\n') 217 218 fout.write('}\n') 219 fout.write('\n') 220 num_functions += 1 221 222def create_wrapper_file(btstackfolder, apis, wrapper_file): 223 with open(wrapper_file, 'w') as fout: 224 fout.write(copyright) 225 fout.write(hfile_header_begin) 226 227 for api_tuple in apis: 228 api_filename = btstackfolder + "/" + api_tuple[0] 229 api_title = api_tuple[1] 230 api_lable = api_tuple[2] 231 need_lock = api_tuple[3] 232 233 header_file = api_tuple[0].replace('src/','') 234 fout.write(hfile_api_header.replace("API_NAME", header_file)) 235 236 with open(api_filename, 'rb') as fin: 237 typedefFound = 0 238 multiline_function_def = 0 239 multiline = '' 240 multiline_comment = 0 241 inline_function = 0 242 state = State.SearchStartAPI 243 244 for line in fin: 245 if state == State.DoneAPI: 246 continue 247 248 if state == State.SearchStartAPI: 249 parts = re.match('.*API_START.*',line) 250 if parts: 251 state = State.SearchEndAPI 252 continue 253 254 if state == State.SearchEndAPI: 255 parts = re.match('.*API_END.*',line) 256 if parts: 257 state = State.DoneAPI 258 continue 259 260 if inline_function: 261 function_end = re.match('.*}.*', line) 262 if function_end: 263 inline_function = 0 264 continue 265 266 if multiline_function_def: 267 multiline += line 268 function_end = re.match('.*\)', line) 269 if function_end: 270 multiline_function_def = 0 271 function = re.match('([\w\s\*]*)\(([\w\s,\*]*)\).*', multiline) 272 if function: 273 type_and_name = function.group(1) 274 arg_string = function.group(2) 275 create_wrapper(fout, type_and_name, arg_string, need_lock) 276 continue 277 278 if multiline_comment: 279 comment_end = re.match('.*\*/.*', line) 280 if comment_end: 281 multiline_comment = 0 282 fout.write(line) 283 continue 284 285 # search typedef struct end 286 if typedefFound: 287 typedef = re.match('}\s*(.*);\n', line) 288 if typedef: 289 typedefFound = 0 290 continue 291 292 # search comment line 293 comment = re.match(".*/\*.*\*/.*", line) 294 if comment: 295 fout.write(line) 296 continue 297 298 # search start of multi line comment 299 comment = re.match(".*/\*", line) 300 if comment: 301 fout.write(line) 302 multiline_comment = 1 303 continue 304 305 # ignore __attribute__ for hci_dump_log in src/hci_dump.h 306 param = re.match(".*__attribute__", line) 307 if param: 308 continue 309 310 # search typedef struct begin 311 typedef = re.match('.*typedef\s+struct.*', line) 312 if typedef: 313 typedefFound = 1 314 315 # complete function declaration 316 function = re.match('([\w\s\*]*)\((.*)\).*', line) 317 if function: 318 if "return" in line: 319 continue 320 type_and_name = function.group(1) 321 arg_string = function.group(2) 322 create_wrapper(fout, type_and_name, arg_string, need_lock) 323 inline_function = 'inline' in line; 324 continue 325 326 # multi-line function declaration 327 function = re.match('([\w\s\*]*)\((.*).*', line) 328 if function: 329 multiline = line 330 multiline_function_def = 1 331 continue 332 333 # fout.write(hfile_header_begin) 334 fout.write(hfile_header_end) 335 336def main(argv): 337 btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..') 338 gen_path = btstack_root + '/src/btstack_rtos.h' 339 print ('BTstack folder is: %s' % btstack_root) 340 print ('Generating RTOS wrapper %s' % gen_path) 341 create_wrapper_file(btstack_root, apis, gen_path) 342 print ('Number wrapped headers: %u' % len(apis)) 343 print ('Number wrapped functions: %u' % num_functions) 344if __name__ == "__main__": 345 main(sys.argv[1:]) 346