![Ayke van Laethem](/assets/img/avatar_default.png)
Very much experimental, no BLE service support yet and BLE LocalName in advertisement packet doesn't seem to work. So rather useless at the moment.
81 lines
2.0 KiB
Go
81 lines
2.0 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
|
|
}
|