Merge pull request #5592 from pan-/ble-nordic-fix-gatt-server-write

BLE: Fix GattServer::write on Nordic targets.
pull/5586/merge
Martin Kojtal 2017-11-30 18:05:27 +00:00 committed by GitHub
commit 1498a807c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 162 additions and 87 deletions

View File

@ -26,6 +26,34 @@
#include "nRF5xn.h" #include "nRF5xn.h"
namespace {
static ble_error_t set_attribute_value(
Gap::Handle_t connectionHandle,
GattAttribute::Handle_t attributeHandle,
ble_gatts_value_t *value
) {
uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, value);
switch(err) {
case NRF_SUCCESS:
return BLE_ERROR_NONE;
case NRF_ERROR_INVALID_ADDR:
case NRF_ERROR_INVALID_PARAM:
return BLE_ERROR_INVALID_PARAM;
case NRF_ERROR_NOT_FOUND:
case NRF_ERROR_DATA_SIZE:
case BLE_ERROR_INVALID_CONN_HANDLE:
case BLE_ERROR_GATTS_INVALID_ATTR_TYPE:
return BLE_ERROR_PARAM_OUT_OF_RANGE;
case NRF_ERROR_FORBIDDEN:
return BLE_ERROR_OPERATION_NOT_PERMITTED;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
} // end of anonymous namespace
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief Adds a new service to the GATT table on the peripheral @brief Adds a new service to the GATT table on the peripheral
@ -244,6 +272,19 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
connectionHandle = gap.getConnectionHandle(); connectionHandle = gap.getConnectionHandle();
} }
bool updatesEnabled = false;
if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);
// FIXME: The softdevice allocates and populates CCCD when the client
// interract with them. Checking for updates may return an out of
// range error in such case.
if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
return err;
}
}
if (updatesEnabled) {
error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
switch (error) { switch (error) {
@ -262,35 +303,21 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
BLE_ERROR_PARAM_OUT_OF_RANGE ); BLE_ERROR_PARAM_OUT_OF_RANGE );
if (connectionHandle == BLE_CONN_HANDLE_INVALID) {
returnValue = BLE_ERROR_NONE;
} else {
/* Notifications consume application buffers. The return value can /* Notifications consume application buffers. The return value can
* be used for resending notifications. */ * be used for resending notifications. */
returnValue = BLE_STACK_BUSY; returnValue = BLE_STACK_BUSY;
}
break; break;
} }
} }
} else { } else {
uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value); returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
switch(err) {
case NRF_SUCCESS:
returnValue = BLE_ERROR_NONE;
break;
case NRF_ERROR_INVALID_ADDR:
case NRF_ERROR_INVALID_PARAM:
returnValue = BLE_ERROR_INVALID_PARAM;
break;
case NRF_ERROR_NOT_FOUND:
case NRF_ERROR_DATA_SIZE:
case BLE_ERROR_INVALID_CONN_HANDLE:
case BLE_ERROR_GATTS_INVALID_ATTR_TYPE:
returnValue = BLE_ERROR_PARAM_OUT_OF_RANGE;
break;
case NRF_ERROR_FORBIDDEN:
returnValue = BLE_ERROR_OPERATION_NOT_PERMITTED;
break;
default:
returnValue = BLE_ERROR_UNSPECIFIED;
break;
} }
} else {
returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
} }
return returnValue; return returnValue;
@ -305,7 +332,12 @@ ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &charact
ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
{ {
int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle()); return areUpdatesEnabled(connectionHandle, characteristic.getValueHandle(), enabledP);
}
ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, bool *enabledP)
{
int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
if (characteristicIndex == -1) { if (characteristicIndex == -1) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }

View File

@ -79,6 +79,15 @@ private:
return -1; return -1;
} }
/**
* Query if updates of a characteristics are enabled for a given connection.
*/
ble_error_t areUpdatesEnabled(
Gap::Handle_t connectionHandle,
GattAttribute::Handle_t valueHandle,
bool *enabledP
);
private: private:
GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS];
ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS];

View File

@ -65,7 +65,31 @@ static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = {
} }
}; };
static ble_error_t set_attribute_value(
Gap::Handle_t connectionHandle,
GattAttribute::Handle_t attributeHandle,
ble_gatts_value_t *value
) {
uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, value);
switch(err) {
case NRF_SUCCESS:
return BLE_ERROR_NONE;
case NRF_ERROR_INVALID_ADDR:
case NRF_ERROR_INVALID_PARAM:
return BLE_ERROR_INVALID_PARAM;
case NRF_ERROR_NOT_FOUND:
case NRF_ERROR_DATA_SIZE:
case BLE_ERROR_INVALID_CONN_HANDLE:
case BLE_ERROR_GATTS_INVALID_ATTR_TYPE:
return BLE_ERROR_PARAM_OUT_OF_RANGE;
case NRF_ERROR_FORBIDDEN:
return BLE_ERROR_OPERATION_NOT_PERMITTED;
default:
return BLE_ERROR_UNSPECIFIED;
} }
}
} // end of anonymous namespace
/**************************************************************************/ /**************************************************************************/
/*! /*!
@ -285,6 +309,20 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
connectionHandle = gap.getConnectionHandle(); connectionHandle = gap.getConnectionHandle();
} }
bool updatesEnabled = false;
if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);
// FIXME: The softdevice allocates and populates CCCD when the client
// interract with them. Checking for updates may return an out of
// range error in such case.
if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
return err;
}
}
if (updatesEnabled) {
error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) { if (error != ERROR_NONE) {
switch (error) { switch (error) {
@ -310,28 +348,10 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
} }
} }
} else { } else {
uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value); returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
switch(err) {
case NRF_SUCCESS:
returnValue = BLE_ERROR_NONE;
break;
case NRF_ERROR_INVALID_ADDR:
case NRF_ERROR_INVALID_PARAM:
returnValue = BLE_ERROR_INVALID_PARAM;
break;
case NRF_ERROR_NOT_FOUND:
case NRF_ERROR_DATA_SIZE:
case BLE_ERROR_INVALID_CONN_HANDLE:
case BLE_ERROR_GATTS_INVALID_ATTR_TYPE:
returnValue = BLE_ERROR_PARAM_OUT_OF_RANGE;
break;
case NRF_ERROR_FORBIDDEN:
returnValue = BLE_ERROR_OPERATION_NOT_PERMITTED;
break;
default:
returnValue = BLE_ERROR_UNSPECIFIED;
break;
} }
} else {
returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
} }
return returnValue; return returnValue;
@ -346,7 +366,12 @@ ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &charact
ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
{ {
int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle()); return areUpdatesEnabled(connectionHandle, characteristic.getValueHandle(), enabledP);
}
ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, bool *enabledP)
{
int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
if (characteristicIndex == -1) { if (characteristicIndex == -1) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }

View File

@ -133,6 +133,15 @@ private:
*/ */
void releaseAllWriteRequests(); void releaseAllWriteRequests();
/**
* Query if updates of a characteristics are enabled for a given connection.
*/
ble_error_t areUpdatesEnabled(
Gap::Handle_t connectionHandle,
GattAttribute::Handle_t valueHandle,
bool *enabledP
);
private: private:
GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS]; GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS];
ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS]; ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS];