15c544019SMatthias Ringwald#!/usr/bin/env python3 23338b9aeSMilanka Ringwald# BlueKitchen GmbH (c) 2014 33338b9aeSMilanka Ringwald 43338b9aeSMilanka Ringwaldimport re 53338b9aeSMilanka Ringwaldimport os 63338b9aeSMilanka Ringwaldimport sys 73338b9aeSMilanka Ringwald 83338b9aeSMilanka Ringwald# paths 93338b9aeSMilanka Ringwaldbluetooth_h_path = 'src/bluetooth.h' 103338b9aeSMilanka Ringwaldbtstack_defines_h_path = 'src/btstack_defines.h' 113338b9aeSMilanka Ringwalddaemon_cmds_c_path = 'platform/daemon/src/daemon_cmds.c' 129b8ab7daSMatthias Ringwalddaemon_cmds_h_path = 'platform/daemon/src/daemon_cmds.h' 133338b9aeSMilanka Ringwaldhci_cmds_c_path = 'src/hci_cmd.c' 143338b9aeSMilanka Ringwaldhci_cmds_h_path = 'src/hci_cmd.h' 153338b9aeSMilanka Ringwaldhci_h_path = 'src/hci.h' 163338b9aeSMilanka Ringwald 1763a4cec0SDirk Helbigopen_bracket = '[' 1863a4cec0SDirk Helbigclosing_bracket = ']' 1963a4cec0SDirk Helbig 203338b9aeSMilanka Ringwaldbtstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..') 213338b9aeSMilanka Ringwaldprint ("BTstack root %s" % btstack_root) 223338b9aeSMilanka Ringwald 233338b9aeSMilanka Ringwalddef set_btstack_root(path): 243338b9aeSMilanka Ringwald global btstack_root 253338b9aeSMilanka Ringwald btstack_root = path 263338b9aeSMilanka Ringwald 273338b9aeSMilanka Ringwalddef assert_dir(path): 283338b9aeSMilanka Ringwald if not os.access(path, os.R_OK): 293338b9aeSMilanka Ringwald os.makedirs(path) 303338b9aeSMilanka Ringwald 313338b9aeSMilanka Ringwalddef cap(x): 323338b9aeSMilanka Ringwald if x.lower() == 'btstack': 333338b9aeSMilanka Ringwald return 'BTstack' 343338b9aeSMilanka Ringwald acronyms = ['ATT', 'GAP', 'GATT', 'HCI', 'L2CAP', 'LE', 'RFCOMM', 'SM', 'SDP', 'UUID16', 'UUID128', 'HSP', 'HFP', 'ANCS'] 353338b9aeSMilanka Ringwald if x.upper() in acronyms: 363338b9aeSMilanka Ringwald return x.upper() 373338b9aeSMilanka Ringwald return x.capitalize() 383338b9aeSMilanka Ringwald 393338b9aeSMilanka Ringwalddef camel_case(name): 403338b9aeSMilanka Ringwald return ''.join(map(cap, name.split('_'))) 413338b9aeSMilanka Ringwald 423338b9aeSMilanka Ringwalddef camel_case_var(name): 433338b9aeSMilanka Ringwald if name in ['uuid128', 'uuid16']: 443338b9aeSMilanka Ringwald return name 453338b9aeSMilanka Ringwald camel = camel_case(name) 463338b9aeSMilanka Ringwald return camel[0].lower() + camel[1:] 473338b9aeSMilanka Ringwald 483338b9aeSMilanka Ringwalddef read_defines(infile): 493338b9aeSMilanka Ringwald defines = dict() 503338b9aeSMilanka Ringwald with open (infile, 'rt') as fin: 513338b9aeSMilanka Ringwald for line in fin: 52*239f77eeSMatthias Ringwald parts = re.match(r'#define\s+(\w+)\s+(\w*)[u]',line) 533338b9aeSMilanka Ringwald if parts and len(parts.groups()) == 2: 543338b9aeSMilanka Ringwald (key, value) = parts.groups() 55401327f3SMatthias Ringwald defines[key] = value.lower() 563338b9aeSMilanka Ringwald return defines 573338b9aeSMilanka Ringwald 583338b9aeSMilanka Ringwalddef parse_defines(): 593338b9aeSMilanka Ringwald global btstack_root 603338b9aeSMilanka Ringwald defines = dict() 613338b9aeSMilanka Ringwald defines.update(read_defines(btstack_root + '/' + hci_cmds_h_path)) 623338b9aeSMilanka Ringwald defines.update(read_defines(btstack_root + '/' + hci_h_path)) 633338b9aeSMilanka Ringwald defines.update(read_defines(btstack_root + '/' + bluetooth_h_path)) 643338b9aeSMilanka Ringwald defines.update(read_defines(btstack_root + '/' + btstack_defines_h_path)) 653338b9aeSMilanka Ringwald return defines 663338b9aeSMilanka Ringwald 673338b9aeSMilanka Ringwalddef my_parse_events(path): 683338b9aeSMilanka Ringwald events = [] 693338b9aeSMilanka Ringwald subevents = [] 703338b9aeSMilanka Ringwald params = [] 713338b9aeSMilanka Ringwald event_types = set() 723338b9aeSMilanka Ringwald format = None 733338b9aeSMilanka Ringwald with open (path, 'rt') as fin: 743338b9aeSMilanka Ringwald for line in fin: 75*239f77eeSMatthias Ringwald parts = re.match(r'.*@format\s*([a-zA-Z0-9_' + re.escape(open_bracket) + re.escape(closing_bracket) + r']*)\s*', line) 763338b9aeSMilanka Ringwald if parts and len(parts.groups()) == 1: 773338b9aeSMilanka Ringwald format = parts.groups()[0] 78*239f77eeSMatthias Ringwald parts = re.match(r'.*@param\s*(\w*)\s*', line) 793338b9aeSMilanka Ringwald if parts and len(parts.groups()) == 1: 803338b9aeSMilanka Ringwald param = parts.groups()[0] 813338b9aeSMilanka Ringwald params.append(param) 82*239f77eeSMatthias Ringwald parts = re.match(r'\s*#define\s+(\w+)\s+(\w*)[u]',line) 833338b9aeSMilanka Ringwald if parts and len(parts.groups()) == 2: 843338b9aeSMilanka Ringwald (key, value) = parts.groups() 853338b9aeSMilanka Ringwald if format != None: 863338b9aeSMilanka Ringwald # renaming needed by Java Binding (... subevents are just enumerated with others due to event factory) 873338b9aeSMilanka Ringwald if "_subevent_" in key.lower(): 883338b9aeSMilanka Ringwald subevents.append((value, key, format, params)) 893338b9aeSMilanka Ringwald else: 903338b9aeSMilanka Ringwald events.append((value, key, format, params)) 913338b9aeSMilanka Ringwald event_types.add(key) 923338b9aeSMilanka Ringwald params = [] 933338b9aeSMilanka Ringwald format = None 943338b9aeSMilanka Ringwald return (events, subevents, event_types) 953338b9aeSMilanka Ringwald 963338b9aeSMilanka Ringwalddef parse_events(): 973338b9aeSMilanka Ringwald global btstack_root 983338b9aeSMilanka Ringwald 993338b9aeSMilanka Ringwald # parse bluetooth.h to get used events 1003338b9aeSMilanka Ringwald (bluetooth_events, bluetooth_subevents, bluetooth_event_types) = my_parse_events(btstack_root + '/' + bluetooth_h_path) 1013338b9aeSMilanka Ringwald 1023338b9aeSMilanka Ringwald # parse btstack_defines to get events 1033338b9aeSMilanka Ringwald (btstack_events, btstack_subevents, btstack_event_types) = my_parse_events(btstack_root + '/' + btstack_defines_h_path) 1043338b9aeSMilanka Ringwald 1053338b9aeSMilanka Ringwald # concat lists 1063338b9aeSMilanka Ringwald (events, subvents, event_types) = (bluetooth_events + btstack_events, bluetooth_subevents + btstack_subevents, bluetooth_event_types | btstack_event_types) 1073338b9aeSMilanka Ringwald 1083338b9aeSMilanka Ringwald return (events, subvents, event_types) 1099b8ab7daSMatthias Ringwalddef my_parse_opcodes(infile, convert_to_camel_case): 1109b8ab7daSMatthias Ringwald opcodes = {} 1119b8ab7daSMatthias Ringwald with open (infile, 'rt') as fin: 1129b8ab7daSMatthias Ringwald for line in fin: 113*239f77eeSMatthias Ringwald definition = re.match(r'\s*(DAEMON_OPCODE_\w+)\s*=\s*DAEMON_OPCODE\s*\(\s*(\w+)\s*\).*', line) 1149b8ab7daSMatthias Ringwald if definition: 1159b8ab7daSMatthias Ringwald (opcode, daemon_ocf) = definition.groups() 1169b8ab7daSMatthias Ringwald # opcodes.append((opcode, 'OGF_BTSTACK', daemon_ocf)) 1179b8ab7daSMatthias Ringwald opcodes[opcode] = ('OGF_BTSTACK', daemon_ocf) 118*239f77eeSMatthias Ringwald definition = re.match(r'\s*(HCI_OPCODE_\w+)\s*=\s*HCI_OPCODE\s*\(\s*(\w+)\s*,\s*(\w+)\s*\).*', line) 1199b8ab7daSMatthias Ringwald if definition: 1209b8ab7daSMatthias Ringwald (opcode, ogf, ocf) = definition.groups() 1219b8ab7daSMatthias Ringwald # opcodes.append((opcode, ogf, ocf)) 1229b8ab7daSMatthias Ringwald opcodes[opcode] = (ogf, ocf) 1239b8ab7daSMatthias Ringwald return opcodes 1243338b9aeSMilanka Ringwald 1259b8ab7daSMatthias Ringwalddef parse_opcodes(camel_case=True): 1269b8ab7daSMatthias Ringwald global btstack_root 1279b8ab7daSMatthias Ringwald opcodes = {} 1289b8ab7daSMatthias Ringwald opcodes.update(my_parse_opcodes(btstack_root + '/' + hci_cmds_h_path, camel_case)) 1299b8ab7daSMatthias Ringwald opcodes.update(my_parse_opcodes(btstack_root + '/' + daemon_cmds_h_path, camel_case)) 1309b8ab7daSMatthias Ringwald return opcodes 1319b8ab7daSMatthias Ringwald 1329b8ab7daSMatthias Ringwalddef my_parse_commands(infile, opcodes, convert_to_camel_case): 1333338b9aeSMilanka Ringwald commands = [] 1343338b9aeSMilanka Ringwald with open (infile, 'rt') as fin: 1353338b9aeSMilanka Ringwald 1363338b9aeSMilanka Ringwald params = [] 1373338b9aeSMilanka Ringwald for line in fin: 1383338b9aeSMilanka Ringwald 139*239f77eeSMatthias Ringwald parts = re.match(r'.*@param\s*(\w*)\s*', line) 1403338b9aeSMilanka Ringwald if parts and len(parts.groups()) == 1: 1413338b9aeSMilanka Ringwald param = parts.groups()[0] 1429c806232SMatthias Ringwald if convert_to_camel_case: 1433ddaf9c7SMatthias Ringwald param = camel_case_var(param) 1443ddaf9c7SMatthias Ringwald else: 1453ddaf9c7SMatthias Ringwald param = param.lower() 1463ddaf9c7SMatthias Ringwald params.append(param) 1473338b9aeSMilanka Ringwald continue 1483338b9aeSMilanka Ringwald 149*239f77eeSMatthias Ringwald declaration = re.match(r'const\s+hci_cmd_t\s+(\w+)[\s=]+', line) 1503338b9aeSMilanka Ringwald if declaration: 1513ddaf9c7SMatthias Ringwald command_name = declaration.groups()[0] 1523ddaf9c7SMatthias Ringwald # drop _cmd suffix for daemon commands 1533ddaf9c7SMatthias Ringwald if command_name.endswith('_cmd'): 1543ddaf9c7SMatthias Ringwald command_name = command_name[:-len('_cmd')] 1559c806232SMatthias Ringwald if convert_to_camel_case: 1563ddaf9c7SMatthias Ringwald command_name = camel_case(command_name) 1573ddaf9c7SMatthias Ringwald else: 1583ddaf9c7SMatthias Ringwald command_name = command_name.lower() 1593338b9aeSMilanka Ringwald continue 1603338b9aeSMilanka Ringwald 1619b8ab7daSMatthias Ringwald # HCI_OPCODE or DAEMON_OPCODE definition 162*239f77eeSMatthias Ringwald definition = re.match(r'\s*(HCI_OPCODE_\w+|DAEMON_OPCODE_\w+)\s*,\s\"(\w*)\".*', line) 1633338b9aeSMilanka Ringwald if definition: 1649b8ab7daSMatthias Ringwald (opcode, format) = definition.groups() 1653338b9aeSMilanka Ringwald if len(params) != len(format): 1663338b9aeSMilanka Ringwald params = [] 1673338b9aeSMilanka Ringwald arg_counter = 1 1683338b9aeSMilanka Ringwald for f in format: 1693338b9aeSMilanka Ringwald arg_name = 'arg%u' % arg_counter 1703338b9aeSMilanka Ringwald params.append(arg_name) 1713338b9aeSMilanka Ringwald arg_counter += 1 1729b8ab7daSMatthias Ringwald (ogf, ocf) = opcodes[opcode] 1733338b9aeSMilanka Ringwald commands.append((command_name, ogf, ocf, format, params)) 1743338b9aeSMilanka Ringwald params = [] 1753338b9aeSMilanka Ringwald continue 1769b8ab7daSMatthias Ringwald 1773338b9aeSMilanka Ringwald return commands 1783338b9aeSMilanka Ringwald 1793ddaf9c7SMatthias Ringwalddef parse_commands(camel_case=True): 1803338b9aeSMilanka Ringwald global btstack_root 1819b8ab7daSMatthias Ringwald opcodes = parse_opcodes(camel_case) 1829b8ab7daSMatthias Ringwald 1833338b9aeSMilanka Ringwald commands = [] 1849b8ab7daSMatthias Ringwald commands += my_parse_commands(btstack_root + '/' + hci_cmds_c_path, opcodes, camel_case) 1859b8ab7daSMatthias Ringwald commands += my_parse_commands(btstack_root + '/' + daemon_cmds_c_path, opcodes, camel_case) 1863338b9aeSMilanka Ringwald return commands 1879b8ab7daSMatthias Ringwald 1889b8ab7daSMatthias Ringwalddef parse_daemon_commands(camel_case=True): 1899b8ab7daSMatthias Ringwald global btstack_root 1909b8ab7daSMatthias Ringwald opcodes = parse_opcodes(camel_case) 1919b8ab7daSMatthias Ringwald return my_parse_commands(btstack_root + '/' + daemon_cmds_c_path, opcodes, camel_case) 1929b8ab7daSMatthias Ringwald 1939b8ab7daSMatthias Ringwalddef print_opcode_enum(commands): 1949b8ab7daSMatthias Ringwald print("typedef enum {") 1959b8ab7daSMatthias Ringwald for command in commands: 196*239f77eeSMatthias Ringwald (name, ogf, ocf, format, params) = command 1979b8ab7daSMatthias Ringwald print(" DAEMON_OPCODE_%s = HCI_OPCODE (%s, %s)," % (name.upper(), ogf, ocf)) 1989b8ab7daSMatthias Ringwald print("} daemon_opcode_t;") 1999b8ab7daSMatthias Ringwald 2009b8ab7daSMatthias Ringwald 201