Skip to content

Commit 31d0fec

Browse files
committed
all: add RequestConnectionParams to request new connection parameters
This allows changing the connection latency, slave latency, and connection timeout of an active connection - whether in the central or peripheral role. This is especially helpful on battery operated BLE devices that don't have a lot of power and need to lower the connection latency for improved speed. It might also be useful for devices that need high speed, as the defaults might be too low.
1 parent a58a503 commit 31d0fec

File tree

8 files changed

+170
-1
lines changed

8 files changed

+170
-1
lines changed

Diff for: Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ smoketest-tinygo:
1111
@md5sum test.hex
1212
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-bluefruit ./examples/circuitplay
1313
@md5sum test.hex
14+
$(TINYGO) build -o test.hex -size=short -target=circuitplay-bluefruit ./examples/connparams
15+
@md5sum test.hex
1416
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-bluefruit ./examples/discover
1517
@md5sum test.hex
1618
$(TINYGO) build -o test.hex -size=short -target=pca10040-s132v6 ./examples/heartrate
@@ -40,6 +42,7 @@ smoketest-tinygo:
4042
smoketest-linux:
4143
# Test on Linux.
4244
GOOS=linux go build -o /tmp/go-build-discard ./examples/advertisement
45+
GOOS=linux go build -o /tmp/go-build-discard ./examples/connparams
4346
GOOS=linux go build -o /tmp/go-build-discard ./examples/heartrate
4447
GOOS=linux go build -o /tmp/go-build-discard ./examples/heartrate-monitor
4548
GOOS=linux go build -o /tmp/go-build-discard ./examples/nusserver

Diff for: examples/connparams/main.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Test for setting connection parameters.
2+
//
3+
// To test this feature, run this either on a desktop OS or by flashing it to a
4+
// device with TinyGo. Then connect to it from a BLE connection debugger, for
5+
// example nRF Connect on Android. After a second, you should see in the log of
6+
// the BLE app that the connection latency has been updated. It might look
7+
// something like this:
8+
//
9+
// Connection parameters updated (interval: 510.0ms, latency: 0, timeout: 10000ms)
10+
package main
11+
12+
import (
13+
"time"
14+
15+
"tinygo.org/x/bluetooth"
16+
)
17+
18+
var (
19+
adapter = bluetooth.DefaultAdapter
20+
newDevice chan bluetooth.Device
21+
)
22+
23+
func main() {
24+
must("enable BLE stack", adapter.Enable())
25+
26+
newDevice = make(chan bluetooth.Device, 1)
27+
adapter.SetConnectHandler(func(device bluetooth.Device, connected bool) {
28+
// If this is a new device, signal it to the separate goroutine.
29+
if connected {
30+
select {
31+
case newDevice <- device:
32+
default:
33+
}
34+
}
35+
})
36+
37+
// Start advertising, so we can be found.
38+
const name = "Go BLE test"
39+
adv := adapter.DefaultAdvertisement()
40+
adv.Configure(bluetooth.AdvertisementOptions{
41+
LocalName: name,
42+
})
43+
adv.Start()
44+
println("advertising:", name)
45+
46+
for device := range newDevice {
47+
println("connection from device:", device.Address.String())
48+
49+
// Discover services and characteristics.
50+
svcs, err := device.DiscoverServices(nil)
51+
if err != nil {
52+
println(" failed to resolve services:", err)
53+
}
54+
for _, svc := range svcs {
55+
println(" service:", svc.UUID().String())
56+
chars, err := svc.DiscoverCharacteristics(nil)
57+
if err != nil {
58+
println(" failed to resolve characteristics:", err)
59+
}
60+
for _, char := range chars {
61+
println(" characteristic:", char.UUID().String())
62+
}
63+
}
64+
65+
// Update connection parameters (as a test).
66+
time.Sleep(time.Second)
67+
err = device.RequestConnectionParams(bluetooth.ConnectionParams{
68+
MinInterval: bluetooth.NewDuration(495 * time.Millisecond),
69+
MaxInterval: bluetooth.NewDuration(510 * time.Millisecond),
70+
Timeout: bluetooth.NewDuration(10 * time.Second),
71+
})
72+
if err != nil {
73+
println(" failed to update connection parameters:", err)
74+
continue
75+
}
76+
println(" updated connection parameters")
77+
}
78+
}
79+
80+
func must(action string, err error) {
81+
if err != nil {
82+
panic("failed to " + action + ": " + err.Error())
83+
}
84+
}

Diff for: gap.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,8 @@ func (buf *rawAdvertisementPayload) addServiceUUID(uuid UUID) (ok bool) {
391391
}
392392
}
393393

