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