Skip to content

Commit 434206b

Browse files
committed
feat(gap): add DiscoverServicesWithContext DiscoverCharacteristicsWithContext WriteWithContext and ReadWithContext
Related #339
1 parent dadb65c commit 434206b

File tree

2 files changed

+63
-8
lines changed

2 files changed

+63
-8
lines changed

gap_darwin.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ func (ad *Address) Set(val string) {
3939
// Scan starts a BLE scan. It is stopped by a call to StopScan. A common pattern
4040
// is to cancel the scan when a particular device has been found.
4141
func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) (err error) {
42+
return a.ScanWithContext(context.Background(), callback)
43+
}
44+
45+
// ScanWithContext starts a BLE scan. It is stopped by a call to StopScan. A common pattern
46+
// is to cancel the scan when a particular device has been found.
47+
func (a *Adapter) ScanWithContext(ctx context.Context, callback func(*Adapter, ScanResult)) (err error) {
4248
if callback == nil {
4349
return errors.New("must provide callback to Scan function")
4450
}
@@ -63,6 +69,11 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) (err error) {
6369
// the callback calls StopScan() (no new callbacks may be called after
6470
// StopScan is called).
6571
select {
72+
case <-ctx.Done():
73+
// StopScan can return an error, but we ignore it here since
74+
// it only returns an error if no scan is in progress.
75+
_ = a.StopScan()
76+
return ctx.Err()
6677
case <-a.scanChan:
6778
close(a.scanChan)
6879
a.scanChan = nil

gattc_darwin.go

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package bluetooth
22

33
import (
4+
"context"
45
"errors"
56
"time"
67

@@ -15,6 +16,19 @@ import (
1516
// Passing a nil slice of UUIDs will return a complete list of
1617
// services.
1718
func (d Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
19+
ctx, cancel := context.WithTimeoutCause(context.Background(), 10*time.Second, errors.New("timeout on DiscoverServices"))
20+
defer cancel()
21+
return d.DiscoverServicesWithContext(ctx, uuids)
22+
}
23+
24+
// DiscoverServicesWithContext starts a service discovery procedure. Pass a list of service
25+
// UUIDs you are interested in to this function. Either a slice of all services
26+
// is returned (of the same length as the requested UUIDs and in the same
27+
// order), or if some services could not be discovered an error is returned.
28+
//
29+
// Passing a nil slice of UUIDs will return a complete list of
30+
// services.
31+
func (d Device) DiscoverServicesWithContext(ctx context.Context, uuids []UUID) ([]DeviceService, error) {
1832
d.prph.DiscoverServices([]cbgo.UUID{})
1933

2034
// clear cache of services
@@ -52,8 +66,8 @@ func (d Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
5266
d.services[svc.uuidWrapper] = svc
5367
}
5468
return svcs, nil
55-
case <-time.NewTimer(10 * time.Second).C:
56-
return nil, errors.New("timeout on DiscoverServices")
69+
case <-ctx.Done():
70+
return nil, ctx.Err()
5771
}
5872
}
5973

@@ -90,6 +104,21 @@ func (s DeviceService) UUID() UUID {
90104
// Passing a nil slice of UUIDs will return a complete list of
91105
// characteristics.
92106
func (s DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacteristic, error) {
107+
ctx, cancel := context.WithTimeoutCause(context.Background(), 10*time.Second, errors.New("timeout on DiscoverCharacteristics"))
108+
defer cancel()
109+
return s.DiscoverCharacteristicsWithContext(ctx, uuids)
110+
}
111+
112+
// DiscoverCharacteristicsWithContext discovers characteristics in this service. Pass a
113+
// list of characteristic UUIDs you are interested in to this function. Either a
114+
// list of all requested services is returned, or if some services could not be
115+
// discovered an error is returned. If there is no error, the characteristics
116+
// slice has the same length as the UUID slice with characteristics in the same
117+
// order in the slice as in the requested UUID list.
118+
//
119+
// Passing a nil slice of UUIDs will return a complete list of
120+
// characteristics.
121+
func (s DeviceService) DiscoverCharacteristicsWithContext(ctx context.Context, uuids []UUID) ([]DeviceCharacteristic, error) {
93122
cbuuids := []cbgo.UUID{}
94123

95124
s.device.prph.DiscoverCharacteristics(cbuuids, s.service)
@@ -136,8 +165,8 @@ func (s DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacteri
136165
}
137166
}
138167
return chars, nil
139-
case <-time.NewTimer(10 * time.Second).C:
140-
return nil, errors.New("timeout on DiscoverCharacteristics")
168+
case <-ctx.Done():
169+
return nil, ctx.Err()
141170
}
142171
}
143172

@@ -179,13 +208,21 @@ func (c DeviceCharacteristic) UUID() UUID {
179208
// Write replaces the characteristic value with a new value. The
180209
// call will return after all data has been written.
181210
func (c DeviceCharacteristic) Write(p []byte) (n int, err error) {
211+
ctx, cancel := context.WithTimeoutCause(context.Background(), 10*time.Second, errors.New("timeout on Write()"))
212+
defer cancel()
213+
return c.WriteWithContext(ctx, p)
214+
}
215+
216+
// WriteWithContext replaces the characteristic value with a new value. The
217+
// call will return after all data has been written.
218+
func (c DeviceCharacteristic) WriteWithContext(ctx context.Context, p []byte) (n int, err error) {
182219
c.writeChan = make(chan error)
183220
c.service.device.prph.WriteCharacteristic(p, c.characteristic, true)
184221

185222
// wait for result
186223
select {
187-
case <-time.NewTimer(10 * time.Second).C:
188-
err = errors.New("timeout on Write()")
224+
case <-ctx.Done():
225+
err = ctx.Err()
189226
case err = <-c.writeChan:
190227
}
191228

@@ -229,6 +266,13 @@ func (c DeviceCharacteristic) GetMTU() (uint16, error) {
229266

230267
// Read reads the current characteristic value.
231268
func (c *deviceCharacteristic) Read(data []byte) (n int, err error) {
269+
ctx, cancel := context.WithTimeoutCause(context.Background(), 10*time.Second, errors.New("timeout on Read()"))
270+
defer cancel()
271+
return c.ReadWithContext(ctx, data)
272+
}
273+
274+
// ReadWithContext reads the current characteristic value.
275+
func (c *deviceCharacteristic) ReadWithContext(ctx context.Context, data []byte) (n int, err error) {
232276
c.readChan = make(chan error)
233277
c.service.device.prph.ReadCharacteristic(c.characteristic)
234278

@@ -239,9 +283,9 @@ func (c *deviceCharacteristic) Read(data []byte) (n int, err error) {
239283
if err != nil {
240284
return 0, err
241285
}
242-
case <-time.NewTimer(10 * time.Second).C:
286+
case <-ctx.Done():
243287
c.readChan = nil
244-
return 0, errors.New("timeout on Read()")
288+
return 0, ctx.Err()
245289
}
246290

247291
copy(data, c.characteristic.Value())

0 commit comments

Comments
 (0)