1# -*- coding: utf-8 -*- 2# Copyright 2019 Oticon A/S 3# SPDX-License-Identifier: Apache-2.0 4 5from enum import IntEnum; 6from .utils import *; 7 8class ADType(IntEnum): 9 FLAGS = 1 # «Flags» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.3 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.3 and 18.1 (v4.0) Core Specification Supplement, Part A, section 1.3 10 ILIST_UUIDS_16 = 2 # «Incomplete List of 16 - bit Service Class UUIDs» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.1 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.1 and 18.2 (v4.0) Core Specification Supplement, Part A, section 1.1 11 CLIST_UUIDS_16 = 3 # «Complete List of 16 - bit Service Class UUIDs» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.1 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.1 and 18.2 (v4.0) Core Specification Supplement, Part A, section 1.1 12 ILIST_UUIDS_32 = 4 # «Incomplete List of 32 - bit Service Class UUIDs» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.1 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, section 18.2 (v4.0) Core Specification Supplement, Part A, section 1.1 13 CLIST_UUIDS_32 = 5 # «Complete List of 32 - bit Service Class UUIDs» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.1 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, section 18.2 (v4.0) Core Specification Supplement, Part A, section 1.1 14 ILIST_UUIDS_128 = 6 # «Incomplete List of 128 - bit Service Class UUIDs» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.1 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.1 and 18.2 (v4.0) Core Specification Supplement, Part A, section 1.1 15 CLIST_UUIDS_128 = 7 # «Complete List of 128 - bit Service Class UUIDs» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.1 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.1 and 18.2 (v4.0) Core Specification Supplement, Part A, section 1.1 16 SHORTENED_LOCAL_NAME = 8 # «Shortened Local Name» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.2 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.2 and 18.4 (v4.0) Core Specification Supplement, Part A, section 1.2 17 COMPLETE_LOCAL_NAME = 9 # «Complete Local Name» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.2 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.2 and 18.4 (v4.0) Core Specification Supplement, Part A, section 1.2 18 TX_POWER_LEVEL = 10 # «Tx Power Level» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.5 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.5 and 18.3 (v4.0) Core Specification Supplement, Part A, section 1.5 19 DEVICE_CLASS = 13 # «Class of Device» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.6 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.5 and 18.5 (v4.0) Core Specification Supplement, Part A, section 1.6 20 PAIR_HASH_C = 14 # «Simple Pairing Hash C» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.6 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.5 and 18.5 (v4.0) 21 PAIR_RANDOM_R = 15 # «Simple Pairing Randomizer R» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.6 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.5 and 18.5 (v4.0) 22 SEC_MANAGER_TK = 16 # «Security Manager TK Value» Bluetooth Core Specification : Vol. 3, Part C, sections 11.1.7 and 18.6 (v4.0) Core Specification Supplement, Part A, section 1.8 23 SEC_MANAGER_OBF = 17 # «Security Manager Out of Band Flags» Bluetooth Core Specification : Vol. 3, Part C, sections 11.1.6 and 18.7 (v4.0) Core Specification Supplement, Part A, section 1.7 24 PERIPHERAL_CONNECT_INT = 18 # «Peripheral Connection Interval Range» Bluetooth Core Specification : Vol. 3, Part C, sections 11.1.8 and 18.8 (v4.0) Core Specification Supplement, Part A, section 1.9 25 SS_UUIDS_16 = 20 # «List of 16 - bit Service Solicitation UUIDs» Bluetooth Core Specification : Vol. 3, Part C, sections 11.1.9 and 18.9 (v4.0) Core Specification Supplement, Part A, section 1.10 26 SS_UUIDS_128 = 21 # «List of 128 - bit Service Solicitation UUIDs» Bluetooth Core Specification : Vol. 3, Part C, sections 11.1.9 and 18.9 (v4.0) Core Specification Supplement, Part A, section 1.10 27 SERVICE_DATA_16 = 22 # «Service Data» Bluetooth Core Specification : Vol. 3, Part C, sections 11.1.10 and 18.10 (v4.0) 28 PUBLIC_ADDRESS = 23 # «Public Target Address» Bluetooth Core Specification : Core Specification Supplement, Part A, section 1.13 29 RANDOM_ADDRESS = 24 # «Random Target Address» Bluetooth Core Specification : Core Specification Supplement, Part A, section 1.14 30 APPEARANCE = 25 # «Appearance» Bluetooth Core Specification : Core Specification Supplement, Part A, section 1.12 31 ADVERTISE_INT = 26 # «Advertising Interval» Bluetooth Core Specification : Core Specification Supplement, Part A, section 1.15 32 DEVICE_ADDRESS = 27 # «LE Bluetooth Device Address» Core Specification Supplement, Part A, section 1.16 33 DEVICE_ROLE = 28 # «LE Role» Core Specification Supplement, Part A, section 1.17 34 PAIR_HASH_C256 = 29 # «Simple Pairing Hash C - 256» Core Specification Supplement, Part A, section 1.6 35 PAIR_RANDOM_R256 = 30 # «Simple Pairing Randomizer R - 256» Core Specification Supplement, Part A, section 1.6 36 SS_UUIDS_32 = 31 # «List of 32 - bit Service Solicitation UUIDs» Core Specification Supplement, Part A, section 1.10 37 SERVICE_DATA_32 = 32 # «Service Data - 32 - bit UUID» Core Specification Supplement, Part A, section 1.11 38 SERVICE_DATA_128 = 33 # «Service Data - 128 - bit UUID» Core Specification Supplement, Part A, section 1.11 39 SEC_CONNECT_CONFIRM = 34 # «LE Secure Connections Confirmation Value» Core Specification Supplement Part A, Section 1.6 40 SEC_CONNECT_RANDOM = 35 # «LE Secure Connections Random Value» Core Specification Supplement Part A, Section 1.6 41 URI = 36 # «URI» Bluetooth Core Specification : Core Specification Supplement, Part A, section 1.18 42 INDOOR_POSITION = 37 # «Indoor Positioning» Indoor Posiioning Service v1.0 or later 43 DISCOVERY_DATA = 38 # «Transport Discovery Data» Transport Discovery Service v1.0 or later 44 LE_SUPPORTED_FEATURES = 39 # «LE Supported Features» Core Specification Supplement, Part A, Section 1.19 45 CHANNEL_MAP_UPDATE = 40 # «Channel Map Update Indication» Core Specification Supplement, Part A, Section 1.20 46 INFO_DATA_3D = 61 # «3D Information Data» 3D Synchronization Profile, v1.0 or later 47 MANUFACTURER_DATA = 255 # «Manufacturer Specific Data» Bluetooth Core Specification : Vol. 3, Part C, section 8.1.4 (v2.1 + EDR, 3.0 + HS and 4.0) Vol. 3, Part C, sections 11.1.4 and 18.11 (v4.0) Core Specification Supplement, Part A, section 1.4 48 49class ADRole(IntEnum): 50 ONLY_PERIPHERAL = 0 # Only Peripheral Role supported 51 ONLY_CENTRAL = 1 # Only Central Role supported 52 PERIPHERAL_PREFERRED = 2 # Peripheral and Central Role supported, Peripheral Role preferred for connection establishment 53 CENTRAL_PREFERRED = 3 # Peripheral and Central Role supported, Central Role preferred for connection establishment 54 55class ADFlag(IntEnum): 56 LE_LIMITED_DISCOVERABLE = 1 # LE Limited Discoverable Mode 57 LE_GENERAL_DISCOVERABLE = 2 # LE General Discoverable Mode 58 BR_EDR_NOT_SUPPORTED = 4 # BR/EDR Not Supported. Bit 37 of LMP Feature Mask Definitions. 59 LE_BR_EDR_CAPABLE_CTRL = 8 # Simultaneous LE and BR/EDR to Same Device Capable (Controller). Bit 49 of LMP Feature Mask Definitions. 60 LE_BR_EDR_CAPABLE_HOST = 16 # Simultaneous LE and BR/EDR to Same Device Capable (Host). Bit 66 of LMP Feature Mask Definitions. 61 LE_FLAGS_ALL = 31 # All flags set 62 63""" 64 Appearance is a 16 bit number divided into a Category (most significant 10 bits) and a Sub-category (least significant 6 bits) 65 66 Category Category Name Sub-category Sub-category Name Appearance Value 67 0 Unknown 0 Unknown 0 68 1 Phone 0 Generic Phone 64 69 2 Computer 0 Generic Computer 128 70 3 Watch 0 Generic Watch 192 71 1 Sports Watch 193 72 4 Clock 0 Generic Clock 256 73 5 Display 0 Generic Display 320 74 6 Remote Control 0 Generic Remote Control 384 75 7 Eye-glasses 0 Generic Eye-glasses 448 76 8 Tag 0 Generic Tag 512 77 9 Keyring 0 Generic Keyring 576 78 10 Media Player 0 Generic Media Player 640 79 11 Barcode Scanner 0 Generic Barcode Scanner 704 80 12 Thermometer 0 Generic Thermometer 768 81 1 Ear Thermometer 769 82 13 Heart rate Sensor 0 Generic Heart rate Sensor 832 83 1 Heart rate Belt 833 84 14 Blood Pressure 0 Generic Blood Pressure 896 85 1 Blood Pressure Arm 897 86 2 Blood Pressure Wrist 898 87 15 Human Interface Device (HID) 0 Generic Human Interface Device 960 88 1 Keyboard 961 89 2 Mouse 962 90 3 Joystick 963 91 4 Gamepad 964 92 5 Digitizer Tablet 965 93 6 Card Reader 966 94 7 Digital Pen 967 95 8 Barcode Scanner 968 96 16 Glucoose Meter 0 Generic Glucoose Meter 1024 97 17 Running Walking Sensor 0 Generic Running Walking Sensor 1088 98 1 In-Shoe Running Walking Sensor 1089 99 2 On-Shoe Running Walking Sensor 1090 100 3 On-Hip Running Walking Sensor 1091 101 18 Cycling 0 Generic Cycling 1152 102 1 Cycling Computer 1153 103 2 Speed Sensor 1154 104 3 Cadence Sensor 1155 105 4 Power Sensor 1156 106 5 Speed and Cadence Sensor 1157 107 49 Pulse Oximeter 0 Generic Pulse Oximeter 3136 108 1 Fingertip 3137 109 2 Wrist Worn 3138 110 50 Weight Scale 0 Generic Weight Scale 3200 111 51 Personal Mobility Device 0 Generic Personal Mobility Device 3264 112 1 Powered Weelchair 3265 113 2 Mobility Scooter 3266 114 52 Continuous Glucoose Monitor 0 Generic Continuous Glucoose Monitor 3328 115 53 Insulin Pump 0 Generic Insulin Pump 3392 116 1 Durable Insulin Pump 3393 117 4 Patch Insulin Pump 3396 118 8 Insulin Pen 3400 119 54 Medication Delivery 0 Generic Medication Delivery 3456 120 81 Outdoor Sports Activity 0 Generic Outdoor Sports Activity 5184 121 1 Location Display Device 5185 122 2 Location and Navigation Display Device 5186 123 3 Location Pod 5187 124 4 Location and Navigation Pod 5188 125""" 126 127__schemeNames__ = { 128 'aaa': [ 0X02 ], 129 'aaas': [ 0X03 ], 130 'about': [ 0X04 ], 131 'acap': [ 0X05 ], 132 'acct': [ 0X06 ], 133 'cap': [ 0X07 ], 134 'cid': [ 0X08 ], 135 'coap': [ 0X09 ], 136 'coaps': [ 0X0A ], 137 'crid': [ 0X0B ], 138 'data': [ 0X0C ], 139 'dav': [ 0X0D ], 140 'dict': [ 0X0E ], 141 'dns': [ 0X0F ], 142 'file': [ 0X10 ], 143 'ftp': [ 0X11 ], 144 'geo': [ 0X12 ], 145 'go': [ 0X13 ], 146 'gopher': [ 0X14 ], 147 'h323': [ 0X15 ], 148 'http': [ 0X16 ], 149 'https': [ 0X17 ], 150 'iax': [ 0X18 ], 151 'icap': [ 0X19 ], 152 'im': [ 0X1A ], 153 'imap': [ 0X1B ], 154 'info': [ 0X1C ], 155 'ipp': [ 0X1D ], 156 'ipps': [ 0X1E ], 157 'iris': [ 0X1F ], 158 'iris.beep': [ 0X20 ], 159 'iris.xpc': [ 0X21 ], 160 'iris.xpcs': [ 0X22 ], 161 'iris.lwz': [ 0X23 ], 162 'jabber': [ 0X24 ], 163 'ldap': [ 0X25 ], 164 'mailto': [ 0X26 ], 165 'mid': [ 0X27 ], 166 'msrp': [ 0X28 ], 167 'msrps': [ 0X29 ], 168 'mtqp': [ 0X2A ], 169 'mupdate': [ 0X2B ], 170 'news': [ 0X2C ], 171 'nfs': [ 0X2D ], 172 'ni': [ 0X2E ], 173 'nih': [ 0X2F ], 174 'nntp': [ 0X30 ], 175 'opaquelocktoken': [ 0X31 ], 176 'pop': [ 0X32 ], 177 'pres': [ 0X33 ], 178 'reload': [ 0X34 ], 179 'rtsp': [ 0X35 ], 180 'rtsps': [ 0X36 ], 181 'rtspu': [ 0X37 ], 182 'service': [ 0X38 ], 183 'session': [ 0X39 ], 184 'shttp': [ 0X3A ], 185 'sieve': [ 0X3B ], 186 'sip': [ 0X3C ], 187 'sips': [ 0X3D ], 188 'sms': [ 0X3E ], 189 'snmp': [ 0X3F ], 190 'soap.beep': [ 0X40 ], 191 'soap.beeps': [ 0X41 ], 192 'stun': [ 0X42 ], 193 'stuns': [ 0X43 ], 194 'tag': [ 0X44 ], 195 'tel': [ 0X45 ], 196 'telnet': [ 0X46 ], 197 'tftp': [ 0X47 ], 198 'thismessage': [ 0X48 ], 199 'tn3270': [ 0X49 ], 200 'tip': [ 0X4A ], 201 'turn': [ 0X4B ], 202 'turns': [ 0X4C ], 203 'tv': [ 0X4D ], 204 'urn': [ 0X4E ], 205 'vemmi': [ 0X4F ], 206 'ws': [ 0X50 ], 207 'wss': [ 0X51 ], 208 'xcon': [ 0X52 ], 209 'xcon-userid': [ 0X53 ], 210 'xmlrpc.beep': [ 0X54 ], 211 'xmlrpc.beeps': [ 0X55 ], 212 'xmpp': [ 0X56 ], 213 'z39.50r': [ 0X57 ], 214 'z39.50s': [ 0X58 ], 215 'acr': [ 0X59 ], 216 'adiumxtra': [ 0X5A ], 217 'afp': [ 0X5B ], 218 'afs': [ 0X5C ], 219 'aim': [ 0X5D ], 220 'apt': [ 0X5E ], 221 'attachment': [ 0X5F ], 222 'aw': [ 0X60 ], 223 'barion': [ 0X61 ], 224 'beshare': [ 0X62 ], 225 'bitcoin': [ 0X63 ], 226 'bolo': [ 0X64 ], 227 'callto': [ 0X65 ], 228 'chrome': [ 0X66 ], 229 'chrome-extension': [ 0X67 ], 230 'com-eventbrite-attendee': [ 0X68 ], 231 'content': [ 0X69 ], 232 'cvs': [ 0X6A ], 233 'dlna-playsingle': [ 0X6B ], 234 'dlna-playcontainer': [ 0X6C ], 235 'dtn': [ 0X6D ], 236 'dvb': [ 0X6E ], 237 'ed2k': [ 0X6F ], 238 'facetime': [ 0X70 ], 239 'feed': [ 0X71 ], 240 'feedready': [ 0X72 ], 241 'finger': [ 0X73 ], 242 'fish': [ 0X74 ], 243 'gg': [ 0X75 ], 244 'git': [ 0X76 ], 245 'gizmoproject': [ 0X77 ], 246 'gtalk': [ 0X78 ], 247 'ham': [ 0X79 ], 248 'hcp': [ 0X7A ], 249 'icon': [ 0X7B ], 250 'ipn': [ 0X7C ], 251 'irc': [ 0X7D ], 252 'irc6': [ 0X7E ], 253 'ircs': [ 0X7F ], 254 'itms': [ 0XC2, 0X80 ], 255 'jar': [ 0XC2, 0X81 ], 256 'jms': [ 0XC2, 0X82 ], 257 'keyparc': [ 0XC2, 0X83 ], 258 'lastfm': [ 0XC2, 0X84 ], 259 'ldaps': [ 0XC2, 0X85 ], 260 'magnet': [ 0XC2, 0X86 ], 261 'maps': [ 0XC2, 0X87 ], 262 'market': [ 0XC2, 0X88 ], 263 'message': [ 0XC2, 0X89 ], 264 'mms': [ 0XC2, 0X8A ], 265 'ms-help': [ 0XC2, 0X8B ], 266 'ms-settings-power': [ 0XC2, 0X8C ], 267 'msnim': [ 0XC2, 0X8D ], 268 'mumble': [ 0XC2, 0X8E ], 269 'mvn': [ 0XC2, 0X8F ], 270 'notes': [ 0XC2, 0X90 ], 271 'oid': [ 0XC2, 0X91 ], 272 'palm': [ 0XC2, 0X92 ], 273 'paparazzi': [ 0XC2, 0X93 ], 274 'pkcs11': [ 0XC2, 0X94 ], 275 'platform': [ 0XC2, 0X95 ], 276 'proxy': [ 0XC2, 0X96 ], 277 'psyc': [ 0XC2, 0X97 ], 278 'query': [ 0XC2, 0X98 ], 279 'res': [ 0XC2, 0X99 ], 280 'resource': [ 0XC2, 0X9A ], 281 'rmi': [ 0XC2, 0X9B ], 282 'rsync': [ 0XC2, 0X9C ], 283 'rtmfp': [ 0XC2, 0X9D ], 284 'rtmp': [ 0XC2, 0X9E ], 285 'secondlife': [ 0XC2, 0X9F ], 286 'sftp': [ 0XC2, 0XA0 ], 287 'sgn': [ 0XC2, 0XA1 ], 288 'skype': [ 0XC2, 0XA2 ], 289 'smb': [ 0XC2, 0XA3 ], 290 'smtp': [ 0XC2, 0XA4 ], 291 'soldat': [ 0XC2, 0XA5 ], 292 'spotify': [ 0XC2, 0XA6 ], 293 'ssh': [ 0XC2, 0XA7 ], 294 'steam': [ 0XC2, 0XA8 ], 295 'submit': [ 0XC2, 0XA9 ], 296 'svn': [ 0XC2, 0XAA ], 297 'teamspeak': [ 0XC2, 0XAB ], 298 'teliaeid': [ 0XC2, 0XAC ], 299 'things': [ 0XC2, 0XAD ], 300 'udp': [ 0XC2, 0XAE ], 301 'unreal': [ 0XC2, 0XAF ], 302 'ut2004': [ 0XC2, 0XB0 ], 303 'ventrilo': [ 0XC2, 0XB1 ], 304 'view-source': [ 0XC2, 0XB2 ], 305 'webcal': [ 0XC2, 0XB3 ], 306 'wtai': [ 0XC2, 0XB4 ], 307 'wyciwyg': [ 0XC2, 0XB5 ], 308 'xfire': [ 0XC2, 0XB6 ], 309 'xri': [ 0XC2, 0XB7 ], 310 'ymsgr': [ 0XC2, 0XB8 ], 311 'example': [ 0XC2, 0XB9 ], 312 'ms-settings-cloudstorage': [ 0XC2, 0XBA ] 313}; 314 315class ADData: 316 317 def __init__(self): 318 self.data = []; 319 320 def encode(self, adType, *args): 321 # 322 # ADType.TX_POWER_LEVEL, <power_level>; where <power_level> [ -127, +127 ] dBm. 323 # 324 if ( adType == ADType.TX_POWER_LEVEL ): 325 self.data = [ 2, adType, args[0] if args[0] >= 0 else 256+args[0] ]; 326 # 327 # ADType.FLAGS, <flags> where <flags> [ 0, 31 ] 328 # ADType.SEC_MANAGER_OBF, <flags> where <flags> [ 0, 15 ] 329 # ADType.DEVICE_ROLE, <role> where <role> [ 0, 3 ] 330 # 331 elif ( adType == ADType.FLAGS or adType == ADType.SEC_MANAGER_OBF or adType == ADType.DEVICE_ROLE ): 332 self.data = [ 2, adType, args[0] ]; 333 # 334 # ADType.ILIST_UUIDS_16, <uuid_A>, <uuid_B>, ... 335 # ADTYpe,CLIST_UUIDS_16, <uuid_A>, <uuid_B>, ... 336 # ADType.SS_UUIDS_16, <uuid_A>, <uuid_B>, ... 337 # 338 elif ( adType == ADType.ILIST_UUIDS_16 or adType == ADType.CLIST_UUIDS_16 or adType == ADType.SS_UUIDS_16 ): 339 self.data = [ 1+2*len(args), adType ]; 340 for arg in args: 341 self.data += toArray(arg, 2); 342 # 343 # ADType.ILIST_UUIDS_32, <uuid_A>, <uuid_B>, ... 344 # ADTYpe,CLIST_UUIDS_32, <uuid_A>, <uuid_B>, ... 345 # ADType.SS_UUIDS_32, <uuid_A>, <uuid_B>, ... 346 # 347 elif ( adType == ADType.ILIST_UUIDS_32 or adType == ADType.CLIST_UUIDS_32 or adType == ADType.SS_UUIDS_32 ): 348 self.data = [ 1+4*len(args), adType ]; 349 for arg in args: 350 self.data += toArray(arg, 4); 351 # 352 # ADType.ILIST_UUIDS_128, <uuid_A>, <uuid_B>, ... 353 # ADTYpe,CLIST_UUIDS_128, <uuid_A>, <uuid_B>, ... 354 # ADType.SS_UUIDS_128, <uuid_A>, <uuid_B>, ... 355 # 356 elif ( adType == ADType.ILIST_UUIDS_128 or adType == ADType.CLIST_UUIDS_128 or adType == ADType.SS_UUIDS_128 ): 357 self.data = [ 1+16*len(args), adType ]; 358 for arg in args: 359 self.data += toArray(arg, 16); 360 # 361 # ADType.SHORTENED_LOCAL_NAME, <unicode_name> 362 # ADType.COMPLETE_LOCAL_NAME, <unicode_name> 363 # 364 elif ( adType == ADType.SHORTENED_LOCAL_NAME or adType == ADType.COMPLETE_LOCAL_NAME ): 365 name = args[0].encode('UTF-8'); 366 if len(name) > 29: 367 name = name[:29]; 368 self.data = [ 1+len(name), adType ] + [ _ for _ in name ]; 369 # 370 # ADType.DEVICE_CLASS, <device_class> 371 # 372 elif ( adType == ADType.DEVICE_CLASS ): 373 self.data = [ 4, adType ] + toArray(args[0], 3); 374 # 375 # ADType.PAIR_HASH_C, <hash_value> 376 # ADType.PAIR_RANDOM_R, <random_value> 377 # ADType.SEC_MANAGER_TK, <tk_value> 378 # 379 elif ( adType == ADType.PAIR_HASH_C or adType == ADType.PAIR_RANDOM_R or adType == ADType.SEC_MANAGER_TK ): 380 self.data = [ 17, adType ] + toArray(args[0], 16); 381 # 382 # ADType.PERIPHERAL_CONNECT_INT, <min_interval>, <max_interval> 383 # 384 elif ( adType == ADType.PERIPHERAL_CONNECT_INT ): 385 self.data = [ 5, adType ] + toArray(args[0], 2) + toArray(args[1], 2); 386 # 387 # ADType.SERVICE_DATA_16, <service_uuid>, [<service_data>...] 388 # 389 elif ( adType == ADType.SERVICE_DATA_16 ): 390 self.data = [ 2+len(args), adType ] + toArray(args[0],2); 391 if len(args) > 1: 392 for arg in args[1:]: 393 self.data += [ arg ]; 394 # 395 # ADType.SERVICE_DATA_32, <service_uuid>, [<service_data>...] 396 # 397 elif ( adType == ADType.SERVICE_DATA_32 ): 398 self.data = [ 4+len(args), adType ] + toArray(args[0], 4); 399 if len(args) > 1: 400 for arg in args[1:]: 401 self.data += [ arg ]; 402 # 403 # ADType.SERVICE_DATA_128, <service_uuid>, [<service_data>...] 404 # 405 elif ( adType == ADType.SERVICE_DATA_128 ): 406 self.data = [ 16+len(args), adType ] + toArray(args[0], 16); 407 if len(args) > 1: 408 for arg in args[1:]: 409 self.data += [ arg ]; 410 # 411 # ADType.PUBLIC_ADDRESS, <address_A>, <address_B>, ... 412 # ADType.RANDOM_ADDRESS, <address_A>, <address_B>, ... 413 # 414 elif ( adType == ADType.PUBLIC_ADDRESS or adType == ADType.RANDOM_ADDRESS ): 415 self.data = [ 1+6*len(args), adType ]; 416 for arg in args: 417 self.data += toArray(arg, 6); 418 # 419 # ADType.APPEARANCE, <apperance> 420 # ADType.ADVERTISE_INT, <interval> 421 # 422 elif ( adType == ADType.APPEARANCE or adType == ADType.ADVERTISE_INT ): 423 self.data = [ 3, adType ] + toArray(args[0], 2); 424 # 425 # ADType.DEVICE_ADDRESS, <address>, <public_or_random> 426 # 427 elif ( adType == ADType.DEVICE_ADDRESS ): 428 self.data = [ 8, adType ] + toArray(args[0], 6) + [ args[1] and 1 ]; 429 # 430 # ADType.LE_SUPPORTED_FEATURES, <features> 431 # 432 elif ( adType == ADType.LE_SUPPORTED_FEATURES ): 433 self.data = [ 4, adType ] + toArray(args[0], 3); 434 # 435 # ADType.CHANNEL_MAP_UPDATE, <channel_map>, <instant> 436 # 437 elif ( adType == ADType.CHANNEL_MAP_UPDATE ): 438 self.data = [ 8, adType ] + toArray(args[0], 5) + toArray(args[1], 2); 439 # 440 # ADType.MANUFACTURER_DATA, <manufacturer>, <data>... 441 # 442 elif ( adType == ADType.MANUFACTURER_DATA ): 443 self.data = [ 2+len(args), adType ] + toArray(args[0], 2); 444 if len(args) > 1: 445 for arg in args[1:]: 446 self.data += [ arg ]; 447 # 448 # ADType.URI, <unicode_uri> 449 # 450 elif ( adType == ADType.URI ): 451 nPos = args[0].find(':'); 452 if nPos > -1 and args[0][:nPos] in __schemeNames__: 453 rest = args[0][(nPos+1):].encode('UTF-8'); 454 self.data = [ 1+len(__schemeNames__[args[0][:nPos]])+len(rest), 455 adType ] + __schemeNames__[args[0][:nPos]] + [ _ for _ in rest ]; 456 else: 457 rest = args[0].encode('UTF-8'); 458 self.data = [ 2+len(rest), adType ] + [ 1 ] + [ _ for _ in rest ]; 459 460 return self.data; 461 462 def decode(self, data): 463 result = { }; 464 size = len(data); 465 466 n = 0; 467 while n < size: 468 length = data[n]; 469 length -= 1; n += 1 470 if length > 0: 471 if data[n] in ADType._value2member_map_: 472 adType = ADType(data[n]); 473 n += 1; 474 # 475 # ADType.TX_POWER_LEVEL, <power_level>; where <power_level> [ -127, +127 ] dBm. 476 # 477 if ( adType == ADType.TX_POWER_LEVEL ): 478 result[adType] = data[n] if data[n] < 128 else data[n]-256; 479 # 480 # ADType.FLAGS, <flags> where <flags> [ 0, 31 ] 481 # ADType.SEC_MANAGER_OBF, <flags> where <flags> [ 0, 15 ] 482 # ADType.DEVICE_ROLE, <role> where <role> [ 0, 3 ] 483 # 484 elif ( adType == ADType.FLAGS or adType == ADType.SEC_MANAGER_OBF or adType == ADType.DEVICE_ROLE ): 485 result[adType] = data[n]; 486 # 487 # ADType.ILIST_UUIDS_16, <uuid_A>, <uuid_B>, ... 488 # ADTYpe,CLIST_UUIDS_16, <uuid_A>, <uuid_B>, ... 489 # ADType.SS_UUIDS_16, <uuid_A>, <uuid_B>, ... 490 # 491 elif ( adType == ADType.ILIST_UUIDS_16 or adType == ADType.CLIST_UUIDS_16 or adType == ADType.SS_UUIDS_16 ): 492 result[adType] = []; 493 for i in range(n, n+length, 2): 494 result[adType] += [ toNumber( data[i:i+2] ) ]; 495 # 496 # ADType.ILIST_UUIDS_32, <uuid_A>, <uuid_B>, ... 497 # ADTYpe,CLIST_UUIDS_32, <uuid_A>, <uuid_B>, ... 498 # ADType.SS_UUIDS_32, <uuid_A>, <uuid_B>, ... 499 # 500 elif ( adType == ADType.ILIST_UUIDS_32 or adType == ADType.CLIST_UUIDS_32 or adType == ADType.SS_UUIDS_32 ): 501 result[adType] = []; 502 for i in range(n, n+length, 4): 503 result[adType] += [ toNumber( data[i:i+4] ) ]; 504 # 505 # ADType.ILIST_UUIDS_128, <uuid_A>, <uuid_B>, ... 506 # ADTYpe,CLIST_UUIDS_128, <uuid_A>, <uuid_B>, ... 507 # ADType.SS_UUIDS_128, <uuid_A>, <uuid_B>, ... 508 # 509 elif ( adType == ADType.ILIST_UUIDS_128 or adType == ADType.CLIST_UUIDS_128 or adType == ADType.SS_UUIDS_128 ): 510 result[adType] = []; 511 for i in range(n, n+length, 16): 512 result[adType] += [ toNumber( data[i:i+16] ) ]; 513 # 514 # ADType.SHORTENED_LOCAL_NAME, <unicode_name> 515 # ADType.COMPLETE_LOCAL_NAME, <unicode_name> 516 # 517 elif ( adType == ADType.SHORTENED_LOCAL_NAME or adType == ADType.COMPLETE_LOCAL_NAME ): 518 name = bytes(data[n:n+length]) 519 result[adType] = name.decode('utf-8'); 520 # 521 # ADType.DEVICE_CLASS, <device_class> 522 # 523 elif ( adType == ADType.DEVICE_CLASS ): 524 result[adType] = toNumber( data[n:n+length] ); 525 # 526 # ADType.PAIR_HASH_C, <hash_value> 527 # ADType.PAIR_RANDOM_R, <random_value> 528 # ADType.SEC_MANAGER_TK, <tk_value> 529 # 530 elif ( adType == ADType.PAIR_HASH_C or adType == ADType.PAIR_RANDOM_R or adType == ADType.SEC_MANAGER_TK ): 531 result[adType] = toNumber( data[n:n+length] ); 532 # 533 # ADType.PERIPHERAL_CONNECT_INT, <min_interval>, <max_interval> 534 # 535 elif ( adType == ADType.PERIPHERAL_CONNECT_INT ): 536 result[adType] = []; 537 for i in range(n, n+length, 2): 538 result[adType] += [ toNumber( data[i:i+2] ) ]; 539 # 540 # ADType.SERVICE_DATA_16, <service_uuid>, [<service_data>...] 541 # 542 elif ( adType == ADType.SERVICE_DATA_16 ): 543 result[adType] = { "uuid": toNumber( data[n:n+2] ), "data": data[n+2:n+length] }; 544 # 545 # ADType.SERVICE_DATA_32, <service_uuid>, [<service_data>...] 546 # 547 elif ( adType == ADType.SERVICE_DATA_32 ): 548 result[adType] = { "uuid": toNumber( data[n:n+4] ), "data": data[n+4:n+length] }; 549 # 550 # ADType.SERVICE_DATA_128, <service_uuid>, [<service_data>...] 551 # 552 elif ( adType == ADType.SERVICE_DATA_128 ): 553 result[adType] = { "uuid": toNumber( data[n:n+16] ), "data": data[n+16:n+length] }; 554 # 555 # ADType.PUBLIC_ADDRESS, <address_A>, <address_B>, ... 556 # ADType.RANDOM_ADDRESS, <address_A>, <address_B>, ... 557 # 558 elif ( adType == ADType.PUBLIC_ADDRESS or adType == ADType.RANDOM_ADDRESS ): 559 result[adType] = []; 560 for i in range(n, n+length, 6): 561 result[adType] += [ toNumber( data[i:i+6] ) ]; 562 # 563 # ADType.APPEARANCE, <apperance> 564 # ADType.ADVERTISE_INT, <interval> 565 # 566 elif ( adType == ADType.APPEARANCE or adType == ADType.ADVERTISE_INT ): 567 result[adType] = toNumber( data[n:n+2] ); 568 # 569 # ADType.DEVICE_ADDRESS, <address>, <public_or_random> 570 # 571 elif ( adType == ADType.DEVICE_ADDRESS ): 572 result[adType] = { "address": toNumber( data[n:n+6] ), "type": data[n+6] }; 573 # 574 # ADType.LE_SUPPORTED_FEATURES, <features> 575 # 576 elif ( adType == ADType.LE_SUPPORTED_FEATURES ): 577 result[adType] = data[n:n+length]; 578 # 579 # ADType.CHANNEL_MAP_UPDATE, <channel_map>, <instant> 580 # 581 elif ( adType == ADType.CHANNEL_MAP_UPDATE ): 582 result[adType] = { "map": toNumber( data[n:n+5] ), "instant": toNumber( data[n+5:n+7] ) }; 583 # 584 # ADType.MANUFACTURER_DATA, <manufacturer>, <data>... 585 # 586 elif ( adType == ADType.MANUFACTURER_DATA ): 587 result[adType] = { "manufacturer": toNumber( data[n:n+2] ), "data": data[n+2:n+length] }; 588 # 589 # ADType.URI, <unicode_uri> 590 # 591 elif ( adType == ADType.URI ): 592 name = [ chr(_) for _ in data[n:n+length] ]; 593 name = ''.join(name).decode('utf-8'); 594 codePoint = ord(name[0]); 595 name = name[1:]; 596 if codePoint > 1: 597 for scheme, code in __schemeNames__.items(): 598 if codePoint == code[-1]: 599 name = scheme + ':' + name; 600 break; 601 result[adType] = name; 602 else: 603 result[adType] = data[n:n+length]; 604 n += length; 605 else: 606 adType = data[n]; 607 n += 1; 608 result[adType] = data[n:n+length]; 609 n += length; 610 611 return result; 612 613 def asBytes(self): 614 return [int(_) for _ in self.data]; 615