compile_gatt.py (e22a261227a2522f26982870e4eee0b42606d652) | compile_gatt.py (d7ec1d24bc1e3be5bf8c482d95765d3ecaaa7bda) |
---|---|
1#!/usr/bin/env python 2# 3# BLE GATT configuration generator for use with BTstack, v0.1 4# Copyright 2011 Matthias Ringwald 5# 6# Format of input file: 7# PRIMARY_SERVICE, SERVICE_UUID 8# CHARACTERISTIC, ATTRIBUTE_TYPE_UUID, [READ | WRITE | DYNAMIC], VALUE --- 33 unchanged lines hidden (view full) --- 42 'GAP_DEVICE_NAME' : 0x2a00, 43 'GAP_APPEARANCE' : 0x2a01, 44 'GAP_PERIPHERAL_PRIVACY_FLAG' : 0x2A02, 45 'GAP_RECONNECTION_ADDRESS' : 0x2A03, 46 'GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS' : 0x2A04, 47 'GATT_SERVICE_CHANGED' : 0x2a05, 48} 49 | 1#!/usr/bin/env python 2# 3# BLE GATT configuration generator for use with BTstack, v0.1 4# Copyright 2011 Matthias Ringwald 5# 6# Format of input file: 7# PRIMARY_SERVICE, SERVICE_UUID 8# CHARACTERISTIC, ATTRIBUTE_TYPE_UUID, [READ | WRITE | DYNAMIC], VALUE --- 33 unchanged lines hidden (view full) --- 42 'GAP_DEVICE_NAME' : 0x2a00, 43 'GAP_APPEARANCE' : 0x2a01, 44 'GAP_PERIPHERAL_PRIVACY_FLAG' : 0x2A02, 45 'GAP_RECONNECTION_ADDRESS' : 0x2A03, 46 'GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS' : 0x2A04, 47 'GATT_SERVICE_CHANGED' : 0x2a05, 48} 49 |
50security_permsission = ['ANYBODY','ENCRYPTED', 'AUTHENTICATED', 'AUTHORIZED'] 51 |
|
50property_flags = { 51 # GATT Characteristic Properties 52 'BROADCAST' : 0x01, 53 'READ' : 0x02, 54 'WRITE_WITHOUT_RESPONSE' : 0x04, 55 'WRITE' : 0x08, 56 'NOTIFY': 0x10, 57 'INDICATE' : 0x20, --- 112 unchanged lines hidden (view full) --- 170 print("WARNING: property %s undefined" % (property)) 171 172 return value; 173 174def gatt_characteristic_properties(properties): 175 return properties & 0xff 176 177def att_flags(properties): | 52property_flags = { 53 # GATT Characteristic Properties 54 'BROADCAST' : 0x01, 55 'READ' : 0x02, 56 'WRITE_WITHOUT_RESPONSE' : 0x04, 57 'WRITE' : 0x08, 58 'NOTIFY': 0x10, 59 'INDICATE' : 0x20, --- 112 unchanged lines hidden (view full) --- 172 print("WARNING: property %s undefined" % (property)) 173 174 return value; 175 176def gatt_characteristic_properties(properties): 177 return properties & 0xff 178 179def att_flags(properties): |
178 print("in %x" % properties) 179 # drop Broadcast (0x01), Notify (0x10), Indicate (0x20)- not used for flags 180 properties &= 0x1ffce | 180 # drop Broadcast (0x01), Notify (0x10), Indicate (0x20) - not used for flags 181 properties &= 0xffffffce |
181 182 # rw permissions distinct 183 distinct_permissions_used = properties & ( 184 property_flags['READ_AUTHORIZED'] | 185 property_flags['READ_AUTHENTICATED'] | 186 property_flags['READ_ENCRYPTED'] | 187 property_flags['READ_ANYBODY'] | 188 property_flags['WRITE_AUTHORIZED'] | 189 property_flags['WRITE_AUTHENTICATED'] | 190 property_flags['WRITE_ENCRYPTED'] | 191 property_flags['WRITE_ANYBODY'] 192 ) != 0 193 194 # post process properties 195 encryption_key_size_specified = (properties & property_flags['ENCRYPTION_KEY_SIZE_MASK']) != 0 196 | 182 183 # rw permissions distinct 184 distinct_permissions_used = properties & ( 185 property_flags['READ_AUTHORIZED'] | 186 property_flags['READ_AUTHENTICATED'] | 187 property_flags['READ_ENCRYPTED'] | 188 property_flags['READ_ANYBODY'] | 189 property_flags['WRITE_AUTHORIZED'] | 190 property_flags['WRITE_AUTHENTICATED'] | 191 property_flags['WRITE_ENCRYPTED'] | 192 property_flags['WRITE_ANYBODY'] 193 ) != 0 194 195 # post process properties 196 encryption_key_size_specified = (properties & property_flags['ENCRYPTION_KEY_SIZE_MASK']) != 0 197 |
197 # set encrypted for both, if distinct permissions not used | 198 # if distinct permissions not used and encyrption key size specified -> set READ/WRITE Encrypted |
198 if encryption_key_size_specified and not distinct_permissions_used: 199 properties |= property_flags['READ_ENCRYPTED'] | property_flags['WRITE_ENCRYPTED'] 200 | 199 if encryption_key_size_specified and not distinct_permissions_used: 200 properties |= property_flags['READ_ENCRYPTED'] | property_flags['WRITE_ENCRYPTED'] 201 |
201 # convert user permissions to att db flags | 202 # if distinct permissions not used and authentication is requires -> set READ/WRITE Authenticated 203 if properties & property_flags['AUTHENTICATION_REQUIRED'] and not distinct_permissions_used: 204 properties |= property_flags['READ_AUTHENTICATED'] | property_flags['WRITE_AUTHENTICATED'] 205 206 # if distinct permissions not used and authorized is requires -> set READ/WRITE Authorized 207 if properties & property_flags['AUTHORIZATION_REQUIRED'] and not distinct_permissions_used: 208 properties |= property_flags['READ_AUTHORIZED'] | property_flags['WRITE_AUTHORIZED'] 209 210 # determine read/write security requirements 211 read_security_level = 0 212 write_security_level = 0 |
202 if properties & property_flags['READ_AUTHORIZED']: | 213 if properties & property_flags['READ_AUTHORIZED']: |
203 properties |= property_flags['READ_PERMISSION_BIT_0'] | property_flags['READ_PERMISSION_BIT_1'] | 214 read_security_level = 3 |
204 elif properties & property_flags['READ_AUTHENTICATED']: | 215 elif properties & property_flags['READ_AUTHENTICATED']: |
205 properties |= property_flags['READ_PERMISSION_BIT_1'] | 216 read_security_level = 2 |
206 elif properties & property_flags['READ_ENCRYPTED']: | 217 elif properties & property_flags['READ_ENCRYPTED']: |
207 properties |= property_flags['READ_PERMISSION_BIT_0'] | 218 read_security_level = 1 |
208 if properties & property_flags['WRITE_AUTHORIZED']: | 219 if properties & property_flags['WRITE_AUTHORIZED']: |
209 properties |= property_flags['WRITE_PERMISSION_BIT_0'] | property_flags['WRITE_PERMISSION_BIT_1'] | 220 write_security_level = 3 |
210 elif properties & property_flags['WRITE_AUTHENTICATED']: | 221 elif properties & property_flags['WRITE_AUTHENTICATED']: |
211 properties |= property_flags['WRITE_PERMISSION_BIT_1'] | 222 write_security_level = 2 |
212 elif properties & property_flags['WRITE_ENCRYPTED']: | 223 elif properties & property_flags['WRITE_ENCRYPTED']: |
224 write_security_level = 1 225 226 # map security requirements to flags 227 if read_security_level & 2: 228 properties |= property_flags['READ_PERMISSION_BIT_1'] 229 if read_security_level & 1: 230 properties |= property_flags['READ_PERMISSION_BIT_0'] 231 if write_security_level & 2: 232 properties |= property_flags['WRITE_PERMISSION_BIT_1'] 233 if write_security_level & 1: |
|
213 properties |= property_flags['WRITE_PERMISSION_BIT_0'] | 234 properties |= property_flags['WRITE_PERMISSION_BIT_0'] |
214 print("out %x" % properties) | |
215 216 return properties 217 | 235 236 return properties 237 |
218def write_permissions_and_key_size(properties): | 238def write_permissions_and_key_size_flags_from_properties(properties): |
219 return att_flags(properties) & (property_flags['ENCRYPTION_KEY_SIZE_MASK'] | property_flags['WRITE_PERMISSION_BIT_0'] | property_flags['WRITE_PERMISSION_BIT_1']) 220 221def write_8(fout, value): 222 fout.write( "0x%02x, " % (value & 0xff)) 223 224def write_16(fout, value): 225 fout.write('0x%02x, 0x%02x, ' % (value & 0xff, (value >> 8) & 0xff)) 226 --- 8 unchanged lines hidden (view full) --- 235def write_sequence(fout, text): 236 parts = text.split() 237 for part in parts: 238 fout.write("0x%s, " % (part.strip())) 239 240def write_indent(fout): 241 fout.write(" ") 242 | 239 return att_flags(properties) & (property_flags['ENCRYPTION_KEY_SIZE_MASK'] | property_flags['WRITE_PERMISSION_BIT_0'] | property_flags['WRITE_PERMISSION_BIT_1']) 240 241def write_8(fout, value): 242 fout.write( "0x%02x, " % (value & 0xff)) 243 244def write_16(fout, value): 245 fout.write('0x%02x, 0x%02x, ' % (value & 0xff, (value >> 8) & 0xff)) 246 --- 8 unchanged lines hidden (view full) --- 255def write_sequence(fout, text): 256 parts = text.split() 257 for part in parts: 258 fout.write("0x%s, " % (part.strip())) 259 260def write_indent(fout): 261 fout.write(" ") 262 |
263def read_permissions_from_flags(flags): 264 permissions = 0 265 if flags & property_flags['READ_PERMISSION_BIT_0']: 266 permissions |= 1 267 if flags & property_flags['READ_PERMISSION_BIT_1']: 268 permissions |= 2 269 return permissions 270 271def write_permissions_from_flags(flags): 272 permissions = 0 273 if flags & property_flags['WRITE_PERMISSION_BIT_0']: 274 permissions |= 1 275 if flags & property_flags['WRITE_PERMISSION_BIT_1']: 276 permissions |= 2 277 return permissions 278 279def encryption_key_size_from_flags(flags): 280 encryption_key_size = (flags & 0xf000) >> 12 281 if encryption_key_size > 0: 282 encryption_key_size += 1 283 return encryption_key_size 284 |
|
243def is_string(text): 244 for item in text.split(" "): 245 if not all(c in string.hexdigits for c in item): 246 return True 247 return False 248 249def add_client_characteristic_configuration(properties): 250 return properties & (property_flags['NOTIFY'] | property_flags['INDICATE']) 251 252def serviceDefinitionComplete(fout): 253 global services 254 if current_service_uuid_string: 255 fout.write("\n") 256 # print("append service %s = [%d, %d]" % (current_characteristic_uuid_string, current_service_start_handle, handle-1)) 257 defines_for_services.append('#define ATT_SERVICE_%s_START_HANDLE 0x%04x' % (current_service_uuid_string, current_service_start_handle)) 258 defines_for_services.append('#define ATT_SERVICE_%s_END_HANDLE 0x%04x' % (current_service_uuid_string, handle-1)) 259 services[current_service_uuid_string] = [current_service_start_handle, handle-1] 260 | 285def is_string(text): 286 for item in text.split(" "): 287 if not all(c in string.hexdigits for c in item): 288 return True 289 return False 290 291def add_client_characteristic_configuration(properties): 292 return properties & (property_flags['NOTIFY'] | property_flags['INDICATE']) 293 294def serviceDefinitionComplete(fout): 295 global services 296 if current_service_uuid_string: 297 fout.write("\n") 298 # print("append service %s = [%d, %d]" % (current_characteristic_uuid_string, current_service_start_handle, handle-1)) 299 defines_for_services.append('#define ATT_SERVICE_%s_START_HANDLE 0x%04x' % (current_service_uuid_string, current_service_start_handle)) 300 defines_for_services.append('#define ATT_SERVICE_%s_END_HANDLE 0x%04x' % (current_service_uuid_string, handle-1)) 301 services[current_service_uuid_string] = [current_service_start_handle, handle-1] 302 |
303def dump_flags(fout, flags): 304 global security_permsission 305 encryption_key_size = encryption_key_size_from_flags(flags) 306 read_permissions = security_permsission[read_permissions_from_flags(flags)] 307 write_permissions = security_permsission[write_permissions_from_flags(flags)] 308 write_indent(fout) 309 fout.write('// ') 310 first = 1 311 if flags & property_flags['READ']: 312 fout.write('READ_%s' % read_permissions) 313 first = 0 314 if flags & (property_flags['WRITE'] | property_flags['WRITE_WITHOUT_RESPONSE']): 315 if not first: 316 fout.write(', ') 317 first = 0 318 fout.write('WRITE_%s' % write_permissions) 319 if encryption_key_size > 0: 320 if not first: 321 fout.write(', ') 322 first = 0 323 fout.write('ENCRYPTION_KEY_SIZE=%u' % encryption_key_size) 324 fout.write('\n') 325 |
|
261def parseService(fout, parts, service_type): 262 global handle 263 global total_size 264 global current_service_uuid_string 265 global current_service_start_handle 266 267 serviceDefinitionComplete(fout) 268 | 326def parseService(fout, parts, service_type): 327 global handle 328 global total_size 329 global current_service_uuid_string 330 global current_service_start_handle 331 332 serviceDefinitionComplete(fout) 333 |
269 property = property_flags['READ']; | 334 read_only_anybody_flags = property_flags['READ']; |
270 271 write_indent(fout) 272 fout.write('// 0x%04x %s\n' % (handle, '-'.join(parts))) 273 274 uuid = parseUUID(parts[1]) 275 uuid_size = len(uuid) 276 277 size = 2 + 2 + 2 + uuid_size + 2 278 279 if service_type == 0x2802: 280 size += 4 281 282 write_indent(fout) 283 write_16(fout, size) | 335 336 write_indent(fout) 337 fout.write('// 0x%04x %s\n' % (handle, '-'.join(parts))) 338 339 uuid = parseUUID(parts[1]) 340 uuid_size = len(uuid) 341 342 size = 2 + 2 + 2 + uuid_size + 2 343 344 if service_type == 0x2802: 345 size += 4 346 347 write_indent(fout) 348 write_16(fout, size) |
284 write_16(fout, property) | 349 write_16(fout, read_only_anybody_flags) |
285 write_16(fout, handle) 286 write_16(fout, service_type) 287 write_uuid(uuid) 288 fout.write("\n") 289 290 current_service_uuid_string = c_string_for_uuid(parts[1]) 291 current_service_start_handle = handle 292 handle = handle + 1 --- 94 unchanged lines hidden (view full) --- 387 value_flags = att_flags(properties) 388 389 # add UUID128 flag for value handle 390 if uuid_size == 16: 391 value_flags = value_flags | property_flags['LONG_UUID']; 392 393 write_indent(fout) 394 fout.write('// 0x%04x VALUE-%s-'"'%s'"'\n' % (handle, '-'.join(parts[1:3]),value)) | 350 write_16(fout, handle) 351 write_16(fout, service_type) 352 write_uuid(uuid) 353 fout.write("\n") 354 355 current_service_uuid_string = c_string_for_uuid(parts[1]) 356 current_service_start_handle = handle 357 handle = handle + 1 --- 94 unchanged lines hidden (view full) --- 452 value_flags = att_flags(properties) 453 454 # add UUID128 flag for value handle 455 if uuid_size == 16: 456 value_flags = value_flags | property_flags['LONG_UUID']; 457 458 write_indent(fout) 459 fout.write('// 0x%04x VALUE-%s-'"'%s'"'\n' % (handle, '-'.join(parts[1:3]),value)) |
460 461 dump_flags(fout, value_flags) 462 |
|
395 write_indent(fout) 396 write_16(fout, size) 397 write_16(fout, value_flags) 398 write_16(fout, handle) 399 write_uuid(uuid) 400 if is_string(value): 401 write_string(fout, value) 402 else: 403 write_sequence(fout,value) 404 405 fout.write("\n") 406 defines_for_characteristics.append('#define ATT_CHARACTERISTIC_%s_VALUE_HANDLE 0x%04x' % (current_characteristic_uuid_string, handle)) 407 handle = handle + 1 408 409 if add_client_characteristic_configuration(properties): 410 # use write permissions and encryption key size from attribute value and set READ_ANYBODY | READ | WRITE | DYNAMIC | 463 write_indent(fout) 464 write_16(fout, size) 465 write_16(fout, value_flags) 466 write_16(fout, handle) 467 write_uuid(uuid) 468 if is_string(value): 469 write_string(fout, value) 470 else: 471 write_sequence(fout,value) 472 473 fout.write("\n") 474 defines_for_characteristics.append('#define ATT_CHARACTERISTIC_%s_VALUE_HANDLE 0x%04x' % (current_characteristic_uuid_string, handle)) 475 handle = handle + 1 476 477 if add_client_characteristic_configuration(properties): 478 # use write permissions and encryption key size from attribute value and set READ_ANYBODY | READ | WRITE | DYNAMIC |
411 flags = write_permissions_and_key_size(properties) | 479 flags = write_permissions_and_key_size_flags_from_properties(properties) |
412 flags |= property_flags['READ'] 413 flags |= property_flags['WRITE'] 414 flags |= property_flags['DYNAMIC'] 415 size = 2 + 2 + 2 + 2 + 2 | 480 flags |= property_flags['READ'] 481 flags |= property_flags['WRITE'] 482 flags |= property_flags['DYNAMIC'] 483 size = 2 + 2 + 2 + 2 + 2 |
484 |
|
416 write_indent(fout) 417 fout.write('// 0x%04x CLIENT_CHARACTERISTIC_CONFIGURATION\n' % (handle)) | 485 write_indent(fout) 486 fout.write('// 0x%04x CLIENT_CHARACTERISTIC_CONFIGURATION\n' % (handle)) |
487 488 dump_flags(fout, flags) 489 |
|
418 write_indent(fout) 419 write_16(fout, size) 420 write_16(fout, flags) 421 write_16(fout, handle) 422 write_16(fout, 0x2902) 423 write_16(fout, 0) 424 fout.write("\n") 425 defines_for_characteristics.append('#define ATT_CHARACTERISTIC_%s_CLIENT_CONFIGURATION_HANDLE 0x%04x' % (current_characteristic_uuid_string, handle)) --- 22 unchanged lines hidden (view full) --- 448 449 size = 2 + 2 + 2 + 2 450 if is_string(value): 451 size = size + len(value) - 2 452 else: 453 size = size + len(value.split()) 454 455 # use write, write permissions and encryption key size from attribute value and set READ_ANYBODY | 490 write_indent(fout) 491 write_16(fout, size) 492 write_16(fout, flags) 493 write_16(fout, handle) 494 write_16(fout, 0x2902) 495 write_16(fout, 0) 496 fout.write("\n") 497 defines_for_characteristics.append('#define ATT_CHARACTERISTIC_%s_CLIENT_CONFIGURATION_HANDLE 0x%04x' % (current_characteristic_uuid_string, handle)) --- 22 unchanged lines hidden (view full) --- 520 521 size = 2 + 2 + 2 + 2 522 if is_string(value): 523 size = size + len(value) - 2 524 else: 525 size = size + len(value.split()) 526 527 # use write, write permissions and encryption key size from attribute value and set READ_ANYBODY |
456 flags = write_permissions_and_key_size(properties) | 528 flags = write_permissions_and_key_size_flags_from_properties(properties) |
457 flags |= properties & property_flags['WRITE'] 458 flags |= property_flags['READ'] 459 460 write_indent(fout) 461 fout.write('// 0x%04x CHARACTERISTIC_USER_DESCRIPTION-%s\n' % (handle, '-'.join(parts[1:]))) | 529 flags |= properties & property_flags['WRITE'] 530 flags |= property_flags['READ'] 531 532 write_indent(fout) 533 fout.write('// 0x%04x CHARACTERISTIC_USER_DESCRIPTION-%s\n' % (handle, '-'.join(parts[1:]))) |
534 535 dump_flags(fout, flags) 536 |
|
462 write_indent(fout) 463 write_16(fout, size) 464 write_16(fout, flags) 465 write_16(fout, handle) 466 write_16(fout, 0x2901) 467 if is_string(value): 468 write_string(fout, value) 469 else: --- 6 unchanged lines hidden (view full) --- 476 global handle 477 global total_size 478 global current_characteristic_uuid_string 479 480 properties = parseProperties(parts[1]) 481 size = 2 + 2 + 2 + 2 482 483 # use write permissions and encryption key size from attribute value and set READ, WRITE, DYNAMIC, READ_ANYBODY | 537 write_indent(fout) 538 write_16(fout, size) 539 write_16(fout, flags) 540 write_16(fout, handle) 541 write_16(fout, 0x2901) 542 if is_string(value): 543 write_string(fout, value) 544 else: --- 6 unchanged lines hidden (view full) --- 551 global handle 552 global total_size 553 global current_characteristic_uuid_string 554 555 properties = parseProperties(parts[1]) 556 size = 2 + 2 + 2 + 2 557 558 # use write permissions and encryption key size from attribute value and set READ, WRITE, DYNAMIC, READ_ANYBODY |
484 flags = write_permissions_and_key_size(properties) | 559 flags = write_permissions_and_key_size_flags_from_properties(properties) |
485 flags |= property_flags['READ'] 486 flags |= property_flags['WRITE'] 487 flags |= property_flags['DYNAMIC'] 488 489 write_indent(fout) 490 fout.write('// 0x%04x SERVER_CHARACTERISTIC_CONFIGURATION-%s\n' % (handle, '-'.join(parts[1:]))) | 560 flags |= property_flags['READ'] 561 flags |= property_flags['WRITE'] 562 flags |= property_flags['DYNAMIC'] 563 564 write_indent(fout) 565 fout.write('// 0x%04x SERVER_CHARACTERISTIC_CONFIGURATION-%s\n' % (handle, '-'.join(parts[1:]))) |
566 567 dump_flags(fout, flags) 568 |
|
491 write_indent(fout) 492 write_16(fout, size) 493 write_16(fout, flags) 494 write_16(fout, handle) 495 write_16(fout, 0x2903) 496 fout.write("\n") 497 defines_for_characteristics.append('#define ATT_CHARACTERISTIC_%s_SERVER_CONFIGURATION_HANDLE 0x%04x' % (current_characteristic_uuid_string, handle)) 498 handle = handle + 1 --- 303 unchanged lines hidden --- | 569 write_indent(fout) 570 write_16(fout, size) 571 write_16(fout, flags) 572 write_16(fout, handle) 573 write_16(fout, 0x2903) 574 fout.write("\n") 575 defines_for_characteristics.append('#define ATT_CHARACTERISTIC_%s_SERVER_CONFIGURATION_HANDLE 0x%04x' % (current_characteristic_uuid_string, handle)) 576 handle = handle + 1 --- 303 unchanged lines hidden --- |