Add connection tracking and timeouts.

This commit is contained in:
Greg 2019-10-24 17:00:54 -04:00
parent c91c83de9c
commit 64b684e419
1 changed files with 116 additions and 33 deletions

View File

@ -14,31 +14,30 @@ import (
) )
type BLE struct { type BLE struct {
events chan interface{} state ns.CBManagerState
events chan interface{}
state ns.CBManagerState
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
type Peripheral struct { type Peripheral struct {
Name string Name string
RSSI int RSSI int
Identifier string Identifier string
p *ns.CBPeripheral p *ns.CBPeripheral
} }
func peripheralName(p *ns.CBPeripheral) string { func peripheralName(p *ns.CBPeripheral) string {
@ -52,14 +51,14 @@ func peripheralName(p *ns.CBPeripheral) string {
func newPeripheral(x *ns.CBPeripheral) Peripheral { func newPeripheral(x *ns.CBPeripheral) Peripheral {
return Peripheral{ return Peripheral{
Name: peripheralName(x), Name: peripheralName(x),
Identifier: x.Identifier().UUIDString().String(), Identifier: x.Identifier().UUIDString().String(),
p: x, p: x,
} }
} }
type PeripheralListItem struct { type PeripheralListItem struct {
p Peripheral p Peripheral
seen time.Time seen time.Time
} }
@ -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)
}
b.connections.items = b.connections.items[:0]
b.ready = false
}
} }
ble.setState(st) b.setState(st)
ble.events <- UpdateStateEvent{State: stringState(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 {
@ -327,15 +410,15 @@ func updateValue(p *ns.CBPeripheral, chr *ns.CBCharacteristic, e *ns.NSError) {
} }
var ( var (
hrm_uuid *ns.CBUUID hrm_uuid *ns.CBUUID
hrv_uuid *ns.CBUUID hrv_uuid *ns.CBUUID
info_uuid *ns.CBUUID info_uuid *ns.CBUUID
gble *BLE gble *BLE
) )
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.