Skip to content

Commit 1977267

Browse files
committed
WIP all: make Device a value instead of a pointer
This is a refactor that is necessary to make it easier to work with connected central devices on a SoftDevice.
1 parent f23703e commit 1977267

File tree

10 files changed

+57
-45
lines changed

10 files changed

+57
-45
lines changed

examples/discover/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func main() {
4444
}
4545
})
4646

47-
var device *bluetooth.Device
47+
var device bluetooth.Device
4848
select {
4949
case result := <-ch:
5050
device, err = adapter.Connect(result.Address, bluetooth.ConnectionParams{})

examples/heartrate-monitor/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func main() {
5252
}
5353
})
5454

55-
var device *bluetooth.Device
55+
var device bluetooth.Device
5656
select {
5757
case result := <-ch:
5858
device, err = adapter.Connect(result.Address, bluetooth.ConnectionParams{})

gap_darwin.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ func (a *Adapter) StopScan() error {
8585

8686
// Device is a connection to a remote peripheral.
8787
type Device struct {
88+
*deviceInternal
89+
}
90+
91+
type deviceInternal struct {
8892
delegate *peripheralDelegate
8993

9094
cm cbgo.CentralManager
@@ -97,14 +101,14 @@ type Device struct {
97101
}
98102

99103
// Connect starts a connection attempt to the given peripheral device address.
100-
func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, error) {
104+
func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, error) {
101105
uuid, err := cbgo.ParseUUID(address.UUID.String())
102106
if err != nil {
103-
return nil, err
107+
return Device{}, err
104108
}
105109
prphs := a.cm.RetrievePeripheralsWithIdentifiers([]cbgo.UUID{uuid})
106110
if len(prphs) == 0 {
107-
return nil, fmt.Errorf("Connect failed: no peer with address: %s", address.UUID.String())
111+
return Device{}, fmt.Errorf("Connect failed: no peer with address: %s", address.UUID.String())
108112
}
109113

110114
timeout := defaultConnectionTimeout
@@ -129,14 +133,16 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
129133

130134
// check if we have received a disconnected peripheral
131135
if p.State() == cbgo.PeripheralStateDisconnected {
132-
return nil, connectionError
136+
return Device{}, connectionError
133137
}
134138

135-
d := &Device{
136-
cm: a.cm,
137-
prph: p,
138-
servicesChan: make(chan error),
139-
charsChan: make(chan error),
139+
d := Device{
140+
&deviceInternal{
141+
cm: a.cm,
142+
prph: p,
143+
servicesChan: make(chan error),
144+
charsChan: make(chan error),
145+
},
140146
}
141147

142148
d.delegate = &peripheralDelegate{d: d}
@@ -162,7 +168,7 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
162168

163169
// Disconnect from the BLE device. This method is non-blocking and does not
164170
// wait until the connection is fully gone.
165-
func (d *Device) Disconnect() error {
171+
func (d Device) Disconnect() error {
166172
d.cm.CancelConnect(d.prph)
167173
return nil
168174
}
@@ -172,7 +178,7 @@ func (d *Device) Disconnect() error {
172178
type peripheralDelegate struct {
173179
cbgo.PeripheralDelegateBase
174180

175-
d *Device
181+
d Device
176182
}
177183

178184
// DidDiscoverServices is called when the services for a Peripheral

gap_linux.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ func makeScanResult(props *device.Device1Properties) ScanResult {
272272

273273
// Device is a connection to a remote peripheral.
274274
type Device struct {
275+
*deviceInternal
276+
}
277+
278+
type deviceInternal struct {
275279
device *device.Device1 // bluez device interface
276280
ctx context.Context // context for our event watcher, canceled on disconnect event
277281
cancel context.CancelFunc // cancel function to halt our event watcher context
@@ -283,17 +287,19 @@ type Device struct {
283287
// Connect starts a connection attempt to the given peripheral device address.
284288
//
285289
// On Linux and Windows, the IsRandom part of the address is ignored.
286-
func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, error) {
290+
func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, error) {
287291
devicePath := dbus.ObjectPath(string(a.adapter.Path()) + "/dev_" + strings.Replace(address.MAC.String(), ":", "_", -1))
288292
dev, err := device.NewDevice1(devicePath)
289293
if err != nil {
290-
return nil, err
294+
return Device{}, err
291295
}
292296

293-
device := &Device{
294-
device: dev,
295-
adapter: a,
296-
address: address,
297+
device := Device{
298+
&deviceInternal{
299+
device: dev,
300+
adapter: a,
301+
address: address,
302+
},
297303
}
298304
device.ctx, device.cancel = context.WithCancel(context.Background())
299305
device.watchForConnect() // Set this up before we trigger a connection so we can capture the connect event
@@ -304,7 +310,7 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
304310
err := dev.Connect()
305311
if err != nil {
306312
device.cancel() // cancel our watcher routine
307-
return nil, err
313+
return Device{}, err
308314
}
309315
}
310316

@@ -313,7 +319,7 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
313319

314320
// Disconnect from the BLE device. This method is non-blocking and does not
315321
// wait until the connection is fully gone.
316-
func (d *Device) Disconnect() error {
322+
func (d Device) Disconnect() error {
317323
// we don't call our cancel function here, instead we wait for the
318324
// property change in `watchForConnect` and cancel things then
319325
return d.device.Disconnect()
@@ -323,7 +329,7 @@ func (d *Device) Disconnect() error {
323329
//
324330
// We can add extra signals to watch for here,
325331
// see https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt, for a full list
326-
func (d *Device) watchForConnect() error {
332+
func (d Device) watchForConnect() error {
327333
var err error
328334
d.propchanged, err = d.device.WatchProperties()
329335
if err != nil {

gap_nrf528xx-central.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ var connectionAttempt struct {
109109
// connection attempt at once and that the address parameter must have the
110110
// IsRandom bit set correctly. This bit is set correctly for scan results, so
111111
// you can reuse that address directly.
112-
func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, error) {
112+
func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, error) {
113113
// Construct an address object as used in the SoftDevice.
114114
var addr C.ble_gap_addr_t
115115
addr.addr = makeSDAddress(address.MAC)
@@ -158,15 +158,15 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
158158
// This should be safe as long as Connect is not called concurrently. And
159159
// even then, it should catch most such race conditions.
160160
if connectionAttempt.state.Get() != 0 {
161-
return nil, errAlreadyConnecting
161+
return Device{}, errAlreadyConnecting
162162
}
163163
connectionAttempt.state.Set(1)
164164

165165
// Start the connection attempt. We'll get a signal in the event handler.
166166
errCode := C.sd_ble_gap_connect(&addr, &scanParams, &connectionParams, C.BLE_CONN_CFG_TAG_DEFAULT)
167167
if errCode != 0 {
168168
connectionAttempt.state.Set(0)
169-
return nil, Error(errCode)
169+
return Device{}, Error(errCode)
170170
}
171171

172172
// Wait until the connection is established.
@@ -179,13 +179,13 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
179179
connectionAttempt.state.Set(0)
180180

181181
// Connection has been established.
182-
return &Device{
182+
return Device{
183183
connectionHandle: connectionHandle,
184184
}, nil
185185
}
186186

187187
// Disconnect from the BLE device.
188-
func (d *Device) Disconnect() error {
188+
func (d Device) Disconnect() error {
189189
errCode := C.sd_ble_gap_disconnect(d.connectionHandle, C.BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)
190190
if errCode != 0 {
191191
return Error(errCode)

gap_windows.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ type Device struct {
170170
// Connect starts a connection attempt to the given peripheral device address.
171171
//
172172
// On Linux and Windows, the IsRandom part of the address is ignored.
173-
func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, error) {
173+
func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, error) {
174174
var winAddr uint64
175175
for i := range address.MAC {
176176
winAddr += uint64(address.MAC[i]) << (8 * i)
@@ -179,23 +179,23 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
179179
// IAsyncOperation<BluetoothLEDevice>
180180
bleDeviceOp, err := bluetooth.FromBluetoothAddressAsync(winAddr)
181181
if err != nil {
182-
return nil, err
182+
return Device{}, err
183183
}
184184

185185
// We need to pass the signature of the parameter returned by the async operation:
186186
// IAsyncOperation<BluetoothLEDevice>
187187
if err := awaitAsyncOperation(bleDeviceOp, bluetooth.SignatureBluetoothLEDevice); err != nil {
188-
return nil, fmt.Errorf("error connecting to device: %w", err)
188+
return Device{}, fmt.Errorf("error connecting to device: %w", err)
189189
}
190190

191191
res, err := bleDeviceOp.GetResults()
192192
if err != nil {
193-
return nil, err
193+
return Device{}, err
194194
}
195195

196196
// The returned BluetoothLEDevice is set to null if FromBluetoothAddressAsync can't find the device identified by bluetoothAddress
197197
if uintptr(res) == 0x0 {
198-
return nil, fmt.Errorf("device with the given address was not found")
198+
return Device{}, fmt.Errorf("device with the given address was not found")
199199
}
200200

201201
bleDevice := (*bluetooth.BluetoothLEDevice)(res)
@@ -204,37 +204,37 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (*Device, er
204204
// To initiate a connection, we need to set GattSession.MaintainConnection to true.
205205
dID, err := bleDevice.GetBluetoothDeviceId()
206206
if err != nil {
207-
return nil, err
207+
return Device{}, err
208208
}
209209

210210
// Windows does not support explicitly connecting to a device.
211211
// Instead it has the concept of a GATT session that is owned
212212
// by the calling program.
213213
gattSessionOp, err := genericattributeprofile.FromDeviceIdAsync(dID) // IAsyncOperation<GattSession>
214214
if err != nil {
215-
return nil, err
215+
return Device{}, err
216216
}
217217

218218
if err := awaitAsyncOperation(gattSessionOp, genericattributeprofile.SignatureGattSession); err != nil {
219-
return nil, fmt.Errorf("error getting gatt session: %w", err)
219+
return Device{}, fmt.Errorf("error getting gatt session: %w", err)
220220
}
221221

222222
gattRes, err := gattSessionOp.GetResults()
223223
if err != nil {
224-
return nil, err
224+
return Device{}, err
225225
}
226226
newSession := (*genericattributeprofile.GattSession)(gattRes)
227227
// This keeps the device connected until we set maintain_connection = False.
228228
if err := newSession.SetMaintainConnection(true); err != nil {
229-
return nil, err
229+
return Device{}, err
230230
}
231231

232-
return &Device{bleDevice, newSession}, nil
232+
return Device{bleDevice, newSession}, nil
233233
}
234234

235235
// Disconnect from the BLE device. This method is non-blocking and does not
236236
// wait until the connection is fully gone.
237-
func (d *Device) Disconnect() error {
237+
func (d Device) Disconnect() error {
238238
defer d.device.Release()
239239
defer d.session.Release()
240240

gattc_darwin.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
//
1515
// Passing a nil slice of UUIDs will return a complete list of
1616
// services.
17-
func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
17+
func (d Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
1818
d.prph.DiscoverServices([]cbgo.UUID{})
1919

2020
// clear cache of services
@@ -69,7 +69,7 @@ type DeviceService struct {
6969
type deviceService struct {
7070
uuidWrapper
7171

72-
device *Device
72+
device Device
7373

7474
service cbgo.Service
7575
characteristics []DeviceCharacteristic

gattc_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (s *DeviceService) UUID() UUID {
4343
//
4444
// On Linux with BlueZ, this just waits for the ServicesResolved signal (if
4545
// services haven't been resolved yet) and uses this list of cached services.
46-
func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
46+
func (d Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
4747
start := time.Now()
4848

4949
for {

gattc_sd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (s *DeviceService) UUID() UUID {
5959
//
6060
// On the Nordic SoftDevice, only one service discovery procedure may be done at
6161
// a time.
62-
func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
62+
func (d Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
6363
if discoveringService.state.Get() != 0 {
6464
// Not concurrency safe, but should catch most concurrency misuses.
6565
return nil, errAlreadyDiscovering

gattc_windows.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var (
3030
//
3131
// Passing a nil slice of UUIDs will return a complete list of
3232
// services.
33-
func (d *Device) DiscoverServices(filterUUIDs []UUID) ([]DeviceService, error) {
33+
func (d Device) DiscoverServices(filterUUIDs []UUID) ([]DeviceService, error) {
3434
// IAsyncOperation<GattDeviceServicesResult>
3535
getServicesOperation, err := d.device.GetGattServicesWithCacheModeAsync(bluetooth.BluetoothCacheModeUncached)
3636
if err != nil {
@@ -133,7 +133,7 @@ type DeviceService struct {
133133
uuidWrapper
134134

135135
service *genericattributeprofile.GattDeviceService
136-
device *Device
136+
device Device
137137
}
138138

139139
// UUID returns the UUID for this DeviceService.

0 commit comments

Comments
 (0)