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,53 +272,52 @@ 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();
} }
error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) {
switch (error) {
case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */
case ERROR_BUSY:
returnValue = BLE_STACK_BUSY;
break;
case ERROR_INVALID_STATE: bool updatesEnabled = false;
case ERROR_BLEGATTS_SYS_ATTR_MISSING: if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
returnValue = BLE_ERROR_INVALID_STATE; ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);
break; // FIXME: The softdevice allocates and populates CCCD when the client
// interract with them. Checking for updates may return an out of
default : // range error in such case.
ASSERT_INT( ERROR_NONE, if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), return err;
BLE_ERROR_PARAM_OUT_OF_RANGE );
/* Notifications consume application buffers. The return value can
* be used for resending notifications. */
returnValue = BLE_STACK_BUSY;
break;
} }
} }
} else {
uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value); if (updatesEnabled) {
switch(err) { error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
case NRF_SUCCESS: if (error != ERROR_NONE) {
returnValue = BLE_ERROR_NONE; switch (error) {
break; case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */
case NRF_ERROR_INVALID_ADDR: case ERROR_BUSY:
case NRF_ERROR_INVALID_PARAM: returnValue = BLE_STACK_BUSY;
returnValue = BLE_ERROR_INVALID_PARAM; break;
break;
case NRF_ERROR_NOT_FOUND: case ERROR_INVALID_STATE:
case NRF_ERROR_DATA_SIZE: case ERROR_BLEGATTS_SYS_ATTR_MISSING:
case BLE_ERROR_INVALID_CONN_HANDLE: returnValue = BLE_ERROR_INVALID_STATE;
case BLE_ERROR_GATTS_INVALID_ATTR_TYPE: break;
returnValue = BLE_ERROR_PARAM_OUT_OF_RANGE;
break; default :
case NRF_ERROR_FORBIDDEN: ASSERT_INT( ERROR_NONE,
returnValue = BLE_ERROR_OPERATION_NOT_PERMITTED; sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
break; BLE_ERROR_PARAM_OUT_OF_RANGE );
default:
returnValue = BLE_ERROR_UNSPECIFIED; if (connectionHandle == BLE_CONN_HANDLE_INVALID) {
break; returnValue = BLE_ERROR_NONE;
} else {
/* Notifications consume application buffers. The return value can
* be used for resending notifications. */
returnValue = BLE_STACK_BUSY;
}
break;
}
}
} else {
returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
} }
} 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,8 +65,32 @@ 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
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief Adds a new service to the GATT table on the peripheral @brief Adds a new service to the GATT table on the peripheral
@ -285,53 +309,49 @@ 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();
} }
error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) {
switch (error) {
case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */
case ERROR_BUSY:
returnValue = BLE_STACK_BUSY;
break;
case ERROR_INVALID_STATE: bool updatesEnabled = false;
case ERROR_BLEGATTS_SYS_ATTR_MISSING: if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
returnValue = BLE_ERROR_INVALID_STATE; ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);
break;
default : // FIXME: The softdevice allocates and populates CCCD when the client
ASSERT_INT( ERROR_NONE, // interract with them. Checking for updates may return an out of
sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), // range error in such case.
BLE_ERROR_PARAM_OUT_OF_RANGE ); if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
return err;
/* Notifications consume application buffers. The return value can
* be used for resending notifications. */
returnValue = BLE_STACK_BUSY;
break;
} }
} }
} else {
uint32_t err = sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value); if (updatesEnabled) {
switch(err) { error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
case NRF_SUCCESS: if (error != ERROR_NONE) {
returnValue = BLE_ERROR_NONE; switch (error) {
break; case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */
case NRF_ERROR_INVALID_ADDR: case ERROR_BUSY:
case NRF_ERROR_INVALID_PARAM: returnValue = BLE_STACK_BUSY;
returnValue = BLE_ERROR_INVALID_PARAM; break;
break;
case NRF_ERROR_NOT_FOUND: case ERROR_INVALID_STATE:
case NRF_ERROR_DATA_SIZE: case ERROR_BLEGATTS_SYS_ATTR_MISSING:
case BLE_ERROR_INVALID_CONN_HANDLE: returnValue = BLE_ERROR_INVALID_STATE;
case BLE_ERROR_GATTS_INVALID_ATTR_TYPE: break;
returnValue = BLE_ERROR_PARAM_OUT_OF_RANGE;
break; default :
case NRF_ERROR_FORBIDDEN: ASSERT_INT( ERROR_NONE,
returnValue = BLE_ERROR_OPERATION_NOT_PERMITTED; sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
break; BLE_ERROR_PARAM_OUT_OF_RANGE );
default:
returnValue = BLE_ERROR_UNSPECIFIED; /* Notifications consume application buffers. The return value can
break; * be used for resending notifications. */
returnValue = BLE_STACK_BUSY;
break;
}
}
} else {
returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
} }
} 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];