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