1
0
mirror of https://github.com/hybridgroup/gobot.git synced 2025-05-08 19:29:16 +08:00

ble: WIP on converting to currantlabs ble package

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
deadprogram 2016-12-28 17:53:41 +01:00
parent 5b337ac2fe
commit 001e7583d8
7 changed files with 105 additions and 201 deletions

View File

@ -49,7 +49,7 @@ func (b *BatteryDriver) Halt() (err error) { return }
// GetBatteryLevel reads and returns the current battery level
func (b *BatteryDriver) GetBatteryLevel() (level uint8) {
var l uint8
c, _ := b.adaptor().ReadCharacteristic("180f", "2a19")
c, _ := b.adaptor().ReadCharacteristic("2a19")
buf := bytes.NewBuffer(c)
val, _ := buf.ReadByte()
l = uint8(val)

View File

@ -1,61 +1,74 @@
package ble
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/currantlabs/gatt"
blelib "github.com/currantlabs/ble"
"github.com/currantlabs/ble/examples/lib/dev"
"github.com/pkg/errors"
)
// Represents a Client Connection to a BLE Peripheral
// ClientAdaptor represents a Client Connection to a BLE Peripheral
type ClientAdaptor struct {
name string
uuid string
device gatt.Device
peripheral gatt.Peripheral
services map[string]*Service
connected bool
ready chan struct{}
name string
address string
// uuid blelib.UUID
addr blelib.Addr
device blelib.Device
client blelib.Client
profile *blelib.Profile
connected bool
ready chan struct{}
}
// NewClientAdaptor returns a new ClientAdaptor given a uuid
func NewClientAdaptor(uuid string) *ClientAdaptor {
// NewClientAdaptor returns a new ClientAdaptor given an address or peripheral name
func NewClientAdaptor(address string) *ClientAdaptor {
return &ClientAdaptor{
name: "BLECLient",
uuid: uuid,
address: address,
connected: false,
ready: make(chan struct{}),
services: make(map[string]*Service),
}
}
func (b *ClientAdaptor) Name() string { return b.name }
func (b *ClientAdaptor) SetName(n string) { b.name = n }
func (b *ClientAdaptor) UUID() string { return b.uuid }
func (b *ClientAdaptor) Peripheral() gatt.Peripheral { return b.peripheral }
func (b *ClientAdaptor) Name() string { return b.name }
func (b *ClientAdaptor) SetName(n string) { b.name = n }
func (b *ClientAdaptor) Address() string { return b.address }
//func (b *ClientAdaptor) Peripheral() gatt.Peripheral { return b.peripheral }
// Connect initiates a connection to the BLE peripheral. Returns true on successful connection.
func (b *ClientAdaptor) Connect() (err error) {
device, e := gatt.NewDevice(DefaultClientOptions...)
if e != nil {
log.Fatalf("Failed to open BLE device, err: %s\n", err)
return e
d, err := dev.NewDevice("default")
if err != nil {
return errors.Wrap(err, "can't new device")
}
blelib.SetDefaultDevice(d)
b.device = d
var cln blelib.Client
ctx := blelib.WithSigHandler(context.WithTimeout(context.Background(), 5*time.Second))
if cln, err = blelib.Connect(ctx, filter(b.Name())); err == nil {
b.addr = cln.Address()
b.address = cln.Address().String()
b.SetName(cln.Name())
}
b.device = device
b.client = cln
// Register handlers.
device.Handle(
gatt.PeripheralDiscovered(b.DiscoveryHandler),
gatt.PeripheralConnected(b.ConnectHandler),
gatt.PeripheralDisconnected(b.DisconnectHandler),
)
p, err := b.client.DiscoverProfile(true)
if err != nil {
return err
}
device.Init(b.StateChangeHandler)
<-b.ready
// TODO: make sure peripheral currently exists for this UUID before returning
return nil
b.profile = p
return
}
// Reconnect attempts to reconnect to the BLE peripheral. If it has an active connection
@ -70,8 +83,7 @@ func (b *ClientAdaptor) Reconnect() (err error) {
// Disconnect terminates the connection to the BLE peripheral. Returns true on successful disconnect.
func (b *ClientAdaptor) Disconnect() (err error) {
b.peripheral.Device().CancelConnection(b.peripheral)
b.client.CancelConnection()
return
}
@ -81,46 +93,43 @@ func (b *ClientAdaptor) Finalize() (err error) {
}
// ReadCharacteristic returns bytes from the BLE device for the
// requested service and characteristic
func (b *ClientAdaptor) ReadCharacteristic(sUUID string, cUUID string) (data []byte, err error) {
// requested characteristic uuid
func (b *ClientAdaptor) ReadCharacteristic(cUUID string) (data []byte, err error) {
if !b.connected {
log.Fatalf("Cannot read from BLE device until connected")
return
}
characteristic := b.lookupCharacteristic(sUUID, cUUID)
if characteristic == nil {
log.Println("Cannot read from unknown characteristic")
return
uuid, _ := blelib.Parse(cUUID)
if u := b.profile.Find(blelib.NewCharacteristic(uuid)); u != nil {
data, err = b.client.ReadCharacteristic(u.(*blelib.Characteristic))
if err != nil {
return nil, err
}
fmt.Printf(" Value %x | %q\n", data, data)
return data, nil
}
val, err := b.peripheral.ReadCharacteristic(characteristic)
if err != nil {
fmt.Printf("Failed to read characteristic, err: %s\n", err)
return nil, err
}
return val, nil
return data, nil
}
// WriteCharacteristic writes bytes to the BLE device for the
// requested service and characteristic
func (b *ClientAdaptor) WriteCharacteristic(sUUID string, cUUID string, data []byte) (err error) {
func (b *ClientAdaptor) WriteCharacteristic(cUUID string, data []byte) (err error) {
if !b.connected {
log.Fatalf("Cannot write to BLE device until connected")
return
}
characteristic := b.lookupCharacteristic(sUUID, cUUID)
if characteristic == nil {
log.Println("Cannot write to unknown characteristic")
return
}
uuid, _ := blelib.Parse(cUUID)
err = b.peripheral.WriteCharacteristic(characteristic, data, true)
if err != nil {
fmt.Printf("Failed to write characteristic, err: %s\n", err)
return err
if u := b.profile.Find(blelib.NewCharacteristic(uuid)); u != nil {
err = b.client.WriteCharacteristic(u.(*blelib.Characteristic), data, false)
if err != nil {
return err
}
return nil
}
return
@ -128,134 +137,29 @@ func (b *ClientAdaptor) WriteCharacteristic(sUUID string, cUUID string, data []b
// Subscribe subscribes to notifications from the BLE device for the
// requested service and characteristic
func (b *ClientAdaptor) Subscribe(sUUID string, cUUID string, f func([]byte, error)) (err error) {
func (b *ClientAdaptor) Subscribe(cUUID string, f func([]byte, error)) (err error) {
if !b.connected {
log.Fatalf("Cannot subscribe to BLE device until connected")
return
}
characteristic := b.lookupCharacteristic(sUUID, cUUID)
if characteristic == nil {
log.Println("Cannot subscribe to unknown characteristic")
return
}
uuid, _ := blelib.Parse(cUUID)
fn := func(c *gatt.Characteristic, b []byte, err error) {
f(b, err)
}
err = b.peripheral.SetNotifyValue(characteristic, fn)
if err != nil {
fmt.Printf("Failed to subscribe to characteristic, err: %s\n", err)
return err
if u := b.profile.Find(blelib.NewCharacteristic(uuid)); u != nil {
h := func(req []byte) { f(req, nil) }
err = b.client.Subscribe(u.(*blelib.Characteristic), false, h)
if err != nil {
return err
}
return nil
}
return
}
func (b *ClientAdaptor) StateChangeHandler(d gatt.Device, s gatt.State) {
fmt.Println("State:", s)
switch s {
case gatt.StatePoweredOn:
fmt.Println("scanning...")
d.Scan([]gatt.UUID{}, false)
return
default:
d.StopScanning()
}
}
func (b *ClientAdaptor) DiscoveryHandler(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
// try looking by local name
if a.LocalName == b.UUID() {
b.uuid = p.ID()
} else {
// try looking by ID
id := strings.ToUpper(b.UUID())
if strings.ToUpper(p.ID()) != id {
return
}
}
// Stop scanning once we've got the peripheral we're looking for.
p.Device().StopScanning()
// and connect to it
p.Device().Connect(p)
}
func (b *ClientAdaptor) ConnectHandler(p gatt.Peripheral, err error) {
fmt.Printf("\nConnected Peripheral ID:%s, NAME:(%s)\n", p.ID(), p.Name())
b.peripheral = p
if err := p.SetMTU(250); err != nil {
fmt.Printf("Failed to set MTU, err: %s\n", err)
}
ss, err := p.DiscoverServices(nil)
if err != nil {
fmt.Printf("Failed to discover services, err: %s\n", err)
return
}
outer:
for _, s := range ss {
b.services[s.UUID().String()] = NewService(s.UUID().String(), s)
cs, err := p.DiscoverCharacteristics(nil, s)
if err != nil {
fmt.Printf("Failed to discover characteristics, err: %s\n", err)
continue
}
for _, c := range cs {
_, err := p.DiscoverDescriptors(nil, c)
if err != nil {
fmt.Printf("Failed to discover descriptors: %v\n", err)
continue outer
}
b.services[s.UUID().String()].characteristics[c.UUID().String()] = c
}
}
b.connected = true
close(b.ready)
}
func (b *ClientAdaptor) DisconnectHandler(p gatt.Peripheral, err error) {
fmt.Println("Disconnected")
}
// Finalize finalizes the ClientAdaptor
func (b *ClientAdaptor) lookupCharacteristic(sUUID string, cUUID string) *gatt.Characteristic {
service := b.services[sUUID]
if service == nil {
log.Printf("Unknown service ID: %s\n", sUUID)
return nil
}
characteristic := service.characteristics[cUUID]
if characteristic == nil {
log.Printf("Unknown characteristic ID: %s\n", cUUID)
return nil
}
return characteristic
}
// Represents a BLE Peripheral's Service
type Service struct {
uuid string
service *gatt.Service
characteristics map[string]*gatt.Characteristic
}
// NewService returns a new BLE Service given a uuid
func NewService(sUuid string, service *gatt.Service) *Service {
return &Service{
uuid: sUuid,
service: service,
characteristics: make(map[string]*gatt.Characteristic),
func filter(name string) blelib.AdvFilter {
return func(a blelib.Advertisement) bool {
return strings.ToLower(a.LocalName()) == strings.ToLower(name) ||
a.Address().String() == strings.ToLower(name)
}
}

View File

@ -1,9 +1,9 @@
package ble
import (
"github.com/currantlabs/gatt"
)
var DefaultClientOptions = []gatt.Option{
gatt.MacDeviceRole(gatt.CentralManager),
}
// import (
// "github.com/currantlabs/gatt"
// )
//
// var DefaultClientOptions = []gatt.Option{
// gatt.MacDeviceRole(gatt.CentralManager),
// }

View File

@ -1,11 +1,11 @@
package ble
import (
"github.com/currantlabs/gatt"
)
// TODO: handle other OS defaults besides Linux
var DefaultClientOptions = []gatt.Option{
gatt.LnxMaxConnections(1),
gatt.LnxDeviceID(-1, false),
}
// import (
// "github.com/currantlabs/gatt"
// )
//
// // TODO: handle other OS defaults besides Linux
// var DefaultClientOptions = []gatt.Option{
// gatt.LnxMaxConnections(1),
// gatt.LnxDeviceID(-1, false),
// }

View File

@ -16,5 +16,5 @@ func initTestBLEClientAdaptor() *ClientAdaptor {
func TestBLEClientAdaptor(t *testing.T) {
a := NewClientAdaptor("D7:99:5A:26:EC:38")
gobottest.Assert(t, a.UUID(), "D7:99:5A:26:EC:38")
gobottest.Assert(t, a.Address(), "D7:99:5A:26:EC:38")
}

View File

@ -48,7 +48,7 @@ func (b *DeviceInformationDriver) Halt() (err error) { return }
// GetModelNumber returns the model number for the BLE Peripheral
func (b *DeviceInformationDriver) GetModelNumber() (model string) {
c, _ := b.adaptor().ReadCharacteristic("180a", "2a24")
c, _ := b.adaptor().ReadCharacteristic("2a24")
buf := bytes.NewBuffer(c)
val := buf.String()
return val
@ -56,7 +56,7 @@ func (b *DeviceInformationDriver) GetModelNumber() (model string) {
// GetFirmwareRevision returns the firmware revision for the BLE Peripheral
func (b *DeviceInformationDriver) GetFirmwareRevision() (revision string) {
c, _ := b.adaptor().ReadCharacteristic("180a", "2a26")
c, _ := b.adaptor().ReadCharacteristic("2a26")
buf := bytes.NewBuffer(c)
val := buf.String()
return val
@ -64,7 +64,7 @@ func (b *DeviceInformationDriver) GetFirmwareRevision() (revision string) {
// GetHardwareRevision returns the hardware revision for the BLE Peripheral
func (b *DeviceInformationDriver) GetHardwareRevision() (revision string) {
c, _ := b.adaptor().ReadCharacteristic("180a", "2a27")
c, _ := b.adaptor().ReadCharacteristic("2a27")
buf := bytes.NewBuffer(c)
val := buf.String()
return val
@ -72,7 +72,7 @@ func (b *DeviceInformationDriver) GetHardwareRevision() (revision string) {
// GetManufacturerName returns the manufacturer name for the BLE Peripheral
func (b *DeviceInformationDriver) GetManufacturerName() (manufacturer string) {
c, _ := b.adaptor().ReadCharacteristic("180a", "2a29")
c, _ := b.adaptor().ReadCharacteristic("2a29")
buf := bytes.NewBuffer(c)
val := buf.String()
return val
@ -80,7 +80,7 @@ func (b *DeviceInformationDriver) GetManufacturerName() (manufacturer string) {
// GetPnPId returns the PnP ID for the BLE Peripheral
func (b *DeviceInformationDriver) GetPnPId() (model string) {
c, _ := b.adaptor().ReadCharacteristic("180a", "2a50")
c, _ := b.adaptor().ReadCharacteristic("2a50")
buf := bytes.NewBuffer(c)
val := buf.String()
return val

View File

@ -49,7 +49,7 @@ func (b *GenericAccessDriver) Halt() (err error) { return }
// GetDeviceName returns the device name for the BLE Peripheral
func (b *GenericAccessDriver) GetDeviceName() string {
c, _ := b.adaptor().ReadCharacteristic("1800", "2a00")
c, _ := b.adaptor().ReadCharacteristic("2a00")
buf := bytes.NewBuffer(c)
val := buf.String()
return val
@ -57,7 +57,7 @@ func (b *GenericAccessDriver) GetDeviceName() string {
// GetAppearance returns the appearance string for the BLE Peripheral
func (b *GenericAccessDriver) GetAppearance() string {
c, _ := b.adaptor().ReadCharacteristic("1800", "2a01")
c, _ := b.adaptor().ReadCharacteristic("2a01")
buf := bytes.NewBuffer(c)
var val uint16