No changes

Fork of nRF51822 by Nordic Semiconductor

Committer:
rgrover1
Date:
Tue Aug 11 15:14:23 2015 +0100
Revision:
416:5b7d26035f2b
Parent:
415:92bda1851be2
Child:
417:d79a89cccddd
Synchronized with git rev 3eabc779
Author: Jean-Philippe Brucker
Disable GattClient features when using S110 SoftDevice

S110 compatibility is already present, but this patch adds proper handling
of observer/central related features:
* Gap::startScan will return BLE_ERRROR_NOT_IMPLEMENTED (instead of
PARAM_OUT_OF_RANGE)
* nRF5xGattClient uses the default GattClient implementation when S110 is
in use. All if its methods return NOT_IMPLEMENTED.

Example: for an application that acts as both a central and a peripheral,
using S110 will make the ble.gap().startScan() call return
BLE_ERROR_NOT_IMPLEMENTED, and advertisement features will continue
running normally.
In addition, with GCC, this patch will free 344 bytes of RAM and 2504
bytes of flash.

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