Add connection tracking and timeouts.
This commit is contained in:
parent
c91c83de9c
commit
64b684e419
129
ble_darwin.go
129
ble_darwin.go
|
@ -14,22 +14,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type BLE struct {
|
type BLE struct {
|
||||||
events chan interface{}
|
|
||||||
|
|
||||||
state ns.CBManagerState
|
state ns.CBManagerState
|
||||||
|
events chan interface{}
|
||||||
peripherals Peripherals
|
peripherals Peripherals
|
||||||
hr int
|
hr int
|
||||||
|
cd *ns.CBDelegate
|
||||||
|
cm *ns.CBCentralManager
|
||||||
|
|
||||||
ready, wantScan bool
|
ready, wantScan bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
cd *ns.CBDelegate
|
connections Connections
|
||||||
cm *ns.CBCentralManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cdLookup map[unsafe.Pointer] *BLE
|
var cdLookup map[unsafe.Pointer]*BLE
|
||||||
var pdLookup map[unsafe.Pointer] *BLE
|
var pdLookup map[unsafe.Pointer]*BLE
|
||||||
|
|
||||||
type State string
|
type State string
|
||||||
|
|
||||||
|
@ -68,11 +67,34 @@ type Peripherals struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConnectionListItem struct {
|
||||||
|
p Peripheral
|
||||||
|
state chan string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Connections struct {
|
||||||
|
items []ConnectionListItem
|
||||||
|
close chan struct{}
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connections) UpdateState(p Peripheral, s string) {
|
||||||
|
var ch chan string
|
||||||
|
c.Lock()
|
||||||
|
for _, item := range c.items {
|
||||||
|
if p.Identifier == item.p.Identifier {
|
||||||
|
ch = item.state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Unlock()
|
||||||
|
ch <- s
|
||||||
|
}
|
||||||
|
|
||||||
func (ps *Peripherals) Add(x Peripheral) bool {
|
func (ps *Peripherals) Add(x Peripheral) bool {
|
||||||
ps.Lock()
|
ps.Lock()
|
||||||
defer ps.Unlock()
|
defer ps.Unlock()
|
||||||
found := false
|
found := false
|
||||||
for n,item := range ps.items {
|
for n, item := range ps.items {
|
||||||
if item.p.Identifier == x.Identifier {
|
if item.p.Identifier == x.Identifier {
|
||||||
item.p = x
|
item.p = x
|
||||||
item.seen = time.Now()
|
item.seen = time.Now()
|
||||||
|
@ -87,11 +109,28 @@ func (ps *Peripherals) Add(x Peripheral) bool {
|
||||||
//take ownership of this Objective-C object
|
//take ownership of this Objective-C object
|
||||||
x.p.Retain()
|
x.p.Retain()
|
||||||
x.p.GC()
|
x.p.GC()
|
||||||
item := PeripheralListItem {p: x, seen: time.Now()}
|
item := PeripheralListItem{p: x, seen: time.Now()}
|
||||||
ps.items = append(ps.items, item)
|
ps.items = append(ps.items, item)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *Connections) Add(x ConnectionListItem) bool {
|
||||||
|
cs.Lock()
|
||||||
|
defer cs.Unlock()
|
||||||
|
found := false
|
||||||
|
for _, item := range cs.items {
|
||||||
|
if item.p.Identifier == x.p.Identifier {
|
||||||
|
// are we allowed to have multiple connections to the same peripheral?
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
cs.items = append(cs.items, x)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type UpdateStateEvent struct {
|
type UpdateStateEvent struct {
|
||||||
State string
|
State string
|
||||||
}
|
}
|
||||||
|
@ -103,6 +142,9 @@ type DiscoverEvent struct {
|
||||||
type ConnectEvent struct {
|
type ConnectEvent struct {
|
||||||
Peripheral Peripheral
|
Peripheral Peripheral
|
||||||
}
|
}
|
||||||
|
type ConnectTimeoutEvent struct {
|
||||||
|
Peripheral Peripheral
|
||||||
|
}
|
||||||
|
|
||||||
func (b *BLE) Events() chan interface{} {
|
func (b *BLE) Events() chan interface{} {
|
||||||
return b.events
|
return b.events
|
||||||
|
@ -174,6 +216,31 @@ func (b *BLE) StopScan() {
|
||||||
b.cm.StopScan()
|
b.cm.StopScan()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func connectTracker(b *BLE, x ConnectionListItem) {
|
||||||
|
tick := time.NewTicker(time.Second * 30)
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *BLE) Connect(p Peripheral) {
|
func (b *BLE) Connect(p Peripheral) {
|
||||||
b.Lock()
|
b.Lock()
|
||||||
if !b.ready {
|
if !b.ready {
|
||||||
|
@ -182,40 +249,56 @@ func (b *BLE) Connect(p Peripheral) {
|
||||||
}
|
}
|
||||||
b.Unlock()
|
b.Unlock()
|
||||||
if p.p == nil {
|
if p.p == nil {
|
||||||
|
fmt.Printf("RetrievePeripheralsWithIdentifiers\n")
|
||||||
ps := b.cm.RetrievePeripheralsWithIdentifiers(ns.NSArrayWithObjects(ns.NSUUIDAlloc().InitWithUUIDString(ns.NSStringWithGoString(p.Identifier))))
|
ps := b.cm.RetrievePeripheralsWithIdentifiers(ns.NSArrayWithObjects(ns.NSUUIDAlloc().InitWithUUIDString(ns.NSStringWithGoString(p.Identifier))))
|
||||||
if (int)(ps.Count()) > 0 {
|
if x := (int)(ps.Count()); x > 0 {
|
||||||
|
fmt.Printf("--found %d\n", x)
|
||||||
p.p = ps.ObjectAtIndex(0).CBPeripheral()
|
p.p = ps.ObjectAtIndex(0).CBPeripheral()
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Printf("--none found\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
item := ConnectionListItem{p, make(chan string)}
|
||||||
|
b.connections.Add(item)
|
||||||
|
go connectTracker(b, item)
|
||||||
|
//time.Sleep(time.Second/10)
|
||||||
b.cm.ConnectPeripheral(p.p, nil)
|
b.cm.ConnectPeripheral(p.p, nil)
|
||||||
fmt.Printf("cm.ConnectPeripheral() returned\n")
|
fmt.Printf("cm.ConnectPeripheral() returned\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateState(c *ns.CBCentralManager) {
|
func updateState(c *ns.CBCentralManager) {
|
||||||
ble := cdLookup[c.Ptr()]
|
b := cdLookup[c.Ptr()]
|
||||||
fmt.Printf("Go: did update state\n")
|
fmt.Printf("Go: did update state\n")
|
||||||
st := c.CBManager.State()
|
st := c.CBManager.State()
|
||||||
if st == (ns.CBManagerState)(ns.CBManagerStatePoweredOn) {
|
if st == (ns.CBManagerState)(ns.CBManagerStatePoweredOn) {
|
||||||
ble.ready = true
|
b.ready = true
|
||||||
|
b.connections.close = make(chan struct{})
|
||||||
} else {
|
} else {
|
||||||
ble.ready = false
|
if b.ready {
|
||||||
|
close(b.connections.close)
|
||||||
|
for _, item := range b.connections.items {
|
||||||
|
fmt.Printf("Closing connection to %s\n", item.p.Name)
|
||||||
|
b.cm.CancelPeripheralConnection(item.p.p)
|
||||||
}
|
}
|
||||||
ble.setState(st)
|
b.connections.items = b.connections.items[:0]
|
||||||
ble.events <- UpdateStateEvent{State: stringState(st)}
|
b.ready = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.setState(st)
|
||||||
|
b.events <- UpdateStateEvent{State: stringState(st)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) {
|
func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDictionary, rssi *ns.NSNumber) {
|
||||||
ble := cdLookup[c.Ptr()]
|
b := cdLookup[c.Ptr()]
|
||||||
peripheral := newPeripheral(p)
|
peripheral := newPeripheral(p)
|
||||||
peripheral.RSSI = (int)(rssi.IntValue())
|
peripheral.RSSI = (int)(rssi.IntValue())
|
||||||
if peripheral.Name == "" {
|
if peripheral.Name == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ok := ble.peripherals.Add(peripheral); ok {
|
if ok := b.peripherals.Add(peripheral); ok {
|
||||||
pdLookup[p.Ptr()] = ble
|
pdLookup[p.Ptr()] = b
|
||||||
ble.events <- DiscoverEvent{Peripheral: peripheral}
|
b.events <- DiscoverEvent{Peripheral: peripheral}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +330,7 @@ func connectPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.connections.UpdateState(peripheral, "connected")
|
||||||
b.events <- ConnectEvent{peripheral}
|
b.events <- ConnectEvent{peripheral}
|
||||||
fmt.Printf("Go: connectPeripheral returning\n")
|
fmt.Printf("Go: connectPeripheral returning\n")
|
||||||
}
|
}
|
||||||
|
@ -260,7 +344,6 @@ func DiscoverServices(x Peripheral) {
|
||||||
p.DiscoverServices(nil)
|
p.DiscoverServices(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func discoverServices(p *ns.CBPeripheral, e *ns.NSError) {
|
func discoverServices(p *ns.CBPeripheral, e *ns.NSError) {
|
||||||
fmt.Printf("Did discover services\n")
|
fmt.Printf("Did discover services\n")
|
||||||
p.Services().ObjectEnumerator().ForIn(func(o *ns.Id) bool {
|
p.Services().ObjectEnumerator().ForIn(func(o *ns.Id) bool {
|
||||||
|
@ -335,7 +418,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBLE() *BLE {
|
func NewBLE() *BLE {
|
||||||
ps := Peripherals{items: make([]PeripheralListItem,0)}
|
ps := Peripherals{items: make([]PeripheralListItem, 0)}
|
||||||
ble := &BLE{events: make(chan interface{}), peripherals: ps}
|
ble := &BLE{events: make(chan interface{}), peripherals: ps}
|
||||||
gble = ble
|
gble = ble
|
||||||
|
|
||||||
|
@ -356,10 +439,10 @@ func NewBLE() *BLE {
|
||||||
|
|
||||||
ble.cd = cd
|
ble.cd = cd
|
||||||
if cdLookup == nil {
|
if cdLookup == nil {
|
||||||
cdLookup = make(map[unsafe.Pointer]*BLE,0)
|
cdLookup = make(map[unsafe.Pointer]*BLE, 0)
|
||||||
}
|
}
|
||||||
if pdLookup == nil {
|
if pdLookup == nil {
|
||||||
pdLookup = make(map[unsafe.Pointer]*BLE,0)
|
pdLookup = make(map[unsafe.Pointer]*BLE, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We defined our own queue because this won't work on the main queue.
|
// We defined our own queue because this won't work on the main queue.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user