sd: handle system attibutes on reconnect

This commit is contained in:
Yurii Soldak 2021-11-01 22:48:16 +01:00
parent 113f5fa503
commit 7384ef4c56
4 changed files with 69 additions and 28 deletions

View file

@ -50,6 +50,19 @@ func handleEvent() {
currentConnection.Reg = gapEvent.conn_handle
DefaultAdapter.connectHandler(Address{}, true)
case C.BLE_GAP_EVT_DISCONNECTED:
if debug {
println("evt: disconnected")
}
// Store system attributes data
dataLen := uint16(0)
C.sd_ble_gatts_sys_attr_get(gapEvent.conn_handle, nil, &dataLen, 0) // get data length
if int(dataLen) <= cap(DefaultAdapter.systemAttributes) { // we can not allocate here, so ensure at least data fits the buffer
DefaultAdapter.systemAttributes = DefaultAdapter.systemAttributes[:dataLen]
C.sd_ble_gatts_sys_attr_get(gapEvent.conn_handle, &DefaultAdapter.systemAttributes[0], &dataLen, 0)
}
// Clean up state for this connection.
currentConnection.Reg = C.BLE_CONN_HANDLE_INVALID
// Auto-restart advertisement if needed.
if defaultAdvertisement.isAdvertising.Get() != 0 {
// The advertisement was running but was automatically stopped
// by the connection event.
@ -59,7 +72,6 @@ func handleEvent() {
// necessary.
defaultAdvertisement.start()
}
currentConnection.Reg = C.BLE_CONN_HANDLE_INVALID
DefaultAdapter.connectHandler(Address{}, false)
case C.BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
// Respond with the default PPCP connection parameters by passing
@ -87,15 +99,16 @@ func handleEvent() {
handler.callback(Connection(gattsEvent.conn_handle), int(writeEvent.offset), data)
}
case C.BLE_GATTS_EVT_SYS_ATTR_MISSING:
// This event is generated when reading the Generic Attribute
// service. It appears to be necessary for bonded devices.
// From the docs:
// > If the pointer is NULL, the system attribute info is
// > initialized, assuming that the application does not have any
// > previously saved system attribute data for this device.
// Maybe we should look at the error, but as there's not really a
// way to handle it, ignore it.
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, nil, 0, 0)
if debug {
println("evt: sys attr missing")
}
// Try and restore system attributes data if we have any (from previous connections)
// Fallback to initialize them from scratch otherwise
if len(DefaultAdapter.systemAttributes) > 0 {
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, &DefaultAdapter.systemAttributes[0], uint16(len(DefaultAdapter.systemAttributes)), 0)
} else {
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, nil, 0, 0)
}
default:
if debug {
println("unknown GATTS event:", id, id-C.BLE_GATTS_EVT_BASE)

View file

@ -49,6 +49,13 @@ func handleEvent() {
if debug {
println("evt: disconnected")
}
// Store system attributes data
dataLen := uint16(0)
C.sd_ble_gatts_sys_attr_get(gapEvent.conn_handle, nil, &dataLen, 0) // get data length
if int(dataLen) <= cap(DefaultAdapter.systemAttributes) { // we can not allocate here, so ensure at least data fits the buffer
DefaultAdapter.systemAttributes = DefaultAdapter.systemAttributes[:dataLen]
C.sd_ble_gatts_sys_attr_get(gapEvent.conn_handle, &DefaultAdapter.systemAttributes[0], &dataLen, 0)
}
// Clean up state for this connection.
for i, cb := range gattcNotificationCallbacks {
if cb.connectionHandle == currentConnection.Reg {
@ -116,15 +123,16 @@ func handleEvent() {
handler.callback(Connection(gattsEvent.conn_handle), int(writeEvent.offset), data)
}
case C.BLE_GATTS_EVT_SYS_ATTR_MISSING:
// This event is generated when reading the Generic Attribute
// service. It appears to be necessary for bonded devices.
// From the docs:
// > If the pointer is NULL, the system attribute info is
// > initialized, assuming that the application does not have any
// > previously saved system attribute data for this device.
// Maybe we should look at the error, but as there's not really a
// way to handle it, ignore it.
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, nil, 0, 0)
if debug {
println("evt: sys attr missing")
}
// Try and restore system attributes data if we have any (from previous connections)
// Fallback to initialize them from scratch otherwise
if len(DefaultAdapter.systemAttributes) > 0 {
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, &DefaultAdapter.systemAttributes[0], uint16(len(DefaultAdapter.systemAttributes)), 0)
} else {
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, nil, 0, 0)
}
case C.BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
// This event is generated by some devices. While we could support
// larger MTUs, this default MTU is supported everywhere.

View file

@ -38,6 +38,14 @@ func handleEvent() {
if debug {
println("evt: disconnected")
}
// Store system attributes data
dataLen := uint16(0)
C.sd_ble_gatts_sys_attr_get(gapEvent.conn_handle, nil, &dataLen, 0) // get data length
if int(dataLen) <= cap(DefaultAdapter.systemAttributes) { // we can not allocate here, so ensure at least data fits the buffer
DefaultAdapter.systemAttributes = DefaultAdapter.systemAttributes[:dataLen]
C.sd_ble_gatts_sys_attr_get(gapEvent.conn_handle, &DefaultAdapter.systemAttributes[0], &dataLen, 0)
}
// Clean up state for this connection.
currentConnection.Reg = C.BLE_CONN_HANDLE_INVALID
// Auto-restart advertisement if needed.
if defaultAdvertisement.isAdvertising.Get() != 0 {
@ -71,15 +79,16 @@ func handleEvent() {
handler.callback(Connection(gattsEvent.conn_handle), int(writeEvent.offset), data)
}
case C.BLE_GATTS_EVT_SYS_ATTR_MISSING:
// This event is generated when reading the Generic Attribute
// service. It appears to be necessary for bonded devices.
// From the docs:
// > If the pointer is NULL, the system attribute info is
// > initialized, assuming that the application does not have any
// > previously saved system attribute data for this device.
// Maybe we should look at the error, but as there's not really a
// way to handle it, ignore it.
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, nil, 0, 0)
if debug {
println("evt: sys attr missing")
}
// Try and restore system attributes data if we have any (from previous connections)
// Fallback to initialize them from scratch otherwise
if len(DefaultAdapter.systemAttributes) > 0 {
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, &DefaultAdapter.systemAttributes[0], uint16(len(DefaultAdapter.systemAttributes)), 0)
} else {
C.sd_ble_gatts_sys_attr_set(gattsEvent.conn_handle, nil, 0, 0)
}
case C.BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
// This event is generated by some devices. While we could support
// larger MTUs, this default MTU is supported everywhere.

View file

@ -50,6 +50,16 @@ type Adapter struct {
charWriteHandlers []charWriteHandler
connectHandler func(device Address, connected bool)
// System attributes in context of SoftDevice primarily mean Client Characteristic Configuration Descriptors (CCCD).
// It is mandated by Bluetooth specification that CCCD values for a bonded peer should be stored between connections.
//
// Our bluetooth stack stores system attributes on disconnect
// and provides them back to SoftDevice on BLE_GATTS_EVT_SYS_ATTR_MISSING event.
//
// Note: CCCD values can be altered only by the peer, so you cannot change them from the application.
// Treat this data as a blob of unknown format, i.e. store it as is and provide it back as is, without changing it.
systemAttributes []byte
}
// DefaultAdapter is the default adapter on the current system. On Nordic chips,
@ -57,6 +67,7 @@ type Adapter struct {
//
// Make sure to call Enable() before using it to initialize the adapter.
var DefaultAdapter = &Adapter{isDefault: true,
systemAttributes: make([]byte, 64)[:0], // capacity 64, length 0
connectHandler: func(device Address, connected bool) {
return
}}