forked from currantlabs/gatt
-
Notifications
You must be signed in to change notification settings - Fork 3
/
central.go
152 lines (126 loc) · 4.01 KB
/
central.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package gatt
import (
"bytes"
"errors"
"fmt"
"sync"
)
// Central is the interface that represent a remote central device.
type Central interface {
ID() string // ID returns platform specific ID of the remote central device.
Close() error // Close disconnects the connection.
MTU() int // MTU returns the current connection mtu.
}
type ResponseWriter interface {
// Write writes data to return as the characteristic value.
Write([]byte) (int, error)
// SetStatus reports the result of the read operation. See the Status* constants.
SetStatus(byte)
}
// responseWriter is the default implementation of ResponseWriter.
type responseWriter struct {
capacity int
buf *bytes.Buffer
status byte
}
func newResponseWriter(c int) *responseWriter {
return &responseWriter{
capacity: c,
buf: new(bytes.Buffer),
status: StatusSuccess,
}
}
func (w *responseWriter) Write(b []byte) (int, error) {
if avail := w.capacity - w.buf.Len(); avail < len(b) {
return 0, fmt.Errorf("requested write %d bytes, %d available", len(b), avail)
}
return w.buf.Write(b)
}
func (w *responseWriter) SetStatus(status byte) { w.status = status }
func (w *responseWriter) bytes() []byte { return w.buf.Bytes() }
// A ReadHandler handles GATT read requests.
type ReadHandler interface {
ServeRead(resp ResponseWriter, req *ReadRequest)
}
// ReadHandlerFunc is an adapter to allow the use of
// ordinary functions as ReadHandlers. If f is a function
// with the appropriate signature, ReadHandlerFunc(f) is a
// ReadHandler that calls f.
type ReadHandlerFunc func(resp ResponseWriter, req *ReadRequest)
// ServeRead returns f(r, maxlen, offset).
func (f ReadHandlerFunc) ServeRead(resp ResponseWriter, req *ReadRequest) {
f(resp, req)
}
// A WriteHandler handles GATT write requests.
// Write and WriteNR requests are presented identically;
// the server will ensure that a response is sent if appropriate.
type WriteHandler interface {
ServeWrite(r Request, data []byte) (status byte)
}
// WriteHandlerFunc is an adapter to allow the use of
// ordinary functions as WriteHandlers. If f is a function
// with the appropriate signature, WriteHandlerFunc(f) is a
// WriteHandler that calls f.
type WriteHandlerFunc func(r Request, data []byte) byte
// ServeWrite returns f(r, data).
func (f WriteHandlerFunc) ServeWrite(r Request, data []byte) byte {
return f(r, data)
}
// A NotifyHandler handles GATT notification requests.
// Notifications can be sent using the provided notifier.
type NotifyHandler interface {
ServeNotify(r Request, n Notifier)
}
// NotifyHandlerFunc is an adapter to allow the use of
// ordinary functions as NotifyHandlers. If f is a function
// with the appropriate signature, NotifyHandlerFunc(f) is a
// NotifyHandler that calls f.
type NotifyHandlerFunc func(r Request, n Notifier)
// ServeNotify calls f(r, n).
func (f NotifyHandlerFunc) ServeNotify(r Request, n Notifier) {
f(r, n)
}
// A Notifier provides a means for a GATT server to send
// notifications about value changes to a connected device.
// Notifiers are provided by NotifyHandlers.
type Notifier interface {
// Write sends data to the central.
Write(data []byte) (int, error)
// Done reports whether the central has requested not to
// receive any more notifications with this notifier.
Done() bool
// Cap returns the maximum number of bytes that may be sent
// in a single notification.
Cap() int
}
type notifier struct {
central *central
a *attr
maxlen int
donemu sync.RWMutex
done bool
}
func newNotifier(c *central, a *attr, maxlen int) *notifier {
return ¬ifier{central: c, a: a, maxlen: maxlen}
}
func (n *notifier) Write(b []byte) (int, error) {
n.donemu.RLock()
defer n.donemu.RUnlock()
if n.done {
return 0, errors.New("central stopped notifications")
}
return n.central.sendNotification(n.a, b)
}
func (n *notifier) Cap() int {
return n.maxlen
}
func (n *notifier) Done() bool {
n.donemu.RLock()
defer n.donemu.RUnlock()
return n.done
}
func (n *notifier) stop() {
n.donemu.Lock()
n.done = true
n.donemu.Unlock()
}