No changes

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Wed Dec 02 12:35:27 2015 +0000
Revision:
514:a3b6d669c210
Parent:
513:9abdc3021d8c
Child:
517:23d16e238129
Synchronized with git rev 4b3a1c85
Author: Andres Amaya Garcia
Allow GattAttributes to have fixed length

Previously the concepts of initLength and lenth were clearly separated.
However, this was at the cost of registering all characteristics in the
SoftDevice as having variable length. Clearly, this is not the desired
behaviour. Therefore, an additional field '_hasVariableLen' is added to the
GattAttribute to address the problem. Also, the GattAttribute and
GattCharacteristic constructors have been modified to take a boolean that
sets '_hasVariableLen'.

**NOTE:** Changes to this module will cause projects to fail the build stage
if changes to the BLE_API are not published first.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 388:db85a09c27ef 1 /* mbed Microcontroller Library
rgrover1 388:db85a09c27ef 2 * Copyright (c) 2006-2013 ARM Limited
rgrover1 388:db85a09c27ef 3 *
rgrover1 388:db85a09c27ef 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 388:db85a09c27ef 5 * you may not use this file except in compliance with the License.
rgrover1 388:db85a09c27ef 6 * You may obtain a copy of the License at
rgrover1 388:db85a09c27ef 7 *
rgrover1 388:db85a09c27ef 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 388:db85a09c27ef 9 *
rgrover1 388:db85a09c27ef 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 388:db85a09c27ef 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 388:db85a09c27ef 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 388:db85a09c27ef 13 * See the License for the specific language governing permissions and
rgrover1 388:db85a09c27ef 14 * limitations under the License.
rgrover1 388:db85a09c27ef 15 */
rgrover1 388:db85a09c27ef 16
rgrover1 388:db85a09c27ef 17 #include "nRF5xGattServer.h"
rgrover1 388:db85a09c27ef 18 #include "mbed.h"
rgrover1 388:db85a09c27ef 19
rgrover1 388:db85a09c27ef 20 #include "common/common.h"
rgrover1 388:db85a09c27ef 21 #include "btle/custom/custom_helper.h"
rgrover1 388:db85a09c27ef 22
rgrover1 388:db85a09c27ef 23 #include "nRF5xGap.h"
rgrover1 388:db85a09c27ef 24
rgrover1 388:db85a09c27ef 25 nRF5xGattServer &nRF5xGattServer::getInstance(void) {
rgrover1 388:db85a09c27ef 26 static nRF5xGattServer m_instance;
rgrover1 388:db85a09c27ef 27 return m_instance;
rgrover1 388:db85a09c27ef 28 }
rgrover1 388:db85a09c27ef 29
rgrover1 388:db85a09c27ef 30 /**************************************************************************/
rgrover1 388:db85a09c27ef 31 /*!
rgrover1 388:db85a09c27ef 32 @brief Adds a new service to the GATT table on the peripheral
rgrover1 388:db85a09c27ef 33
rgrover1 388:db85a09c27ef 34 @returns ble_error_t
rgrover1 388:db85a09c27ef 35
rgrover1 388:db85a09c27ef 36 @retval BLE_ERROR_NONE
rgrover1 388:db85a09c27ef 37 Everything executed properly
rgrover1 388:db85a09c27ef 38
rgrover1 388:db85a09c27ef 39 @section EXAMPLE
rgrover1 388:db85a09c27ef 40
rgrover1 388:db85a09c27ef 41 @code
rgrover1 388:db85a09c27ef 42
rgrover1 388:db85a09c27ef 43 @endcode
rgrover1 388:db85a09c27ef 44 */
rgrover1 388:db85a09c27ef 45 /**************************************************************************/
rgrover1 388:db85a09c27ef 46 ble_error_t nRF5xGattServer::addService(GattService &service)
rgrover1 388:db85a09c27ef 47 {
rgrover1 388:db85a09c27ef 48 /* ToDo: Make sure this service UUID doesn't already exist (?) */
rgrover1 388:db85a09c27ef 49 /* ToDo: Basic validation */
rgrover1 388:db85a09c27ef 50
rgrover1 388:db85a09c27ef 51 /* Add the service to the nRF51 */
rgrover1 388:db85a09c27ef 52 ble_uuid_t nordicUUID;
rgrover1 388:db85a09c27ef 53 nordicUUID = custom_convert_to_nordic_uuid(service.getUUID());
rgrover1 388:db85a09c27ef 54
rgrover1 388:db85a09c27ef 55 uint16_t serviceHandle;
rgrover1 388:db85a09c27ef 56 ASSERT( ERROR_NONE ==
rgrover1 388:db85a09c27ef 57 sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
rgrover1 388:db85a09c27ef 58 &nordicUUID,
rgrover1 388:db85a09c27ef 59 &serviceHandle),
rgrover1 388:db85a09c27ef 60 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 61 service.setHandle(serviceHandle);
rgrover1 388:db85a09c27ef 62
rgrover1 388:db85a09c27ef 63 /* Add characteristics to the service */
rgrover1 388:db85a09c27ef 64 for (uint8_t i = 0; i < service.getCharacteristicCount(); i++) {
rgrover1 455:e33de7c4574c 65 if (characteristicCount >= BLE_TOTAL_CHARACTERISTICS) {
rgrover1 455:e33de7c4574c 66 return BLE_ERROR_NO_MEM;
rgrover1 455:e33de7c4574c 67 }
rgrover1 451:87e7f14a3fa1 68 GattCharacteristic *p_char = service.getCharacteristic(i);
rgrover1 388:db85a09c27ef 69
rgrover1 388:db85a09c27ef 70 /* Skip any incompletely defined, read-only characteristics. */
rgrover1 388:db85a09c27ef 71 if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
rgrover1 513:9abdc3021d8c 72 (p_char->getValueAttribute().getLength() == 0) &&
rgrover1 388:db85a09c27ef 73 (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) {
rgrover1 388:db85a09c27ef 74 continue;
rgrover1 388:db85a09c27ef 75 }
rgrover1 388:db85a09c27ef 76
rgrover1 388:db85a09c27ef 77 nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID());
rgrover1 388:db85a09c27ef 78
rgrover1 388:db85a09c27ef 79 /* The user-description descriptor is a special case which needs to be
rgrover1 388:db85a09c27ef 80 * handled at the time of adding the characteristic. The following block
rgrover1 388:db85a09c27ef 81 * is meant to discover its presence. */
rgrover1 388:db85a09c27ef 82 const uint8_t *userDescriptionDescriptorValuePtr = NULL;
rgrover1 388:db85a09c27ef 83 uint16_t userDescriptionDescriptorValueLen = 0;
rgrover1 388:db85a09c27ef 84 for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
rgrover1 388:db85a09c27ef 85 GattAttribute *p_desc = p_char->getDescriptor(j);
rgrover1 388:db85a09c27ef 86 if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
rgrover1 388:db85a09c27ef 87 userDescriptionDescriptorValuePtr = p_desc->getValuePtr();
rgrover1 388:db85a09c27ef 88 userDescriptionDescriptorValueLen = p_desc->getLength();
rgrover1 388:db85a09c27ef 89 }
rgrover1 388:db85a09c27ef 90 }
rgrover1 388:db85a09c27ef 91
rgrover1 388:db85a09c27ef 92 ASSERT ( ERROR_NONE ==
rgrover1 388:db85a09c27ef 93 custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
rgrover1 388:db85a09c27ef 94 &nordicUUID,
rgrover1 388:db85a09c27ef 95 p_char->getProperties(),
rgrover1 388:db85a09c27ef 96 p_char->getRequiredSecurity(),
rgrover1 388:db85a09c27ef 97 p_char->getValueAttribute().getValuePtr(),
rgrover1 513:9abdc3021d8c 98 p_char->getValueAttribute().getLength(),
rgrover1 388:db85a09c27ef 99 p_char->getValueAttribute().getMaxLength(),
rgrover1 514:a3b6d669c210 100 p_char->getValueAttribute().hasVariableLength(),
rgrover1 388:db85a09c27ef 101 userDescriptionDescriptorValuePtr,
rgrover1 388:db85a09c27ef 102 userDescriptionDescriptorValueLen,
rgrover1 388:db85a09c27ef 103 p_char->isReadAuthorizationEnabled(),
rgrover1 388:db85a09c27ef 104 p_char->isWriteAuthorizationEnabled(),
rgrover1 388:db85a09c27ef 105 &nrfCharacteristicHandles[characteristicCount]),
rgrover1 388:db85a09c27ef 106 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 107
rgrover1 388:db85a09c27ef 108 /* Update the characteristic handle */
rgrover1 388:db85a09c27ef 109 p_characteristics[characteristicCount] = p_char;
rgrover1 388:db85a09c27ef 110 p_char->getValueAttribute().setHandle(nrfCharacteristicHandles[characteristicCount].value_handle);
rgrover1 388:db85a09c27ef 111 characteristicCount++;
rgrover1 388:db85a09c27ef 112
rgrover1 388:db85a09c27ef 113 /* Add optional descriptors if any */
rgrover1 388:db85a09c27ef 114 for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
rgrover1 455:e33de7c4574c 115 if (descriptorCount >= BLE_TOTAL_DESCRIPTORS) {
rgrover1 455:e33de7c4574c 116 return BLE_ERROR_NO_MEM;
rgrover1 455:e33de7c4574c 117 }
rgrover1 455:e33de7c4574c 118
rgrover1 451:87e7f14a3fa1 119 GattAttribute *p_desc = p_char->getDescriptor(j);
rgrover1 388:db85a09c27ef 120 /* skip the user-description-descriptor here; this has already been handled when adding the characteristic (above). */
rgrover1 388:db85a09c27ef 121 if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
rgrover1 388:db85a09c27ef 122 continue;
rgrover1 388:db85a09c27ef 123 }
rgrover1 388:db85a09c27ef 124
rgrover1 388:db85a09c27ef 125 nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID());
rgrover1 388:db85a09c27ef 126
rgrover1 388:db85a09c27ef 127 ASSERT(ERROR_NONE ==
rgrover1 388:db85a09c27ef 128 custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID,
rgrover1 388:db85a09c27ef 129 &nordicUUID,
rgrover1 388:db85a09c27ef 130 p_desc->getValuePtr(),
rgrover1 513:9abdc3021d8c 131 p_desc->getLength(),
rgrover1 388:db85a09c27ef 132 p_desc->getMaxLength(),
rgrover1 514:a3b6d669c210 133 p_desc->hasVariableLength(),
rgrover1 388:db85a09c27ef 134 &nrfDescriptorHandles[descriptorCount]),
rgrover1 388:db85a09c27ef 135 BLE_ERROR_PARAM_OUT_OF_RANGE);
rgrover1 388:db85a09c27ef 136
rgrover1 388:db85a09c27ef 137 p_descriptors[descriptorCount++] = p_desc;
rgrover1 388:db85a09c27ef 138 p_desc->setHandle(nrfDescriptorHandles[descriptorCount]);
rgrover1 388:db85a09c27ef 139 }
rgrover1 388:db85a09c27ef 140 }
rgrover1 388:db85a09c27ef 141
rgrover1 388:db85a09c27ef 142 serviceCount++;
rgrover1 388:db85a09c27ef 143
rgrover1 388:db85a09c27ef 144 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 145 }
rgrover1 388:db85a09c27ef 146
rgrover1 388:db85a09c27ef 147 /**************************************************************************/
rgrover1 388:db85a09c27ef 148 /*!
rgrover1 388:db85a09c27ef 149 @brief Reads the value of a characteristic, based on the service
rgrover1 388:db85a09c27ef 150 and characteristic index fields
rgrover1 388:db85a09c27ef 151
rgrover1 388:db85a09c27ef 152 @param[in] attributeHandle
rgrover1 388:db85a09c27ef 153 The handle of the GattCharacteristic to read from
rgrover1 388:db85a09c27ef 154 @param[in] buffer
rgrover1 388:db85a09c27ef 155 Buffer to hold the the characteristic's value
rgrover1 388:db85a09c27ef 156 (raw byte array in LSB format)
rgrover1 388:db85a09c27ef 157 @param[in/out] len
rgrover1 388:db85a09c27ef 158 input: Length in bytes to be read.
rgrover1 388:db85a09c27ef 159 output: Total length of attribute value upon successful return.
rgrover1 388:db85a09c27ef 160
rgrover1 388:db85a09c27ef 161 @returns ble_error_t
rgrover1 388:db85a09c27ef 162
rgrover1 388:db85a09c27ef 163 @retval BLE_ERROR_NONE
rgrover1 388:db85a09c27ef 164 Everything executed properly
rgrover1 388:db85a09c27ef 165 */
rgrover1 388:db85a09c27ef 166 /**************************************************************************/
rgrover1 388:db85a09c27ef 167 ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
rgrover1 388:db85a09c27ef 168 {
rgrover1 388:db85a09c27ef 169 return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP);
rgrover1 388:db85a09c27ef 170 }
rgrover1 388:db85a09c27ef 171
rgrover1 388:db85a09c27ef 172 ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
rgrover1 388:db85a09c27ef 173 {
rgrover1 388:db85a09c27ef 174 ble_gatts_value_t value = {
rgrover1 388:db85a09c27ef 175 .len = *lengthP,
rgrover1 388:db85a09c27ef 176 .offset = 0,
rgrover1 388:db85a09c27ef 177 .p_value = buffer,
rgrover1 388:db85a09c27ef 178 };
rgrover1 388:db85a09c27ef 179
rgrover1 388:db85a09c27ef 180 ASSERT( ERROR_NONE ==
rgrover1 388:db85a09c27ef 181 sd_ble_gatts_value_get(connectionHandle, attributeHandle, &value),
rgrover1 388:db85a09c27ef 182 BLE_ERROR_PARAM_OUT_OF_RANGE);
rgrover1 388:db85a09c27ef 183 *lengthP = value.len;
rgrover1 388:db85a09c27ef 184
rgrover1 388:db85a09c27ef 185 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 186 }
rgrover1 388:db85a09c27ef 187
rgrover1 388:db85a09c27ef 188 /**************************************************************************/
rgrover1 388:db85a09c27ef 189 /*!
rgrover1 388:db85a09c27ef 190 @brief Updates the value of a characteristic, based on the service
rgrover1 388:db85a09c27ef 191 and characteristic index fields
rgrover1 388:db85a09c27ef 192
rgrover1 388:db85a09c27ef 193 @param[in] charHandle
rgrover1 388:db85a09c27ef 194 The handle of the GattCharacteristic to write to
rgrover1 388:db85a09c27ef 195 @param[in] buffer
rgrover1 388:db85a09c27ef 196 Data to use when updating the characteristic's value
rgrover1 388:db85a09c27ef 197 (raw byte array in LSB format)
rgrover1 388:db85a09c27ef 198 @param[in] len
rgrover1 388:db85a09c27ef 199 The number of bytes in buffer
rgrover1 388:db85a09c27ef 200
rgrover1 388:db85a09c27ef 201 @returns ble_error_t
rgrover1 388:db85a09c27ef 202
rgrover1 388:db85a09c27ef 203 @retval BLE_ERROR_NONE
rgrover1 388:db85a09c27ef 204 Everything executed properly
rgrover1 388:db85a09c27ef 205 */
rgrover1 388:db85a09c27ef 206 /**************************************************************************/
rgrover1 388:db85a09c27ef 207 ble_error_t nRF5xGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
rgrover1 388:db85a09c27ef 208 {
rgrover1 388:db85a09c27ef 209 return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly);
rgrover1 388:db85a09c27ef 210 }
rgrover1 388:db85a09c27ef 211
rgrover1 388:db85a09c27ef 212 ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
rgrover1 388:db85a09c27ef 213 {
rgrover1 388:db85a09c27ef 214 ble_error_t returnValue = BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 215
rgrover1 388:db85a09c27ef 216 ble_gatts_value_t value = {
rgrover1 388:db85a09c27ef 217 .len = len,
rgrover1 388:db85a09c27ef 218 .offset = 0,
rgrover1 388:db85a09c27ef 219 .p_value = const_cast<uint8_t *>(buffer),
rgrover1 388:db85a09c27ef 220 };
rgrover1 388:db85a09c27ef 221
rgrover1 388:db85a09c27ef 222 if (localOnly) {
rgrover1 388:db85a09c27ef 223 /* Only update locally regardless of notify/indicate */
rgrover1 388:db85a09c27ef 224 ASSERT_INT( ERROR_NONE,
rgrover1 388:db85a09c27ef 225 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
rgrover1 388:db85a09c27ef 226 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 227 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 228 }
rgrover1 388:db85a09c27ef 229
rgrover1 388:db85a09c27ef 230 int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
rgrover1 388:db85a09c27ef 231 if ((characteristicIndex != -1) &&
rgrover1 445:8328a7d1eac2 232 (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
rgrover1 388:db85a09c27ef 233 /* HVX update for the characteristic value */
rgrover1 388:db85a09c27ef 234 ble_gatts_hvx_params_t hvx_params;
rgrover1 388:db85a09c27ef 235
rgrover1 388:db85a09c27ef 236 hvx_params.handle = attributeHandle;
rgrover1 388:db85a09c27ef 237 hvx_params.type =
rgrover1 388:db85a09c27ef 238 (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
rgrover1 388:db85a09c27ef 239 hvx_params.offset = 0;
rgrover1 388:db85a09c27ef 240 hvx_params.p_data = const_cast<uint8_t *>(buffer);
rgrover1 388:db85a09c27ef 241 hvx_params.p_len = &len;
rgrover1 441:b52f5b70e62a 242
rgrover1 445:8328a7d1eac2 243 if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */
rgrover1 445:8328a7d1eac2 244 connectionHandle = nRF5xGap::getInstance().getConnectionHandle();
rgrover1 445:8328a7d1eac2 245 }
rgrover1 445:8328a7d1eac2 246 error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
rgrover1 445:8328a7d1eac2 247 if (error != ERROR_NONE) {
rgrover1 445:8328a7d1eac2 248 switch (error) {
rgrover1 445:8328a7d1eac2 249 case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */
rgrover1 445:8328a7d1eac2 250 case ERROR_BUSY:
rgrover1 445:8328a7d1eac2 251 returnValue = BLE_STACK_BUSY;
rgrover1 445:8328a7d1eac2 252 break;
rgrover1 388:db85a09c27ef 253
rgrover1 445:8328a7d1eac2 254 case ERROR_INVALID_STATE:
rgrover1 445:8328a7d1eac2 255 case ERROR_BLEGATTS_SYS_ATTR_MISSING:
rgrover1 445:8328a7d1eac2 256 returnValue = BLE_ERROR_INVALID_STATE;
rgrover1 445:8328a7d1eac2 257 break;
rgrover1 388:db85a09c27ef 258
rgrover1 445:8328a7d1eac2 259 default :
rgrover1 445:8328a7d1eac2 260 ASSERT_INT( ERROR_NONE,
rgrover1 445:8328a7d1eac2 261 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
rgrover1 445:8328a7d1eac2 262 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 445:8328a7d1eac2 263
rgrover1 445:8328a7d1eac2 264 /* Notifications consume application buffers. The return value can
rgrover1 445:8328a7d1eac2 265 * be used for resending notifications. */
rgrover1 445:8328a7d1eac2 266 returnValue = BLE_STACK_BUSY;
rgrover1 445:8328a7d1eac2 267 break;
rgrover1 445:8328a7d1eac2 268 }
rgrover1 388:db85a09c27ef 269 }
rgrover1 388:db85a09c27ef 270 } else {
rgrover1 445:8328a7d1eac2 271 returnValue = BLE_ERROR_INVALID_STATE; // if assert is not used
rgrover1 388:db85a09c27ef 272 ASSERT_INT( ERROR_NONE,
rgrover1 388:db85a09c27ef 273 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
rgrover1 388:db85a09c27ef 274 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 275 }
rgrover1 388:db85a09c27ef 276
rgrover1 388:db85a09c27ef 277 return returnValue;
rgrover1 388:db85a09c27ef 278 }
rgrover1 388:db85a09c27ef 279
rgrover1 388:db85a09c27ef 280 ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
rgrover1 388:db85a09c27ef 281 {
rgrover1 388:db85a09c27ef 282 /* Forward the call with the default connection handle. */
rgrover1 388:db85a09c27ef 283 return areUpdatesEnabled(nRF5xGap::getInstance().getConnectionHandle(), characteristic, enabledP);
rgrover1 388:db85a09c27ef 284 }
rgrover1 388:db85a09c27ef 285
rgrover1 388:db85a09c27ef 286 ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
rgrover1 388:db85a09c27ef 287 {
rgrover1 388:db85a09c27ef 288 int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle());
rgrover1 388:db85a09c27ef 289 if (characteristicIndex == -1) {
rgrover1 388:db85a09c27ef 290 return BLE_ERROR_INVALID_PARAM;
rgrover1 388:db85a09c27ef 291 }
rgrover1 388:db85a09c27ef 292
rgrover1 388:db85a09c27ef 293 /* Read the cccd value from the GATT server. */
rgrover1 388:db85a09c27ef 294 GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle;
rgrover1 388:db85a09c27ef 295 uint16_t cccdValue;
rgrover1 388:db85a09c27ef 296 uint16_t length = sizeof(cccdValue);
rgrover1 388:db85a09c27ef 297 ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast<uint8_t *>(&cccdValue), &length);
rgrover1 388:db85a09c27ef 298 if (rc != BLE_ERROR_NONE) {
rgrover1 388:db85a09c27ef 299 return rc;
rgrover1 388:db85a09c27ef 300 }
rgrover1 388:db85a09c27ef 301 if (length != sizeof(cccdValue)) {
rgrover1 388:db85a09c27ef 302 return BLE_ERROR_INVALID_STATE;
rgrover1 388:db85a09c27ef 303 }
rgrover1 388:db85a09c27ef 304
rgrover1 388:db85a09c27ef 305 /* Check for NOTFICATION or INDICATION in CCCD. */
rgrover1 388:db85a09c27ef 306 if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) {
rgrover1 388:db85a09c27ef 307 *enabledP = true;
rgrover1 388:db85a09c27ef 308 }
rgrover1 388:db85a09c27ef 309
rgrover1 388:db85a09c27ef 310 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 311 }
rgrover1 388:db85a09c27ef 312
rgrover1 388:db85a09c27ef 313 /**************************************************************************/
rgrover1 388:db85a09c27ef 314 /*!
rgrover1 388:db85a09c27ef 315 @brief Callback handler for events getting pushed up from the SD
rgrover1 388:db85a09c27ef 316 */
rgrover1 388:db85a09c27ef 317 /**************************************************************************/
rgrover1 388:db85a09c27ef 318 void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
rgrover1 388:db85a09c27ef 319 {
rgrover1 388:db85a09c27ef 320 GattAttribute::Handle_t handle_value;
rgrover1 388:db85a09c27ef 321 GattServerEvents::gattEvent_t eventType;
rgrover1 388:db85a09c27ef 322 const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt;
rgrover1 388:db85a09c27ef 323
rgrover1 388:db85a09c27ef 324 switch (p_ble_evt->header.evt_id) {
rgrover1 388:db85a09c27ef 325 case BLE_GATTS_EVT_WRITE: {
rgrover1 388:db85a09c27ef 326 /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */
rgrover1 388:db85a09c27ef 327
rgrover1 388:db85a09c27ef 328 /* 1.) Handle CCCD changes */
rgrover1 388:db85a09c27ef 329 handle_value = gattsEventP->params.write.handle;
rgrover1 388:db85a09c27ef 330 int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value);
rgrover1 388:db85a09c27ef 331 if ((characteristicIndex != -1) &&
rgrover1 388:db85a09c27ef 332 (p_characteristics[characteristicIndex]->getProperties() &
rgrover1 388:db85a09c27ef 333 (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
rgrover1 388:db85a09c27ef 334
rgrover1 388:db85a09c27ef 335 uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */
rgrover1 388:db85a09c27ef 336
rgrover1 388:db85a09c27ef 337 if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) ||
rgrover1 388:db85a09c27ef 338 ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) {
rgrover1 388:db85a09c27ef 339 eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
rgrover1 388:db85a09c27ef 340 } else {
rgrover1 388:db85a09c27ef 341 eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
rgrover1 388:db85a09c27ef 342 }
rgrover1 388:db85a09c27ef 343
rgrover1 388:db85a09c27ef 344 handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle());
rgrover1 388:db85a09c27ef 345 return;
rgrover1 388:db85a09c27ef 346 }
rgrover1 388:db85a09c27ef 347
rgrover1 388:db85a09c27ef 348 /* 2.) Changes to the characteristic value will be handled with other events below */
rgrover1 388:db85a09c27ef 349 eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
rgrover1 388:db85a09c27ef 350 }
rgrover1 388:db85a09c27ef 351 break;
rgrover1 388:db85a09c27ef 352
rgrover1 388:db85a09c27ef 353 case BLE_GATTS_EVT_HVC:
rgrover1 388:db85a09c27ef 354 /* Indication confirmation received */
rgrover1 388:db85a09c27ef 355 eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
rgrover1 388:db85a09c27ef 356 handle_value = gattsEventP->params.hvc.handle;
rgrover1 388:db85a09c27ef 357 break;
rgrover1 388:db85a09c27ef 358
rgrover1 388:db85a09c27ef 359 case BLE_EVT_TX_COMPLETE: {
rgrover1 388:db85a09c27ef 360 handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count);
rgrover1 388:db85a09c27ef 361 return;
rgrover1 388:db85a09c27ef 362 }
rgrover1 388:db85a09c27ef 363
rgrover1 388:db85a09c27ef 364 case BLE_GATTS_EVT_SYS_ATTR_MISSING:
rgrover1 388:db85a09c27ef 365 sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0);
rgrover1 388:db85a09c27ef 366 return;
rgrover1 388:db85a09c27ef 367
rgrover1 388:db85a09c27ef 368 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
rgrover1 388:db85a09c27ef 369 switch (gattsEventP->params.authorize_request.type) {
rgrover1 388:db85a09c27ef 370 case BLE_GATTS_AUTHORIZE_TYPE_READ:
rgrover1 388:db85a09c27ef 371 eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ;
rgrover1 388:db85a09c27ef 372 handle_value = gattsEventP->params.authorize_request.request.read.handle;
rgrover1 388:db85a09c27ef 373 break;
rgrover1 388:db85a09c27ef 374 case BLE_GATTS_AUTHORIZE_TYPE_WRITE:
rgrover1 388:db85a09c27ef 375 eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ;
rgrover1 388:db85a09c27ef 376 handle_value = gattsEventP->params.authorize_request.request.write.handle;
rgrover1 388:db85a09c27ef 377 break;
rgrover1 388:db85a09c27ef 378 default:
rgrover1 388:db85a09c27ef 379 return;
rgrover1 388:db85a09c27ef 380 }
rgrover1 388:db85a09c27ef 381 break;
rgrover1 388:db85a09c27ef 382
rgrover1 388:db85a09c27ef 383 default:
rgrover1 388:db85a09c27ef 384 return;
rgrover1 388:db85a09c27ef 385 }
rgrover1 388:db85a09c27ef 386
rgrover1 388:db85a09c27ef 387 int characteristicIndex = resolveValueHandleToCharIndex(handle_value);
rgrover1 388:db85a09c27ef 388 if (characteristicIndex == -1) {
rgrover1 388:db85a09c27ef 389 return;
rgrover1 388:db85a09c27ef 390 }
rgrover1 388:db85a09c27ef 391
rgrover1 388:db85a09c27ef 392 /* Find index (charHandle) in the pool */
rgrover1 388:db85a09c27ef 393 switch (eventType) {
rgrover1 388:db85a09c27ef 394 case GattServerEvents::GATT_EVENT_DATA_WRITTEN: {
rgrover1 388:db85a09c27ef 395 GattWriteCallbackParams cbParams = {
rgrover1 430:db7edc9ad0bc 396 .connHandle = gattsEventP->conn_handle,
rgrover1 430:db7edc9ad0bc 397 .handle = handle_value,
rgrover1 430:db7edc9ad0bc 398 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op),
rgrover1 430:db7edc9ad0bc 399 .offset = gattsEventP->params.write.offset,
rgrover1 430:db7edc9ad0bc 400 .len = gattsEventP->params.write.len,
rgrover1 430:db7edc9ad0bc 401 .data = gattsEventP->params.write.data
rgrover1 388:db85a09c27ef 402 };
rgrover1 388:db85a09c27ef 403 handleDataWrittenEvent(&cbParams);
rgrover1 388:db85a09c27ef 404 break;
rgrover1 388:db85a09c27ef 405 }
rgrover1 388:db85a09c27ef 406 case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: {
rgrover1 388:db85a09c27ef 407 GattWriteAuthCallbackParams cbParams = {
rgrover1 430:db7edc9ad0bc 408 .connHandle = gattsEventP->conn_handle,
rgrover1 430:db7edc9ad0bc 409 .handle = handle_value,
rgrover1 430:db7edc9ad0bc 410 .offset = gattsEventP->params.authorize_request.request.write.offset,
rgrover1 430:db7edc9ad0bc 411 .len = gattsEventP->params.authorize_request.request.write.len,
rgrover1 430:db7edc9ad0bc 412 .data = gattsEventP->params.authorize_request.request.write.data,
rgrover1 445:8328a7d1eac2 413 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
rgrover1 445:8328a7d1eac2 414 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
rgrover1 445:8328a7d1eac2 415 * request is to proceed. */
rgrover1 388:db85a09c27ef 416 };
rgrover1 388:db85a09c27ef 417 ble_gatts_rw_authorize_reply_params_t reply = {
rgrover1 388:db85a09c27ef 418 .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
rgrover1 388:db85a09c27ef 419 .params = {
rgrover1 388:db85a09c27ef 420 .write = {
rgrover1 388:db85a09c27ef 421 .gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams)
rgrover1 388:db85a09c27ef 422 }
rgrover1 388:db85a09c27ef 423 }
rgrover1 388:db85a09c27ef 424 };
rgrover1 388:db85a09c27ef 425 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
rgrover1 388:db85a09c27ef 426
rgrover1 388:db85a09c27ef 427 /*
rgrover1 388:db85a09c27ef 428 * If write-authorization is enabled for a characteristic,
rgrover1 388:db85a09c27ef 429 * AUTHORIZATION_REQ event (if replied with true) is *not*
rgrover1 388:db85a09c27ef 430 * followed by another DATA_WRITTEN event; so we still need
rgrover1 388:db85a09c27ef 431 * to invoke handleDataWritten(), much the same as we would
rgrover1 388:db85a09c27ef 432 * have done if write-authorization had not been enabled.
rgrover1 388:db85a09c27ef 433 */
rgrover1 388:db85a09c27ef 434 if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) {
rgrover1 388:db85a09c27ef 435 GattWriteCallbackParams cbParams = {
rgrover1 430:db7edc9ad0bc 436 .connHandle = gattsEventP->conn_handle,
rgrover1 430:db7edc9ad0bc 437 .handle = handle_value,
rgrover1 430:db7edc9ad0bc 438 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op),
rgrover1 430:db7edc9ad0bc 439 .offset = gattsEventP->params.authorize_request.request.write.offset,
rgrover1 430:db7edc9ad0bc 440 .len = gattsEventP->params.authorize_request.request.write.len,
rgrover1 430:db7edc9ad0bc 441 .data = gattsEventP->params.authorize_request.request.write.data,
rgrover1 388:db85a09c27ef 442 };
rgrover1 388:db85a09c27ef 443 handleDataWrittenEvent(&cbParams);
rgrover1 388:db85a09c27ef 444 }
rgrover1 388:db85a09c27ef 445 break;
rgrover1 388:db85a09c27ef 446 }
rgrover1 388:db85a09c27ef 447 case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
rgrover1 388:db85a09c27ef 448 GattReadAuthCallbackParams cbParams = {
rgrover1 445:8328a7d1eac2 449 .connHandle = gattsEventP->conn_handle,
rgrover1 445:8328a7d1eac2 450 .handle = handle_value,
rgrover1 445:8328a7d1eac2 451 .offset = gattsEventP->params.authorize_request.request.read.offset,
rgrover1 445:8328a7d1eac2 452 .len = 0,
rgrover1 445:8328a7d1eac2 453 .data = NULL,
rgrover1 445:8328a7d1eac2 454 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
rgrover1 445:8328a7d1eac2 455 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
rgrover1 445:8328a7d1eac2 456 * request is to proceed. */
rgrover1 388:db85a09c27ef 457 };
rgrover1 388:db85a09c27ef 458
rgrover1 388:db85a09c27ef 459 ble_gatts_rw_authorize_reply_params_t reply = {
rgrover1 388:db85a09c27ef 460 .type = BLE_GATTS_AUTHORIZE_TYPE_READ,
rgrover1 388:db85a09c27ef 461 .params = {
rgrover1 388:db85a09c27ef 462 .read = {
rgrover1 388:db85a09c27ef 463 .gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
rgrover1 388:db85a09c27ef 464 }
rgrover1 388:db85a09c27ef 465 }
rgrover1 388:db85a09c27ef 466 };
rgrover1 388:db85a09c27ef 467
rgrover1 388:db85a09c27ef 468 if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) {
rgrover1 388:db85a09c27ef 469 if (cbParams.data != NULL) {
rgrover1 388:db85a09c27ef 470 reply.params.read.update = 1;
rgrover1 388:db85a09c27ef 471 reply.params.read.offset = cbParams.offset;
rgrover1 388:db85a09c27ef 472 reply.params.read.len = cbParams.len;
rgrover1 388:db85a09c27ef 473 reply.params.read.p_data = cbParams.data;
rgrover1 388:db85a09c27ef 474 }
rgrover1 388:db85a09c27ef 475 }
rgrover1 388:db85a09c27ef 476
rgrover1 388:db85a09c27ef 477 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
rgrover1 388:db85a09c27ef 478 break;
rgrover1 388:db85a09c27ef 479 }
rgrover1 388:db85a09c27ef 480
rgrover1 388:db85a09c27ef 481 default:
rgrover1 388:db85a09c27ef 482 handleEvent(eventType, handle_value);
rgrover1 388:db85a09c27ef 483 break;
rgrover1 388:db85a09c27ef 484 }
rgrover1 388:db85a09c27ef 485 }