diff --git a/ble_darwin.go b/ble_darwin.go index 5607b77..1b85894 100644 --- a/ble_darwin.go +++ b/ble_darwin.go @@ -119,6 +119,7 @@ func (ps *Peripherals) Add(x Peripheral) bool { } //take ownership of this Objective-C object x.p.Retain() + runtime.SetFinalizer(x.p, nil) x.p.GC() item := PeripheralListItem{p: x, seen: time.Now()} ps.items = append(ps.items, item) @@ -225,6 +226,9 @@ func (b *BLE) Scan() { if b.state != (ns.CBManagerState)(ns.CBManagerStatePoweredOn) { b.wantScan = true } else { + b.peripherals.Lock() + b.peripherals.items = b.peripherals.items[:0] + b.peripherals.Unlock() fmt.Printf("Go: Scanning\n") b.cm.ScanForPeripheralsWithServices(nil, nil) } @@ -241,37 +245,51 @@ func (b *BLE) StopScan() { b.cm.StopScan() } -func connectTracker(b *BLE, x ConnectionListItem) { +func connectTracker(b *BLE, x ConnectionListItem) bool { fmt.Printf("connectTracker(): %s\n", x.p.Name) - tick := time.NewTicker(time.Second * 5) - select { - case <-b.connections.close: - fmt.Printf("Closing connection to %s\n", x.p.Name) - b.cm.CancelPeripheralConnection(x.p.p) - case <-tick.C: - fmt.Printf("Connection to %s timed out\n", x.p.Name) - b.cm.CancelPeripheralConnection(x.p.p) - b.connections.Lock() - for n, item := range b.connections.items { - if item.p.Identifier == x.p.Identifier { - b.connections.items = append(b.connections.items[:n], b.connections.items[n+1:]...) - } - } - b.connections.Unlock() - b.events <- ConnectTimeoutEvent{x.p} - case state := <-x.state: - fmt.Printf("connectTracker: state\n") - if state == "connected" { - fmt.Printf("--connected") + b.connections.Lock() + for _, item := range b.connections.items { + if item.p.Identifier == x.p.Identifier { + fmt.Printf("connectTracker(): already connecting to %s\n", x.p.Name) + b.connections.Unlock() + return false } } + b.connections.items = append(b.connections.items, x) + b.connections.Unlock() + fmt.Printf("BLE.Connect(): calling cm.ConnectPeripheral(%p)\n", x.p.p.Ptr()) + b.cm.ConnectPeripheral(x.p.p, nil) + + go func() { + tick := time.NewTicker(time.Second * 5) + select { + case <-b.connections.close: + fmt.Printf("connectTracker(): Closing connection to %s\n", x.p.Name) + b.cm.CancelPeripheralConnection(x.p.p) + case <-tick.C: + fmt.Printf("connectTracker(): Connection to %s timed out\n", x.p.Name) + b.cm.CancelPeripheralConnection(x.p.p) + b.connections.Lock() + for n, item := range b.connections.items { + if item.p.Identifier == x.p.Identifier { + b.connections.items = append(b.connections.items[:n], b.connections.items[n+1:]...) + } + } + b.connections.Unlock() + b.events <- ConnectTimeoutEvent{x.p} + case state := <-x.state: + fmt.Printf("connectTracker(): state %s\n", state) + } + }() + return true } -func (b *BLE) Connect(p Peripheral) { +func (b *BLE) Connect(p Peripheral) bool { b.Lock() if !b.ready { b.Unlock() - return + fmt.Printf("--BLE not ready\n") + return false } b.Unlock() if p.p == nil { @@ -279,19 +297,19 @@ func (b *BLE) Connect(p Peripheral) { ps := b.cm.RetrievePeripheralsWithIdentifiers(ns.NSArrayWithObjects(ns.NSUUIDAlloc().InitWithUUIDString(ns.NSStringWithGoString(p.Identifier)))) if x := (int)(ps.Count()); x > 0 { fmt.Printf("--found %d\n", x) - p.p = ps.ObjectAtIndex(0).CBPeripheral() + cbp := ps.ObjectAtIndex(0).CBPeripheral() +//NOTE: ns.ObjectAtIndex() calls SetFinalizer for us, which will be a problem +//later when we call GC(), so we first clear the finalizer here. + runtime.SetFinalizer(cbp, nil) + p = newPeripheral(cbp) } else { fmt.Printf("--none found\n") - return + return false } } item := ConnectionListItem{p, make(chan string)} - b.connections.Add(item) - go connectTracker(b, item) - //time.Sleep(time.Second/10) - fmt.Printf("BLE.Connect(): calling cm.ConnectPeripheral(%p)\n", p.p.Ptr()) - b.cm.ConnectPeripheral(p.p, nil) - fmt.Printf("BLE.Connect() returned\n") + fmt.Printf("BLE.Connect() calling connectTracker\n") + return connectTracker(b, item) } func updateState(c *ns.CBCentralManager) { @@ -319,11 +337,15 @@ func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDict b := cdLookup[c.Ptr()] peripheral := newPeripheral(p) peripheral.RSSI = (int)(rssi.IntValue()) + _discoverPeripheral(b, peripheral) +} + +func _discoverPeripheral(b *BLE, peripheral Peripheral) { if peripheral.Name == "" { return } if ok := b.peripherals.Add(peripheral); ok { - pdLookup[p.Ptr()] = b + pdLookup[peripheral.p.Ptr()] = b b.events <- DiscoverPeripheralEvent{Peripheral: peripheral} } }