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): 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 = (ord(action_data[2]) << 8) | ord(action_data[1]) 146 opcode = (action_data[2] << 8) | action_data[1] 147 if opcode == 0xFF36: 148 continue # skip baud rate command 149 if opcode == 0xFD0C: 150 have_eHCILL = True 151 if opcode == 0xFD82: 152 modulation_type = ord(action_data[4]) 153 if modulation_type == 0: 154 have_power_vector_gfsk = True 155 elif modulation_type == 1: 156 have_power_vector_edr2 + True 157 elif modulation_type == 2: 158 have_power_vector_edr3 = True 159 if opcode == 0xFD80: 160 # add missing power command templates 161 if not have_power_vector_gfsk: 162 part_size += append_power_vector_gfsk(additions, str_list, data_indent) 163 have_power_vector_gfsk = True; 164 if not have_power_vector_edr2: 165 part_size += append_power_vector_edr2(additions, str_list, data_indent) 166 have_power_vector_edr2 = True; 167 if not have_power_vector_edr3: 168 part_size += append_power_vector_edr2(additions, str_list, data_indent) 169 have_power_vector_edr3 = True; 170 if not have_class2_single_power: 171 part_size += append_class2_single_power(additions, str_list, data_indent) 172 have_class2_single_power = True; 173 174 counter = 0 175 str_list.append(data_indent) 176 for byte in action_data: 177 str_list.append("0x{0:02x}, ".format(byte)) 178 counter = counter + 1 179 if (counter != 15): 180 continue 181 counter = 0 182 str_list.append("\n") 183 str_list.append(data_indent) 184 str_list.append("\n\n") 185 186 part_size = part_size + action_size 187 188 # 30 kB chunks 189 if part_size < 30 * 1024: 190 continue 191 192 part_strings.append(''.join(str_list)) 193 part_sizes.append(part_size) 194 parts += 1 195 196 str_list = [] 197 part_size = 0 198 199 if (action_type == 6): # comment 200 action_data = action_data.decode('ascii').rstrip('\0') 201 str_list.append(data_indent) 202 str_list.append("// " + action_data + "\n") 203 204 if (action_type < 0): # EOF 205 break; 206 207 208 if not have_eHCILL: 209 part_size += append_ehcill(additions, str_list, data_indent) 210 211 # append calibration step, if missing so far 212 all_power_commands_provided = have_power_vector_gfsk and have_power_vector_edr2 and have_power_vector_edr3 and have_class2_single_power 213 if not all_power_commands_provided: 214 str_list.append("\n" + data_indent + "// BTstack: no calibration sequence found, adding power commands and calibration\n\n") 215 part_size += append_power_vector_gfsk(additions, str_list, data_indent) 216 part_size += append_power_vector_edr2(additions, str_list, data_indent) 217 part_size += append_power_vector_edr2(additions, str_list, data_indent) 218 part_size += append_class2_single_power(additions, str_list, data_indent) 219 part_size += append_calibration_sequence(additions, str_list, data_indent) 220 221 part_strings.append(''.join(str_list)) 222 part_sizes.append(part_size) 223 parts += 1 224 225 fout.write( '// init script created from\n') 226 fout.write( '// - {0}\n'.format(main_bts_file)) 227 if bts_add_on != "": 228 fout.write( '// - {0}\n'.format(bts_add_on)) 229 fout.write( '#include <stdint.h>\n') 230 231 part = 0 232 size = 0 233 for part_size in part_sizes: 234 part += 1 235 size += part_size 236 print("- part", part, "size", part_size) 237 238 print('- total size', size) 239 240 print("\n".join(additions)) 241 242 243 part = 0 244 for part_text in part_strings: 245 part += 1 246 suffix = '' 247 248 if part == 1: 249 fout.write( fartext ) 250 251 if (part > 1): 252 suffix = '_{0}'.format(part) 253 fout.write('#if defined(__GNUC__) && defined(__GNUC__) && (__MSP430X__ > 0)\n') 254 fout.write('};\n') 255 fout.write('__attribute__((section (".fartext")))\n') 256 257 fout.write('const uint8_t {0}_init_script{1}[] = {2}\n\n'.format(array_name, suffix, '{')) 258 259 if (part > 1): 260 fout.write('#endif\n') 261 262 fout.write(part_text) 263 264 265 fout.write('};\n\n') 266 267 fout.write('const uint32_t {0}_init_script_size = {1};\n\n'.format(array_name,size)); 268 # fout.write('void main() {0} printf("size {1}\\n", {2}_init_script_size); {3}'.format('{', '%u', array_name,'}')); 269 270# get list of *.bts files 271files = glob.glob('*.bts') 272if not files: 273 print(usage) 274 sys.exit(1) 275 276# convert each of them 277for name in files: 278 name_lower = name.lower() 279 # skip BLE and AVRP add-ons 280 if name_lower.startswith('ble_init_cc'): 281 print("Skipping BLE add-on", name) 282 continue 283 if name_lower.startswith('avpr_init_cc'): 284 print("Skipping AVPR add-on", name) 285 continue 286 if re.match("initscripts_tiinit_.*_ble_add-on.bts", name_lower): 287 print("Skipping BLE add-on", name) 288 continue 289 if re.match("initscripts_tiinit_.*_avpr_add-on.bts", name_lower): 290 print("Skipping AVPR add-on", name) 291 continue 292 293 # check for BLE add-on 294 add_on = "" 295 name_parts = re.match('bluetooth_init_(.....+_...)_.*.bts', name) 296 if name_parts: 297 potential_add_on = 'BLE_init_%s.bts' % name_parts.group(1) 298 if os.path.isfile(potential_add_on): 299 add_on = potential_add_on 300 print("Found", add_on, "add-on for", name) 301 302 name_parts = re.match('initscripts_TIInit_(\d*\.\d*\.\d*)_.*.bts', name) 303 if name_parts: 304 potential_add_on = 'initscripts_TIInit_%s_ble_add-on.bts' % name_parts.group(1) 305 if os.path.isfile(potential_add_on): 306 add_on = potential_add_on 307 print("Found", add_on, "add-on for", name) 308 309 convert_bts(name, add_on) 310 311# done 312print('\nConversion(s) successful!\n') 313 314 315 316