Nordic stack and drivers for the mbed BLE API. Version to work around build bug.

Dependents:   microbit_rubber_ducky microbit_mouse_BLE microbit_mouse_BLE_daybreak_version microbit_presenter

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Mon Nov 02 09:05:09 2015 +0000
Revision:
448:1ed5645452e8
Parent:
445:8328a7d1eac2
Child:
449:fd09f590751b
Synchronized with git rev 4af5d03c
Author: Tim
Error check number of characteristics

Currently it just blindly writes beyond the end of the array, leading to impossible-to-find bugs.

It doesn't help that the limit on the number of characteristics doesn't seem to be documented anywhere.

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 448:1ed5645452e8 65 if (characteristicCount >= BLE_TOTAL_CHARACTERISTICS) {
rgrover1 448:1ed5645452e8 66 return BLE_ERROR_NO_MEM;
rgrover1 448:1ed5645452e8 67 }
rgrover1 448:1ed5645452e8 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 388:db85a09c27ef 72 (p_char->getValueAttribute().getInitialLength() == 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 388:db85a09c27ef 98 p_char->getValueAttribute().getInitialLength(),
rgrover1 388:db85a09c27ef 99 p_char->getValueAttribute().getMaxLength(),
rgrover1 388:db85a09c27ef 100 userDescriptionDescriptorValuePtr,
rgrover1 388:db85a09c27ef 101 userDescriptionDescriptorValueLen,
rgrover1 388:db85a09c27ef 102 p_char->isReadAuthorizationEnabled(),
rgrover1 388:db85a09c27ef 103 p_char->isWriteAuthorizationEnabled(),
rgrover1 388:db85a09c27ef 104 &nrfCharacteristicHandles[characteristicCount]),
rgrover1 388:db85a09c27ef 105 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 106
rgrover1 388:db85a09c27ef 107 /* Update the characteristic handle */
rgrover1 388:db85a09c27ef 108 p_characteristics[characteristicCount] = p_char;
rgrover1 388:db85a09c27ef 109 p_char->getValueAttribute().setHandle(nrfCharacteristicHandles[characteristicCount].value_handle);
rgrover1 388:db85a09c27ef 110 characteristicCount++;
rgrover1 388:db85a09c27ef 111
rgrover1 388:db85a09c27ef 112 /* Add optional descriptors if any */
rgrover1 388:db85a09c27ef 113 for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
rgrover1 448:1ed5645452e8 114 if (descriptorCount >= BLE_TOTAL_DESCRIPTORS) {
rgrover1 448:1ed5645452e8 115 return BLE_ERROR_NO_MEM;
rgrover1 448:1ed5645452e8 116 }
rgrover1 448:1ed5645452e8 117
rgrover1 448:1ed5645452e8 118 GattAttribute *p_desc = p_char->getDescriptor(j);
rgrover1 388:db85a09c27ef 119 /* skip the user-description-descriptor here; this has already been handled when adding the characteristic (above). */
rgrover1 388:db85a09c27ef 120 if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
rgrover1 388:db85a09c27ef 121 continue;
rgrover1 388:db85a09c27ef 122 }
rgrover1 388:db85a09c27ef 123
rgrover1 388:db85a09c27ef 124 nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID());
rgrover1 388:db85a09c27ef 125
rgrover1 388:db85a09c27ef 126 ASSERT(ERROR_NONE ==
rgrover1 388:db85a09c27ef 127 custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID,
rgrover1 388:db85a09c27ef 128 &nordicUUID,
rgrover1 388:db85a09c27ef 129 p_desc->getValuePtr(),
rgrover1 388:db85a09c27ef 130 p_desc->getInitialLength(),
rgrover1 388:db85a09c27ef 131 p_desc->getMaxLength(),
rgrover1 388:db85a09c27ef 132 &nrfDescriptorHandles[descriptorCount]),
rgrover1 388:db85a09c27ef 133 BLE_ERROR_PARAM_OUT_OF_RANGE);
rgrover1 388:db85a09c27ef 134
rgrover1 388:db85a09c27ef 135 p_descriptors[descriptorCount++] = p_desc;
rgrover1 388:db85a09c27ef 136 p_desc->setHandle(nrfDescriptorHandles[descriptorCount]);
rgrover1 388:db85a09c27ef 137 }
rgrover1 388:db85a09c27ef 138 }
rgrover1 388:db85a09c27ef 139
rgrover1 388:db85a09c27ef 140 serviceCount++;
rgrover1 388:db85a09c27ef 141
rgrover1 388:db85a09c27ef 142 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 143 }
rgrover1 388:db85a09c27ef 144
rgrover1 388:db85a09c27ef 145 /**************************************************************************/
rgrover1 388:db85a09c27ef 146 /*!
rgrover1 388:db85a09c27ef 147 @brief Reads the value of a characteristic, based on the service
rgrover1 388:db85a09c27ef 148 and characteristic index fields
rgrover1 388:db85a09c27ef 149
rgrover1 388:db85a09c27ef 150 @param[in] attributeHandle
rgrover1 388:db85a09c27ef 151 The handle of the GattCharacteristic to read from
rgrover1 388:db85a09c27ef 152 @param[in] buffer
rgrover1 388:db85a09c27ef 153 Buffer to hold the the characteristic's value
rgrover1 388:db85a09c27ef 154 (raw byte array in LSB format)
rgrover1 388:db85a09c27ef 155 @param[in/out] len
rgrover1 388:db85a09c27ef 156 input: Length in bytes to be read.
rgrover1 388:db85a09c27ef 157 output: Total length of attribute value upon successful return.
rgrover1 388:db85a09c27ef 158
rgrover1 388:db85a09c27ef 159 @returns ble_error_t
rgrover1 388:db85a09c27ef 160
rgrover1 388:db85a09c27ef 161 @retval BLE_ERROR_NONE
rgrover1 388:db85a09c27ef 162 Everything executed properly
rgrover1 388:db85a09c27ef 163 */
rgrover1 388:db85a09c27ef 164 /**************************************************************************/
rgrover1 388:db85a09c27ef 165 ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
rgrover1 388:db85a09c27ef 166 {
rgrover1 388:db85a09c27ef 167 return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP);
rgrover1 388:db85a09c27ef 168 }
rgrover1 388:db85a09c27ef 169
rgrover1 388:db85a09c27ef 170 ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
rgrover1 388:db85a09c27ef 171 {
rgrover1 388:db85a09c27ef 172 ble_gatts_value_t value = {
rgrover1 388:db85a09c27ef 173 .len = *lengthP,
rgrover1 388:db85a09c27ef 174 .offset = 0,
rgrover1 388:db85a09c27ef 175 .p_value = buffer,
rgrover1 388:db85a09c27ef 176 };
rgrover1 388:db85a09c27ef 177
rgrover1 388:db85a09c27ef 178 ASSERT( ERROR_NONE ==
rgrover1 388:db85a09c27ef 179 sd_ble_gatts_value_get(connectionHandle, attributeHandle, &value),
rgrover1 388:db85a09c27ef 180 BLE_ERROR_PARAM_OUT_OF_RANGE);
rgrover1 388:db85a09c27ef 181 *lengthP = value.len;
rgrover1 388:db85a09c27ef 182
rgrover1 388:db85a09c27ef 183 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 184 }
rgrover1 388:db85a09c27ef 185
rgrover1 388:db85a09c27ef 186 /**************************************************************************/
rgrover1 388:db85a09c27ef 187 /*!
rgrover1 388:db85a09c27ef 188 @brief Updates the value of a characteristic, based on the service
rgrover1 388:db85a09c27ef 189 and characteristic index fields
rgrover1 388:db85a09c27ef 190
rgrover1 388:db85a09c27ef 191 @param[in] charHandle
rgrover1 388:db85a09c27ef 192 The handle of the GattCharacteristic to write to
rgrover1 388:db85a09c27ef 193 @param[in] buffer
rgrover1 388:db85a09c27ef 194 Data to use when updating the characteristic's value
rgrover1 388:db85a09c27ef 195 (raw byte array in LSB format)
rgrover1 388:db85a09c27ef 196 @param[in] len
rgrover1 388:db85a09c27ef 197 The number of bytes in buffer
rgrover1 388:db85a09c27ef 198
rgrover1 388:db85a09c27ef 199 @returns ble_error_t
rgrover1 388:db85a09c27ef 200
rgrover1 388:db85a09c27ef 201 @retval BLE_ERROR_NONE
rgrover1 388:db85a09c27ef 202 Everything executed properly
rgrover1 388:db85a09c27ef 203 */
rgrover1 388:db85a09c27ef 204 /**************************************************************************/
rgrover1 388:db85a09c27ef 205 ble_error_t nRF5xGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
rgrover1 388:db85a09c27ef 206 {
rgrover1 388:db85a09c27ef 207 return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly);
rgrover1 388:db85a09c27ef 208 }
rgrover1 388:db85a09c27ef 209
rgrover1 388:db85a09c27ef 210 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 211 {
rgrover1 388:db85a09c27ef 212 ble_error_t returnValue = BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 213
rgrover1 388:db85a09c27ef 214 ble_gatts_value_t value = {
rgrover1 388:db85a09c27ef 215 .len = len,
rgrover1 388:db85a09c27ef 216 .offset = 0,
rgrover1 388:db85a09c27ef 217 .p_value = const_cast<uint8_t *>(buffer),
rgrover1 388:db85a09c27ef 218 };
rgrover1 388:db85a09c27ef 219
rgrover1 388:db85a09c27ef 220 if (localOnly) {
rgrover1 388:db85a09c27ef 221 /* Only update locally regardless of notify/indicate */
rgrover1 388:db85a09c27ef 222 ASSERT_INT( ERROR_NONE,
rgrover1 388:db85a09c27ef 223 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
rgrover1 388:db85a09c27ef 224 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 225 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 226 }
rgrover1 388:db85a09c27ef 227
rgrover1 388:db85a09c27ef 228 int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
rgrover1 388:db85a09c27ef 229 if ((characteristicIndex != -1) &&
rgrover1 445:8328a7d1eac2 230 (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
rgrover1 388:db85a09c27ef 231 /* HVX update for the characteristic value */
rgrover1 388:db85a09c27ef 232 ble_gatts_hvx_params_t hvx_params;
rgrover1 388:db85a09c27ef 233
rgrover1 388:db85a09c27ef 234 hvx_params.handle = attributeHandle;
rgrover1 388:db85a09c27ef 235 hvx_params.type =
rgrover1 388:db85a09c27ef 236 (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
rgrover1 388:db85a09c27ef 237 hvx_params.offset = 0;
rgrover1 388:db85a09c27ef 238 hvx_params.p_data = const_cast<uint8_t *>(buffer);
rgrover1 388:db85a09c27ef 239 hvx_params.p_len = &len;
rgrover1 441:b52f5b70e62a 240
rgrover1 445:8328a7d1eac2 241 if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */
rgrover1 445:8328a7d1eac2 242 connectionHandle = nRF5xGap::getInstance().getConnectionHandle();
rgrover1 445:8328a7d1eac2 243 }
rgrover1 445:8328a7d1eac2 244 error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
rgrover1 445:8328a7d1eac2 245 if (error != ERROR_NONE) {
rgrover1 445:8328a7d1eac2 246 switch (error) {
rgrover1 445:8328a7d1eac2 247 case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */
rgrover1 445:8328a7d1eac2 248 case ERROR_BUSY:
rgrover1 445:8328a7d1eac2 249 returnValue = BLE_STACK_BUSY;
rgrover1 445:8328a7d1eac2 250 break;
rgrover1 388:db85a09c27ef 251
rgrover1 445:8328a7d1eac2 252 case ERROR_INVALID_STATE:
rgrover1 445:8328a7d1eac2 253 case ERROR_BLEGATTS_SYS_ATTR_MISSING:
rgrover1 445:8328a7d1eac2 254 returnValue = BLE_ERROR_INVALID_STATE;
rgrover1 445:8328a7d1eac2 255 break;
rgrover1 388:db85a09c27ef 256
rgrover1 445:8328a7d1eac2 257 default :
rgrover1 445:8328a7d1eac2 258 ASSERT_INT( ERROR_NONE,
rgrover1 445:8328a7d1eac2 259 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
rgrover1 445:8328a7d1eac2 260 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 445:8328a7d1eac2 261
rgrover1 445:8328a7d1eac2 262 /* Notifications consume application buffers. The return value can
rgrover1 445:8328a7d1eac2 263 * be used for resending notifications. */
rgrover1 445:8328a7d1eac2 264 returnValue = BLE_STACK_BUSY;
rgrover1 445:8328a7d1eac2 265 break;
rgrover1 445:8328a7d1eac2 266 }
rgrover1 388:db85a09c27ef 267 }
rgrover1 388:db85a09c27ef 268 } else {
rgrover1 445:8328a7d1eac2 269 returnValue = BLE_ERROR_INVALID_STATE; // if assert is not used
rgrover1 388:db85a09c27ef 270 ASSERT_INT( ERROR_NONE,
rgrover1 388:db85a09c27ef 271 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
rgrover1 388:db85a09c27ef 272 BLE_ERROR_PARAM_OUT_OF_RANGE );
rgrover1 388:db85a09c27ef 273 }
rgrover1 388:db85a09c27ef 274
rgrover1 388:db85a09c27ef 275 return returnValue;
rgrover1 388:db85a09c27ef 276 }
rgrover1 388:db85a09c27ef 277
rgrover1 388:db85a09c27ef 278 ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
rgrover1 388:db85a09c27ef 279 {
rgrover1 388:db85a09c27ef 280 /* Forward the call with the default connection handle. */
rgrover1 388:db85a09c27ef 281 return areUpdatesEnabled(nRF5xGap::getInstance().getConnectionHandle(), characteristic, enabledP);
rgrover1 388:db85a09c27ef 282 }
rgrover1 388:db85a09c27ef 283
rgrover1 388:db85a09c27ef 284 ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
rgrover1 388:db85a09c27ef 285 {
rgrover1 388:db85a09c27ef 286 int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle());
rgrover1 388:db85a09c27ef 287 if (characteristicIndex == -1) {
rgrover1 388:db85a09c27ef 288 return BLE_ERROR_INVALID_PARAM;
rgrover1 388:db85a09c27ef 289 }
rgrover1 388:db85a09c27ef 290
rgrover1 388:db85a09c27ef 291 /* Read the cccd value from the GATT server. */
rgrover1 388:db85a09c27ef 292 GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle;
rgrover1 388:db85a09c27ef 293 uint16_t cccdValue;
rgrover1 388:db85a09c27ef 294 uint16_t length = sizeof(cccdValue);
rgrover1 388:db85a09c27ef 295 ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast<uint8_t *>(&cccdValue), &length);
rgrover1 388:db85a09c27ef 296 if (rc != BLE_ERROR_NONE) {
rgrover1 388:db85a09c27ef 297 return rc;
rgrover1 388:db85a09c27ef 298 }
rgrover1 388:db85a09c27ef 299 if (length != sizeof(cccdValue)) {
rgrover1 388:db85a09c27ef 300 return BLE_ERROR_INVALID_STATE;
rgrover1 388:db85a09c27ef 301 }
rgrover1 388:db85a09c27ef 302
rgrover1 388:db85a09c27ef 303 /* Check for NOTFICATION or INDICATION in CCCD. */
rgrover1 388:db85a09c27ef 304 if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) {
rgrover1 388:db85a09c27ef 305 *enabledP = true;
rgrover1 388:db85a09c27ef 306 }
rgrover1 388:db85a09c27ef 307
rgrover1 388:db85a09c27ef 308 return BLE_ERROR_NONE;
rgrover1 388:db85a09c27ef 309 }
rgrover1 388:db85a09c27ef 310
rgrover1 388:db85a09c27ef 311 /**************************************************************************/
rgrover1 388:db85a09c27ef 312 /*!
rgrover1 388:db85a09c27ef 313 @brief Callback handler for events getting pushed up from the SD
rgrover1 388:db85a09c27ef 314 */
rgrover1 388:db85a09c27ef 315 /**************************************************************************/
rgrover1 388:db85a09c27ef 316 void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
rgrover1 388:db85a09c27ef 317 {
rgrover1 388:db85a09c27ef 318 GattAttribute::Handle_t handle_value;
rgrover1 388:db85a09c27ef 319 GattServerEvents::gattEvent_t eventType;
rgrover1 388:db85a09c27ef 320 const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt;
rgrover1 388:db85a09c27ef 321
rgrover1 388:db85a09c27ef 322 switch (p_ble_evt->header.evt_id) {
rgrover1 388:db85a09c27ef 323 case BLE_GATTS_EVT_WRITE: {
rgrover1 388:db85a09c27ef 324 /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */
rgrover1 388:db85a09c27ef 325
rgrover1 388:db85a09c27ef 326 /* 1.) Handle CCCD changes */
rgrover1 388:db85a09c27ef 327 handle_value = gattsEventP->params.write.handle;
rgrover1 388:db85a09c27ef 328 int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value);
rgrover1 388:db85a09c27ef 329 if ((characteristicIndex != -1) &&
rgrover1 388:db85a09c27ef 330 (p_characteristics[characteristicIndex]->getProperties() &
rgrover1 388:db85a09c27ef 331 (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
rgrover1 388:db85a09c27ef 332
rgrover1 388:db85a09c27ef 333 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 334
rgrover1 388:db85a09c27ef 335 if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) ||
rgrover1 388:db85a09c27ef 336 ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) {
rgrover1 388:db85a09c27ef 337 eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
rgrover1 388:db85a09c27ef 338 } else {
rgrover1 388:db85a09c27ef 339 eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
rgrover1 388:db85a09c27ef 340 }
rgrover1 388:db85a09c27ef 341
rgrover1 388:db85a09c27ef 342 handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle());
rgrover1 388:db85a09c27ef 343 return;
rgrover1 388:db85a09c27ef 344 }
rgrover1 388:db85a09c27ef 345
rgrover1 388:db85a09c27ef 346 /* 2.) Changes to the characteristic value will be handled with other events below */
rgrover1 388:db85a09c27ef 347 eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
rgrover1 388:db85a09c27ef 348 }
rgrover1 388:db85a09c27ef 349 break;
rgrover1 388:db85a09c27ef 350
rgrover1 388:db85a09c27ef 351 case BLE_GATTS_EVT_HVC:
rgrover1 388:db85a09c27ef 352 /* Indication confirmation received */
rgrover1 388:db85a09c27ef 353 eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
rgrover1 388:db85a09c27ef 354 handle_value = gattsEventP->params.hvc.handle;
rgrover1 388:db85a09c27ef 355 break;
rgrover1 388:db85a09c27ef 356
rgrover1 388:db85a09c27ef 357 case BLE_EVT_TX_COMPLETE: {
rgrover1 388:db85a09c27ef 358 handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count);
rgrover1 388:db85a09c27ef 359 return;
rgrover1 388:db85a09c27ef 360 }
rgrover1 388:db85a09c27ef 361
rgrover1 388:db85a09c27ef 362 case BLE_GATTS_EVT_SYS_ATTR_MISSING:
rgrover1 388:db85a09c27ef 363 sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0);
rgrover1 388:db85a09c27ef 364 return;
rgrover1 388:db85a09c27ef 365
rgrover1 388:db85a09c27ef 366 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
rgrover1 388:db85a09c27ef 367 switch (gattsEventP->params.authorize_request.type) {
rgrover1 388:db85a09c27ef 368 case BLE_GATTS_AUTHORIZE_TYPE_READ:
rgrover1 388:db85a09c27ef 369 eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ;
rgrover1 388:db85a09c27ef 370 handle_value = gattsEventP->params.authorize_request.request.read.handle;
rgrover1 388:db85a09c27ef 371 break;
rgrover1 388:db85a09c27ef 372 case BLE_GATTS_AUTHORIZE_TYPE_WRITE:
rgrover1 388:db85a09c27ef 373 eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ;
rgrover1 388:db85a09c27ef 374 handle_value = gattsEventP->params.authorize_request.request.write.handle;
rgrover1 388:db85a09c27ef 375 break;
rgrover1 388:db85a09c27ef 376 default:
rgrover1 388:db85a09c27ef 377 return;
rgrover1 388:db85a09c27ef 378 }
rgrover1 388:db85a09c27ef 379 break;
rgrover1 388:db85a09c27ef 380
rgrover1 388:db85a09c27ef 381 default:
rgrover1 388:db85a09c27ef 382 return;
rgrover1 388:db85a09c27ef 383 }
rgrover1 388:db85a09c27ef 384
rgrover1 388:db85a09c27ef 385 int characteristicIndex = resolveValueHandleToCharIndex(handle_value);
rgrover1 388:db85a09c27ef 386 if (characteristicIndex == -1) {
rgrover1 388:db85a09c27ef 387 return;
rgrover1 388:db85a09c27ef 388 }
rgrover1 388:db85a09c27ef 389
rgrover1 388:db85a09c27ef 390 /* Find index (charHandle) in the pool */
rgrover1 388:db85a09c27ef 391 switch (eventType) {
rgrover1 388:db85a09c27ef 392 case GattServerEvents::GATT_EVENT_DATA_WRITTEN: {
rgrover1 388:db85a09c27ef 393 GattWriteCallbackParams cbParams = {
rgrover1 430:db7edc9ad0bc 394 .connHandle = gattsEventP->conn_handle,
rgrover1 430:db7edc9ad0bc 395 .handle = handle_value,
rgrover1 430:db7edc9ad0bc 396 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op),
rgrover1 430:db7edc9ad0bc 397 .offset = gattsEventP->params.write.offset,
rgrover1 430:db7edc9ad0bc 398 .len = gattsEventP->params.write.len,
rgrover1 430:db7edc9ad0bc 399 .data = gattsEventP->params.write.data
rgrover1 388:db85a09c27ef 400 };
rgrover1 388:db85a09c27ef 401 handleDataWrittenEvent(&cbParams);
rgrover1 388:db85a09c27ef 402 break;
rgrover1 388:db85a09c27ef 403 }
rgrover1 388:db85a09c27ef 404 case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: {
rgrover1 388:db85a09c27ef 405 GattWriteAuthCallbackParams cbParams = {
rgrover1 430:db7edc9ad0bc 406 .connHandle = gattsEventP->conn_handle,
rgrover1 430:db7edc9ad0bc 407 .handle = handle_value,
rgrover1 430:db7edc9ad0bc 408 .offset = gattsEventP->params.authorize_request.request.write.offset,
rgrover1 430:db7edc9ad0bc 409 .len = gattsEventP->params.authorize_request.request.write.len,
rgrover1 430:db7edc9ad0bc 410 .data = gattsEventP->params.authorize_request.request.write.data,
rgrover1 445:8328a7d1eac2 411 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
rgrover1 445:8328a7d1eac2 412 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
rgrover1 445:8328a7d1eac2 413 * request is to proceed. */
rgrover1 388:db85a09c27ef 414 };
rgrover1 388:db85a09c27ef 415 ble_gatts_rw_authorize_reply_params_t reply = {
rgrover1 388:db85a09c27ef 416 .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
rgrover1 388:db85a09c27ef 417 .params = {
rgrover1 388:db85a09c27ef 418 .write = {
rgrover1 388:db85a09c27ef 419 .gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams)
rgrover1 388:db85a09c27ef 420 }
rgrover1 388:db85a09c27ef 421 }
rgrover1 388:db85a09c27ef 422 };
rgrover1 388:db85a09c27ef 423 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
rgrover1 388:db85a09c27ef 424
rgrover1 388:db85a09c27ef 425 /*
rgrover1 388:db85a09c27ef 426 * If write-authorization is enabled for a characteristic,
rgrover1 388:db85a09c27ef 427 * AUTHORIZATION_REQ event (if replied with true) is *not*
rgrover1 388:db85a09c27ef 428 * followed by another DATA_WRITTEN event; so we still need
rgrover1 388:db85a09c27ef 429 * to invoke handleDataWritten(), much the same as we would
rgrover1 388:db85a09c27ef 430 * have done if write-authorization had not been enabled.
rgrover1 388:db85a09c27ef 431 */
rgrover1 388:db85a09c27ef 432 if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) {
rgrover1 388:db85a09c27ef 433 GattWriteCallbackParams cbParams = {
rgrover1 430:db7edc9ad0bc 434 .connHandle = gattsEventP->conn_handle,
rgrover1 430:db7edc9ad0bc 435 .handle = handle_value,
rgrover1 430:db7edc9ad0bc 436 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op),
rgrover1 430:db7edc9ad0bc 437 .offset = gattsEventP->params.authorize_request.request.write.offset,
rgrover1 430:db7edc9ad0bc 438 .len = gattsEventP->params.authorize_request.request.write.len,
rgrover1 430:db7edc9ad0bc 439 .data = gattsEventP->params.authorize_request.request.write.data,
rgrover1 388:db85a09c27ef 440 };
rgrover1 388:db85a09c27ef 441 handleDataWrittenEvent(&cbParams);
rgrover1 388:db85a09c27ef 442 }
rgrover1 388:db85a09c27ef 443 break;
rgrover1 388:db85a09c27ef 444 }
rgrover1 388:db85a09c27ef 445 case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
rgrover1 388:db85a09c27ef 446 GattReadAuthCallbackParams cbParams = {
rgrover1 445:8328a7d1eac2 447 .connHandle = gattsEventP->conn_handle,
rgrover1 445:8328a7d1eac2 448 .handle = handle_value,
rgrover1 445:8328a7d1eac2 449 .offset = gattsEventP->params.authorize_request.request.read.offset,
rgrover1 445:8328a7d1eac2 450 .len = 0,
rgrover1 445:8328a7d1eac2 451 .data = NULL,
rgrover1 445:8328a7d1eac2 452 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
rgrover1 445:8328a7d1eac2 453 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
rgrover1 445:8328a7d1eac2 454 * request is to proceed. */
rgrover1 388:db85a09c27ef 455 };
rgrover1 388:db85a09c27ef 456
rgrover1 388:db85a09c27ef 457 ble_gatts_rw_authorize_reply_params_t reply = {
rgrover1 388:db85a09c27ef 458 .type = BLE_GATTS_AUTHORIZE_TYPE_READ,
rgrover1 388:db85a09c27ef 459 .params = {
rgrover1 388:db85a09c27ef 460 .read = {
rgrover1 388:db85a09c27ef 461 .gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
rgrover1 388:db85a09c27ef 462 }
rgrover1 388:db85a09c27ef 463 }
rgrover1 388:db85a09c27ef 464 };
rgrover1 388:db85a09c27ef 465
rgrover1 388:db85a09c27ef 466 if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) {
rgrover1 388:db85a09c27ef 467 if (cbParams.data != NULL) {
rgrover1 388:db85a09c27ef 468 reply.params.read.update = 1;
rgrover1 388:db85a09c27ef 469 reply.params.read.offset = cbParams.offset;
rgrover1 388:db85a09c27ef 470 reply.params.read.len = cbParams.len;
rgrover1 388:db85a09c27ef 471 reply.params.read.p_data = cbParams.data;
rgrover1 388:db85a09c27ef 472 }
rgrover1 388:db85a09c27ef 473 }
rgrover1 388:db85a09c27ef 474
rgrover1 388:db85a09c27ef 475 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
rgrover1 388:db85a09c27ef 476 break;
rgrover1 388:db85a09c27ef 477 }
rgrover1 388:db85a09c27ef 478
rgrover1 388:db85a09c27ef 479 default:
rgrover1 388:db85a09c27ef 480 handleEvent(eventType, handle_value);
rgrover1 388:db85a09c27ef 481 break;
rgrover1 388:db85a09c27ef 482 }
rgrover1 388:db85a09c27ef 483 }