// DiscoverDescriptors finds all the descriptors within a characteristic. [Vol 3, Part G, 4.7.1] // If filter is specified, only filtered descriptors are returned. func (p *Client) DiscoverDescriptors(filter []ble.UUID, c *ble.Characteristic) ([]*ble.Descriptor, error) { p.Lock() defer p.Unlock() start := c.ValueHandle + 1 for start <= c.EndHandle { fmt, b, err := p.ac.FindInformation(start, c.EndHandle) if err == ble.ErrAttrNotFound { break } else if err != nil { return nil, err } length := 2 + 2 if fmt == 0x02 { length = 2 + 16 } for len(b) != 0 { h := binary.LittleEndian.Uint16(b[:2]) u := ble.UUID(b[2:length]) d := &ble.Descriptor{UUID: u, Handle: h} if filter == nil || ble.Contains(filter, u) { c.Descriptors = append(c.Descriptors, d) } if u.Equal(ble.ClientCharacteristicConfigUUID) { c.CCCD = d } start = h + 1 b = b[length:] } } return c.Descriptors, nil }
// DiscoverServices finds all the primary services on a server. [Vol 3, Part G, 4.4.1] // If filter is specified, only filtered services are returned. func (p *Client) DiscoverServices(filter []ble.UUID) ([]*ble.Service, error) { p.Lock() defer p.Unlock() if p.profile == nil { p.profile = &ble.Profile{} } start := uint16(0x0001) for { length, b, err := p.ac.ReadByGroupType(start, 0xFFFF, ble.PrimaryServiceUUID) if err == ble.ErrAttrNotFound { return p.profile.Services, nil } if err != nil { return nil, err } for len(b) != 0 { h := binary.LittleEndian.Uint16(b[:2]) endh := binary.LittleEndian.Uint16(b[2:4]) u := ble.UUID(b[4:length]) if filter == nil || ble.Contains(filter, u) { s := &ble.Service{ UUID: u, Handle: h, EndHandle: endh, } p.profile.Services = append(p.profile.Services, s) } if endh == 0xFFFF { return p.profile.Services, nil } start = endh + 1 b = b[length:] } } }
// DiscoverCharacteristics finds all the characteristics within a service. [Vol 3, Part G, 4.6.1] // If filter is specified, only filtered characteristics are returned. func (p *Client) DiscoverCharacteristics(filter []ble.UUID, s *ble.Service) ([]*ble.Characteristic, error) { p.Lock() defer p.Unlock() start := s.Handle var lastChar *ble.Characteristic for start <= s.EndHandle { length, b, err := p.ac.ReadByType(start, s.EndHandle, ble.CharacteristicUUID) if err == ble.ErrAttrNotFound { break } else if err != nil { return nil, err } for len(b) != 0 { h := binary.LittleEndian.Uint16(b[:2]) p := ble.Property(b[2]) vh := binary.LittleEndian.Uint16(b[3:5]) u := ble.UUID(b[5:length]) c := &ble.Characteristic{ UUID: u, Property: p, Handle: h, ValueHandle: vh, EndHandle: s.EndHandle, } if filter == nil || ble.Contains(filter, u) { s.Characteristics = append(s.Characteristics, c) } if lastChar != nil { lastChar.EndHandle = c.Handle - 1 } lastChar = c start = vh + 1 b = b[length:] } } return s.Characteristics, nil }