bluetooth/gap_linux.go

81 lines
2 KiB
Go
Raw Normal View History

// +build !baremetal
package bluetooth
import (
"errors"
"github.com/muka/go-bluetooth/api"
"github.com/muka/go-bluetooth/bluez/profile/advertising"
)
var (
ErrMalformedAdvertisement = errors.New("bluetooth: malformed advertisement packet")
)
// Advertisement encapsulates a single advertisement instance.
type Advertisement struct {
adapter *Adapter
advertisement *api.Advertisement
properties *advertising.LEAdvertisement1Properties
}
// NewAdvertisement creates a new advertisement instance but does not configure
// it.
func (a *Adapter) NewAdvertisement() *Advertisement {
return &Advertisement{
adapter: a,
}
}
// Configure this advertisement.
func (a *Advertisement) Configure(broadcastData, scanResponseData []byte, options *AdvertiseOptions) error {
if a.advertisement != nil {
panic("todo: configure advertisement a second time")
}
if scanResponseData != nil {
panic("todo: scan response data")
}
// Quick-and-dirty advertisement packet parser.
a.properties = &advertising.LEAdvertisement1Properties{
Type: advertising.AdvertisementTypeBroadcast,
Timeout: 1<<16 - 1,
}
for len(broadcastData) != 0 {
if len(broadcastData) < 2 {
return ErrMalformedAdvertisement
}
fieldLength := broadcastData[0]
fieldType := broadcastData[1]
fieldValue := broadcastData[2 : fieldLength+1]
if int(fieldLength) > len(broadcastData) {
return ErrMalformedAdvertisement
}
switch fieldType {
case 1:
// BLE advertisement flags. Ignore.
case 9:
// Complete Local Name.
a.properties.LocalName = string(fieldValue)
default:
return ErrMalformedAdvertisement
}
broadcastData = broadcastData[fieldLength+1:]
}
return nil
}
// Start advertisement. May only be called after it has been configured.
func (a *Advertisement) Start() error {
if a.advertisement != nil {
panic("todo: start advertisement a second time")
}
_, err := api.ExposeAdvertisement(a.adapter.id, a.properties, uint32(a.properties.Timeout))
if err != nil {
return err
}
return nil
}