1#!/usr/bin/env python3 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-2017 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 36get_lmp_subversion = ''' 37const uint16_t {prefix}_init_script_lmp_subversion = {lmp_subversion}; 38 39uint16_t btstack_chipset_cc256x_lmp_subversion(void){{ 40 return {prefix}_init_script_lmp_subversion; 41}} 42''' 43 44data_indent = ' ' 45 46def read_little_endian_16(f): 47 low = f.read(1) 48 if len(low) == 0: 49 return -1 50 high = f.read(1) 51 return ord(high) << 8 | ord(low) 52 53def append_power_vector_gfsk(additions, str_list, data_indent): 54 additions.append("- added HCI_VS_SET_POWER_VECTOR(GFSK) template") 55 str_list.append(data_indent) 56 str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(GFSK) 0xFD82 template\n'); 57 str_list.append(data_indent) 58 str_list.append("0x01, 0x82, 0xfd, 0x14, 0x00, 0x9c, 0x18, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xdc,\n"); 59 str_list.append(data_indent) 60 str_list.append("0xe6, 0xf0, 0xfa, 0x04, 0x0e, 0x18, 0xff, 0x00, 0x00,\n\n"); 61 return 24 62 63def append_power_vector_edr2(additions, str_list, data_indent): 64 additions.append("- added HCI_VS_SET_POWER_VECTOR(EDR2) template") 65 str_list.append(data_indent) 66 str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(EDR2) 0xFD82 template\n'); 67 str_list.append(data_indent) 68 str_list.append("0x01, 0x82, 0xfd, 0x14, 0x01, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8, \n"); 69 str_list.append(data_indent) 70 str_list.append("0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,\n\n"); 71 return 24 72 73def append_power_vector_edr3(additions, str_list, data_indent): 74 additions.append("- added HCI_VS_SET_POWER_VECTOR(EDR3) template") 75 str_list.append(data_indent) 76 str_list.append('// BTstack: added HCI_VS_SET_POWER_VECTOR(EDR3) 0xFD82 for EDR3 template\n'); 77 str_list.append(data_indent) 78 str_list.append("0x01, 0x82, 0xfd, 0x14, 0x02, 0x9c, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xd8,\n"); 79 str_list.append(data_indent) 80 str_list.append("0xe2, 0xec, 0xf6, 0x00, 0x0a, 0x14, 0xff, 0x00, 0x00,\n\n"); 81 return 24 82 83def append_class2_single_power(additions, str_list, data_indent): 84 additions.append("- added HCI_VS_SET_CLASS2_SINGLE_POWER template") 85 str_list.append(data_indent) 86 str_list.append('// BTstack: added HCI_VS_SET_CLASS2_SINGLE_POWER 0xFD87 template\n'); 87 str_list.append(data_indent) 88 str_list.append("0x01, 0x87, 0xfd, 0x03, 0x0d, 0x0d, 0x0d,\n\n"); 89 return 7 90 91def append_ehcill(additions, str_list, data_indent): 92 additions.append("- added eHCILL template") 93 str_list.append('\n') 94 str_list.append(data_indent) 95 str_list.append('// BTstack: added HCI_VS_Sleep_Mode_Configurations 0xFD0C template for eHCILL\n'); 96 str_list.append(data_indent) 97 str_list.append('0x01, 0x0c, 0xfd, 9 , 1, 0, 0, 0xff, 0xff, 0xff, 0xff, 100, 0,\n\n'); 98 return 13 99 100def append_calibration_sequence(additions, str_list, data_indent): 101 additions.append("- added calibration sequence") 102 str_list.append(data_indent) 103 str_list.append("// BTstack: added calibration sequence\n") 104 str_list.append(data_indent) 105 str_list.append("0x01, 0x80, 0xfd, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,\n") 106 str_list.append(data_indent) 107 str_list.append("0x01, 0x80, 0xfd, 0x06, 0x3c, 0xf0, 0x5f, 0x00, 0x00, 0x00,\n\n") 108 return 20 109 110 111def convert_bts(output_file, main_bts_file, bts_add_on, aka, lmp_subversion): 112 array_name = 'cc256x' 113 114 input_files = [ main_bts_file ] 115 if bts_add_on != "": 116 input_files.append(bts_add_on) 117 118 with open(output_file, 'w') as fout: 119 120 # assert script contains templates for configuration by BTstack 121 have_eHCILL = False 122 have_power_vector_gfsk = False; 123 have_power_vector_edr2 = False; 124 have_power_vector_edr3 = False; 125 have_class2_single_power = False; 126 127 print("Creating {0}".format(output_file)) 128 129 part_size = 0 130 131 parts = 0 132 str_list = [] 133 part_strings = [] 134 part_sizes = [] 135 additions = [] 136 137 for bts_file in input_files: 138 139 with open (bts_file, 'rb') as fin: 140 141 print("- parsing {0:32}".format(bts_file)) 142 143 header = fin.read(32) 144 if header[0:4].decode('ascii') != 'BTSB': 145 print('Error', bts_file, 'is not a valid .BTS file') 146 sys.exit(1) 147 148 149 while True: 150 action_type = read_little_endian_16(fin) 151 action_size = read_little_endian_16(fin) 152 action_data = bytearray(fin.read(action_size)) 153 154 if (action_type == 1): # hci command 155 156 opcode = (action_data[2] << 8) | action_data[1] 157 if opcode == 0xFF36: 158 continue # skip baud rate command 159 if opcode == 0xFD0C: 160 have_eHCILL = True 161 if opcode == 0xFD82: 162 modulation_type = action_data[4] 163 if modulation_type == 0: 164 have_power_vector_gfsk = True 165 elif modulation_type == 1: 166 have_power_vector_edr2 + True 167 elif modulation_type == 2: 168 have_power_vector_edr3 = True 169 if opcode == 0xFD80: 170 # add missing power command templates 171 if not have_power_vector_gfsk: 172 part_size += append_power_vector_gfsk(additions, str_list, data_indent) 173 have_power_vector_gfsk = True; 174 if not have_power_vector_edr2: 175 part_size += append_power_vector_edr2(additions, str_list, data_indent) 176 have_power_vector_edr2 = True; 177 if not have_power_vector_edr3: 178 part_size += append_power_vector_edr3(additions, str_list, data_indent) 179 have_power_vector_edr3 = True; 180 if not have_class2_single_power: 181 part_size += append_class2_single_power(additions, str_list, data_indent) 182 have_class2_single_power = True; 183 184 counter = 0 185 str_list.append(data_indent) 186 for byte in action_data: 187 str_list.append("0x{0:02x}, ".format(byte)) 188 counter = counter + 1 189 if (counter != 15): 190 continue 191 counter = 0 192 str_list.append("\n") 193 str_list.append(data_indent) 194 str_list.append("\n\n") 195 196 part_size = part_size + action_size 197 198 # 30 kB chunks 199 if part_size < 30 * 1024: 200 continue 201 202 part_strings.append(''.join(str_list)) 203 part_sizes.append(part_size) 204 parts += 1 205 206 str_list = [] 207 part_size = 0 208 209 if (action_type == 6): # comment 210 action_data = action_data.decode('ascii').rstrip('\0') 211 str_list.append(data_indent) 212 str_list.append("// " + action_data + "\n") 213 214 if (action_type < 0): # EOF 215 break; 216 217 218 if not have_eHCILL: 219 part_size += append_ehcill(additions, str_list, data_indent) 220 221 # append calibration step, if missing so far 222 all_power_commands_provided = have_power_vector_gfsk and have_power_vector_edr2 and have_power_vector_edr3 and have_class2_single_power 223 if not all_power_commands_provided: 224 str_list.append("\n" + data_indent + "// BTstack: no calibration sequence found, adding power commands and calibration\n\n") 225 part_size += append_power_vector_gfsk(additions, str_list, data_indent) 226 part_size += append_power_vector_edr2(additions, str_list, data_indent) 227 part_size += append_power_vector_edr3(additions, str_list, data_indent) 228 part_size += append_class2_single_power(additions, str_list, data_indent) 229 part_size += append_calibration_sequence(additions, str_list, data_indent) 230 231 part_strings.append(''.join(str_list)) 232 part_sizes.append(part_size) 233 parts += 1 234 235 fout.write( '// init script created from\n') 236 fout.write( '// - {0}\n'.format(main_bts_file)) 237 if aka != "": 238 fout.write( '// - AKA TIInit_{0}.bts\n'.format(aka)) 239 if bts_add_on != "": 240 fout.write( '// - {0}\n'.format(bts_add_on)) 241 fout.write( '#include <stdint.h>\n') 242 fout.write( '#include "btstack_chipset_cc256x.h"\n') 243 fout.write( '\n') 244 # if aka != "": 245 # fout.write( 'const char * {0}_init_script_aka = "{1}";\n'.format(array_name, aka)) 246 if lmp_subversion != 0: 247 fout.write( get_lmp_subversion.format(prefix = array_name, lmp_subversion = "0x%04x" % lmp_subversion)) 248 part = 0 249 size = 0 250 for part_size in part_sizes: 251 part += 1 252 size += part_size 253 print("- part %u, size %u" % (part,part_size)) 254 255 print('- total size %u' % size) 256 257 print("\n".join(additions)) 258 259 260 part = 0 261 for part_text in part_strings: 262 part += 1 263 suffix = '' 264 265 if part == 1: 266 fout.write( fartext ) 267 268 if (part > 1): 269 suffix = '_{0}'.format(part) 270 fout.write('#if defined(__GNUC__) && defined(__GNUC__) && (__MSP430X__ > 0)\n') 271 fout.write('};\n') 272 fout.write('__attribute__((section (".fartext")))\n') 273 274 fout.write('const uint8_t {0}_init_script{1}[] = {2}\n\n'.format(array_name, suffix, '{')) 275 276 if (part > 1): 277 fout.write('#endif\n') 278 279 fout.write(part_text) 280 281 282 fout.write('};\n\n') 283 284 fout.write('const uint32_t {0}_init_script_size = sizeof({0}_init_script); // size = {1} bytes\n\n'.format(array_name,size)); 285 286# check usage: 2-3 param 287if len(sys.argv) < 3 or len(sys.argv) > 4: 288 print(usage) 289 sys.exit(1) 290 291main_bts = sys.argv[1] 292add_on = "" 293if len(sys.argv) == 4: 294 add_on = sys.argv[2] 295output_file = sys.argv[-1] 296 297# get AKA from file names that include model name 298aka = "" 299lmp_subversion = 0 300name_lower = main_bts.lower() 301if 'cc2560_' in name_lower: 302 aka = "6.2.31" 303if 'cc2560a_' in name_lower or 'cc2564_' in name_lower or 'cc2567_' in name_lower: 304 aka = "6.6.15" 305if 'cc2560b_' in name_lower or 'cc2564b_' in name_lower: 306 aka = "6.7.16" 307if 'cc2564c_' in name_lower: 308 aka = "6.12.26" 309 310# hardcode AKA for CC2567 v2.8 311if 'cc256x_bt_service_pack_2.8_ant_1.16' in name_lower: 312 aka = "6.6.15" 313 314# use AKA from .bts file that it 315name_parts = re.match('.*TIInit_(\d*\.\d*\.\d*).*.bts', main_bts) 316if name_parts: 317 aka = name_parts.group(1) 318 319# calculate subversion from AKA "CHIP.MAJ.MIN" 320# lmp scheme: ABBB BBCC CDDD DDDD 321# - chip = BBB 322# - maj = ACCC 323# - min = DDDD DDD 324if len(aka) > 0: 325 nums = aka.split('.') 326 chip = int(nums[0]) 327 maj_ver = int(nums[1]) 328 min_ver = int(nums[2]) 329 lmp_subversion = ((maj_ver & 0x08) << 12) | (chip << 10) | ((maj_ver & 0x07) << 7) | min_ver 330 331# print summary 332print ("Main file: %s"% main_bts) 333if add_on != "": 334 print ("Add-on file: %s" % add_on) 335if aka != "": 336 print ("- AKA TIInit_%s.bts" % aka) 337 338if lmp_subversion: 339 print ("- LMP Subversion: 0x%04x" % lmp_subversion) 340else: 341 print ("- LMP Subversion: Unknown") 342 343convert_bts(output_file, main_bts, add_on, aka, lmp_subversion) 344print 345 346 347 348