Skip to content

Commit 5376bd2

Browse files
committed
all: add SetConnectionLatency to update 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 767271a commit 5376bd2

File tree

7 files changed

+167
-0
lines changed

7 files changed

+167
-0
lines changed

Diff for: Makefile

+4
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
@@ -36,6 +38,7 @@ smoketest-tinygo:
3638
smoketest-linux:
3739
# Test on Linux.
3840
GOOS=linux go build -o /tmp/go-build-discard ./examples/advertisement
41+
GOOS=linux go build -o /tmp/go-build-discard ./examples/connparams
3942
GOOS=linux go build -o /tmp/go-build-discard ./examples/heartrate
4043
GOOS=linux go build -o /tmp/go-build-discard ./examples/heartrate-monitor
4144
GOOS=linux go build -o /tmp/go-build-discard ./examples/nusserver
@@ -45,6 +48,7 @@ smoketest-linux:
4548
smoketest-windows:
4649
# Test on Windows.
4750
GOOS=windows go build -o /tmp/go-build-discard ./examples/scanner
51+
GOOS=windows go build -o /tmp/go-build-discard ./examples/connparams
4852
GOOS=windows go build -o /tmp/go-build-discard ./examples/discover
4953
GOOS=windows go build -o /tmp/go-build-discard ./examples/heartrate-monitor
5054

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.SetConnectionLatency(bluetooth.ConnectionLatency{
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

+13
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,16 @@ type ConnectionParams struct {
404404
MinInterval Duration
405405
MaxInterval Duration
406406
}
407+
408+
// Connection latency and timeout for a connection to a peripheral or central.
409+
type ConnectionLatency struct {
410+
// Connection Supervision Timeout. After this time has passed with no
411+
// communication, the connection is considered lost. If no timeout is
412+
// specified, the timeout will be unchanged.
413+
Timeout Duration
414+
415+
// Minimum and maximum connection interval to be used for this connection.
416+
// Fields that are unset will be unchanged.
417+
MinInterval Duration
418+
MaxInterval Duration
419+
}

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+
// SetConnectionLatency requests a different connection latency and timeout of
180+
// 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) SetConnectionLatency(latency ConnectionLatency) 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
@@ -326,6 +326,17 @@ func (d Device) Disconnect() error {
326326
return d.device.Disconnect()
327327
}
328328

329+
// SetConnectionLatency requests a different connection latency and timeout of
330+
// the given device connection. Fields that are unset will be left alone.
331+
// Whether or not the device will actually honor this, depends on the device and
332+
// on the specific parameters.
333+
//
334+
// On Linux, this call doesn't do anything because BlueZ doesn't support
335+
// changing the connection latency.
336+
func (d Device) SetConnectionLatency(latency ConnectionLatency) error {
337+
return nil
338+
}
339+
329340
// watchForConnect watches for a signal from the bluez device interface that indicates a Connection/Disconnection.
330341
//
331342
// We can add extra signals to watch for here,

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+
// SetConnectionLatency requests a different connection latency and timeout of
193+
// 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) SetConnectionLatency(latency ConnectionLatency) 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 latency.MinInterval != 0 {
209+
connParams.min_conn_interval = C.uint16_t(latency.MinInterval) / 2
210+
}
211+
if latency.MaxInterval != 0 {
212+
connParams.max_conn_interval = C.uint16_t(latency.MaxInterval) / 2
213+
}
214+
if latency.Timeout != 0 {
215+
connParams.conn_sup_timeout = C.uint16_t(latency.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+
// SetConnectionLatency requests a different connection latency and timeout of
252+
// 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) SetConnectionLatency(latency ConnectionLatency) error {
258+
// TODO: implement this using
259+
// BluetoothLEDevice.RequestPreferredConnectionParameters.
260+
return nil
261+
}

0 commit comments

Comments
 (0)