blob: 1e3bb2892340d1fcf8c84d67c90d77533b66febc [file] [log] [blame]
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
}