Skip to content

Commit d74f6a1

Browse files
aykevldeadprogram
authored andcommitted
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 5d805a9 commit d74f6a1

File tree

8 files changed

+170
-1
lines changed

8 files changed

+170
-1
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
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
@@ -42,6 +44,7 @@ smoketest-tinygo:
4244
smoketest-linux:
4345
# Test on Linux.
4446
GOOS=linux go build -o /tmp/go-build-discard ./examples/advertisement
47+
GOOS=linux go build -o /tmp/go-build-discard ./examples/connparams
4548
GOOS=linux go build -o /tmp/go-build-discard ./examples/heartrate
4649
GOOS=linux go build -o /tmp/go-build-discard ./examples/heartrate-monitor
4750
GOOS=linux go build -o /tmp/go-build-discard ./examples/nusserver

examples/connparams/main.go

Lines changed: 84 additions & 0 deletions
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+
}

gap.go

Lines changed: 7 additions & 1 deletion
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
}

gap_darwin.go

Lines changed: 12 additions & 0 deletions
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 {

gap_linux.go

Lines changed: 11 additions & 0 deletions
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+
}

gap_ninafw.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,16 @@ func (d Device) Disconnect() error {
230230
return nil
231231
}
232232

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

gap_nrf528xx-central.go

Lines changed: 31 additions & 0 deletions
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+
}

gap_windows.go

Lines changed: 12 additions & 0 deletions
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)