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