1#!/usr/bin/env python 2# BlueKitchen GmbH (c) 2014 3 4import re 5import os 6import sys 7 8# paths 9bluetooth_h_path = 'src/bluetooth.h' 10btstack_defines_h_path = 'src/btstack_defines.h' 11daemon_cmds_c_path = 'platform/daemon/src/daemon_cmds.c' 12hci_cmds_c_path = 'src/hci_cmd.c' 13hci_cmds_h_path = 'src/hci_cmd.h' 14hci_h_path = 'src/hci.h' 15 16btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..') 17print ("BTstack root %s" % btstack_root) 18 19def set_btstack_root(path): 20 global btstack_root 21 btstack_root = path 22 23def assert_dir(path): 24 if not os.access(path, os.R_OK): 25 os.makedirs(path) 26 27def cap(x): 28 if x.lower() == 'btstack': 29 return 'BTstack' 30 acronyms = ['ATT', 'GAP', 'GATT', 'HCI', 'L2CAP', 'LE', 'RFCOMM', 'SM', 'SDP', 'UUID16', 'UUID128', 'HSP', 'HFP', 'ANCS'] 31 if x.upper() in acronyms: 32 return x.upper() 33 return x.capitalize() 34 35def camel_case(name): 36 return ''.join(map(cap, name.split('_'))) 37 38def camel_case_var(name): 39 if name in ['uuid128', 'uuid16']: 40 return name 41 camel = camel_case(name) 42 return camel[0].lower() + camel[1:] 43 44def read_defines(infile): 45 defines = dict() 46 with open (infile, 'rt') as fin: 47 for line in fin: 48 parts = re.match('#define\s+(\w+)\s+(\w*)',line) 49 if parts and len(parts.groups()) == 2: 50 (key, value) = parts.groups() 51 defines[key] = value 52 return defines 53 54def parse_defines(): 55 global btstack_root 56 defines = dict() 57 defines.update(read_defines(btstack_root + '/' + hci_cmds_h_path)) 58 defines.update(read_defines(btstack_root + '/' + hci_h_path)) 59 defines.update(read_defines(btstack_root + '/' + bluetooth_h_path)) 60 defines.update(read_defines(btstack_root + '/' + btstack_defines_h_path)) 61 return defines 62 63def my_parse_events(path): 64 events = [] 65 subevents = [] 66 params = [] 67 event_types = set() 68 format = None 69 with open (path, 'rt') as fin: 70 for line in fin: 71 parts = re.match('.*@format\s*(\w*)\s*', line) 72 if parts and len(parts.groups()) == 1: 73 format = parts.groups()[0] 74 parts = re.match('.*@param\s*(\w*)\s*', line) 75 if parts and len(parts.groups()) == 1: 76 param = parts.groups()[0] 77 params.append(param) 78 parts = re.match('\s*#define\s+(\w+)\s+(\w*)',line) 79 if parts and len(parts.groups()) == 2: 80 (key, value) = parts.groups() 81 if format != None: 82 # renaming needed by Java Binding (... subevents are just enumerated with others due to event factory) 83 if "_subevent_" in key.lower(): 84 subevents.append((value, key, format, params)) 85 else: 86 events.append((value, key, format, params)) 87 event_types.add(key) 88 params = [] 89 format = None 90 return (events, subevents, event_types) 91 92def parse_events(): 93 global btstack_root 94 95 # parse bluetooth.h to get used events 96 (bluetooth_events, bluetooth_subevents, bluetooth_event_types) = my_parse_events(btstack_root + '/' + bluetooth_h_path) 97 98 # parse btstack_defines to get events 99 (btstack_events, btstack_subevents, btstack_event_types) = my_parse_events(btstack_root + '/' + btstack_defines_h_path) 100 101 # concat lists 102 (events, subvents, event_types) = (bluetooth_events + btstack_events, bluetooth_subevents + btstack_subevents, bluetooth_event_types | btstack_event_types) 103 104 return (events, subvents, event_types) 105 106def my_parse_commands(infile): 107 commands = [] 108 with open (infile, 'rt') as fin: 109 110 params = [] 111 for line in fin: 112 113 parts = re.match('.*@param\s*(\w*)\s*', line) 114 if parts and len(parts.groups()) == 1: 115 param = parts.groups()[0] 116 params.append(camel_case_var(param)) 117 continue 118 119 declaration = re.match('const\s+hci_cmd_t\s+(\w+)[\s=]+', line) 120 if declaration: 121 command_name = camel_case(declaration.groups()[0]) 122 if command_name.endswith('Cmd'): 123 command_name = command_name[:-len('Cmd')] 124 continue 125 126 definition = re.match('\s*OPCODE\\(\s*(\w+)\s*,\s+(\w+)\s*\\)\s*,\s\\"(\w*)\\".*', line) 127 if definition: 128 (ogf, ocf, format) = definition.groups() 129 if len(params) != len(format): 130 params = [] 131 arg_counter = 1 132 for f in format: 133 arg_name = 'arg%u' % arg_counter 134 params.append(arg_name) 135 arg_counter += 1 136 commands.append((command_name, ogf, ocf, format, params)) 137 params = [] 138 continue 139 return commands 140 141def parse_commands(): 142 global btstack_root 143 commands = [] 144 commands = commands = my_parse_commands(btstack_root + '/' + hci_cmds_c_path) 145 commands = commands = my_parse_commands(btstack_root + '/' + daemon_cmds_c_path) 146 return commands