xref: /btstack/tool/python_generator.py (revision 760c66926a811b812c71f9da75ea15d6c9efb673)
173a17974SMatthias Ringwald#!/usr/bin/env python
273a17974SMatthias Ringwald# BlueKitchen GmbH (c) 2018
373a17974SMatthias Ringwald
473a17974SMatthias Ringwaldimport glob
573a17974SMatthias Ringwaldimport re
673a17974SMatthias Ringwaldimport sys
773a17974SMatthias Ringwaldimport os
873a17974SMatthias Ringwald
973a17974SMatthias Ringwaldimport btstack_parser as parser
1073a17974SMatthias Ringwald
1173a17974SMatthias Ringwaldprint('''
1273a17974SMatthias RingwaldPython binding generator for BTstack Server
1373a17974SMatthias RingwaldCopyright 2018, BlueKitchen GmbH
1473a17974SMatthias Ringwald''')
1573a17974SMatthias Ringwald
1673a17974SMatthias Ringwald# com.bluekitchen.btstack.BTstack.java templates
1773a17974SMatthias Ringwaldcommand_builder_header = \
1873a17974SMatthias Ringwald'''#!/usr/bin/env python3
1973a17974SMatthias Ringwald
2073a17974SMatthias Ringwaldimport struct
2173a17974SMatthias Ringwald
2201aeeea2SMatthias Ringwalddef opcode(ogf, ocf):
2301aeeea2SMatthias Ringwald    return ocf | (ogf << 10)
2473a17974SMatthias Ringwald
2573a17974SMatthias Ringwalddef pack24(value):
2673a17974SMatthias Ringwald    return struct.pack("B", value & 0xff) + struct.pack("<H", value >> 8)
2773a17974SMatthias Ringwald
2873a17974SMatthias Ringwalddef name248(str):
2973a17974SMatthias Ringwald    arg = str.encode('utf-8')
3073a17974SMatthias Ringwald    return arg[:248] + bytes(248-len(arg))
3173a17974SMatthias Ringwald
3201aeeea2SMatthias Ringwald# Command Builder
3301aeeea2SMatthias Ringwald
3401aeeea2SMatthias Ringwaldclass CommandBuilder(object):
35*760c6692SMatthias Ringwald
3601aeeea2SMatthias Ringwald    def __init__(self):
3701aeeea2SMatthias Ringwald        pass
3801aeeea2SMatthias Ringwald
3973a17974SMatthias Ringwald    def send_command(command):
4073a17974SMatthias Ringwald        return FALSE
4173a17974SMatthias Ringwald
4273a17974SMatthias Ringwald'''
43*760c6692SMatthias Ringwald
4473a17974SMatthias Ringwaldcommand_builder_command = '''
4501aeeea2SMatthias Ringwald    def {name}(self, {args}):
4673a17974SMatthias Ringwald        cmd_args = bytes()
4773a17974SMatthias Ringwald{args_builder}
4801aeeea2SMatthias Ringwald        cmd = struct.pack("<HB", opcode(self.{ogf}, self.{ocf}), len(cmd_args)) + cmd_args
4973a17974SMatthias Ringwald        return self.send_hci_command(cmd)
5073a17974SMatthias Ringwald'''
5173a17974SMatthias Ringwald
5273a17974SMatthias Ringwald# com.bluekitchen.btstack.EventFactory template
53*760c6692SMatthias Ringwaldevent_factory_template = \
54dbd33601SMatthias Ringwald'''
5573a17974SMatthias Ringwald
56*760c6692SMatthias Ringwald# dictionary to map hci event types to event classes
57*760c6692SMatthias Ringwaldevent_class_for_type = {{
58*760c6692SMatthias Ringwald{1}}}
5973a17974SMatthias Ringwald
60*760c6692SMatthias Ringwald# dictionary to map hci le event types to event classes
61*760c6692SMatthias Ringwaldle_event_class_for_type = {{
62*760c6692SMatthias Ringwald{2}}}
6373a17974SMatthias Ringwald
64*760c6692SMatthias Ringwald# list of all event types - not actually used
65dbd33601SMatthias Ringwald{0}
6673a17974SMatthias Ringwald
67*760c6692SMatthias Ringwalddef event_for_payload(payload):
68*760c6692SMatthias Ringwald    event_type  = payload[0]
69*760c6692SMatthias Ringwald    event_class = btstack.btstack_types.Event
70*760c6692SMatthias Ringwald    # LE Subevent
71*760c6692SMatthias Ringwald    if event_type == 0x3e:
72*760c6692SMatthias Ringwald        subevent_type = payload[2]
73*760c6692SMatthias Ringwald        event_class = le_event_class_for_type[subevent_type]
74*760c6692SMatthias Ringwald    else:
75*760c6692SMatthias Ringwald        event_class = event_class_for_type[event_type]
76*760c6692SMatthias Ringwald    return event_class(payload)
7773a17974SMatthias Ringwald'''
78*760c6692SMatthias Ringwaldevent_factory_event =  \
79*760c6692SMatthias Ringwald'''    {0} : {1},
8073a17974SMatthias Ringwald'''
81*760c6692SMatthias Ringwaldevent_factory_subevent = \
82*760c6692SMatthias Ringwald'''    {0} : {1},
8373a17974SMatthias Ringwald'''
8473a17974SMatthias Ringwald
85*760c6692SMatthias Ringwaldevent_header = '''
86*760c6692SMatthias Ringwaldimport btstack.btstack_types
87dbd33601SMatthias Ringwald'''
8873a17974SMatthias Ringwald
89*760c6692SMatthias Ringwaldevent_template = \
90*760c6692SMatthias Ringwald'''
9173a17974SMatthias Ringwald
92*760c6692SMatthias Ringwaldclass {0}(btstack.btstack_types.Event):
93*760c6692SMatthias Ringwald
94*760c6692SMatthias Ringwald    def __init__(self, payload):
95*760c6692SMatthias Ringwald        super().__init__(payload)
96dbd33601SMatthias Ringwald    {1}
9773a17974SMatthias Ringwald    {2}
9873a17974SMatthias Ringwald'''
9973a17974SMatthias Ringwald
100*760c6692SMatthias Ringwaldevent_getter = \
10173a17974SMatthias Ringwald'''
102*760c6692SMatthias Ringwald    def get_{0}(self):
103dbd33601SMatthias Ringwald        {1}
104*760c6692SMatthias Ringwald'''
105*760c6692SMatthias Ringwald
106*760c6692SMatthias Ringwaldevent_getter_data = \
107*760c6692SMatthias Ringwald'''# len = self.get_{length_name}()
108*760c6692SMatthias Ringwald        return self.payload[{offset},{offset}+len]
109*760c6692SMatthias Ringwald'''
110*760c6692SMatthias Ringwald
111*760c6692SMatthias Ringwaldevent_getter_data_fixed = \
112*760c6692SMatthias Ringwald'''return self.payload[{offset},{offset}+{size}]
113*760c6692SMatthias Ringwald'''
114*760c6692SMatthias Ringwald
115*760c6692SMatthias Ringwaldevent_to_string = \
116*760c6692SMatthias Ringwald'''def __repr__(self):
117*760c6692SMatthias Ringwald        repr  = '{0} < type=0x%02x' % self.get_event_type()
118*760c6692SMatthias Ringwald{1}
119*760c6692SMatthias Ringwald        repr += " >"
120*760c6692SMatthias Ringwald        return repr
12173a17974SMatthias Ringwald'''
12273a17974SMatthias Ringwald
12373a17974SMatthias Ringwald
12473a17974SMatthias Ringwald# global variables/defines
12573a17974SMatthias Ringwaldpackage  ='com.bluekitchen.btstack'
12673a17974SMatthias Ringwaldgen_path = 'gen/' + package.replace('.', '/')
12773a17974SMatthias Ringwald
12873a17974SMatthias Ringwalddefines = dict()
12973a17974SMatthias Ringwalddefines_used = set()
13073a17974SMatthias Ringwald
13173a17974SMatthias Ringwalddef size_for_type(type):
13273a17974SMatthias Ringwald    param_sizes = { '1' : 1, '2' : 2, '3' : 3, '4' : 4, 'H' : 2, 'B' : 6, 'D' : 8, 'E' : 240, 'N' : 248, 'P' : 16,
13373a17974SMatthias Ringwald                    'A' : 31, 'S' : -1, 'V': -1, 'J' : 1, 'L' : 2, 'Q' : 32, 'U' : 16, 'X' : 20, 'Y' : 24, 'Z' : 18, 'T':-1}
13473a17974SMatthias Ringwald    return param_sizes[type]
13573a17974SMatthias Ringwald
13673a17974SMatthias Ringwalddef create_command_python(fout, name, ogf, ocf, format, params):
13773a17974SMatthias Ringwald    global command_builder_command
13873a17974SMatthias Ringwald
13973a17974SMatthias Ringwald    ind = '        '
14073a17974SMatthias Ringwald    param_store = {
14173a17974SMatthias Ringwald     '1' : 'cmd_args += struct.pack("B", %s)',
14273a17974SMatthias Ringwald     'J' : 'cmd_args += struct.pack("B", %s)',
14373a17974SMatthias Ringwald     '2' : 'cmd_args += struct.pack("<H", %s)',
14473a17974SMatthias Ringwald     'H' : 'cmd_args += struct.pack("<H", %s)',
14573a17974SMatthias Ringwald     'L' : 'cmd_args += struct.pack("<H", %s)',
14601aeeea2SMatthias Ringwald     '3' : 'cmd_args += pack24(%s)',
14773a17974SMatthias Ringwald     '4' : 'cmd_args += struct.pack("<H", %s)',
14801aeeea2SMatthias Ringwald     'N' : 'cmd_args += name248(%s)',
14973a17974SMatthias Ringwald     'B' : 'cmd_args += %s.get_bytes()',
15073a17974SMatthias Ringwald     'U' : 'cmd_args += %s.get_bytes()',
15173a17974SMatthias Ringwald     'X' : 'cmd_args += %s.get_bytes()',
15273a17974SMatthias Ringwald     'Y' : 'cmd_args += %s.get_bytes()',
15373a17974SMatthias Ringwald     'Z' : 'cmd_args += %s.get_bytes()',
15473a17974SMatthias Ringwald     'S' : 'cmd_args += %s',
15573a17974SMatthias Ringwald     # TODO: support serialization for these
15673a17974SMatthias Ringwald     'D' : '# D / TODO Util.storeBytes(command, offset, %s, 8)',
15773a17974SMatthias Ringwald     'E' : '# E / TODO Util.storeBytes(command, offset, %s, 240)',
15873a17974SMatthias Ringwald     'P' : '# P / TODO Util.storeBytes(command, offset, %s, 16)',
15973a17974SMatthias Ringwald     'Q' : '# Q / TODO Util.storeBytes(command, offset, %s, 32)',
16073a17974SMatthias Ringwald     'A' : '# A / TODO Util.storeBytes(command, offset, %s, 31)',
16173a17974SMatthias Ringwald     }
16273a17974SMatthias Ringwald    # method arguments
16373a17974SMatthias Ringwald    arg_counter = 1
16473a17974SMatthias Ringwald    args = []
16573a17974SMatthias Ringwald    for param_type, arg_name in zip(format, params):
16673a17974SMatthias Ringwald        arg_size = size_for_type(param_type)
16773a17974SMatthias Ringwald        arg = (param_type, arg_size, arg_name)
16873a17974SMatthias Ringwald        args.append(arg)
16973a17974SMatthias Ringwald        arg_counter += 1
17073a17974SMatthias Ringwald
17173a17974SMatthias Ringwald    # method argument declaration
17273a17974SMatthias Ringwald    args2 = []
17373a17974SMatthias Ringwald    for arg in args:
17473a17974SMatthias Ringwald        args2.append(arg[2])
17573a17974SMatthias Ringwald    args_string = ', '.join(args2)
17673a17974SMatthias Ringwald
17773a17974SMatthias Ringwald    # command size (opcode, len)
17873a17974SMatthias Ringwald    size_fixed = 3
17973a17974SMatthias Ringwald    size_var = ''
18073a17974SMatthias Ringwald    for arg in args:
18173a17974SMatthias Ringwald        size = arg[1]
18273a17974SMatthias Ringwald        if size > 0:
18373a17974SMatthias Ringwald            size_fixed += size
18473a17974SMatthias Ringwald        else:
18573a17974SMatthias Ringwald            size_var += ' + %s.length' % arg[2]
18673a17974SMatthias Ringwald    size_string = '%u%s' % (size_fixed, size_var)
18773a17974SMatthias Ringwald
18873a17974SMatthias Ringwald    store_params = ''
18973a17974SMatthias Ringwald
19073a17974SMatthias Ringwald    length_name = ''
19173a17974SMatthias Ringwald    for (param_type, arg_size, arg_name) in args:
19273a17974SMatthias Ringwald        if param_type in ['L', 'J']:
19373a17974SMatthias Ringwald            length_name = arg_name
19473a17974SMatthias Ringwald        if param_type == 'V':
19573a17974SMatthias Ringwald            store_params += ind + 'Util.storeBytes(command, offset, %s, %s);' % (arg_name, length_name) + '\n';
19673a17974SMatthias Ringwald            length_name = ''
19773a17974SMatthias Ringwald        else:
19873a17974SMatthias Ringwald            store_params += ind + (param_store[param_type] % arg_name) + '\n';
19973a17974SMatthias Ringwald            size = arg_size
20073a17974SMatthias Ringwald
20173a17974SMatthias Ringwald    fout.write( command_builder_command.format(name=name, args=args_string, ogf=ogf, ocf=ocf, args_builder=store_params))
20273a17974SMatthias Ringwald
20373a17974SMatthias Ringwalddef mark_define_as_used(term):
20473a17974SMatthias Ringwald    if term.startswith('0'):
20573a17974SMatthias Ringwald        return
20673a17974SMatthias Ringwald    defines_used.add(term)
20773a17974SMatthias Ringwald
20801aeeea2SMatthias Ringwalddef python_define_string(key):
20973a17974SMatthias Ringwald    global defines
21073a17974SMatthias Ringwald    if key in defines:
21101aeeea2SMatthias Ringwald        return '    %s = %s\n' % (key, defines[key])
21273a17974SMatthias Ringwald    else:
21301aeeea2SMatthias Ringwald        return '    # defines[%s] not set\n' % key
21473a17974SMatthias Ringwald
215b2929115SMatthias Ringwalddef python_defines_string(keys):
21601aeeea2SMatthias Ringwald    return '\n'.join( map(python_define_string, sorted(keys)))
21773a17974SMatthias Ringwald
21873a17974SMatthias Ringwalddef create_command_builder(commands):
21973a17974SMatthias Ringwald    global gen_path
22073a17974SMatthias Ringwald    parser.assert_dir(gen_path)
22173a17974SMatthias Ringwald
22273a17974SMatthias Ringwald    outfile = '%s/command_builder.py' % gen_path
22373a17974SMatthias Ringwald
22473a17974SMatthias Ringwald    with open(outfile, 'wt') as fout:
22573a17974SMatthias Ringwald
22673a17974SMatthias Ringwald        fout.write(command_builder_header)
22773a17974SMatthias Ringwald
22873a17974SMatthias Ringwald        for command in commands:
22973a17974SMatthias Ringwald                (command_name, ogf, ocf, format, params) = command
23073a17974SMatthias Ringwald                create_command_python(fout, command_name, ogf, ocf, format, params);
23173a17974SMatthias Ringwald                mark_define_as_used(ogf)
23273a17974SMatthias Ringwald                mark_define_as_used(ocf)
23373a17974SMatthias Ringwald
23401aeeea2SMatthias Ringwald        fout.write('\n    # defines used\n\n')
23501aeeea2SMatthias Ringwald        for key in sorted(defines_used):
23601aeeea2SMatthias Ringwald            fout.write(python_define_string(key))
23773a17974SMatthias Ringwald
238b2929115SMatthias Ringwalddef create_event(fout, event_name, format, args):
23973a17974SMatthias Ringwald    global gen_path
240*760c6692SMatthias Ringwald    global event_template
24173a17974SMatthias Ringwald
24273a17974SMatthias Ringwald    param_read = {
243dbd33601SMatthias Ringwald     '1' : 'return self.payload[{offset}]',
244dbd33601SMatthias Ringwald     'J' : 'return self.payload[{offset}]',
245dbd33601SMatthias Ringwald     '2' : 'return struct.unpack("<H", self.payload[{offset}, {offset}+2])',
246dbd33601SMatthias Ringwald     'H' : 'return struct.unpack("<H", self.payload[{offset}, {offset}+2])',
247dbd33601SMatthias Ringwald     'L' : 'return struct.unpack("<H", self.payload[{offset}, {offset}+2])',
248dbd33601SMatthias Ringwald     '3' : 'return btstack.btstack_types.unpack24(self.payload[{offset}:3])',
249dbd33601SMatthias Ringwald     '4' : 'return struct.unpack("<I", self.payload[{offset}, {offset}+4])',
250dbd33601SMatthias Ringwald     'B' : 'return btstack.btstack_types.BD_ADDR(self.payload[{offset}:6])',
251dbd33601SMatthias Ringwald     'X' : 'return btstack.btstack_types.GATTService(self.payload[{offset}:20])',
252dbd33601SMatthias Ringwald     'Y' : 'return btstack.btstack_types.GATTCharacteristic(self.payload[{offset}:24])',
253dbd33601SMatthias Ringwald     'Z' : 'return btstack.btstack_types.GATTCharacteristicDescriptor(self.payload[{offset}:18])',
254*760c6692SMatthias Ringwald     'T' : 'return self.payload[{offset}:].decode("utf-8")',
255*760c6692SMatthias Ringwald     'N' : 'return self.payload[{offset}:{offset}+248].decode("utf-8")',
256dbd33601SMatthias Ringwald     # 'D' : 'Util.storeBytes(self.payload, %u, 8);',
257dbd33601SMatthias Ringwald     # 'Q' : 'Util.storeBytes(self.payload, %u, 32);',
25873a17974SMatthias Ringwald     # 'E' : 'Util.storeBytes(data, %u, 240);',
25973a17974SMatthias Ringwald     # 'P' : 'Util.storeBytes(data, %u, 16);',
26073a17974SMatthias Ringwald     # 'A' : 'Util.storeBytes(data, %u, 31);',
26173a17974SMatthias Ringwald     # 'S' : 'Util.storeBytes(data, %u);'
262*760c6692SMatthias Ringwald     'R' : 'return self.payload[{offset}:]',
26373a17974SMatthias Ringwald     }
26473a17974SMatthias Ringwald
26573a17974SMatthias Ringwald    offset = 2
26673a17974SMatthias Ringwald    getters = ''
26773a17974SMatthias Ringwald    length_name = ''
26873a17974SMatthias Ringwald    for f, arg in zip(format, args):
26973a17974SMatthias Ringwald        # just remember name
27073a17974SMatthias Ringwald        if f in ['L','J']:
271dbd33601SMatthias Ringwald            length_name = arg.lower()
27273a17974SMatthias Ringwald        if f == 'R':
27373a17974SMatthias Ringwald            # remaining data
274*760c6692SMatthias Ringwald            access = param_read[f].format(offset=offset)
27573a17974SMatthias Ringwald            size = 0
27673a17974SMatthias Ringwald        elif f == 'V':
277*760c6692SMatthias Ringwald            access = event_getter_data.format(length_name=length_name, offset=offset)
27873a17974SMatthias Ringwald            size = 0
27973a17974SMatthias Ringwald        elif f in ['D', 'Q']:
28073a17974SMatthias Ringwald            size = size_for_type(f)
281*760c6692SMatthias Ringwald            access = event_getter_data_fixed.format(size=size, offset=offset)
28273a17974SMatthias Ringwald        else:
283dbd33601SMatthias Ringwald            access = param_read[f].format(offset=offset)
28473a17974SMatthias Ringwald            size = size_for_type(f)
285*760c6692SMatthias Ringwald        getters += event_getter.format(arg.lower(), access)
28673a17974SMatthias Ringwald        offset += size
28773a17974SMatthias Ringwald    to_string_args = ''
28873a17974SMatthias Ringwald    for arg in args:
289*760c6692SMatthias Ringwald        to_string_args += '        repr += ", %s = "\n' % arg
290*760c6692SMatthias Ringwald        to_string_args += '        repr += str(self.get_%s())\n' % arg.lower()
291*760c6692SMatthias Ringwald    to_string_method = event_to_string.format(event_name, to_string_args)
292*760c6692SMatthias Ringwald    fout.write(event_template.format(event_name, getters, to_string_method))
29373a17974SMatthias Ringwald
29473a17974SMatthias Ringwalddef event_supported(event_name):
29573a17974SMatthias Ringwald    parts = event_name.split('_')
29673a17974SMatthias Ringwald    return parts[0] in ['ATT', 'BTSTACK', 'DAEMON', 'L2CAP', 'RFCOMM', 'SDP', 'GATT', 'GAP', 'HCI', 'SM', 'BNEP']
29773a17974SMatthias Ringwald
29873a17974SMatthias Ringwalddef class_name_for_event(event_name):
29973a17974SMatthias Ringwald    return parser.camel_case(event_name.replace('SUBEVENT','EVENT'))
30073a17974SMatthias Ringwald
301b2929115SMatthias Ringwalddef create_events(fout, events):
30273a17974SMatthias Ringwald    global gen_path
30373a17974SMatthias Ringwald    gen_path_events = gen_path + '/event'
30473a17974SMatthias Ringwald    parser.assert_dir(gen_path_events)
30573a17974SMatthias Ringwald
30673a17974SMatthias Ringwald    for event_type, event_name, format, args in events:
30773a17974SMatthias Ringwald        if not event_supported(event_name):
30873a17974SMatthias Ringwald            continue
30973a17974SMatthias Ringwald        class_name = class_name_for_event(event_name)
310b2929115SMatthias Ringwald        create_event(fout, class_name, format, args)
31173a17974SMatthias Ringwald
31273a17974SMatthias Ringwald
31373a17974SMatthias Ringwalddef create_event_factory(events, subevents, defines):
31473a17974SMatthias Ringwald    global gen_path
315*760c6692SMatthias Ringwald    global event_factory_event
316*760c6692SMatthias Ringwald    global event_factory_template
31773a17974SMatthias Ringwald
318b2929115SMatthias Ringwald    outfile = '%s/event_factory.py' % gen_path
31973a17974SMatthias Ringwald
320*760c6692SMatthias Ringwald
32173a17974SMatthias Ringwald    cases = ''
32273a17974SMatthias Ringwald    for event_type, event_name, format, args in events:
32373a17974SMatthias Ringwald        event_name = parser.camel_case(event_name)
324*760c6692SMatthias Ringwald        cases += event_factory_event.format(event_type, event_name)
32573a17974SMatthias Ringwald    subcases = ''
32673a17974SMatthias Ringwald    for event_type, event_name, format, args in subevents:
32773a17974SMatthias Ringwald        if not event_supported(event_name):
32873a17974SMatthias Ringwald            continue
32973a17974SMatthias Ringwald        class_name = class_name_for_event(event_name)
330*760c6692SMatthias Ringwald        subcases += event_factory_subevent.format(event_type, class_name)
33173a17974SMatthias Ringwald
33273a17974SMatthias Ringwald    with open(outfile, 'wt') as fout:
333*760c6692SMatthias Ringwald        # header
334*760c6692SMatthias Ringwald        fout.write(event_header)
335b2929115SMatthias Ringwald        # event classes
336b2929115SMatthias Ringwald        create_events(fout, events)
337b2929115SMatthias Ringwald        create_events(fout, subevents)
338b2929115SMatthias Ringwald        #
339*760c6692SMatthias Ringwald        defines_text = ''
340*760c6692SMatthias Ringwald        # python_defines_string(,defines)
341*760c6692SMatthias Ringwald        fout.write(event_factory_template.format(defines_text, cases, subcases))
34273a17974SMatthias Ringwald
34373a17974SMatthias Ringwald# find root
34473a17974SMatthias Ringwaldbtstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..')
34573a17974SMatthias Ringwaldgen_path = btstack_root + '/platform/daemon/binding/python/btstack/'
34673a17974SMatthias Ringwald
34773a17974SMatthias Ringwald
34873a17974SMatthias Ringwald# read defines from hci_cmds.h and hci.h
34973a17974SMatthias Ringwalddefines = parser.parse_defines()
35073a17974SMatthias Ringwald
35173a17974SMatthias Ringwald# parse commands
3529fb9416bSMatthias Ringwaldcommands = parser.parse_commands(camel_case=False)
35373a17974SMatthias Ringwald
35473a17974SMatthias Ringwald# parse bluetooth.h to get used events
355b2929115SMatthias Ringwald(events, le_events, event_types) = parser.parse_events()
35673a17974SMatthias Ringwald
35773a17974SMatthias Ringwald# create events, le meta events, event factory, and
358b2929115SMatthias Ringwaldcreate_event_factory(events, le_events, event_types)
35973a17974SMatthias Ringwaldcreate_command_builder(commands)
36073a17974SMatthias Ringwald
36173a17974SMatthias Ringwald# done
36273a17974SMatthias Ringwaldprint('Done!')
363