xref: /btstack/chipset/cc256x/convert_bts_init_scripts.py (revision c4054521daf7c655daf9e9e940fd64602dc4f740)
1d5814ca7SMatthias Ringwald#!/usr/bin/env python
2d5814ca7SMatthias Ringwald# BlueKitchen GmbH (c) 2012-2014
3d5814ca7SMatthias Ringwald
4d5814ca7SMatthias Ringwald# documentation for TI Vendor Specific commands:
5d5814ca7SMatthias Ringwald# http://processors.wiki.ti.com/index.php/CC256x_VS_HCI_Commands
6d5814ca7SMatthias Ringwald
7d5814ca7SMatthias Ringwaldimport glob
8d5814ca7SMatthias Ringwaldimport re
9d5814ca7SMatthias Ringwaldimport sys
10d5814ca7SMatthias Ringwaldimport os
11d5814ca7SMatthias Ringwald
12f55dd2adSMatthias Ringwaldprint('''
13d5814ca7SMatthias RingwaldCC256x init script conversion tool for use with BTstack, v0.1
14d5814ca7SMatthias RingwaldCopyright 2012-2014 BlueKitchen GmbH
15f55dd2adSMatthias Ringwald''')
16d5814ca7SMatthias Ringwald
17*c4054521SMatthias Ringwaldusage = '''This script prepares init scripts for TI's
18d5814ca7SMatthias RingwaldCC256x chipsets for use with BTstack .
19d5814ca7SMatthias Ringwald
20d5814ca7SMatthias RingwaldPlease download the Service Pack for your module from http://processors.wiki.ti.com/index.php/CC256x_Downloads
21d5814ca7SMatthias RingwaldThen, unzip it and copy the *.bts file into this folder and start the script again.
22d5814ca7SMatthias Ringwald'''
23d5814ca7SMatthias Ringwald
24d5814ca7SMatthias Ringwaldfartext = '''
25d5814ca7SMatthias Ringwald#if defined(__GNUC__) && defined(__MSP430X__) && (__MSP430X__ > 0)
26d5814ca7SMatthias Ringwald__attribute__((section (".fartext")))
27d5814ca7SMatthias Ringwald#endif
28d5814ca7SMatthias Ringwald#ifdef __AVR__
29d5814ca7SMatthias Ringwald__attribute__((__progmem__))
30d5814ca7SMatthias Ringwald#endif
31d5814ca7SMatthias Ringwald'''
32d5814ca7SMatthias Ringwald
33d5814ca7SMatthias Ringwalddata_indent = '    '
34d5814ca7SMatthias Ringwald
35d5814ca7SMatthias Ringwalddef read_little_endian_16(f):
36d5814ca7SMatthias Ringwald    low  = f.read(1)
37f55dd2adSMatthias Ringwald    if len(low) == 0:
38d5814ca7SMatthias Ringwald        return -1
39d5814ca7SMatthias Ringwald    high = f.read(1)
40d5814ca7SMatthias Ringwald    return ord(high) << 8 | ord(low)
41d5814ca7SMatthias Ringwald
42d5814ca7SMatthias Ringwalddef append_power_vector_gfsk(additions, str_list, data_indent):
43d5814ca7SMatthias Ringwald    additions.append("- added HCI_VS_SET_POWER_VECTOR(GFSK) template")
44d5814ca7SMatthias Ringwald    str_list.append(data_indent)
45d5814ca7SMatthias Ringwald    str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(GFSK) 0xFD82 template\n');
46d5814ca7SMatthias Ringwald    str_list.append(data_indent)
47d5814ca7SMatthias Ringwald    str_list.append("0x01, 0x82, 0xfd, 0x14, 0x00, 0x9c, 0x18, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xdc,\n");
48d5814ca7SMatthias Ringwald    str_list.append(data_indent)
49d5814ca7SMatthias Ringwald    str_list.append("0xe6, 0xf0, 0xfa, 0x04, 0x0e, 0x18, 0xff, 0x00, 0x00,\n\n");
50*c4054521SMatthias Ringwald    return 24
51d5814ca7SMatthias Ringwald
52d5814ca7SMatthias Ringwalddef append_power_vector_edr2(additions, str_list, data_indent):
53d5814ca7SMatthias Ringwald    additions.append("- added HCI_VS_SET_POWER_VECTOR(EDR2) template")
54d5814ca7SMatthias Ringwald    str_list.append(data_indent)
55d5814ca7SMatthias Ringwald    str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(EDR2) 0xFD82 template\n');
56d5814ca7SMatthias Ringwald    str_list.append(data_indent)
57d5814ca7SMatthias Ringwald    str_list.append("0x01, 0x82, 0xfd, 0x14, 0x01, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8, \n");
58d5814ca7SMatthias Ringwald    str_list.append(data_indent)
59d5814ca7SMatthias Ringwald    str_list.append("0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,\n\n");
60*c4054521SMatthias Ringwald    return 24
61d5814ca7SMatthias Ringwald
62d5814ca7SMatthias Ringwalddef append_power_vector_edr3(additions, str_list, data_indent):
63d5814ca7SMatthias Ringwald    additions.append("- added HCI_VS_SET_POWER_VECTOR(EDR3) template")
64d5814ca7SMatthias Ringwald    str_list.append(data_indent)
65d5814ca7SMatthias Ringwald    str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(EDR3) 0xFD82 for EDR3 template\n');
66d5814ca7SMatthias Ringwald    str_list.append(data_indent)
67d5814ca7SMatthias Ringwald    str_list.append("0x01, 0x82, 0xfd, 0x14, 0x02, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8,\n");
68d5814ca7SMatthias Ringwald    str_list.append(data_indent)
69d5814ca7SMatthias Ringwald    str_list.append("0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,\n\n");
70*c4054521SMatthias Ringwald    return 24
71d5814ca7SMatthias Ringwald
72d5814ca7SMatthias Ringwalddef append_class2_single_power(additions, str_list, data_indent):
73d5814ca7SMatthias Ringwald    additions.append("- added HCI_VS_SET_CLASS2_SINGLE_POWER template")
74d5814ca7SMatthias Ringwald    str_list.append(data_indent)
75d5814ca7SMatthias Ringwald    str_list.append('// BTstack: added HCI_VS_SET_CLASS2_SINGLE_POWER 0xFD87 template\n');
76d5814ca7SMatthias Ringwald    str_list.append(data_indent)
77d5814ca7SMatthias Ringwald    str_list.append("0x01, 0x87, 0xfd, 0x03, 0x0d, 0x0d, 0x0d,\n\n");
78d5814ca7SMatthias Ringwald    return 7
79d5814ca7SMatthias Ringwald
80d5814ca7SMatthias Ringwalddef append_ehcill(additions, str_list, data_indent):
81d5814ca7SMatthias Ringwald    additions.append("- added eHCILL template")
82d5814ca7SMatthias Ringwald    str_list.append('\n')
83d5814ca7SMatthias Ringwald    str_list.append(data_indent)
84d5814ca7SMatthias Ringwald    str_list.append('// BTstack: added HCI_VS_Sleep_Mode_Configurations 0xFD0C template for eHCILL\n');
85d5814ca7SMatthias Ringwald    str_list.append(data_indent)
86d5814ca7SMatthias Ringwald    str_list.append('0x01, 0x0c, 0xfd, 9 , 1, 0, 0,  0xff, 0xff, 0xff, 0xff, 100, 0,\n\n');
87d5814ca7SMatthias Ringwald    return 13
88d5814ca7SMatthias Ringwald
89d5814ca7SMatthias Ringwalddef append_calibration_sequence(additions, str_list, data_indent):
90d5814ca7SMatthias Ringwald    additions.append("- added calibration sequence")
91d5814ca7SMatthias Ringwald    str_list.append(data_indent)
92d5814ca7SMatthias Ringwald    str_list.append("// BTstack: added calibration sequence\n")
93d5814ca7SMatthias Ringwald    str_list.append(data_indent)
94d5814ca7SMatthias Ringwald    str_list.append("0x01, 0x80, 0xfd, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,\n")
95d5814ca7SMatthias Ringwald    str_list.append(data_indent)
96d5814ca7SMatthias Ringwald    str_list.append("0x01, 0x80, 0xfd, 0x06, 0x3c, 0xf0, 0x5f, 0x00, 0x00, 0x00,\n\n")
97d5814ca7SMatthias Ringwald    return 20
98d5814ca7SMatthias Ringwald
99d5814ca7SMatthias Ringwalddef convert_bts(main_bts_file, bts_add_on):
100d5814ca7SMatthias Ringwald    array_name = 'cc256x'
101d5814ca7SMatthias Ringwald    c_file   = main_bts_file.replace('bts', 'c')
102d5814ca7SMatthias Ringwald
103d5814ca7SMatthias Ringwald    input_files = [ main_bts_file ]
104d5814ca7SMatthias Ringwald    if bts_add_on != "":
105d5814ca7SMatthias Ringwald        input_files.append(bts_add_on)
106d5814ca7SMatthias Ringwald
107d5814ca7SMatthias Ringwald    with open(c_file, 'w') as fout:
108d5814ca7SMatthias Ringwald
109d5814ca7SMatthias Ringwald        # assert script contains templates for configuration by BTstack
110d5814ca7SMatthias Ringwald        have_eHCILL = False
111d5814ca7SMatthias Ringwald        have_power_vector_gfsk = False;
112d5814ca7SMatthias Ringwald        have_power_vector_edr2 = False;
113d5814ca7SMatthias Ringwald        have_power_vector_edr3 = False;
114d5814ca7SMatthias Ringwald        have_class2_single_power = False;
115d5814ca7SMatthias Ringwald
116f55dd2adSMatthias Ringwald        print("Creating {0}".format(c_file))
117d5814ca7SMatthias Ringwald
118d5814ca7SMatthias Ringwald        part_size = 0
119d5814ca7SMatthias Ringwald
120d5814ca7SMatthias Ringwald        parts = 0
121d5814ca7SMatthias Ringwald        str_list = []
122d5814ca7SMatthias Ringwald        part_strings = []
123d5814ca7SMatthias Ringwald        part_sizes   = []
124d5814ca7SMatthias Ringwald        additions = []
125d5814ca7SMatthias Ringwald
126d5814ca7SMatthias Ringwald        for bts_file in input_files:
127d5814ca7SMatthias Ringwald
128d5814ca7SMatthias Ringwald            with open (bts_file, 'rb') as fin:
129d5814ca7SMatthias Ringwald
130f55dd2adSMatthias Ringwald                print("- parsing {0:32}".format(bts_file))
131d5814ca7SMatthias Ringwald
132d5814ca7SMatthias Ringwald                header = fin.read(32)
133f55dd2adSMatthias Ringwald                if header[0:4].decode('ascii') != 'BTSB':
134f55dd2adSMatthias Ringwald                    print('Error', bts_file, 'is not a valid .BTS file')
135d5814ca7SMatthias Ringwald                    sys.exit(1)
136d5814ca7SMatthias Ringwald
137d5814ca7SMatthias Ringwald
138d5814ca7SMatthias Ringwald                while True:
139d5814ca7SMatthias Ringwald                    action_type = read_little_endian_16(fin)
140d5814ca7SMatthias Ringwald                    action_size = read_little_endian_16(fin)
141f55dd2adSMatthias Ringwald                    action_data = bytearray(fin.read(action_size))
142d5814ca7SMatthias Ringwald
143d5814ca7SMatthias Ringwald                    if (action_type == 1):  # hci command
144d5814ca7SMatthias Ringwald
145f55dd2adSMatthias Ringwald                        # opcode = (ord(action_data[2]) << 8) | ord(action_data[1])
146f55dd2adSMatthias Ringwald                        opcode = (action_data[2] << 8) | action_data[1]
147d5814ca7SMatthias Ringwald                        if opcode == 0xFF36:
148d5814ca7SMatthias Ringwald                            continue    # skip baud rate command
149d5814ca7SMatthias Ringwald                        if opcode == 0xFD0C:
150d5814ca7SMatthias Ringwald                            have_eHCILL = True
151d5814ca7SMatthias Ringwald                        if opcode == 0xFD82:
152d5814ca7SMatthias Ringwald                            modulation_type = ord(action_data[4])
153d5814ca7SMatthias Ringwald                            if modulation_type == 0:
154d5814ca7SMatthias Ringwald                                have_power_vector_gfsk = True
155d5814ca7SMatthias Ringwald                            elif modulation_type == 1:
156d5814ca7SMatthias Ringwald                                have_power_vector_edr2 + True
157d5814ca7SMatthias Ringwald                            elif modulation_type == 2:
158d5814ca7SMatthias Ringwald                                have_power_vector_edr3 = True
159d5814ca7SMatthias Ringwald                        if opcode == 0xFD80:
160d5814ca7SMatthias Ringwald                            # add missing power command templates
161d5814ca7SMatthias Ringwald                            if not have_power_vector_gfsk:
162d5814ca7SMatthias Ringwald                                part_size += append_power_vector_gfsk(additions, str_list, data_indent)
163d5814ca7SMatthias Ringwald                                have_power_vector_gfsk = True;
164d5814ca7SMatthias Ringwald                            if not have_power_vector_edr2:
165d5814ca7SMatthias Ringwald                                part_size += append_power_vector_edr2(additions, str_list, data_indent)
166d5814ca7SMatthias Ringwald                                have_power_vector_edr2 = True;
167d5814ca7SMatthias Ringwald                            if not have_power_vector_edr3:
168d5814ca7SMatthias Ringwald                                part_size += append_power_vector_edr2(additions, str_list, data_indent)
169d5814ca7SMatthias Ringwald                                have_power_vector_edr3 = True;
170d5814ca7SMatthias Ringwald                            if not have_class2_single_power:
171d5814ca7SMatthias Ringwald                                part_size += append_class2_single_power(additions, str_list, data_indent)
172d5814ca7SMatthias Ringwald                                have_class2_single_power = True;
173d5814ca7SMatthias Ringwald
174d5814ca7SMatthias Ringwald                        counter = 0
175d5814ca7SMatthias Ringwald                        str_list.append(data_indent)
176d5814ca7SMatthias Ringwald                        for byte in action_data:
177f55dd2adSMatthias Ringwald                            str_list.append("0x{0:02x}, ".format(byte))
178d5814ca7SMatthias Ringwald                            counter = counter + 1
179d5814ca7SMatthias Ringwald                            if (counter != 15):
180d5814ca7SMatthias Ringwald                                continue
181d5814ca7SMatthias Ringwald                            counter = 0
182d5814ca7SMatthias Ringwald                            str_list.append("\n")
183d5814ca7SMatthias Ringwald                            str_list.append(data_indent)
184d5814ca7SMatthias Ringwald                        str_list.append("\n\n")
185d5814ca7SMatthias Ringwald
186d5814ca7SMatthias Ringwald                        part_size = part_size + action_size
187d5814ca7SMatthias Ringwald
188d5814ca7SMatthias Ringwald                        # 30 kB chunks
189d5814ca7SMatthias Ringwald                        if part_size < 30 * 1024:
190d5814ca7SMatthias Ringwald                            continue
191d5814ca7SMatthias Ringwald
192d5814ca7SMatthias Ringwald                        part_strings.append(''.join(str_list))
193d5814ca7SMatthias Ringwald                        part_sizes.append(part_size)
194d5814ca7SMatthias Ringwald                        parts += 1
195d5814ca7SMatthias Ringwald
196d5814ca7SMatthias Ringwald                        str_list = []
197d5814ca7SMatthias Ringwald                        part_size = 0
198d5814ca7SMatthias Ringwald
199d5814ca7SMatthias Ringwald                    if (action_type == 6):  # comment
200f55dd2adSMatthias Ringwald                        action_data = action_data.decode('ascii').rstrip('\0')
201d5814ca7SMatthias Ringwald                        str_list.append(data_indent)
202d5814ca7SMatthias Ringwald                        str_list.append("// " + action_data + "\n")
203d5814ca7SMatthias Ringwald
204d5814ca7SMatthias Ringwald                    if (action_type < 0):   # EOF
205d5814ca7SMatthias Ringwald                        break;
206d5814ca7SMatthias Ringwald
207d5814ca7SMatthias Ringwald
208d5814ca7SMatthias Ringwald        if not have_eHCILL:
209d5814ca7SMatthias Ringwald            part_size += append_ehcill(additions, str_list, data_indent)
210d5814ca7SMatthias Ringwald
211d5814ca7SMatthias Ringwald        # append calibration step, if missing so far
212d5814ca7SMatthias Ringwald        all_power_commands_provided = have_power_vector_gfsk and have_power_vector_edr2 and have_power_vector_edr3 and have_class2_single_power
213d5814ca7SMatthias Ringwald        if not all_power_commands_provided:
214d5814ca7SMatthias Ringwald            str_list.append("\n" + data_indent + "// BTstack: no calibration sequence found, adding power commands and calibration\n\n")
215d5814ca7SMatthias Ringwald            part_size += append_power_vector_gfsk(additions, str_list, data_indent)
216d5814ca7SMatthias Ringwald            part_size += append_power_vector_edr2(additions, str_list, data_indent)
217d5814ca7SMatthias Ringwald            part_size += append_power_vector_edr2(additions, str_list, data_indent)
218d5814ca7SMatthias Ringwald            part_size += append_class2_single_power(additions, str_list, data_indent)
219d5814ca7SMatthias Ringwald            part_size += append_calibration_sequence(additions, str_list, data_indent)
220d5814ca7SMatthias Ringwald
221d5814ca7SMatthias Ringwald        part_strings.append(''.join(str_list))
222d5814ca7SMatthias Ringwald        part_sizes.append(part_size)
223d5814ca7SMatthias Ringwald        parts += 1
224d5814ca7SMatthias Ringwald
225d5814ca7SMatthias Ringwald        fout.write( '// init script created from\n')
226d5814ca7SMatthias Ringwald        fout.write( '// - {0}\n'.format(main_bts_file))
227d5814ca7SMatthias Ringwald        if bts_add_on != "":
228d5814ca7SMatthias Ringwald            fout.write( '// - {0}\n'.format(bts_add_on))
229d5814ca7SMatthias Ringwald        fout.write( '#include <stdint.h>\n')
230d5814ca7SMatthias Ringwald
231d5814ca7SMatthias Ringwald        part = 0
232d5814ca7SMatthias Ringwald        size = 0
233d5814ca7SMatthias Ringwald        for part_size in part_sizes:
234d5814ca7SMatthias Ringwald            part += 1
235d5814ca7SMatthias Ringwald            size += part_size
236f55dd2adSMatthias Ringwald            print("- part", part, "size", part_size)
237d5814ca7SMatthias Ringwald
238f55dd2adSMatthias Ringwald        print('- total size', size)
239d5814ca7SMatthias Ringwald
240f55dd2adSMatthias Ringwald        print("\n".join(additions))
241d5814ca7SMatthias Ringwald
242d5814ca7SMatthias Ringwald
243d5814ca7SMatthias Ringwald        part = 0
244d5814ca7SMatthias Ringwald        for part_text in part_strings:
245d5814ca7SMatthias Ringwald            part += 1
246d5814ca7SMatthias Ringwald            suffix = ''
247d5814ca7SMatthias Ringwald
248d5814ca7SMatthias Ringwald            if part == 1:
249d5814ca7SMatthias Ringwald                fout.write( fartext )
250d5814ca7SMatthias Ringwald
251d5814ca7SMatthias Ringwald            if (part > 1):
252d5814ca7SMatthias Ringwald                suffix = '_{0}'.format(part)
253d5814ca7SMatthias Ringwald                fout.write('#if defined(__GNUC__) && defined(__GNUC__) && (__MSP430X__ > 0)\n')
254d5814ca7SMatthias Ringwald                fout.write('};\n')
255d5814ca7SMatthias Ringwald                fout.write('__attribute__((section (".fartext")))\n')
256d5814ca7SMatthias Ringwald
257d5814ca7SMatthias Ringwald            fout.write('const uint8_t {0}_init_script{1}[] = {2}\n\n'.format(array_name, suffix, '{'))
258d5814ca7SMatthias Ringwald
259d5814ca7SMatthias Ringwald            if (part > 1):
260d5814ca7SMatthias Ringwald                fout.write('#endif\n')
261d5814ca7SMatthias Ringwald
262d5814ca7SMatthias Ringwald            fout.write(part_text)
263d5814ca7SMatthias Ringwald
264d5814ca7SMatthias Ringwald
265d5814ca7SMatthias Ringwald        fout.write('};\n\n')
266d5814ca7SMatthias Ringwald
267d5814ca7SMatthias Ringwald        fout.write('const uint32_t {0}_init_script_size = {1};\n\n'.format(array_name,size));
268d5814ca7SMatthias Ringwald        # fout.write('void main() {0} printf("size {1}\\n", {2}_init_script_size); {3}'.format('{', '%u', array_name,'}'));
269d5814ca7SMatthias Ringwald
270d5814ca7SMatthias Ringwald# get list of *.bts files
271d5814ca7SMatthias Ringwaldfiles =  glob.glob('*.bts')
272d5814ca7SMatthias Ringwaldif not files:
273f55dd2adSMatthias Ringwald    print(usage)
274d5814ca7SMatthias Ringwald    sys.exit(1)
275d5814ca7SMatthias Ringwald
276d5814ca7SMatthias Ringwald# convert each of them
277d5814ca7SMatthias Ringwaldfor name in files:
278d5814ca7SMatthias Ringwald    name_lower = name.lower()
279d5814ca7SMatthias Ringwald    # skip BLE and AVRP add-ons
280d5814ca7SMatthias Ringwald    if name_lower.startswith('ble_init_cc'):
281f55dd2adSMatthias Ringwald        print("Skipping BLE add-on", name)
282d5814ca7SMatthias Ringwald        continue
283d5814ca7SMatthias Ringwald    if name_lower.startswith('avpr_init_cc'):
284f55dd2adSMatthias Ringwald        print("Skipping AVPR add-on", name)
285d5814ca7SMatthias Ringwald        continue
286d5814ca7SMatthias Ringwald    if re.match("initscripts_tiinit_.*_ble_add-on.bts", name_lower):
287f55dd2adSMatthias Ringwald        print("Skipping BLE add-on", name)
288d5814ca7SMatthias Ringwald        continue
289d5814ca7SMatthias Ringwald    if re.match("initscripts_tiinit_.*_avpr_add-on.bts", name_lower):
290f55dd2adSMatthias Ringwald        print("Skipping AVPR add-on", name)
291f55dd2adSMatthias Ringwald        continue
292d5814ca7SMatthias Ringwald
293d5814ca7SMatthias Ringwald    # check for BLE add-on
294d5814ca7SMatthias Ringwald    add_on = ""
295d5814ca7SMatthias Ringwald    name_parts = re.match('bluetooth_init_(.....+_...)_.*.bts', name)
296d5814ca7SMatthias Ringwald    if name_parts:
297d5814ca7SMatthias Ringwald        potential_add_on = 'BLE_init_%s.bts' % name_parts.group(1)
298d5814ca7SMatthias Ringwald        if os.path.isfile(potential_add_on):
299d5814ca7SMatthias Ringwald            add_on = potential_add_on
300f55dd2adSMatthias Ringwald            print("Found", add_on, "add-on for", name)
301d5814ca7SMatthias Ringwald
302d5814ca7SMatthias Ringwald    name_parts = re.match('initscripts_TIInit_(\d*\.\d*\.\d*)_.*.bts', name)
303d5814ca7SMatthias Ringwald    if name_parts:
304d5814ca7SMatthias Ringwald        potential_add_on = 'initscripts_TIInit_%s_ble_add-on.bts' % name_parts.group(1)
305d5814ca7SMatthias Ringwald        if os.path.isfile(potential_add_on):
306d5814ca7SMatthias Ringwald            add_on = potential_add_on
307f55dd2adSMatthias Ringwald            print("Found", add_on, "add-on for", name)
308d5814ca7SMatthias Ringwald
309d5814ca7SMatthias Ringwald    convert_bts(name, add_on)
310d5814ca7SMatthias Ringwald
311d5814ca7SMatthias Ringwald# done
312f55dd2adSMatthias Ringwaldprint('\nConversion(s) successful!\n')
313d5814ca7SMatthias Ringwald
314d5814ca7SMatthias Ringwald
315d5814ca7SMatthias Ringwald
316