xref: /btstack/chipset/cc256x/convert_bts_init_scripts.py (revision 06ee659a5cb472429e65cec0ba8372344d493c7f)
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
12usage = '''
13CC256x init script conversion tool for use with BTstack, v0.2
14Copyright 2012-2014 BlueKitchen GmbH
15
16Usage:
17$ ./convert_bts_init_scripts.py main.bts [ble-add-on.bts] output.c
18
19Please specify the main .bts script and optionally the BLE Add-on to generate the init script .c file.
20
21The Makefile include chipset/cc256x/Makefile.inc automates the process of downloading and converting .bts files.
22
23If this is not an option, you can download the Service Packs for your module from http://processors.wiki.ti.com/index.php/CC256x_Downloads
24Then, unzip it and copy the *.bts file into this folder before start the script again.
25'''
26
27fartext = '''
28#if defined(__GNUC__) && defined(__MSP430X__) && (__MSP430X__ > 0)
29__attribute__((section (".fartext")))
30#endif
31#ifdef __AVR__
32__attribute__((__progmem__))
33#endif
34'''
35
36data_indent = '    '
37
38def read_little_endian_16(f):
39    low  = f.read(1)
40    if len(low) == 0:
41        return -1
42    high = f.read(1)
43    return ord(high) << 8 | ord(low)
44
45def append_power_vector_gfsk(additions, str_list, data_indent):
46    additions.append("- added HCI_VS_SET_POWER_VECTOR(GFSK) template")
47    str_list.append(data_indent)
48    str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(GFSK) 0xFD82 template\n');
49    str_list.append(data_indent)
50    str_list.append("0x01, 0x82, 0xfd, 0x14, 0x00, 0x9c, 0x18, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xdc,\n");
51    str_list.append(data_indent)
52    str_list.append("0xe6, 0xf0, 0xfa, 0x04, 0x0e, 0x18, 0xff, 0x00, 0x00,\n\n");
53    return 24
54
55def append_power_vector_edr2(additions, str_list, data_indent):
56    additions.append("- added HCI_VS_SET_POWER_VECTOR(EDR2) template")
57    str_list.append(data_indent)
58    str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(EDR2) 0xFD82 template\n');
59    str_list.append(data_indent)
60    str_list.append("0x01, 0x82, 0xfd, 0x14, 0x01, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8, \n");
61    str_list.append(data_indent)
62    str_list.append("0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,\n\n");
63    return 24
64
65def append_power_vector_edr3(additions, str_list, data_indent):
66    additions.append("- added HCI_VS_SET_POWER_VECTOR(EDR3) template")
67    str_list.append(data_indent)
68    str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(EDR3) 0xFD82 for EDR3 template\n');
69    str_list.append(data_indent)
70    str_list.append("0x01, 0x82, 0xfd, 0x14, 0x02, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8,\n");
71    str_list.append(data_indent)
72    str_list.append("0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,\n\n");
73    return 24
74
75def append_class2_single_power(additions, str_list, data_indent):
76    additions.append("- added HCI_VS_SET_CLASS2_SINGLE_POWER template")
77    str_list.append(data_indent)
78    str_list.append('// BTstack: added HCI_VS_SET_CLASS2_SINGLE_POWER 0xFD87 template\n');
79    str_list.append(data_indent)
80    str_list.append("0x01, 0x87, 0xfd, 0x03, 0x0d, 0x0d, 0x0d,\n\n");
81    return 7
82
83def append_ehcill(additions, str_list, data_indent):
84    additions.append("- added eHCILL template")
85    str_list.append('\n')
86    str_list.append(data_indent)
87    str_list.append('// BTstack: added HCI_VS_Sleep_Mode_Configurations 0xFD0C template for eHCILL\n');
88    str_list.append(data_indent)
89    str_list.append('0x01, 0x0c, 0xfd, 9 , 1, 0, 0,  0xff, 0xff, 0xff, 0xff, 100, 0,\n\n');
90    return 13
91
92def append_calibration_sequence(additions, str_list, data_indent):
93    additions.append("- added calibration sequence")
94    str_list.append(data_indent)
95    str_list.append("// BTstack: added calibration sequence\n")
96    str_list.append(data_indent)
97    str_list.append("0x01, 0x80, 0xfd, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,\n")
98    str_list.append(data_indent)
99    str_list.append("0x01, 0x80, 0xfd, 0x06, 0x3c, 0xf0, 0x5f, 0x00, 0x00, 0x00,\n\n")
100    return 20
101
102def convert_bts(output_file, main_bts_file, bts_add_on, aka, lmp_subversion):
103    array_name = 'cc256x'
104
105    input_files = [ main_bts_file ]
106    if bts_add_on != "":
107        input_files.append(bts_add_on)
108
109    with open(output_file, 'w') as fout:
110
111        # assert script contains templates for configuration by BTstack
112        have_eHCILL = False
113        have_power_vector_gfsk = False;
114        have_power_vector_edr2 = False;
115        have_power_vector_edr3 = False;
116        have_class2_single_power = False;
117
118        print("Creating {0}".format(output_file))
119
120        part_size = 0
121
122        parts = 0
123        str_list = []
124        part_strings = []
125        part_sizes   = []
126        additions = []
127
128        for bts_file in input_files:
129
130            with open (bts_file, 'rb') as fin:
131
132                print("- parsing {0:32}".format(bts_file))
133
134                header = fin.read(32)
135                if header[0:4].decode('ascii') != 'BTSB':
136                    print('Error', bts_file, 'is not a valid .BTS file')
137                    sys.exit(1)
138
139
140                while True:
141                    action_type = read_little_endian_16(fin)
142                    action_size = read_little_endian_16(fin)
143                    action_data = bytearray(fin.read(action_size))
144
145                    if (action_type == 1):  # hci command
146
147                        opcode = (action_data[2] << 8) | action_data[1]
148                        if opcode == 0xFF36:
149                            continue    # skip baud rate command
150                        if opcode == 0xFD0C:
151                            have_eHCILL = True
152                        if opcode == 0xFD82:
153                            modulation_type = action_data[4]
154                            if modulation_type == 0:
155                                have_power_vector_gfsk = True
156                            elif modulation_type == 1:
157                                have_power_vector_edr2 + True
158                            elif modulation_type == 2:
159                                have_power_vector_edr3 = True
160                        if opcode == 0xFD80:
161                            # add missing power command templates
162                            if not have_power_vector_gfsk:
163                                part_size += append_power_vector_gfsk(additions, str_list, data_indent)
164                                have_power_vector_gfsk = True;
165                            if not have_power_vector_edr2:
166                                part_size += append_power_vector_edr2(additions, str_list, data_indent)
167                                have_power_vector_edr2 = True;
168                            if not have_power_vector_edr3:
169                                part_size += append_power_vector_edr2(additions, str_list, data_indent)
170                                have_power_vector_edr3 = True;
171                            if not have_class2_single_power:
172                                part_size += append_class2_single_power(additions, str_list, data_indent)
173                                have_class2_single_power = True;
174
175                        counter = 0
176                        str_list.append(data_indent)
177                        for byte in action_data:
178                            str_list.append("0x{0:02x}, ".format(byte))
179                            counter = counter + 1
180                            if (counter != 15):
181                                continue
182                            counter = 0
183                            str_list.append("\n")
184                            str_list.append(data_indent)
185                        str_list.append("\n\n")
186
187                        part_size = part_size + action_size
188
189                        # 30 kB chunks
190                        if part_size < 30 * 1024:
191                            continue
192
193                        part_strings.append(''.join(str_list))
194                        part_sizes.append(part_size)
195                        parts += 1
196
197                        str_list = []
198                        part_size = 0
199
200                    if (action_type == 6):  # comment
201                        action_data = action_data.decode('ascii').rstrip('\0')
202                        str_list.append(data_indent)
203                        str_list.append("// " + action_data + "\n")
204
205                    if (action_type < 0):   # EOF
206                        break;
207
208
209        if not have_eHCILL:
210            part_size += append_ehcill(additions, str_list, data_indent)
211
212        # append calibration step, if missing so far
213        all_power_commands_provided = have_power_vector_gfsk and have_power_vector_edr2 and have_power_vector_edr3 and have_class2_single_power
214        if not all_power_commands_provided:
215            str_list.append("\n" + data_indent + "// BTstack: no calibration sequence found, adding power commands and calibration\n\n")
216            part_size += append_power_vector_gfsk(additions, str_list, data_indent)
217            part_size += append_power_vector_edr2(additions, str_list, data_indent)
218            part_size += append_power_vector_edr2(additions, str_list, data_indent)
219            part_size += append_class2_single_power(additions, str_list, data_indent)
220            part_size += append_calibration_sequence(additions, str_list, data_indent)
221
222        part_strings.append(''.join(str_list))
223        part_sizes.append(part_size)
224        parts += 1
225
226        fout.write( '// init script created from\n')
227        fout.write( '// - {0}\n'.format(main_bts_file))
228        if aka != "":
229            fout.write( '// - AKA TIInit_{0}.bts\n'.format(aka))
230        if bts_add_on != "":
231            fout.write( '// - {0}\n'.format(bts_add_on))
232        fout.write( '#include <stdint.h>\n')
233        fout.write( '\n')
234        # if aka != "":
235        #     fout.write( 'const char * {0}_init_script_aka = "{1}";\n'.format(array_name, aka))
236        if lmp_subversion != 0:
237            fout.write( 'const uint16_t %s_init_script_lmp_subversion = 0x%04x;\n' % (array_name, lmp_subversion))
238        part = 0
239        size = 0
240        for part_size in part_sizes:
241            part += 1
242            size += part_size
243            print("- part %u, size %u" % (part,part_size))
244
245        print('- total size %u' % size)
246
247        print("\n".join(additions))
248
249
250        part = 0
251        for part_text in part_strings:
252            part += 1
253            suffix = ''
254
255            if part == 1:
256                fout.write( fartext )
257
258            if (part > 1):
259                suffix = '_{0}'.format(part)
260                fout.write('#if defined(__GNUC__) && defined(__GNUC__) && (__MSP430X__ > 0)\n')
261                fout.write('};\n')
262                fout.write('__attribute__((section (".fartext")))\n')
263
264            fout.write('const uint8_t {0}_init_script{1}[] = {2}\n\n'.format(array_name, suffix, '{'))
265
266            if (part > 1):
267                fout.write('#endif\n')
268
269            fout.write(part_text)
270
271
272        fout.write('};\n\n')
273
274        fout.write('const uint32_t {0}_init_script_size = {1};\n\n'.format(array_name,size));
275        # fout.write('void main() {0} printf("size {1}\\n", {2}_init_script_size); {3}'.format('{', '%u', array_name,'}'));
276
277# check usage: 2-3 param
278if len(sys.argv) < 3 or len(sys.argv) > 4:
279    print(usage)
280    sys.exit(1)
281
282main_bts = sys.argv[1]
283add_on = ""
284if len(sys.argv) == 4:
285    add_on = sys.argv[2]
286output_file = sys.argv[-1]
287
288# get AKA and lmp subversion from file names that include model name
289aka = ""
290lmp_subversion = 0
291name_lower = main_bts.lower()
292if 'cc2560_' in name_lower:
293    aka = "6.2.31"
294    lmp_subversion = 0x191f
295if 'cc2560a_' in name_lower or 'cc2564_' in name_lower:
296    aka = "6.6.15"
297    lmp_subversion = 0x1B0F
298if 'cc2560b_' in name_lower or 'cc2564b_' in name_lower:
299    aka = "6.7.16"
300    lmp_subversion = 0x1B90
301if 'cc2564c_' in name_lower:
302    aka = "6.12.26"
303    lmp_subversion = 0x9a1a
304
305# use AKA from .bts file that it
306name_parts = re.match('.*TIInit_(\d*\.\d*\.\d*).*.bts', main_bts)
307if name_parts:
308    aka = name_parts.group(1)
309
310print ("Main file: %s"% main_bts)
311if add_on != "":
312    print ("Add-on file: %s" % add_on)
313if aka != "":
314    print ("- AKA TIInit_%s.bts" % aka)
315
316if lmp_subversion:
317    print ("- LMP Subversion: 0x%04x" % lmp_subversion)
318else:
319    print ("- LMP Subversion: Unknown")
320
321convert_bts(output_file, main_bts, add_on, aka, lmp_subversion)
322print
323
324
325
326