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()
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
220
ble_darwin.go
220
ble_darwin.go
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user