library for BLE_GAP_backpack

Dependencies:   nrf51-sdk

Fork of nRF51822 by Nordic Semiconductor

Committer:
vcoubard
Date:
Mon Jan 11 10:19:03 2016 +0000
Revision:
543:53215259c0d2
Parent:
541:884f95bf5351
Child:
544:9e3d053ad4ec
Synchronized with git rev cdd5b921
Author: Vincent Coubard
Relaunch discovery operation when gatt event status is
BLE_GATT_STATUS_SUCCESS.
Report error in the Termination callback

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vcoubard 541:884f95bf5351 1 /* mbed Microcontroller Library
vcoubard 541:884f95bf5351 2 * Copyright (c) 2006-2013 ARM Limited
vcoubard 541:884f95bf5351 3 *
vcoubard 541:884f95bf5351 4 * Licensed under the Apache License, Version 2.0 (the "License");
vcoubard 541:884f95bf5351 5 * you may not use this file except in compliance with the License.
vcoubard 541:884f95bf5351 6 * You may obtain a copy of the License at
vcoubard 541:884f95bf5351 7 *
vcoubard 541:884f95bf5351 8 * http://www.apache.org/licenses/LICENSE-2.0
vcoubard 541:884f95bf5351 9 *
vcoubard 541:884f95bf5351 10 * Unless required by applicable law or agreed to in writing, software
vcoubard 541:884f95bf5351 11 * distributed under the License is distributed on an "AS IS" BASIS,
vcoubard 541:884f95bf5351 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
vcoubard 541:884f95bf5351 13 * See the License for the specific language governing permissions and
vcoubard 541:884f95bf5351 14 * limitations under the License.
vcoubard 541:884f95bf5351 15 */
vcoubard 541:884f95bf5351 16
vcoubard 541:884f95bf5351 17 #include "nRF5xServiceDiscovery.h"
vcoubard 541:884f95bf5351 18
vcoubard 541:884f95bf5351 19 ble_error_t
vcoubard 541:884f95bf5351 20 nRF5xServiceDiscovery::launchCharacteristicDiscovery(Gap::Handle_t connectionHandle,
vcoubard 541:884f95bf5351 21 Gap::Handle_t startHandle,
vcoubard 541:884f95bf5351 22 Gap::Handle_t endHandle)
vcoubard 541:884f95bf5351 23 {
vcoubard 541:884f95bf5351 24 characteristicDiscoveryStarted(connectionHandle);
vcoubard 541:884f95bf5351 25
vcoubard 541:884f95bf5351 26 ble_gattc_handle_range_t handleRange = {
vcoubard 541:884f95bf5351 27 .start_handle = startHandle,
vcoubard 541:884f95bf5351 28 .end_handle = endHandle
vcoubard 541:884f95bf5351 29 };
vcoubard 541:884f95bf5351 30 uint32_t rc;
vcoubard 541:884f95bf5351 31 if ((rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange)) != NRF_SUCCESS) {
vcoubard 541:884f95bf5351 32 terminateCharacteristicDiscovery();
vcoubard 541:884f95bf5351 33 switch (rc) {
vcoubard 541:884f95bf5351 34 case BLE_ERROR_INVALID_CONN_HANDLE:
vcoubard 541:884f95bf5351 35 case NRF_ERROR_INVALID_ADDR:
vcoubard 541:884f95bf5351 36 return BLE_ERROR_INVALID_PARAM;
vcoubard 541:884f95bf5351 37 case NRF_ERROR_BUSY:
vcoubard 541:884f95bf5351 38 return BLE_STACK_BUSY;
vcoubard 541:884f95bf5351 39 default:
vcoubard 541:884f95bf5351 40 case NRF_ERROR_INVALID_STATE:
vcoubard 541:884f95bf5351 41 return BLE_ERROR_INVALID_STATE;
vcoubard 541:884f95bf5351 42 }
vcoubard 541:884f95bf5351 43 }
vcoubard 541:884f95bf5351 44
vcoubard 541:884f95bf5351 45 return BLE_ERROR_NONE;
vcoubard 541:884f95bf5351 46 }
vcoubard 541:884f95bf5351 47
vcoubard 541:884f95bf5351 48 void
vcoubard 541:884f95bf5351 49 nRF5xServiceDiscovery::setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response)
vcoubard 541:884f95bf5351 50 {
vcoubard 541:884f95bf5351 51 serviceIndex = 0;
vcoubard 541:884f95bf5351 52 numServices = response->count;
vcoubard 541:884f95bf5351 53
vcoubard 541:884f95bf5351 54 /* Account for the limitation on the number of discovered services we can handle at a time. */
vcoubard 541:884f95bf5351 55 if (numServices > BLE_DB_DISCOVERY_MAX_SRV) {
vcoubard 541:884f95bf5351 56 numServices = BLE_DB_DISCOVERY_MAX_SRV;
vcoubard 541:884f95bf5351 57 }
vcoubard 541:884f95bf5351 58
vcoubard 541:884f95bf5351 59 serviceUUIDDiscoveryQueue.reset();
vcoubard 541:884f95bf5351 60 for (unsigned serviceIndex = 0; serviceIndex < numServices; serviceIndex++) {
vcoubard 541:884f95bf5351 61 if (response->services[serviceIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
vcoubard 541:884f95bf5351 62 serviceUUIDDiscoveryQueue.enqueue(serviceIndex);
vcoubard 541:884f95bf5351 63 services[serviceIndex].setup(response->services[serviceIndex].handle_range.start_handle,
vcoubard 541:884f95bf5351 64 response->services[serviceIndex].handle_range.end_handle);
vcoubard 541:884f95bf5351 65 } else {
vcoubard 541:884f95bf5351 66 services[serviceIndex].setup(response->services[serviceIndex].uuid.uuid,
vcoubard 541:884f95bf5351 67 response->services[serviceIndex].handle_range.start_handle,
vcoubard 541:884f95bf5351 68 response->services[serviceIndex].handle_range.end_handle);
vcoubard 541:884f95bf5351 69 }
vcoubard 541:884f95bf5351 70 }
vcoubard 541:884f95bf5351 71
vcoubard 541:884f95bf5351 72 /* Trigger discovery of service UUID if necessary. */
vcoubard 541:884f95bf5351 73 if (serviceUUIDDiscoveryQueue.getCount()) {
vcoubard 541:884f95bf5351 74 serviceUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 75 }
vcoubard 541:884f95bf5351 76 }
vcoubard 541:884f95bf5351 77
vcoubard 541:884f95bf5351 78 void
vcoubard 541:884f95bf5351 79 nRF5xServiceDiscovery::setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response)
vcoubard 541:884f95bf5351 80 {
vcoubard 541:884f95bf5351 81 numCharacteristics = response->count;
vcoubard 541:884f95bf5351 82
vcoubard 541:884f95bf5351 83 /* Account for the limitation on the number of discovered characteristics we can handle at a time. */
vcoubard 541:884f95bf5351 84 if (numCharacteristics > BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) {
vcoubard 541:884f95bf5351 85 numCharacteristics = BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV;
vcoubard 541:884f95bf5351 86 }
vcoubard 541:884f95bf5351 87
vcoubard 541:884f95bf5351 88 charUUIDDiscoveryQueue.reset();
vcoubard 541:884f95bf5351 89 for (unsigned charIndex = 0; charIndex < numCharacteristics; charIndex++) {
vcoubard 541:884f95bf5351 90 if (response->chars[charIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
vcoubard 541:884f95bf5351 91 charUUIDDiscoveryQueue.enqueue(charIndex);
vcoubard 541:884f95bf5351 92 characteristics[charIndex].setup(gattc,
vcoubard 541:884f95bf5351 93 connHandle,
vcoubard 541:884f95bf5351 94 response->chars[charIndex].char_props,
vcoubard 541:884f95bf5351 95 response->chars[charIndex].handle_decl,
vcoubard 541:884f95bf5351 96 response->chars[charIndex].handle_value);
vcoubard 541:884f95bf5351 97 } else {
vcoubard 541:884f95bf5351 98 characteristics[charIndex].setup(gattc,
vcoubard 541:884f95bf5351 99 connHandle,
vcoubard 541:884f95bf5351 100 response->chars[charIndex].uuid.uuid,
vcoubard 541:884f95bf5351 101 response->chars[charIndex].char_props,
vcoubard 541:884f95bf5351 102 response->chars[charIndex].handle_decl,
vcoubard 541:884f95bf5351 103 response->chars[charIndex].handle_value);
vcoubard 541:884f95bf5351 104 }
vcoubard 541:884f95bf5351 105 }
vcoubard 541:884f95bf5351 106
vcoubard 541:884f95bf5351 107 /* Trigger discovery of char UUID if necessary. */
vcoubard 541:884f95bf5351 108 if (charUUIDDiscoveryQueue.getCount()) {
vcoubard 541:884f95bf5351 109 charUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 110 }
vcoubard 541:884f95bf5351 111 }
vcoubard 541:884f95bf5351 112
vcoubard 541:884f95bf5351 113 void
vcoubard 541:884f95bf5351 114 nRF5xServiceDiscovery::progressCharacteristicDiscovery(void)
vcoubard 541:884f95bf5351 115 {
vcoubard 543:53215259c0d2 116 for(uint8_t i = 0; i < numCharacteristics; ++i) {
vcoubard 543:53215259c0d2 117 if(state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
vcoubard 543:53215259c0d2 118 return;
vcoubard 543:53215259c0d2 119 }
vcoubard 543:53215259c0d2 120
vcoubard 541:884f95bf5351 121 if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
vcoubard 541:884f95bf5351 122 ((matchingCharacteristicUUID == characteristics[characteristicIndex].getUUID()) &&
vcoubard 541:884f95bf5351 123 (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
vcoubard 541:884f95bf5351 124 if (characteristicCallback) {
vcoubard 543:53215259c0d2 125 characteristicCallback(&characteristics[i]);
vcoubard 541:884f95bf5351 126 }
vcoubard 541:884f95bf5351 127 }
vcoubard 543:53215259c0d2 128 }
vcoubard 541:884f95bf5351 129
vcoubard 543:53215259c0d2 130 if(state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
vcoubard 543:53215259c0d2 131 return;
vcoubard 541:884f95bf5351 132 }
vcoubard 541:884f95bf5351 133
vcoubard 543:53215259c0d2 134 Gap::Handle_t startHandle = characteristics[characteristicIndex - 1].getValueHandle() + 1;
vcoubard 543:53215259c0d2 135 Gap::Handle_t endHandle = services[serviceIndex].getEndHandle();
vcoubard 543:53215259c0d2 136 resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */
vcoubard 541:884f95bf5351 137
vcoubard 543:53215259c0d2 138 if (startHandle < endHandle) {
vcoubard 543:53215259c0d2 139 ble_gattc_handle_range_t handleRange = {
vcoubard 543:53215259c0d2 140 .start_handle = startHandle,
vcoubard 543:53215259c0d2 141 .end_handle = endHandle
vcoubard 543:53215259c0d2 142 };
vcoubard 543:53215259c0d2 143 if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) {
vcoubard 541:884f95bf5351 144 terminateCharacteristicDiscovery();
vcoubard 541:884f95bf5351 145 }
vcoubard 543:53215259c0d2 146 } else {
vcoubard 543:53215259c0d2 147 terminateCharacteristicDiscovery();
vcoubard 541:884f95bf5351 148 }
vcoubard 541:884f95bf5351 149 }
vcoubard 541:884f95bf5351 150
vcoubard 541:884f95bf5351 151 void
vcoubard 541:884f95bf5351 152 nRF5xServiceDiscovery::progressServiceDiscovery(void)
vcoubard 541:884f95bf5351 153 {
vcoubard 541:884f95bf5351 154 /* Iterate through the previously discovered services cached in services[]. */
vcoubard 541:884f95bf5351 155 while ((state == SERVICE_DISCOVERY_ACTIVE) && (serviceIndex < numServices)) {
vcoubard 541:884f95bf5351 156 if ((matchingServiceUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
vcoubard 541:884f95bf5351 157 (matchingServiceUUID == services[serviceIndex].getUUID())) {
vcoubard 541:884f95bf5351 158
vcoubard 541:884f95bf5351 159 if (serviceCallback && (matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN))) {
vcoubard 541:884f95bf5351 160 serviceCallback(&services[serviceIndex]);
vcoubard 541:884f95bf5351 161 }
vcoubard 541:884f95bf5351 162
vcoubard 541:884f95bf5351 163 if ((state == SERVICE_DISCOVERY_ACTIVE) && characteristicCallback) {
vcoubard 541:884f95bf5351 164 launchCharacteristicDiscovery(connHandle, services[serviceIndex].getStartHandle(), services[serviceIndex].getEndHandle());
vcoubard 541:884f95bf5351 165 } else {
vcoubard 541:884f95bf5351 166 serviceIndex++;
vcoubard 541:884f95bf5351 167 }
vcoubard 541:884f95bf5351 168 } else {
vcoubard 541:884f95bf5351 169 serviceIndex++;
vcoubard 541:884f95bf5351 170 }
vcoubard 541:884f95bf5351 171 }
vcoubard 541:884f95bf5351 172
vcoubard 541:884f95bf5351 173 /* Relaunch discovery of new services beyond the last entry cached in services[]. */
vcoubard 541:884f95bf5351 174 if ((state == SERVICE_DISCOVERY_ACTIVE) && (numServices > 0) && (serviceIndex > 0)) {
vcoubard 541:884f95bf5351 175 /* Determine the ending handle of the last cached service. */
vcoubard 541:884f95bf5351 176 Gap::Handle_t endHandle = services[serviceIndex - 1].getEndHandle();
vcoubard 541:884f95bf5351 177 resetDiscoveredServices(); /* Note: resetDiscoveredServices() must come after fetching endHandle. */
vcoubard 541:884f95bf5351 178
vcoubard 541:884f95bf5351 179 if (endHandle == SRV_DISC_END_HANDLE) {
vcoubard 541:884f95bf5351 180 terminateServiceDiscovery();
vcoubard 541:884f95bf5351 181 } else {
vcoubard 541:884f95bf5351 182 if (sd_ble_gattc_primary_services_discover(connHandle, endHandle, NULL) != NRF_SUCCESS) {
vcoubard 541:884f95bf5351 183 terminateServiceDiscovery();
vcoubard 541:884f95bf5351 184 }
vcoubard 541:884f95bf5351 185 }
vcoubard 541:884f95bf5351 186 }
vcoubard 541:884f95bf5351 187 }
vcoubard 541:884f95bf5351 188
vcoubard 541:884f95bf5351 189 void
vcoubard 541:884f95bf5351 190 nRF5xServiceDiscovery::ServiceUUIDDiscoveryQueue::triggerFirst(void)
vcoubard 541:884f95bf5351 191 {
vcoubard 541:884f95bf5351 192 while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
vcoubard 541:884f95bf5351 193 parentDiscoveryObject->state = DISCOVER_SERVICE_UUIDS;
vcoubard 541:884f95bf5351 194
vcoubard 541:884f95bf5351 195 unsigned serviceIndex = getFirst();
vcoubard 541:884f95bf5351 196 ble_uuid_t uuid = {
vcoubard 541:884f95bf5351 197 .uuid = BLE_UUID_SERVICE_PRIMARY,
vcoubard 541:884f95bf5351 198 .type = BLE_UUID_TYPE_BLE,
vcoubard 541:884f95bf5351 199 };
vcoubard 541:884f95bf5351 200 ble_gattc_handle_range_t handleRange = {
vcoubard 541:884f95bf5351 201 .start_handle = parentDiscoveryObject->services[serviceIndex].getStartHandle(),
vcoubard 541:884f95bf5351 202 .end_handle = parentDiscoveryObject->services[serviceIndex].getEndHandle(),
vcoubard 541:884f95bf5351 203 };
vcoubard 541:884f95bf5351 204 if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
vcoubard 541:884f95bf5351 205 return;
vcoubard 541:884f95bf5351 206 }
vcoubard 541:884f95bf5351 207
vcoubard 541:884f95bf5351 208 /* Skip this service if we fail to launch a read for its service-declaration
vcoubard 541:884f95bf5351 209 * attribute. Its UUID will remain INVALID, and it may not match any filters. */
vcoubard 541:884f95bf5351 210 dequeue();
vcoubard 541:884f95bf5351 211 }
vcoubard 541:884f95bf5351 212
vcoubard 541:884f95bf5351 213 /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
vcoubard 541:884f95bf5351 214 if (parentDiscoveryObject->state == DISCOVER_SERVICE_UUIDS) {
vcoubard 541:884f95bf5351 215 parentDiscoveryObject->state = SERVICE_DISCOVERY_ACTIVE;
vcoubard 541:884f95bf5351 216 }
vcoubard 541:884f95bf5351 217 }
vcoubard 541:884f95bf5351 218
vcoubard 541:884f95bf5351 219 void
vcoubard 541:884f95bf5351 220 nRF5xServiceDiscovery::CharUUIDDiscoveryQueue::triggerFirst(void)
vcoubard 541:884f95bf5351 221 {
vcoubard 541:884f95bf5351 222 while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
vcoubard 541:884f95bf5351 223 parentDiscoveryObject->state = DISCOVER_CHARACTERISTIC_UUIDS;
vcoubard 541:884f95bf5351 224
vcoubard 541:884f95bf5351 225 unsigned charIndex = getFirst();
vcoubard 541:884f95bf5351 226 ble_uuid_t uuid = {
vcoubard 541:884f95bf5351 227 .uuid = BLE_UUID_CHARACTERISTIC,
vcoubard 541:884f95bf5351 228 .type = BLE_UUID_TYPE_BLE,
vcoubard 541:884f95bf5351 229 };
vcoubard 541:884f95bf5351 230 ble_gattc_handle_range_t handleRange = { };
vcoubard 541:884f95bf5351 231 handleRange.start_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle();
vcoubard 541:884f95bf5351 232 handleRange.end_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle() + 1;
vcoubard 541:884f95bf5351 233 if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
vcoubard 541:884f95bf5351 234 return;
vcoubard 541:884f95bf5351 235 }
vcoubard 541:884f95bf5351 236
vcoubard 541:884f95bf5351 237 /* Skip this service if we fail to launch a read for its service-declaration
vcoubard 541:884f95bf5351 238 * attribute. Its UUID will remain INVALID, and it may not match any filters. */
vcoubard 541:884f95bf5351 239 dequeue();
vcoubard 541:884f95bf5351 240 }
vcoubard 541:884f95bf5351 241
vcoubard 541:884f95bf5351 242 /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
vcoubard 541:884f95bf5351 243 if (parentDiscoveryObject->state == DISCOVER_CHARACTERISTIC_UUIDS) {
vcoubard 541:884f95bf5351 244 parentDiscoveryObject->state = CHARACTERISTIC_DISCOVERY_ACTIVE;
vcoubard 541:884f95bf5351 245 }
vcoubard 541:884f95bf5351 246 }
vcoubard 541:884f95bf5351 247
vcoubard 541:884f95bf5351 248 void
vcoubard 541:884f95bf5351 249 nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response)
vcoubard 541:884f95bf5351 250 {
vcoubard 541:884f95bf5351 251 if (state == DISCOVER_SERVICE_UUIDS) {
vcoubard 541:884f95bf5351 252 if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID)) {
vcoubard 541:884f95bf5351 253 UUID::LongUUIDBytes_t uuid;
vcoubard 541:884f95bf5351 254 /* Switch longUUID bytes to MSB */
vcoubard 541:884f95bf5351 255 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
vcoubard 541:884f95bf5351 256 uuid[i] = response->handle_value[0].p_value[UUID::LENGTH_OF_LONG_UUID - 1 - i];
vcoubard 541:884f95bf5351 257 }
vcoubard 541:884f95bf5351 258
vcoubard 541:884f95bf5351 259 unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 260 services[serviceIndex].setupLongUUID(uuid);
vcoubard 541:884f95bf5351 261
vcoubard 541:884f95bf5351 262 serviceUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 263 } else {
vcoubard 541:884f95bf5351 264 serviceUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 265 }
vcoubard 541:884f95bf5351 266 } else if (state == DISCOVER_CHARACTERISTIC_UUIDS) {
vcoubard 541:884f95bf5351 267 if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) {
vcoubard 541:884f95bf5351 268 UUID::LongUUIDBytes_t uuid;
vcoubard 541:884f95bf5351 269 /* Switch longUUID bytes to MSB */
vcoubard 541:884f95bf5351 270 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
vcoubard 541:884f95bf5351 271 uuid[i] = response->handle_value[0].p_value[3 + UUID::LENGTH_OF_LONG_UUID - 1 - i];
vcoubard 541:884f95bf5351 272 }
vcoubard 541:884f95bf5351 273
vcoubard 541:884f95bf5351 274 unsigned charIndex = charUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 275 characteristics[charIndex].setupLongUUID(uuid);
vcoubard 541:884f95bf5351 276
vcoubard 541:884f95bf5351 277 charUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 278 } else {
vcoubard 541:884f95bf5351 279 charUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 280 }
vcoubard 541:884f95bf5351 281 }
rgrover1 393:0f7c5048efb3 282 }