Prepare for Android port -- move CancelConnection into ble.go and

re-arrange functions in ble_darwin.go into API calls, Core Bluetooth
callbacks and internal convenience functions.
This commit is contained in:
Greg 2019-10-28 11:39:05 -04:00
parent c911bbb547
commit 206bd70461
2 changed files with 127 additions and 120 deletions

19
ble.go
View File

@ -173,6 +173,25 @@ func (b *BLE) StopScan() {
b.stopScan()
}
func CancelConnection(p Peripheral) {
b := peripheralLookup(p)
if b == nil {
return
}
b.connections.Lock()
var ch chan string;
for _, item := range b.connections.items {
if item.p.Identifier == p.Identifier {
ch = item.state
break
}
}
b.connections.Unlock()
if ch != nil {
ch <- "cancel"
}
}
func connectTracker(b *BLE, x ConnectionListItem) bool {
fmt.Printf("connectTracker(): %s\n", x.p.Name)
b.connections.Lock()

View File

@ -3,7 +3,6 @@ package ble
import "C"
import (
"encoding/binary"
"fmt"
"runtime"
"time"
@ -13,6 +12,8 @@ import (
"git.wow.st/gmp/ble/ns"
)
// Types required for ble.go
type bleState ns.CBManagerState
type bleHandle struct {
@ -24,12 +25,6 @@ var cdLookup map[unsafe.Pointer]*BLE
var pdLookup map[unsafe.Pointer]*BLE
var pcache map[unsafe.Pointer]*Peripheral
func peripheralLookup(p Peripheral) *BLE {
return pdLookup[p.p.Ptr()]
}
type State string
type Peripheral struct {
Name string
RSSI int
@ -41,30 +36,19 @@ type Peripheral struct {
type Service *ns.CBService
type Characteristic *ns.CBCharacteristic
// Functions required by API
func peripheralLookup(p Peripheral) *BLE {
return pdLookup[p.p.Ptr()]
}
//Init needs to be called before the BLE library can be used. No setup needed
//on Darwin.
func Init() {
}
func (x *Peripheral) Retain() {
//NOTE: ns.ObjectAtIndex() calls SetFinalizer for us, which will be a problem
//later when we call GC(), so we always first clear the finalizer before
//setting a new one.
runtime.SetFinalizer(x.p, nil)
x.p.Retain()
x.p.GC()
}
func peripheralName(p *ns.CBPeripheral) string {
var ret string
nsname := p.Name()
if nsname.Ptr() != nil {
ret = nsname.String()
}
return ret
}
//newPeripheral creates a new Peripheral struct
func newPeripheral(x *ns.CBPeripheral) Peripheral {
if pcache == nil {
pcache = make(map[unsafe.Pointer]*Peripheral)
@ -82,6 +66,7 @@ func newPeripheral(x *ns.CBPeripheral) Peripheral {
return ret
}
//stringState returns a string version of the BLE state
func (b *BLE) stringState() string {
x := b.state
switch (ns.NSInteger)(x) {
@ -102,57 +87,35 @@ func (b *BLE) stringState() string {
}
}
//readyToScan returns true if the hardware is ready to initiate a scan
func (b *BLE) readyToScan() bool {
return b.state == (bleState)(ns.CBManagerStatePoweredOn)
}
//scan puts the BLE hardware into scanning mode
func (b *BLE) scan() {
b.handle.cm.ScanForPeripheralsWithServices(nil, nil)
}
//stopScan stops a scan in progress
func (b *BLE) stopScan() {
b.handle.cm.StopScan()
}
func (b *BLE) setState(x ns.CBManagerState) {
b.Lock()
defer b.Unlock()
b.state = (bleState)(x)
if b.ready && b.wantScan {
fmt.Printf("Go: Scanning\n")
b.scan()
b.wantScan = false
}
}
//connectPeripheral attempts to connect to a Peripheral
func (b *BLE) connectPeripheral(x Peripheral) {
fmt.Printf("BLE.Connect(): calling cm.ConnectPeripheral(%p)\n", x.p.Ptr())
b.handle.cm.ConnectPeripheral(x.p, nil)
}
func CancelConnection(p Peripheral) {
b := peripheralLookup(p)
if b == nil {
return
}
b.connections.Lock()
var ch chan string;
for _, item := range b.connections.items {
if item.p.Identifier == p.Identifier {
ch = item.state
break
}
}
b.connections.Unlock()
if ch != nil {
ch <- "cancel"
}
}
//cancelConnection cancels an in-progress connection attempt
func (b *BLE) cancelConnection(p Peripheral) {
b.handle.cm.CancelPeripheralConnection(p.p)
}
//knownPeripheral returns a Peripheral that is known to the system without
//scanning
func (b *BLE) knownPeripheral(p Peripheral) (Peripheral, bool) {
fmt.Printf("RetrievePeripheralsWithIdentifiers\n")
ps := b.handle.cm.RetrievePeripheralsWithIdentifiers(ns.NSArrayWithObjects(ns.NSUUIDAlloc().InitWithUUIDString(ns.NSStringWithGoString(p.Identifier))))
@ -162,10 +125,72 @@ func (b *BLE) knownPeripheral(p Peripheral) (Peripheral, bool) {
return newPeripheral(cbp), true
} else {
fmt.Printf("--none found\n")
return Peripheral{}, false
return p, false
}
}
//DiscoverServices asks a Peripheral for its Services
func (x Peripheral) DiscoverServices() {
fmt.Printf("Discovering services on %s\n", x.Name)
// discover all services on this device
x.p.DiscoverServices(nil)
}
//DiscoverCharacteristics asks a Peripheral for the Characteristics related
//to a Service
func (p Peripheral) DiscoverCharacteristics(serv Service) {
p.p.DiscoverCharacteristics(nil, serv)
}
//SetNotifyValue subscribes to a characteristic
func (p Peripheral) SetNotifyValue(c Characteristic) {
p.p.SetNotifyValue(1, c)
}
//NewBLE returns a pointer to a BLE struct after setting up the OS
//Bluetooth API.
func NewBLE() *BLE {
ps := Peripherals{items: make([]PeripheralListItem, 0)}
ble := &BLE{events: make(chan interface{}), peripherals: ps}
queue := ns.DispatchQueueCreate(ns.CharWithGoString("go_hrm_queue"), nil)
cd := ns.CBDelegateAlloc()
cd.CentralManagerDidUpdateStateCallback(didUpdateState)
cd.CentralManagerDidDiscoverPeripheralCallback(didDiscoverPeripheral)
cd.CentralManagerDidConnectPeripheralCallback(didConnectPeripheral)
cd.PeripheralDidDiscoverServicesCallback(didDiscoverServices)
cd.PeripheralDidDiscoverCharacteristicsForServiceCallback(didDiscoverCharacteristics)
cd.PeripheralDidUpdateValueForCharacteristicCallback(didUpdateValue)
ble.handle.cd = cd
if cdLookup == nil {
cdLookup = make(map[unsafe.Pointer]*BLE, 0)
}
if pdLookup == nil {
pdLookup = make(map[unsafe.Pointer]*BLE, 0)
}
// We defined our own queue because this won't work on the main queue.
ble.handle.cm = ns.CBCentralManagerAlloc().InitWithDelegateQueue(cd, queue)
cdLookup[ble.handle.cm.Ptr()] = ble
// For debugging purposes, run GC every second to make sure things are
// not over-released.
go func() {
for {
runtime.GC()
time.Sleep(time.Second * 30)
}
}()
return ble
}
// Core Bluetooth callback functions
func didUpdateState(c *ns.CBCentralManager) {
b := cdLookup[c.Ptr()]
st := c.CBManager.State()
@ -239,15 +264,6 @@ func didConnectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) {
fmt.Printf("Go: didConnectPeripheral returning\n")
}
func (x Peripheral) DiscoverServices() {
fmt.Printf("Discovering services on %s\n", x.Name)
p := x.p
// discover all services on this device
p.DiscoverServices(nil)
}
func didDiscoverServices(p *ns.CBPeripheral, e *ns.NSError) {
b := pdLookup[p.Ptr()]
fmt.Printf("Did discover services\n")
@ -264,23 +280,6 @@ func didDiscoverServices(p *ns.CBPeripheral, e *ns.NSError) {
fmt.Printf("Go: didDiscoverServices returning\n")
}
func hr(d *ns.NSData) int {
if l := int(d.Length()); l < 4 {
return 0
}
x := C.GoBytes(d.Bytes(), 4)
flags := x[0]
if flags&0x80 != 0 { // uint16 format
return int(binary.BigEndian.Uint16(x[1:2]))
} else {
return int(x[1])
}
}
func (p Peripheral) DiscoverCharacteristics(serv *ns.CBService) {
p.p.DiscoverCharacteristics(nil, serv)
}
func didDiscoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError) {
b := pdLookup[p.Ptr()]
fmt.Printf("Did discover characteristics\n")
@ -299,10 +298,6 @@ func didDiscoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSErr
fmt.Printf("Go: didDiscoverCharacteristics returning\n")
}
func (p Peripheral) SetNotifyValue(c *ns.CBCharacteristic) {
p.p.SetNotifyValue(1, c)
}
func didUpdateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError) {
b := pdLookup[p.Ptr()]
v := chr.Value()
@ -313,41 +308,34 @@ func didUpdateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError)
}
}
func NewBLE() *BLE {
ps := Peripherals{items: make([]PeripheralListItem, 0)}
ble := &BLE{events: make(chan interface{}), peripherals: ps}
// internal convenience functions
queue := ns.DispatchQueueCreate(ns.CharWithGoString("go_hrm_queue"), nil)
cd := ns.CBDelegateAlloc()
cd.CentralManagerDidUpdateStateCallback(didUpdateState)
cd.CentralManagerDidDiscoverPeripheralCallback(didDiscoverPeripheral)
cd.CentralManagerDidConnectPeripheralCallback(didConnectPeripheral)
cd.PeripheralDidDiscoverServicesCallback(didDiscoverServices)
cd.PeripheralDidDiscoverCharacteristicsForServiceCallback(didDiscoverCharacteristics)
cd.PeripheralDidUpdateValueForCharacteristicCallback(didUpdateValue)
ble.handle.cd = cd
if cdLookup == nil {
cdLookup = make(map[unsafe.Pointer]*BLE, 0)
func peripheralName(p *ns.CBPeripheral) string {
var ret string
nsname := p.Name()
if nsname.Ptr() != nil {
ret = nsname.String()
}
if pdLookup == nil {
pdLookup = make(map[unsafe.Pointer]*BLE, 0)
return ret
}
// We defined our own queue because this won't work on the main queue.
ble.handle.cm = ns.CBCentralManagerAlloc().InitWithDelegateQueue(cd, queue)
cdLookup[ble.handle.cm.Ptr()] = ble
func (x *Peripheral) Retain() {
//NOTE: ns.ObjectAtIndex() calls SetFinalizer for us, which will be a problem
//later when we call GC(), so we always first clear the finalizer before
//setting a new one.
runtime.SetFinalizer(x.p, nil)
x.p.Retain()
x.p.GC()
}
// For debugging purposes, run GC every second to make sure things are
// not over-released.
go func() {
for {
runtime.GC()
time.Sleep(time.Second * 30)
func (b *BLE) setState(x ns.CBManagerState) {
b.Lock()
defer b.Unlock()
b.state = (bleState)(x)
if b.ready && b.wantScan {
fmt.Printf("Go: Scanning\n")
b.scan()
b.wantScan = false
}
}()
return ble
}