81 lines
2 KiB
Go
81 lines
2 KiB
Go
|
// +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
|
||
|
}
|