package ble // NewService creates and initialize a new Service using u as it's UUID. func NewService(u UUID) *Service { return &Service{UUID: u} } // NewDescriptor creates and returns a Descriptor. func NewDescriptor(u UUID) *Descriptor { return &Descriptor{UUID: u} } // NewCharacteristic creates and returns a Characteristic. func NewCharacteristic(u UUID) *Characteristic { return &Characteristic{UUID: u} } // Property ... type Property int // Characteristic property flags (spec 3.3.3.1) const ( CharBroadcast Property = 0x01 // may be brocasted CharRead Property = 0x02 // may be read CharWriteNR Property = 0x04 // may be written to, with no reply CharWrite Property = 0x08 // may be written to, with a reply CharNotify Property = 0x10 // supports notifications CharIndicate Property = 0x20 // supports Indications CharSignedWrite Property = 0x40 // supports signed write CharExtended Property = 0x80 // supports extended properties ) // A Profile is composed of one or more services necessary to fulfill a use case. type Profile struct { Services []*Service } // Find searches discovered profile for the specified target's type and UUID. // The target must has the type of *Service, *Characteristic, or *Descriptor. func (p *Profile) Find(target interface{}) interface{} { switch t := target.(type) { case *Service: return p.FindService(t) case *Characteristic: return p.FindCharacteristic(t) case *Descriptor: return p.FindDescriptor(t) default: return nil } } // FindService searches discoverd profile for the specified service and UUID func (p *Profile) FindService(service *Service) *Service { for _, s := range p.Services { if s.UUID.Equal(service.UUID) { return s } } return nil } // FindCharacteristic searches discoverd profile for the specified characteristic and UUID func (p *Profile) FindCharacteristic(char *Characteristic) *Characteristic { for _, s := range p.Services { for _, c := range s.Characteristics { if c.UUID.Equal(char.UUID) { return c } } } return nil } // FindDescriptor searches discoverd profile for the specified descriptor and UUID func (p *Profile) FindDescriptor(desc *Descriptor) *Descriptor { for _, s := range p.Services { for _, c := range s.Characteristics { for _, d := range c.Descriptors { if d.UUID.Equal(desc.UUID) { return d } } } } return nil } // A Service is a BLE service. type Service struct { UUID UUID Characteristics []*Characteristic Handle uint16 EndHandle uint16 } // AddCharacteristic adds a characteristic to a service. // AddCharacteristic panics if the service already contains another characteristic with the same UUID. func (s *Service) AddCharacteristic(c *Characteristic) *Characteristic { for _, x := range s.Characteristics { if x.UUID.Equal(c.UUID) { panic("service already contains a characteristic with UUID " + c.UUID.String()) } } s.Characteristics = append(s.Characteristics, c) return c } // NewCharacteristic adds a characteristic to a service. // NewCharacteristic panics if the service already contains another characteristic with the same UUID. func (s *Service) NewCharacteristic(u UUID) *Characteristic { return s.AddCharacteristic(&Characteristic{UUID: u}) } // A Characteristic is a BLE characteristic. type Characteristic struct { UUID UUID Property Property Secure Property // FIXME Descriptors []*Descriptor CCCD *Descriptor Value []byte ReadHandler ReadHandler WriteHandler WriteHandler NotifyHandler NotifyHandler IndicateHandler NotifyHandler Handle uint16 ValueHandle uint16 EndHandle uint16 } // AddDescriptor adds a descriptor to a characteristic. // AddDescriptor panics if the characteristic already contains another descriptor with the same UUID. func (c *Characteristic) AddDescriptor(d *Descriptor) *Descriptor { for _, x := range c.Descriptors { if x.UUID.Equal(d.UUID) { panic("service already contains a characteristic with UUID " + d.UUID.String()) } } c.Descriptors = append(c.Descriptors, d) return d } // NewDescriptor adds a descriptor to a characteristic. // NewDescriptor panics if the characteristic already contains another descriptor with the same UUID. func (c *Characteristic) NewDescriptor(u UUID) *Descriptor { return c.AddDescriptor(&Descriptor{UUID: u}) } // SetValue makes the characteristic support read requests, and returns a static value. // SetValue must be called before the containing service is added to a server. // SetValue panics if the characteristic has been configured with a ReadHandler. func (c *Characteristic) SetValue(b []byte) { if c.ReadHandler != nil { panic("charactristic has been configured with a read handler") } c.Property |= CharRead c.Value = make([]byte, len(b)) copy(c.Value, b) } // HandleRead makes the characteristic support read requests, and routes read requests to h. // HandleRead must be called before the containing service is added to a server. // HandleRead panics if the characteristic has been configured with a static value. func (c *Characteristic) HandleRead(h ReadHandler) { if c.Value != nil { panic("charactristic has been configured with a static value") } c.Property |= CharRead c.ReadHandler = h } // HandleWrite makes the characteristic support write and write-no-response requests, and routes write requests to h. // The WriteHandler does not differentiate between write and write-no-response requests; it is handled automatically. // HandleWrite must be called before the containing service is added to a server. func (c *Characteristic) HandleWrite(h WriteHandler) { c.Property |= CharWrite | CharWriteNR c.WriteHandler = h } // HandleNotify makes the characteristic support notify requests, and routes notification requests to h. // HandleNotify must be called before the containing service is added to a server. func (c *Characteristic) HandleNotify(h NotifyHandler) { c.Property |= CharNotify c.NotifyHandler = h } // HandleIndicate makes the characteristic support indicate requests, and routes notification requests to h. // HandleIndicate must be called before the containing service is added to a server. func (c *Characteristic) HandleIndicate(h NotifyHandler) { c.Property |= CharIndicate c.IndicateHandler = h } // Descriptor is a BLE descriptor type Descriptor struct { UUID UUID Property Property Handle uint16 Value []byte ReadHandler ReadHandler WriteHandler WriteHandler } // SetValue makes the descriptor support read requests, and returns a static value. // SetValue must be called before the containing service is added to a server. // SetValue panics if the descriptor has already configured with a ReadHandler. func (d *Descriptor) SetValue(b []byte) { if d.ReadHandler != nil { panic("descriptor has been configured with a read handler") } d.Property |= CharRead d.Value = make([]byte, len(b)) copy(d.Value, b) } // HandleRead makes the descriptor support read requests, and routes read requests to h. // HandleRead must be called before the containing service is added to a server. // HandleRead panics if the descriptor has been configured with a static value. func (d *Descriptor) HandleRead(h ReadHandler) { if d.Value != nil { panic("descriptor has been configured with a static value") } d.Property |= CharRead d.ReadHandler = h } // HandleWrite makes the descriptor support write and write-no-response requests, and routes write requests to h. // The WriteHandler does not differentiate between write and write-no-response requests; it is handled automatically. // HandleWrite must be called before the containing service is added to a server. func (d *Descriptor) HandleWrite(h WriteHandler) { d.Property |= CharWrite | CharWriteNR d.WriteHandler = h }