all: use Device instead of Address in SetConnectHandler

This makes it possible to discover services on a connected central while
in peripheral mode, for example.
This commit is contained in:
Ayke van Laethem 2023-12-25 14:52:10 +01:00 committed by Ron Evans
parent c9eafaff20
commit 5d805a929c
15 changed files with 65 additions and 32 deletions

View file

@ -6,6 +6,6 @@ const debug = false
// SetConnectHandler sets a handler function to be called whenever the adaptor connects // SetConnectHandler sets a handler function to be called whenever the adaptor connects
// or disconnects. You must call this before you call adaptor.Connect() for centrals // or disconnects. You must call this before you call adaptor.Connect() for centrals
// or adaptor.Start() for peripherals in order for it to work. // or adaptor.Start() for peripherals in order for it to work.
func (a *Adapter) SetConnectHandler(c func(device Address, connected bool)) { func (a *Adapter) SetConnectHandler(c func(device Device, connected bool)) {
a.connectHandler = c a.connectHandler = c
} }

View file

@ -24,7 +24,7 @@ type Adapter struct {
// used to allow multiple callers to call Connect concurrently. // used to allow multiple callers to call Connect concurrently.
connectMap sync.Map connectMap sync.Map
connectHandler func(device Address, connected bool) connectHandler func(device Device, connected bool)
} }
// DefaultAdapter is the default adapter on the system. // DefaultAdapter is the default adapter on the system.
@ -35,7 +35,7 @@ var DefaultAdapter = &Adapter{
pm: cbgo.NewPeripheralManager(nil), pm: cbgo.NewPeripheralManager(nil),
connectMap: sync.Map{}, connectMap: sync.Map{},
connectHandler: func(device Address, connected bool) { connectHandler: func(device Device, connected bool) {
return return
}, },
} }
@ -106,7 +106,7 @@ func (cmd *centralManagerDelegate) DidDisconnectPeripheral(cmgr cbgo.CentralMana
addr := Address{} addr := Address{}
uuid, _ := ParseUUID(id) uuid, _ := ParseUUID(id)
addr.UUID = uuid addr.UUID = uuid
cmd.a.connectHandler(addr, false) cmd.a.connectHandler(Device{Address: addr}, false)
// like with DidConnectPeripheral, check if we have a chan allocated for this and send through the peripheral // like with DidConnectPeripheral, check if we have a chan allocated for this and send through the peripheral
// this will only be true if the receiving side is still waiting for a connection to complete // this will only be true if the receiving side is still waiting for a connection to complete

View file

@ -23,7 +23,7 @@ type Adapter struct {
address string address string
defaultAdvertisement *Advertisement defaultAdvertisement *Advertisement
connectHandler func(device Address, connected bool) connectHandler func(device Device, connected bool)
} }
// DefaultAdapter is the default adapter on the system. On Linux, it is the // DefaultAdapter is the default adapter on the system. On Linux, it is the
@ -32,7 +32,7 @@ type Adapter struct {
// Make sure to call Enable() before using it to initialize the adapter. // Make sure to call Enable() before using it to initialize the adapter.
var DefaultAdapter = &Adapter{ var DefaultAdapter = &Adapter{
id: defaultAdapter, id: defaultAdapter,
connectHandler: func(device Address, connected bool) { connectHandler: func(device Device, connected bool) {
}, },
} }

View file

@ -19,7 +19,7 @@ type Adapter struct {
isDefault bool isDefault bool
scanning bool scanning bool
connectHandler func(device Address, connected bool) connectHandler func(device Device, connected bool)
connectedDevices []Device connectedDevices []Device
notificationsStarted bool notificationsStarted bool
@ -30,7 +30,7 @@ type Adapter struct {
// Make sure to call Enable() before using it to initialize the adapter. // Make sure to call Enable() before using it to initialize the adapter.
var DefaultAdapter = &Adapter{ var DefaultAdapter = &Adapter{
isDefault: true, isDefault: true,
connectHandler: func(device Address, connected bool) { connectHandler: func(device Device, connected bool) {
return return
}, },
connectedDevices: make([]Device, 0, maxConnections), connectedDevices: make([]Device, 0, maxConnections),

View file

@ -44,8 +44,11 @@ func handleEvent() {
case C.BLE_GAP_EVT_CONNECTED: case C.BLE_GAP_EVT_CONNECTED:
currentConnection.handle.Reg = uint16(gapEvent.conn_handle) currentConnection.handle.Reg = uint16(gapEvent.conn_handle)
connectEvent := gapEvent.params.unionfield_connected() connectEvent := gapEvent.params.unionfield_connected()
address := Address{makeMACAddress(connectEvent.peer_addr)} device := Device{
DefaultAdapter.connectHandler(address, true) Address: Address{makeMACAddress(connectEvent.peer_addr)},
connectionHandle: gapEvent.conn_handle,
}
DefaultAdapter.connectHandler(device, true)
case C.BLE_GAP_EVT_DISCONNECTED: case C.BLE_GAP_EVT_DISCONNECTED:
if defaultAdvertisement.isAdvertising.Get() != 0 { if defaultAdvertisement.isAdvertising.Get() != 0 {
// The advertisement was running but was automatically stopped // The advertisement was running but was automatically stopped
@ -57,7 +60,10 @@ func handleEvent() {
defaultAdvertisement.start() defaultAdvertisement.start()
} }
currentConnection.handle.Reg = C.BLE_CONN_HANDLE_INVALID currentConnection.handle.Reg = C.BLE_CONN_HANDLE_INVALID
DefaultAdapter.connectHandler(Address{}, false) device := Device{
connectionHandle: gapEvent.conn_handle,
}
DefaultAdapter.connectHandler(device, false)
case C.BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: case C.BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
// Respond with the default PPCP connection parameters by passing // Respond with the default PPCP connection parameters by passing
// nil: // nil:

View file

@ -25,21 +25,24 @@ func handleEvent() {
switch id { switch id {
case C.BLE_GAP_EVT_CONNECTED: case C.BLE_GAP_EVT_CONNECTED:
connectEvent := gapEvent.params.unionfield_connected() connectEvent := gapEvent.params.unionfield_connected()
address := Address{makeMACAddress(connectEvent.peer_addr)} device := Device{
Address: Address{makeMACAddress(connectEvent.peer_addr)},
connectionHandle: gapEvent.conn_handle,
}
switch connectEvent.role { switch connectEvent.role {
case C.BLE_GAP_ROLE_PERIPH: case C.BLE_GAP_ROLE_PERIPH:
if debug { if debug {
println("evt: connected in peripheral role") println("evt: connected in peripheral role")
} }
currentConnection.handle.Reg = uint16(gapEvent.conn_handle) currentConnection.handle.Reg = uint16(gapEvent.conn_handle)
DefaultAdapter.connectHandler(address, true) DefaultAdapter.connectHandler(device, true)
case C.BLE_GAP_ROLE_CENTRAL: case C.BLE_GAP_ROLE_CENTRAL:
if debug { if debug {
println("evt: connected in central role") println("evt: connected in central role")
} }
connectionAttempt.connectionHandle = gapEvent.conn_handle connectionAttempt.connectionHandle = gapEvent.conn_handle
connectionAttempt.state.Set(2) // connection was successful connectionAttempt.state.Set(2) // connection was successful
DefaultAdapter.connectHandler(address, true) DefaultAdapter.connectHandler(device, true)
} }
case C.BLE_GAP_EVT_DISCONNECTED: case C.BLE_GAP_EVT_DISCONNECTED:
if debug { if debug {
@ -62,7 +65,10 @@ func handleEvent() {
// necessary. // necessary.
C.sd_ble_gap_adv_start(defaultAdvertisement.handle, C.BLE_CONN_CFG_TAG_DEFAULT) C.sd_ble_gap_adv_start(defaultAdvertisement.handle, C.BLE_CONN_CFG_TAG_DEFAULT)
} }
DefaultAdapter.connectHandler(Address{}, false) device := Device{
connectionHandle: gapEvent.conn_handle,
}
DefaultAdapter.connectHandler(device, false)
case C.BLE_GAP_EVT_CONN_PARAM_UPDATE: case C.BLE_GAP_EVT_CONN_PARAM_UPDATE:
if debug { if debug {
// Print connection parameters for easy debugging. // Print connection parameters for easy debugging.

View file

@ -29,7 +29,11 @@ func handleEvent() {
} }
currentConnection.handle.Reg = uint16(gapEvent.conn_handle) currentConnection.handle.Reg = uint16(gapEvent.conn_handle)
connectEvent := gapEvent.params.unionfield_connected() connectEvent := gapEvent.params.unionfield_connected()
DefaultAdapter.connectHandler(Address{makeMACAddress(connectEvent.peer_addr)}, true) device := Device{
Address: Address{makeMACAddress(connectEvent.peer_addr)},
connectionHandle: gapEvent.conn_handle,
}
DefaultAdapter.connectHandler(device, true)
case C.BLE_GAP_EVT_DISCONNECTED: case C.BLE_GAP_EVT_DISCONNECTED:
if debug { if debug {
println("evt: disconnected") println("evt: disconnected")
@ -45,7 +49,10 @@ func handleEvent() {
// necessary. // necessary.
C.sd_ble_gap_adv_start(defaultAdvertisement.handle, C.BLE_CONN_CFG_TAG_DEFAULT) C.sd_ble_gap_adv_start(defaultAdvertisement.handle, C.BLE_CONN_CFG_TAG_DEFAULT)
} }
DefaultAdapter.connectHandler(Address{}, false) device := Device{
connectionHandle: gapEvent.conn_handle,
}
DefaultAdapter.connectHandler(device, false)
case C.BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: case C.BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
// We need to respond with sd_ble_gap_data_length_update. Setting // We need to respond with sd_ble_gap_data_length_update. Setting
// both parameters to nil will make sure we send the default values. // both parameters to nil will make sure we send the default values.

View file

@ -48,7 +48,7 @@ type Adapter struct {
scanning bool scanning bool
charWriteHandlers []charWriteHandler charWriteHandlers []charWriteHandler
connectHandler func(device Address, connected bool) connectHandler func(device Device, connected bool)
} }
// DefaultAdapter is the default adapter on the current system. On Nordic chips, // DefaultAdapter is the default adapter on the current system. On Nordic chips,
@ -56,7 +56,7 @@ type Adapter struct {
// //
// Make sure to call Enable() before using it to initialize the adapter. // Make sure to call Enable() before using it to initialize the adapter.
var DefaultAdapter = &Adapter{isDefault: true, var DefaultAdapter = &Adapter{isDefault: true,
connectHandler: func(device Address, connected bool) { connectHandler: func(device Device, connected bool) {
return return
}} }}

View file

@ -12,14 +12,14 @@ import (
type Adapter struct { type Adapter struct {
watcher *advertisement.BluetoothLEAdvertisementWatcher watcher *advertisement.BluetoothLEAdvertisementWatcher
connectHandler func(device Address, connected bool) connectHandler func(device Device, connected bool)
} }
// DefaultAdapter is the default adapter on the system. // DefaultAdapter is the default adapter on the system.
// //
// Make sure to call Enable() before using it to initialize the adapter. // Make sure to call Enable() before using it to initialize the adapter.
var DefaultAdapter = &Adapter{ var DefaultAdapter = &Adapter{
connectHandler: func(device Address, connected bool) { connectHandler: func(device Device, connected bool) {
return return
}, },
} }

View file

@ -38,7 +38,7 @@ func main() {
neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
ws = ws2812.New(neo) ws = ws2812.New(neo)
adapter.SetConnectHandler(func(d bluetooth.Address, c bool) { adapter.SetConnectHandler(func(d bluetooth.Device, c bool) {
connected = c connected = c
if !connected && !disconnected { if !connected && !disconnected {

View file

@ -21,7 +21,7 @@ func main() {
must("config adv", adv.Configure(bluetooth.AdvertisementOptions{ must("config adv", adv.Configure(bluetooth.AdvertisementOptions{
LocalName: "Go Bluetooth", LocalName: "Go Bluetooth",
})) }))
adapter.SetConnectHandler(func(device bluetooth.Address, connected bool) { adapter.SetConnectHandler(func(device bluetooth.Device, connected bool) {
if connected { if connected {
println("connected, not advertising...") println("connected, not advertising...")
advState = false advState = false

View file

@ -85,6 +85,8 @@ func (a *Adapter) StopScan() error {
// Device is a connection to a remote peripheral. // Device is a connection to a remote peripheral.
type Device struct { type Device struct {
Address Address
*deviceInternal *deviceInternal
} }
@ -137,7 +139,8 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, err
} }
d := Device{ d := Device{
&deviceInternal{ Address: address,
deviceInternal: &deviceInternal{
cm: a.cm, cm: a.cm,
prph: p, prph: p,
servicesChan: make(chan error), servicesChan: make(chan error),
@ -148,7 +151,7 @@ func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, err
d.delegate = &peripheralDelegate{d: d} d.delegate = &peripheralDelegate{d: d}
p.SetDelegate(d.delegate) p.SetDelegate(d.delegate)
a.connectHandler(address, true) a.connectHandler(d, true)
return d, nil return d, nil

View file

@ -292,9 +292,10 @@ func makeScanResult(props map[string]dbus.Variant) ScanResult {
// Device is a connection to a remote peripheral. // Device is a connection to a remote peripheral.
type Device struct { type Device struct {
Address Address // the MAC address of the device
device dbus.BusObject // bluez device interface device dbus.BusObject // bluez device interface
adapter *Adapter // the adapter that was used to form this device connection adapter *Adapter // the adapter that was used to form this device connection
address Address // the address of the device
} }
// Connect starts a connection attempt to the given peripheral device address. // Connect starts a connection attempt to the given peripheral device address.
@ -303,9 +304,9 @@ type Device struct {
func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, error) { func (a *Adapter) Connect(address Address, params ConnectionParams) (Device, error) {
devicePath := dbus.ObjectPath(string(a.adapter.Path()) + "/dev_" + strings.Replace(address.MAC.String(), ":", "_", -1)) devicePath := dbus.ObjectPath(string(a.adapter.Path()) + "/dev_" + strings.Replace(address.MAC.String(), ":", "_", -1))
device := Device{ device := Device{
Address: address,
device: a.bus.Object("org.bluez", devicePath), device: a.bus.Object("org.bluez", devicePath),
adapter: a, adapter: a,
address: address,
} }
// Already start watching for property changes. We do this before reading // Already start watching for property changes. We do this before reading

View file

@ -92,11 +92,6 @@ func (a *Adapter) StopScan() error {
return nil return nil
} }
// Device is a connection to a remote peripheral.
type Device struct {
connectionHandle C.uint16_t
}
// In-progress connection attempt. // In-progress connection attempt.
var connectionAttempt struct { var connectionAttempt struct {
state volatile.Register8 // 0 means unused, 1 means connecting, 2 means ready (connected or timeout) state volatile.Register8 // 0 means unused, 1 means connecting, 2 means ready (connected or timeout)

15
gap_sd.go Normal file
View file

@ -0,0 +1,15 @@
//go:build softdevice
package bluetooth
/*
#include "ble_gap.h"
*/
import "C"
// Device is a connection to a remote peripheral or central.
type Device struct {
Address Address
connectionHandle C.uint16_t
}