forked from go-ble/ble
/
pmgprdlg.go
136 lines (113 loc) · 3.32 KB
/
pmgprdlg.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// pmgrdlg.go: Implements the PeripheralManagerDelegate interface.
// CoreBluetooth communicates events asynchronously via callbacks. This file
// implements a synchronous interface by translating these callbacks into
// channel operations.
package darwin
import (
"bytes"
"fmt"
"log"
"github.com/JuulLabs-OSS/ble"
"github.com/JuulLabs-OSS/cbgo"
)
func (d *Device) PeripheralManagerDidUpdateState(pmgr cbgo.PeripheralManager) {
d.evl.stateChanged.RxSignal(struct{}{})
}
func (d *Device) DidAddService(pmgr cbgo.PeripheralManager, svc cbgo.Service, err error) {
d.evl.svcAdded.RxSignal(err)
}
func (d *Device) DidStartAdvertising(pmgr cbgo.PeripheralManager, err error) {
d.evl.advStarted.RxSignal(err)
}
func (d *Device) DidReceiveReadRequest(pmgr cbgo.PeripheralManager, cbreq cbgo.ATTRequest) {
chr, _ := d.pc.findChr(cbreq.Characteristic())
if chr == nil || chr.ReadHandler == nil {
return
}
c := d.findConn(cbreq.Central().Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cbreq.Central())
if err != nil {
log.Printf("failed to process read response: %v", err)
return
}
}
req := ble.NewRequest(c, nil, cbreq.Offset())
buf := bytes.NewBuffer(make([]byte, 0, c.txMTU-1))
rsp := ble.NewResponseWriter(buf)
chr.ReadHandler.ServeRead(req, rsp)
cbreq.SetValue(buf.Bytes())
pmgr.RespondToRequest(cbreq, cbgo.ATTError(rsp.Status()))
}
func (d *Device) DidReceiveWriteRequests(pmgr cbgo.PeripheralManager, cbreqs []cbgo.ATTRequest) {
serveOne := func(cbreq cbgo.ATTRequest) {
chr, _ := d.pc.findChr(cbreq.Characteristic())
if chr == nil || chr.WriteHandler == nil {
return
}
c := d.findConn(cbreq.Central().Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cbreq.Central())
if err != nil {
log.Printf("failed to process write response: %v", err)
return
}
}
req := ble.NewRequest(c, cbreq.Value(), cbreq.Offset())
rsp := ble.NewResponseWriter(nil)
chr.WriteHandler.ServeWrite(req, rsp)
pmgr.RespondToRequest(cbreq, cbgo.ATTError(rsp.Status()))
}
for _, cbreq := range cbreqs {
serveOne(cbreq)
}
}
func (d *Device) CentralDidSubscribe(pmgr cbgo.PeripheralManager, cent cbgo.Central, cbchr cbgo.Characteristic) {
c := d.findConn(cent.Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cent)
if err != nil {
log.Printf("failed to process subscribe request: %v", err)
return
}
}
if c.notifiers[cbchr] != nil {
return
}
chr, _ := d.pc.findChr(cbchr)
if chr == nil {
return
}
send := func(b []byte) (int, error) {
sent := d.pm.UpdateValue(b, cbchr, nil)
if !sent {
return len(b), fmt.Errorf("failed to send notification: tx queue full")
}
return len(b), nil
}
n := ble.NewNotifier(send)
c.notifiers[cbchr] = n
req := ble.NewRequest(c, nil, 0) // convey *conn to user handler.
go chr.NotifyHandler.ServeNotify(req, n)
}
func (d *Device) CentralDidUnsubscribe(pmgr cbgo.PeripheralManager, cent cbgo.Central, chr cbgo.Characteristic) {
c := d.findConn(cent.Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cent)
if err != nil {
log.Printf("failed to process unsubscribe request: %v", err)
return
}
}
n := c.notifiers[chr]
if n != nil {
if err := n.Close(); err != nil {
log.Printf("failed to close notifier: %v", err)
}
delete(c.notifiers, chr)
}
}