394-
// ConnectionParams are used when connecting to a peripherals.
394+
// ConnectionParams are used when connecting to a peripherals or when changing
395+
// the parameters of an active connection.
395396
type ConnectionParams struct {
396397
// The timeout for the connection attempt. Not used during the rest of the
397398
// connection. If no duration is specified, a default timeout will be used.
@@ -403,4 +404,9 @@ type ConnectionParams struct {
403404
// will be used.
404405
MinInterval Duration
405406
MaxInterval Duration
407+
408+
// Connection Supervision Timeout. After this time has passed with no
409+
// communication, the connection is considered lost. If no timeout is
410+
// specified, the timeout will be unchanged.
411+
Timeout Duration
406412
}

Diff for: gap_darwin.go

+12
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,18 @@ func (d Device) Disconnect() error {
176176
return nil
177177
}
178178

179+
// RequestConnectionParams requests a different connection latency and timeout
180+
// of the given device connection. Fields that are unset will be left alone.
181+
// Whether or not the device will actually honor this, depends on the device and
182+
// on the specific parameters.
183+
//
184+
// This call has not yet been implemented on macOS.
185+
func (d Device) RequestConnectionParams(params ConnectionParams) error {
186+
// TODO: implement this using setDesiredConnectionLatency, see:
187+
// https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393277-setdesiredconnectionlatency
188+
return nil
189+
}
190+
179191
// Peripheral delegate functions
180192

181193
type peripheralDelegate struct {

Diff for: gap_linux.go

+11
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,14 @@ func (d Device) Disconnect() error {
366366
// property change in `watchForConnect` and cancel things then
367367
return d.device.Call("org.bluez.Device1.Disconnect", 0).Err
368368
}
369+
370+
// RequestConnectionParams requests a different connection latency and timeout
371+
// of the given device connection. Fields that are unset will be left alone.
372+
// Whether or not the device will actually honor this, depends on the device and
373+
// on the specific parameters.
374+
//
375+
// On Linux, this call doesn't do anything because BlueZ doesn't support
376+
// changing the connection latency.
377+
func (d Device) RequestConnectionParams(params ConnectionParams) error {
378+
return nil
379+
}

Diff for: gap_ninafw.go

+10
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,16 @@ func (d Device) Disconnect() error {
231231
return nil
232232
}
233233

234+
// RequestConnectionParams requests a different connection latency and timeout
235+
// of the given device connection. Fields that are unset will be left alone.
236+
// Whether or not the device will actually honor this, depends on the device and
237+
// on the specific parameters.
238+
//
239+
// On NINA, this call hasn't been implemented yet.
240+
func (d Device) RequestConnectionParams(params ConnectionParams) error {
241+
return nil
242+
}
243+
234244
func (d Device) findNotificationRegistration(handle uint16) *notificationRegistration {
235245
for _, n := range d.notificationRegistrations {
236246
if n.handle == handle {

Diff for: gap_nrf528xx-central.go

+31
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,34 @@ func (d Device) Disconnect() error {
188188

189189
return nil
190190
}
191+
192+
// RequestConnectionParams requests a different connection latency and timeout
193+
// of the given device connection. Fields that are unset will be left alone.
194+
// Whether or not the device will actually honor this, depends on the device and
195+
// on the specific parameters.
196+
//
197+
// On the Nordic SoftDevice, this call will also set the slave latency to 0.
198+
func (d Device) RequestConnectionParams(params ConnectionParams) error {
199+
// The default parameters if no specific parameters are picked.
200+
connParams := C.ble_gap_conn_params_t{
201+
min_conn_interval: C.BLE_GAP_CP_MIN_CONN_INTVL_NONE,
202+
max_conn_interval: C.BLE_GAP_CP_MAX_CONN_INTVL_NONE,
203+
slave_latency: 0,
204+
conn_sup_timeout: C.BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE,
205+
}
206+
207+
// Use specified parameters if available.
208+
if params.MinInterval != 0 {
209+
connParams.min_conn_interval = C.uint16_t(params.MinInterval) / 2
210+
}
211+
if params.MaxInterval != 0 {
212+
connParams.max_conn_interval = C.uint16_t(params.MaxInterval) / 2
213+
}
214+
if params.Timeout != 0 {
215+
connParams.conn_sup_timeout = C.uint16_t(params.Timeout) / 16
216+
}
217+
218+
// Send them to peer device.
219+
errCode := C.sd_ble_gap_conn_param_update(d.connectionHandle, &connParams)
220+
return makeError(errCode)
221+
}

Diff for: gap_windows.go

+12
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,15 @@ func (d Device) Disconnect() error {
247247

248248
return nil
249249
}
250+
251+
// RequestConnectionParams requests a different connection latency and timeout
252+
// of the given device connection. Fields that are unset will be left alone.
253+
// Whether or not the device will actually honor this, depends on the device and
254+
// on the specific parameters.
255+
//
256+
// On Windows, this call doesn't do anything.
257+
func (d Device) RequestConnectionParams(params ConnectionParams) error {
258+
// TODO: implement this using
259+
// BluetoothLEDevice.RequestPreferredConnectionParameters.
260+
return nil
261+
}

0 commit comments

Comments
 (0)