241 lines
7.7 KiB
Go
241 lines
7.7 KiB
Go
|
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
|
||
|
}
|