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