1# -*- coding: utf-8 -*- 2# Copyright 2019 Oticon A/S 3# SPDX-License-Identifier: Apache-2.0 4 5import string; 6import re; 7from xml.dom import minidom; 8 9class GATTData: 10 __instance = None; 11 12 @staticmethod 13 def instance(): 14 if GATTData.__instance == None: 15 GATTData(); 16 return GATTData.__instance; 17 18 def __init__(self): 19 if GATTData.__instance != None: 20 raise Exception("GATTData is a Singleton!"); 21 else: 22 GATTData.__instance = self; 23 self.mydoc = minidom.parse('src/components/GATT Database.xml'); 24 25 def __handleRange(self, service): 26 characteristics = service.getElementsByTagName('Characteristic'); 27 descriptors = service.getElementsByTagName('Descriptor'); 28 includes = service.getElementsByTagName('Include'); 29 30 first = int(service.attributes['handle'].value); 31 last = []; 32 if len(includes) > 0: 33 last += [ max([int(include.attributes['handle'].value) for include in includes]) ]; 34 if len(descriptors) > 0: 35 last += [ max([int(descriptor.attributes['handle'].value) for descriptor in descriptors]) ]; 36 if len(characteristics) > 0: 37 last += [ max([int(characteristic.attributes['handle'].value) for characteristic in characteristics]) ]; 38 last[-1] += 1; 39 return first, max(last) if len(last) > 0 else first; 40 41 def __allInSet(self, setNo, elementType): 42 sets = self.mydoc.getElementsByTagName('ServiceSet_%d' % setNo); 43 return sets[0].getElementsByTagName(elementType); 44 45 def __shortServices(self, setNo, serviceType=None, uuid=None): 46 services = { 'uuid': [], 'handle': [] }; 47 48 alls = self.__allInSet(setNo, 'Service'); 49 for service in alls: 50 if (serviceType is None) or (serviceType == service.attributes['type'].value): 51 _uuid = int(service.attributes['uuid'].value, 16); 52 if (uuid is None) or (uuid == _uuid): 53 services['uuid'] += [ _uuid ]; 54 first, last = self.__handleRange( service ); 55 services['handle'] += [ first ]; 56 return services; 57 58 def __services(self, setNo, serviceType=None, uuid=None): 59 services = { 'uuids': [], 'handles': [] }; 60 61 alls = self.__allInSet(setNo, 'Service'); 62 for service in alls: 63 if (serviceType is None) or (serviceType == service.attributes['type'].value): 64 _uuid = int(service.attributes['uuid'].value, 16); 65 if (uuid is None) or (uuid == _uuid): 66 services['uuids'] += [ _uuid ]; 67 first, last = self.__handleRange( service ); 68 services['handles'] += [ [first, last] ]; 69 return services; 70 71 def allServices(self, setNo): 72 return self.__services(setNo); 73 74 def primaryServices(self, setNo, uuid=None): 75 return self.__services(setNo, 'Primary Service', uuid); 76 77 def secondaryServices(self, setNo, uuid=None): 78 return self.__shortServices(setNo, 'Secondary Service', uuid); 79 80 def includedServices(self, setNo): 81 includes = { 'uuids': [], 'handles': [] }; 82 83 alls = self.__allInSet(setNo, 'Include'); 84 for include in alls: 85 includes['uuids'] += [ int(include.attributes['uuid'].value, 16) ]; 86 includes['handles'] += [ [ int(include.attributes['first'].value), int(include.attributes['last'].value) ] ]; 87 return includes; 88 89 def descriptors(self, setNo, serviceHandle=None, permissionsMask=None, invertMask=False): 90 descriptors = { 'uuid': [], 'handle': [] }; 91 92 alls = self.__allInSet(setNo, 'Service'); 93 for service in alls: 94 _serviceHandle = int(service.attributes['handle'].value); 95 if (serviceHandle is None) or (serviceHandle == _serviceHandle): 96 for descriptor in service.getElementsByTagName('Descriptor'): 97 _permissions = int(descriptor.attributes['permissions'].value); 98 if (permissionsMask is None) or ((_permissions & permissionsMask) == (0 if invertMask else permissionsMask)): 99 descriptors['uuid'] += [ int(descriptor.attributes['uuid'].value, 16) ]; 100 descriptors['handle'] += [ int(descriptor.attributes['handle'].value) ]; 101 if not serviceHandle is None: 102 break; 103 return descriptors; 104 105 def serviceCovering(self, setNo, handle): 106 service = {}; 107 108 services = self.__services(setNo); 109 for _uuid, _handles in zip(services['uuids'], services['handles']): 110 if _handles[0] <= handle and handle <= _handles[1]: 111 service['uuid'] = _uuid; 112 service['handles'] = _handles; 113 break; 114 return service; 115 116 def characteristics(self, setNo, serviceHandle=None, permissionsMask=None, invertMask=False): 117 characteristics = { 'uuid': [], 'handle': [], 'value_handle': [], 'property': [], 'permission': [] }; 118 119 alls = self.__allInSet(setNo, 'Service'); 120 for service in alls: 121 _serviceHandle = int(service.attributes['handle'].value); 122 if (serviceHandle is None) or (serviceHandle == _serviceHandle): 123 for characteristic in service.getElementsByTagName('Characteristic'): 124 _permissions = int(characteristic.attributes['permissions'].value); 125 if (permissionsMask is None) or ((_permissions & permissionsMask) == (0 if invertMask else permissionsMask)): 126 characteristics['uuid'] += [ int(characteristic.attributes['uuid'].value, 16) ]; 127 characteristics['handle'] += [ int(characteristic.attributes['handle'].value) ]; 128 characteristics['value_handle'] += [ int(characteristic.attributes['handle'].value)+1 ]; 129 characteristics['property'] += [ int(characteristic.attributes['properties'].value) ]; 130 characteristics['permission'] += [ int(characteristic.attributes['permissions'].value) ]; 131 if not serviceHandle is None: 132 break; 133 return characteristics; 134 135 def __toArray(self, value): 136 data = []; 137 if value: 138 if re.match('[0-9A-F]{2}( [0-9A-F]{2})+', value): 139 data = [ int(hexNumber, 16) for hexNumber in value.split(' ') ]; 140 elif len(value) > 2: 141 data = [ ord(char) for char in value ]; 142 else: 143 data = [ int(value, 16) ]; 144 return data; 145 146 def characteristicValue(self, setNo, handle): 147 value = None; 148 alls = self.__allInSet(setNo, 'Characteristic'); 149 for characteristic in alls: 150 if int(characteristic.attributes['handle'].value) == handle: 151 value = characteristic.firstChild.data.strip('\r\n\t'); 152 break; 153 return self.__toArray(value); 154 155 def characteristicString(self, setNo, handle): 156 value = None; 157 alls = self.__allInSet(setNo, 'Characteristic'); 158 for characteristic in alls: 159 if int(characteristic.attributes['handle'].value) == handle: 160 value = characteristic.firstChild.data.strip('\r\n\t'); 161 break; 162 return value; 163 164 def descriptorValue(self, setNo, handle): 165 value = None; 166 alls = self.__allInSet(setNo, 'Descriptor'); 167 for descriptor in alls: 168 if int(descriptor.attributes['handle'].value) == handle: 169 value = descriptor.firstChild.data.strip('\r\n\t'); 170 break; 171 return self.__toArray(value); 172 173 def descriptorString(self, setNo, handle): 174 value = None; 175 alls = self.__allInSet(setNo, 'Descriptor'); 176 for descriptor in alls: 177 if int(descriptor.attributes['handle'].value) == handle: 178 value = descriptor.firstChild.data.strip('\r\n\t'); 179 break; 180 return value; 181 182 def characteristicWithDescriptor(self, setNo, handle): 183 j, _characteristics = -1, self.characteristics(setNo); 184 for i, _handle in enumerate(_characteristics['handle']): 185 if _handle > handle: 186 j = i-1; 187 break; 188 return { 'uuid': _characteristics['uuid'][j], 189 'handle': _characteristics['handle'][j], 190 'value_handle': _characteristics['value_handle'][j], 191 'property': _characteristics['property'][j], 192 'permission': _characteristics['permission'][j] }; 193