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