def create_generic_attribute_service(self): gsrv = GattService() gsrv.uuid = BluetoothUuid(GattConst.UUID_GENERIC_ATTRIBUTE) gsrv.idstr = "generic_attribute" gsrv.capabilities = self.capabilities #service->caps = db->caps_declare; gsrv.chars.append( GattCharacteristic(uuid="2a05", id="service_changed_char", properties=GattConst.CHR_PROPERTY_INDICATE, value=GattValue(GattConst.DynamicValue, bytearray(4)), permissions=GattConst.Discoverable, capabilities=self.capabilities)) gsrv.chars.append( GattCharacteristic(uuid="2b2a", id="database_hash", properties=GattConst.CHR_PROPERTY_READ, value=GattValue(GattConst.DynamicValue, bytearray(16)), capabilities=self.capabilities)) gsrv.chars.append( GattCharacteristic(uuid="2b29", id="client_support_features", properties=GattConst.CHR_PROPERTY_READ | GattConst.CHR_PROPERTY_WRITE, value=GattValue(GattConst.DynamicValue, bytearray(1)), permissions=GattConst.Discoverable | GattConst.Read | GattConst.Write, capabilities=self.capabilities)) return gsrv
def uuid_handle(self, uuid): if (not isinstance(uuid, BluetoothUuid)): uuid = BluetoothUuid(uuid) try: if (uuid.isshort): return self.uuid16s.index(uuid) return self.uuid128s.index(uuid) | 0x8000 except ValueError: print("Error, UUID not found:", str(uuid)) return 0
def __build_service(self, service): rows = [] service.start = len(self.attribute_rows) + 1 permissions = GattConst.Read | GattConst.Discoverable # service declaration attribute: if service.secondary is True: uuid = BluetoothUuid(GattConst.UUID_SECONDARY_SERVICE) else: uuid = BluetoothUuid(GattConst.UUID_PRIMARY_SERVICE) if service.advertise is True: permissions |= GattConst.Advertise value = GattValue(GattConst.ConstValue, service.uuid.bytes) service_declare = GattAttribute(uuid=uuid, permissions=permissions, value=value, capabilities=service.capabilities) rows.append(service_declare) #service includes for inc in service.include_service_ids: a = GattAttribute(uuid=GattConst.UUID_INCLUDE_SERVICE, permissions=GattConst.Read | GattConst.Discoverable, capabilities=service.capabilities) a.include = inc rows.append(a) self.__add_uuid(a.uuid) #characteristic if service.chars is not None: for ch in service.chars: rows += (self.__build_characteristic_db( ch, len(self.attribute_rows) + len(rows) + 1)) service.end = service.start + len(rows) - 1 return rows
def set_services(self, services, add_generic_attribute_service=True): self.uuid16s = [ BluetoothUuid(GattConst.UUID_PRIMARY_SERVICE), BluetoothUuid(GattConst.UUID_SECONDARY_SERVICE), BluetoothUuid(GattConst.UUID_CHR) ] self.uuid128s = [] self.services = services #first add all uuids, this is to replicate bgbuild behaviour for s in self.services: self.__add_uuids_in_service(s) #create generic service if (add_generic_attribute_service): s = self.create_generic_attribute_service() self.__add_uuids_in_service(s) self.services = [s] + self.services #Create all attributes self.__build_atrribute_rows() #link includes #for s in self.services: # self.__resolve_service_relations(s, services) for a in self.attribute_rows: #find include attributes if a.uuid == BluetoothUuid(GattConst.UUID_INCLUDE_SERVICE): included = next((s for s in services if s.idstr == a.include), None) gatt_assert( included != None, "Included service " + a.include + " does not exist!") #gatt_assert(included != service, "Included service " + id + " cannot be self!") a.include = included a.value = GattValue(GattConst.ServiceInclude, bytearray())
def __add_uuid(self, uuid): if type(uuid) is not BluetoothUuid: uuid = BluetoothUuid(uuid) if self.__uuid_index(uuid) == -1: if uuid.isshort: try: self.uuid16s.index(uuid) except ValueError: self.uuid16s.append(uuid) else: try: self.uuid128s.index(uuid) except ValueError: self.uuid128s.append(uuid) return 1
def parse_service(self, xml,parent_caps): s = GattService() s.uuid = BluetoothUuid(xml.get('uuid', "00")) s.idstr = xml.get('id', "") s.secondary = xml.get('type', "primary") == "secondary" s.advertise = s.secondary is False and xml.get('advertise', "false") == "true" s.capabilities=self.parse_capabilities(xml,parent_caps) # description of service is informative and not exposed in the actual GATT database if xml.find('description') is not None: s.description = xml.find('description').text includes = xml.iterfind('include') for i in includes: s.include_service_ids.append(i.get('id', "")) cnodes = xml.iterfind('characteristic') for c in cnodes: s.chars.append(self.parse_characteristic(c,s.capabilities)) return s
def __parse_attrobj(self, xml, attr): if attr.uuid == "0000": attr.uuid = BluetoothUuid(xml.get('uuid', "00")) attr.idstr = xml.get('id', "") const_value = True properties = GattConst.CHR_PROPERTY_READ permissions = GattConst.Read | GattConst.Discoverable ext_properties = 0 if xml.find('properties') is not None: properties, permissions, const_value, ext_properties = self.parse_properties(xml.find('properties')) if xml.get("const","false") == "true": const_value = True attr.properties = properties attr.permissions = permissions attr.ext_properties = ext_properties if xml.find('value') is not None: attr.value = self.parse_value( xml.find('value')) #if there is no value element, then use contents of the parent tag, backwards compability elif xml.text is not None: attr.value = self.parse_value(xml) if attr.value!=None and const_value is True: attr.value.type = GattConst.ConstValue return attr