1#!/usr/bin/env python3 2 3import struct 4 5BLUETOOTH_BASE_UUID = bytes ([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB ]); 6 7def hex_string(bytes): 8 return " ".join([('%02x' % a) for a in bytes]) 9 10def unpack24(data): 11 (upper, ) = struct.unpack("<H", data[1:]) 12 return data[0] | (upper << 8) 13 14class BD_ADDR(object): 15 # addr stored in big endian 16 def __init__(self, addr): 17 if isinstance(addr, str): 18 parts = addr.split(':') 19 if len(parts) != 6: 20 return 21 # list comprehension 22 self.addr = bytes([int(a,16) for a in parts]) 23 elif isinstance(addr, bytes): 24 self.addr = addr 25 elif isinstance(addr, bytearray): 26 self.addr = addr 27 else: 28 print('cannot use for bdaddr, len %u' % len(addr)) 29 print(addr) 30 31 def get_bytes(self): 32 data = bytearray(self.addr) 33 data.reverse() 34 return data 35 36 def __repr__(self): 37 return ":".join([('%02x' % a) for a in self.addr]) 38 39class BT_UUID(object): 40 # uuid stored in big endian 41 42 def __init__(self, uuid): 43 global BLUETOOTH_BASE_UUID 44 if isinstance(uuid,bytes): 45 self.uuid = uuid 46 if isinstance(uuid,int): 47 self.uuid = struct.pack(">I", uuid) + BLUETOOTH_BASE_UUID[4:] 48 if isinstance(uuid,str): 49 parts = uuid.split('-') 50 if len(parts) != 5: 51 return 52 # list comprehension 53 self.uuid = bytes([int(a,16) for a in uuid.replace('-','')]) 54 55 def get_uuid32(self): 56 global BLUETOOTH_BASE_UUID 57 result = 0 58 if self.uuid[4:] == BLUETOOTH_BASE_UUID[4:]: 59 (result,) = struct.unpack(">I", self.uuid[:4]) 60 return result 61 62 def get_bytes(self): 63 data = bytearray(self.uuid) 64 data.reverse() 65 return data 66 67 def __repr__(self): 68 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( 69 self.uuid[0], self.uuid[1], self.uuid[2], self.uuid[3], self.uuid[4], self.uuid[5], self.uuid[6], self.uuid[7], 70 self.uuid[8], self.uuid[9], self.uuid[10], self.uuid[11], self.uuid[12], self.uuid[13], self.uuid[14], self.uuid[15]); 71 72 73class GATTCharacteristic(object): 74 75 # uint16_t start_handle; 76 # uint16_t value_handle; 77 # uint16_t end_handle; 78 # uint16_t properties; 79 # uint8_t uuid128[16]; 80 81 def __init__(self, data): 82 self.data = data 83 84 def get_bytes(self): 85 return self.data 86 87 def get_start_handle(self): 88 (result, ) = struct.unpack('<H', self.data[0:2]) 89 return result 90 91 def get_value_handle(self): 92 (result, ) = struct.unpack('<H', self.data[2:4]) 93 return result 94 95 def get_ned_handle(self): 96 (result, ) = struct.unpack('<H', self.data[4:6]) 97 return result 98 99 def get_properties(self): 100 (result, ) = struct.unpack('<H', self.data[6:8]) 101 return result 102 103 def get_uuid(self): 104 return BT_UUID(self.data[8:]) 105 106 def __repr__(self): 107 return "GATTCharacteristic [start_handle={start_handle}, value_handle={value_handle}, end_handle={end_handle}, get_uuid={uuid}]".format( 108 start_handle=self.get_start_handle(), value_handle=self.get_value_handle(), end_handle=self.get_end_handle(), uuid=self.get_uuid()) 109 110 111 112class GATTCharacteristicDescriptor(object): 113 114 # uint16_t handle; 115 # uint8_t uuid128[16]; 116 117 def __init__(self, data): 118 self.data = data 119 120 def get_bytes(self): 121 return self.data 122 123 def get_handle(self): 124 (result, ) = struct.unpack('<H', self.data[0:2]) 125 return result 126 127 def get_uuid(self): 128 return BT_UUID(self.data[2:]) 129 130 def __repr__(self): 131 return "GATTCharacteristicDescriptor [handle={handle}, get_uuid={uuid}]".format( 132 handle=self.get_handle(), uuid=self.get_uuid()) 133 134 135class GATTService(object): 136 137 # uint16_t start_group_handle; 138 # uint16_t end_group_handle; 139 # uint8_t uuid128[16]; 140 141 def __init__(self, data): 142 self.data = data 143 144 def get_bytes(self): 145 return self.data 146 147 def get_start_group_handle(self): 148 (result, ) = struct.unpack('<H', self.data[0:2]) 149 return result 150 151 def get_end_group_handle(self): 152 (result, ) = struct.unpack('<H', self.data[2:4]) 153 return result 154 155 def get_uuid(self): 156 return BT_UUID(self.data[4:]) 157 158 def __repr__(self): 159 return "GattService [start_group_handle={start_group_handle}, [end_group_handle={end_group_handle}, get_uuid={uuid}]".format( 160 start_group_handle=self.get_start_group_handle(), end_group_handle=self.get_end_group_handle(), uuid=self.get_uuid()) 161 162 163class Packet(object): 164 165 HCI_COMMAND_PACKET = 1; 166 HCI_EVENT_PACKET = 4; 167 L2CAP_DATA_PACKET = 6; 168 RFCOMM_DATA_PACKET = 7; 169 170 def __init__(self, packet_type, channel, payload): 171 self.packet_type = packet_type 172 self.channel = channel 173 self.payload = payload 174 175 def get_packet_type(self): 176 return self.packet_type 177 178 def get_channel(self): 179 return self.channel 180 181 def get_payload(self): 182 return self.payload 183 184 def __repr__(self): 185 return "Packet type {packet_type}, channel {channel}, payload {payload}".format(packet_type={self.get_packet_type()}, 186 channel={self.get_channel()}, payload=hex_string(self.get_payload())) 187 188 189class Event(Packet): 190 191 def __init__(self, payload): 192 self.packet_type = Packet.HCI_COMMAND_PACKET 193 self.channel = 0 194 self.payload = payload 195 196 def get_event_type(self): 197 return self.payload[0] 198 199 def __repr__(self): 200 return "Event type {event_type}, payload {payload}".format(event_type={self.get_event_type()}, 201 payload=hex_string(self.get_payload())) 202 203 204class BTstackEventState(Packet): 205 206 def __init__(self, payload): 207 self.packet_type = Packet.HCI_COMMAND_PACKET 208 self.channel = 0 209 self.payload = payload 210 211 def get_state(self): 212 return self.payload[2] 213 214