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:
parent
c911bbb547
commit
206bd70461
19
ble.go
19
ble.go
|
@ -173,6 +173,25 @@ func (b *BLE) StopScan() {
|
||||||
b.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 {
|
func connectTracker(b *BLE, x ConnectionListItem) bool {
|
||||||
fmt.Printf("connectTracker(): %s\n", x.p.Name)
|
fmt.Printf("connectTracker(): %s\n", x.p.Name)
|
||||||
b.connections.Lock()
|
b.connections.Lock()
|
||||||
|
|
220
ble_darwin.go
220
ble_darwin.go
|
@ -3,7 +3,6 @@ package ble
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
@ -13,6 +12,8 @@ import (
|
||||||
"git.wow.st/gmp/ble/ns"
|
"git.wow.st/gmp/ble/ns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Types required for ble.go
|
||||||
|
|
||||||
type bleState ns.CBManagerState
|
type bleState ns.CBManagerState
|
||||||
|
|
||||||
type bleHandle struct {
|
type bleHandle struct {
|
||||||
|
@ -24,12 +25,6 @@ var cdLookup map[unsafe.Pointer]*BLE
|
||||||
var pdLookup map[unsafe.Pointer]*BLE
|
var pdLookup map[unsafe.Pointer]*BLE
|
||||||
var pcache map[unsafe.Pointer]*Peripheral
|
var pcache map[unsafe.Pointer]*Peripheral
|
||||||
|
|
||||||
func peripheralLookup(p Peripheral) *BLE {
|
|
||||||
return pdLookup[p.p.Ptr()]
|
|
||||||
}
|
|
||||||
|
|
||||||
type State string
|
|
||||||
|
|
||||||
type Peripheral struct {
|
type Peripheral struct {
|
||||||
Name string
|
Name string
|
||||||
RSSI int
|
RSSI int
|
||||||
|
@ -41,30 +36,19 @@ type Peripheral struct {
|
||||||
type Service *ns.CBService
|
type Service *ns.CBService
|
||||||
type Characteristic *ns.CBCharacteristic
|
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
|
//Init needs to be called before the BLE library can be used. No setup needed
|
||||||
//on Darwin.
|
//on Darwin.
|
||||||
func Init() {
|
func Init() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Peripheral) Retain() {
|
//newPeripheral creates a new Peripheral struct
|
||||||
//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
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPeripheral(x *ns.CBPeripheral) Peripheral {
|
func newPeripheral(x *ns.CBPeripheral) Peripheral {
|
||||||
if pcache == nil {
|
if pcache == nil {
|
||||||
pcache = make(map[unsafe.Pointer]*Peripheral)
|
pcache = make(map[unsafe.Pointer]*Peripheral)
|
||||||
|
@ -82,6 +66,7 @@ func newPeripheral(x *ns.CBPeripheral) Peripheral {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stringState returns a string version of the BLE state
|
||||||
func (b *BLE) stringState() string {
|
func (b *BLE) stringState() string {
|
||||||
x := b.state
|
x := b.state
|
||||||
switch (ns.NSInteger)(x) {
|
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 {
|
func (b *BLE) readyToScan() bool {
|
||||||
return b.state == (bleState)(ns.CBManagerStatePoweredOn)
|
return b.state == (bleState)(ns.CBManagerStatePoweredOn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//scan puts the BLE hardware into scanning mode
|
||||||
func (b *BLE) scan() {
|
func (b *BLE) scan() {
|
||||||
b.handle.cm.ScanForPeripheralsWithServices(nil, nil)
|
b.handle.cm.ScanForPeripheralsWithServices(nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stopScan stops a scan in progress
|
||||||
func (b *BLE) stopScan() {
|
func (b *BLE) stopScan() {
|
||||||
b.handle.cm.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) {
|
func (b *BLE) connectPeripheral(x Peripheral) {
|
||||||
fmt.Printf("BLE.Connect(): calling cm.ConnectPeripheral(%p)\n", x.p.Ptr())
|
fmt.Printf("BLE.Connect(): calling cm.ConnectPeripheral(%p)\n", x.p.Ptr())
|
||||||
b.handle.cm.ConnectPeripheral(x.p, nil)
|
b.handle.cm.ConnectPeripheral(x.p, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CancelConnection(p Peripheral) {
|
//cancelConnection cancels an in-progress connection attempt
|
||||||
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 (b *BLE) cancelConnection(p Peripheral) {
|
func (b *BLE) cancelConnection(p Peripheral) {
|
||||||
b.handle.cm.CancelPeripheralConnection(p.p)
|
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) {
|
func (b *BLE) knownPeripheral(p Peripheral) (Peripheral, bool) {
|
||||||
fmt.Printf("RetrievePeripheralsWithIdentifiers\n")
|
fmt.Printf("RetrievePeripheralsWithIdentifiers\n")
|
||||||
ps := b.handle.cm.RetrievePeripheralsWithIdentifiers(ns.NSArrayWithObjects(ns.NSUUIDAlloc().InitWithUUIDString(ns.NSStringWithGoString(p.Identifier))))
|
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
|
return newPeripheral(cbp), true
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("--none found\n")
|
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) {
|
func didUpdateState(c *ns.CBCentralManager) {
|
||||||
b := cdLookup[c.Ptr()]
|
b := cdLookup[c.Ptr()]
|
||||||
st := c.CBManager.State()
|
st := c.CBManager.State()
|
||||||
|
@ -239,15 +264,6 @@ func didConnectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) {
|
||||||
fmt.Printf("Go: didConnectPeripheral returning\n")
|
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) {
|
func didDiscoverServices(p *ns.CBPeripheral, e *ns.NSError) {
|
||||||
b := pdLookup[p.Ptr()]
|
b := pdLookup[p.Ptr()]
|
||||||
fmt.Printf("Did discover services\n")
|
fmt.Printf("Did discover services\n")
|
||||||
|
@ -264,23 +280,6 @@ func didDiscoverServices(p *ns.CBPeripheral, e *ns.NSError) {
|
||||||
fmt.Printf("Go: didDiscoverServices returning\n")
|
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) {
|
func didDiscoverCharacteristics(p *ns.CBPeripheral, s *ns.CBService, e *ns.NSError) {
|
||||||
b := pdLookup[p.Ptr()]
|
b := pdLookup[p.Ptr()]
|
||||||
fmt.Printf("Did discover characteristics\n")
|
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")
|
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) {
|
func didUpdateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError) {
|
||||||
b := pdLookup[p.Ptr()]
|
b := pdLookup[p.Ptr()]
|
||||||
v := chr.Value()
|
v := chr.Value()
|
||||||
|
@ -313,41 +308,34 @@ func didUpdateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBLE() *BLE {
|
// internal convenience functions
|
||||||
ps := Peripherals{items: make([]PeripheralListItem, 0)}
|
|
||||||
ble := &BLE{events: make(chan interface{}), peripherals: ps}
|
|
||||||
|
|
||||||
queue := ns.DispatchQueueCreate(ns.CharWithGoString("go_hrm_queue"), nil)
|
func peripheralName(p *ns.CBPeripheral) string {
|
||||||
|
var ret string
|
||||||
cd := ns.CBDelegateAlloc()
|
nsname := p.Name()
|
||||||
|
if nsname.Ptr() != nil {
|
||||||
cd.CentralManagerDidUpdateStateCallback(didUpdateState)
|
ret = nsname.String()
|
||||||
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 {
|
return ret
|
||||||
pdLookup = make(map[unsafe.Pointer]*BLE, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We defined our own queue because this won't work on the main queue.
|
func (x *Peripheral) Retain() {
|
||||||
ble.handle.cm = ns.CBCentralManagerAlloc().InitWithDelegateQueue(cd, queue)
|
//NOTE: ns.ObjectAtIndex() calls SetFinalizer for us, which will be a problem
|
||||||
cdLookup[ble.handle.cm.Ptr()] = ble
|
//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
|
func (b *BLE) setState(x ns.CBManagerState) {
|
||||||
// not over-released.
|
b.Lock()
|
||||||
go func() {
|
defer b.Unlock()
|
||||||
for {
|
b.state = (bleState)(x)
|
||||||
runtime.GC()
|
if b.ready && b.wantScan {
|
||||||
time.Sleep(time.Second * 30)
|
fmt.Printf("Go: Scanning\n")
|
||||||
|
b.scan()
|
||||||
|
b.wantScan = false
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
return ble
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user