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:
parent
5b337ac2fe
commit
001e7583d8
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
// }
|
||||
|
@ -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),
|
||||
// }
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user