Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended advertising scan #113

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.*.swp
.tags
.tags1

/examples/bin/*
vendor
.idea
.idea
.uuid
*DS_Store
7 changes: 6 additions & 1 deletion device.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ble

import "context"
import (
"context"
)

// Device ...
type Device interface {
Expand Down Expand Up @@ -40,6 +42,9 @@ type Device interface {
// Scan starts scanning. Duplicated advertisements will be filtered out if allowDup is set to false.
Scan(ctx context.Context, allowDup bool, h AdvHandler) error

// ExtendedScan starts scanning. Duplicated advertisements will be filtered out if allowDup is set to false.
ExtendedScan(ctx context.Context, allowDup bool, h ExtendedAdvHandler) error

// Dial ...
Dial(ctx context.Context, a Addr) (Client, error)
}
66 changes: 66 additions & 0 deletions examples/basic/extended_scanner/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"context"
"flag"
"fmt"
"github.com/go-ble/ble/examples/lib/dev"
"log"
"time"

"github.com/go-ble/ble"
"github.com/pkg/errors"
)

var (
device = flag.String("device", "default", "implementation of ble")
du = flag.Duration("du", 5*time.Second, "scanning duration")
dup = flag.Bool("dup", true, "allow duplicate reported")
)

func main() {
flag.Parse()

d, err := dev.AdvertisingExtensionsDevice()
if err != nil {
log.Fatalf("can't new device : %s", err)
}
ble.SetDefaultDevice(d)
// ExtendedScan for specified durantion, or until interrupted by user.
fmt.Printf("ExtendedScaning for %s...\n", *du)
ctx := ble.WithSigHandler(context.WithTimeout(context.Background(), *du))
chkErr(ble.ExtendedScan(ctx, *dup, advHandler, nil))
}

func advHandler(a ble.ExtendedAdvertisement) {
if a.Connectable() {
fmt.Printf("[%s] C %3d:", a.Addr(), a.RSSI())
} else {
fmt.Printf("[%s] N %3d:", a.Addr(), a.RSSI())
}
comma := ""
if len(a.LocalName()) > 0 {
fmt.Printf(" Name: %s", a.LocalName())
comma = ","
}
if len(a.Services()) > 0 {
fmt.Printf("%s Svcs: %v", comma, a.Services())
comma = ","
}
if len(a.ManufacturerData()) > 0 {
fmt.Printf("%s MD: %X", comma, a.ManufacturerData())
}
fmt.Printf("\n")
}

func chkErr(err error) {
switch errors.Cause(err) {
case nil:
case context.DeadlineExceeded:
fmt.Printf("done\n")
case context.Canceled:
fmt.Printf("canceled\n")
default:
log.Fatalf(err.Error())
}
}
14 changes: 14 additions & 0 deletions examples/blesh/lnx.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ func updateLinuxParam(d *linux.Device) error {
return errors.Wrap(err, "can't set scan param")
}

if err := d.HCI.Send(&cmd.LESetExtendedScanParameters{
OwnAddressType: 0x00, // 0x00: public, 0x01: random
ScanningFilterPolicy: 0x00, // 0x00: accept all, 0x01: ignore non-white-listed
ScanningPHYs: 0x01, // 0x01: Scan on the LE 1M PHY, 0x04: Scan on the LE Coded PHY
ScanType1M: 0x01, // 0x00: passive scan, 0x01: active scan
ScanInterval1M: 0x0004, // 0x0004 - 0x4000; N * 0.625 msec (2.5 ms)
ScanWindow1M: 0x0004, // 0x0004 - 0x4000; N * 0.625 msec (2.5 ms)
ScanTypeCoded: 0x01, // 0x00: passive scan, 0x01: active scan (for Coded PHY)
ScanIntervalCoded: 0x0004, // N * 0.625 msec, scan interval for Coded PHY
ScanWindowCoded: 0x0004, // N * 0.625 msec, scan window for Coded PHY
}, nil); err != nil {
return errors.Wrap(err, "can't set scan param")
}

if err := d.HCI.Option(ble.OptConnParams(
cmd.LECreateConnection{
LEScanInterval: 0x0004, // 0x0004 - 0x4000; N * 0.625 msec
Expand Down
5 changes: 5 additions & 0 deletions examples/lib/dev/default_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ import (
func DefaultDevice(opts ...ble.Option) (d ble.Device, err error) {
return linux.NewDevice(opts...)
}

// AdvertisingExtensionsDevice ...
func AdvertisingExtensionsDevice(opts ...ble.Option) (d ble.Device, err error) {
return linux.NewAdvertisingExtensionsDevice(opts...)
}
5 changes: 5 additions & 0 deletions examples/lib/dev/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ import (
func NewDevice(impl string, opts ...ble.Option) (d ble.Device, err error) {
return DefaultDevice(opts...)
}

// NewAdvertisingExtensionsDevice ...
func NewAdvertisingExtensionsDevice(impl string, opts ...ble.Option) (d ble.Device, err error) {
return AdvertisingExtensionsDevice(opts...)
}
22 changes: 22 additions & 0 deletions extended_adv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ble

// ExtendedAdvHandler handles extended advertisements.
type ExtendedAdvHandler func(a ExtendedAdvertisement)

// ExtendedAdvFilter returns true if the extended advertisement matches specified condition.
type ExtendedAdvFilter func(a ExtendedAdvertisement) bool

// ExtendedAdvertisement ...
type ExtendedAdvertisement interface {
LocalName() string
ManufacturerData() []byte
ServiceData() []ServiceData
Services() []UUID
OverflowService() []UUID
TxPowerLevel() int
Connectable() bool
SolicitedService() []UUID

RSSI() int
Addr() Addr
}
20 changes: 20 additions & 0 deletions gatt.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ func Scan(ctx context.Context, allowDup bool, h AdvHandler, f AdvFilter) error {
return defaultDevice.Scan(ctx, allowDup, h2)
}

// ExtendedScan starts scanning. Duplicated advertisements will be filtered out if allowDup is set to false.
func ExtendedScan(ctx context.Context, allowDup bool, h ExtendedAdvHandler, f AdvFilter) error {
if defaultDevice == nil {
return ErrDefaultDevice
}
defer untrap(trap(ctx))

if f == nil {
return defaultDevice.ExtendedScan(ctx, allowDup, h)
}

h2 := func(a ExtendedAdvertisement) {
if f(a) {
h(a)
}
}

return defaultDevice.ExtendedScan(ctx, allowDup, h2)
}

// Find ...
func Find(ctx context.Context, allowDup bool, f AdvFilter) ([]Advertisement, error) {
if defaultDevice == nil {
Expand Down
1 change: 0 additions & 1 deletion linux/adv/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package adv

import (
"encoding/binary"

"github.com/go-ble/ble"
)

Expand Down
56 changes: 56 additions & 0 deletions linux/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,44 @@ func NewDeviceWithNameAndHandler(name string, handler ble.NotifyHandler, opts ..
return &Device{HCI: dev, Server: srv}, nil
}

// NewAdvertisingExtensionsDevice returns the default HCI device.
func NewAdvertisingExtensionsDevice(opts ...ble.Option) (*Device, error) {
return NewAdvertisingExtensionsDeviceWithName("Gopher", opts...)
}

// NewAdvertisingExtensionsDeviceWithName returns the default HCI device.
func NewAdvertisingExtensionsDeviceWithName(name string, opts ...ble.Option) (*Device, error) {
return NewAdvertisingExtensionsDeviceWithNameAndHandler(name, nil, opts...)
}

func NewAdvertisingExtensionsDeviceWithNameAndHandler(name string, handler ble.NotifyHandler, opts ...ble.Option) (*Device, error) {
dev, err := hci.NewHCIForAdvertisingExtensions(opts...)
if err != nil {
return nil, errors.Wrap(err, "can't create hci")
}
if err = dev.Init(); err != nil {
dev.Close()
return nil, errors.Wrap(err, "can't init hci")
}

srv, err := gatt.NewServerWithNameAndHandler(name, handler)
if err != nil {
dev.Close()
return nil, errors.Wrap(err, "can't create server")
}

// mtu := ble.DefaultMTU
mtu := ble.MaxMTU // TODO: get this from user using Option.
if mtu > ble.MaxMTU {
dev.Close()
return nil, errors.Wrapf(err, "maximum ATT_MTU is %d", ble.MaxMTU)
}

go loop(dev, srv, mtu)

return &Device{HCI: dev, Server: srv}, nil
}

func loop(dev *hci.HCI, s *gatt.Server, mtu int) {
for {
l2c, err := dev.Accept()
Expand Down Expand Up @@ -105,6 +143,11 @@ func (d *Device) Stop() error {
return d.HCI.Close()
}

// Reset
func (d *Device) Reset(ctx context.Context) error {
return d.HCI.ResetHCI()
}

func (d *Device) Advertise(ctx context.Context, adv ble.Advertisement) error {
if err := d.HCI.AdvertiseAdv(adv); err != nil {
return err
Expand Down Expand Up @@ -208,6 +251,19 @@ func (d *Device) Scan(ctx context.Context, allowDup bool, h ble.AdvHandler) erro
return ctx.Err()
}

// ExtendedScan starts scanning. Duplicated advertisements will be filtered out if allowDup is set to false.
func (d *Device) ExtendedScan(ctx context.Context, allowDup bool, h ble.ExtendedAdvHandler) error {
if err := d.HCI.SetExtendedAdvHandler(h); err != nil {
return err
}
if err := d.HCI.ExtendedScan(allowDup); err != nil {
return err
}
<-ctx.Done()
d.HCI.StopExtendedScan()
return ctx.Err()
}

// Dial ...
func (d *Device) Dial(ctx context.Context, a ble.Addr) (ble.Client, error) {
// d.HCI.Dial is a blocking call, although most of time it should return immediately.
Expand Down
Loading