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()
}
|