No changes

Fork of nRF51822 by Nordic Semiconductor

Committer:
vcoubard
Date:
Mon Jan 11 10:19:12 2016 +0000
Revision:
555:dc3945bd78d7
Parent:
549:3f782c64d014
Child:
557:e4218a32be51
Synchronized with git rev dd41fd0f
Author: Rohit Grover
Release 2.1.4
=============

Minor change: retain discovered UUIDs in little-endian order.

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 549:3f782c64d014 30 uint32_t rc;
vcoubard 549:3f782c64d014 31 if ((rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange)) != NRF_SUCCESS) {
vcoubard 549:3f782c64d014 32 terminateCharacteristicDiscovery();
vcoubard 549:3f782c64d014 33 switch (rc) {
vcoubard 549:3f782c64d014 34 case BLE_ERROR_INVALID_CONN_HANDLE:
vcoubard 549:3f782c64d014 35 case NRF_ERROR_INVALID_ADDR:
vcoubard 549:3f782c64d014 36 return BLE_ERROR_INVALID_PARAM;
vcoubard 549:3f782c64d014 37 case NRF_ERROR_BUSY:
vcoubard 549:3f782c64d014 38 return BLE_STACK_BUSY;
vcoubard 549:3f782c64d014 39 default:
vcoubard 549:3f782c64d014 40 case NRF_ERROR_INVALID_STATE:
vcoubard 549:3f782c64d014 41 return BLE_ERROR_INVALID_STATE;
vcoubard 549:3f782c64d014 42 }
vcoubard 541:884f95bf5351 43 }
vcoubard 541:884f95bf5351 44
vcoubard 549:3f782c64d014 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 549:3f782c64d014 81 characteristicIndex = 0;
vcoubard 541:884f95bf5351 82 numCharacteristics = response->count;
vcoubard 541:884f95bf5351 83
vcoubard 541:884f95bf5351 84 /* Account for the limitation on the number of discovered characteristics we can handle at a time. */
vcoubard 541:884f95bf5351 85 if (numCharacteristics > BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) {
vcoubard 541:884f95bf5351 86 numCharacteristics = BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV;
vcoubard 541:884f95bf5351 87 }
vcoubard 541:884f95bf5351 88
vcoubard 541:884f95bf5351 89 charUUIDDiscoveryQueue.reset();
vcoubard 541:884f95bf5351 90 for (unsigned charIndex = 0; charIndex < numCharacteristics; charIndex++) {
vcoubard 541:884f95bf5351 91 if (response->chars[charIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
vcoubard 541:884f95bf5351 92 charUUIDDiscoveryQueue.enqueue(charIndex);
vcoubard 541:884f95bf5351 93 characteristics[charIndex].setup(gattc,
vcoubard 541:884f95bf5351 94 connHandle,
vcoubard 541:884f95bf5351 95 response->chars[charIndex].char_props,
vcoubard 541:884f95bf5351 96 response->chars[charIndex].handle_decl,
vcoubard 541:884f95bf5351 97 response->chars[charIndex].handle_value);
vcoubard 541:884f95bf5351 98 } else {
vcoubard 541:884f95bf5351 99 characteristics[charIndex].setup(gattc,
vcoubard 541:884f95bf5351 100 connHandle,
vcoubard 541:884f95bf5351 101 response->chars[charIndex].uuid.uuid,
vcoubard 541:884f95bf5351 102 response->chars[charIndex].char_props,
vcoubard 541:884f95bf5351 103 response->chars[charIndex].handle_decl,
vcoubard 541:884f95bf5351 104 response->chars[charIndex].handle_value);
vcoubard 541:884f95bf5351 105 }
vcoubard 541:884f95bf5351 106 }
vcoubard 541:884f95bf5351 107
vcoubard 541:884f95bf5351 108 /* Trigger discovery of char UUID if necessary. */
vcoubard 541:884f95bf5351 109 if (charUUIDDiscoveryQueue.getCount()) {
vcoubard 541:884f95bf5351 110 charUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 111 }
vcoubard 541:884f95bf5351 112 }
vcoubard 541:884f95bf5351 113
vcoubard 541:884f95bf5351 114 void
vcoubard 541:884f95bf5351 115 nRF5xServiceDiscovery::progressCharacteristicDiscovery(void)
vcoubard 541:884f95bf5351 116 {
vcoubard 549:3f782c64d014 117 /* Iterate through the previously discovered characteristics cached in characteristics[]. */
vcoubard 549:3f782c64d014 118 while ((state == CHARACTERISTIC_DISCOVERY_ACTIVE) && (characteristicIndex < numCharacteristics)) {
vcoubard 544:9e3d053ad4ec 119 if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
vcoubard 549:3f782c64d014 120 ((matchingCharacteristicUUID == characteristics[characteristicIndex].getUUID()) &&
vcoubard 544:9e3d053ad4ec 121 (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
vcoubard 544:9e3d053ad4ec 122 if (characteristicCallback) {
vcoubard 549:3f782c64d014 123 characteristicCallback(&characteristics[characteristicIndex]);
vcoubard 544:9e3d053ad4ec 124 }
vcoubard 544:9e3d053ad4ec 125 }
vcoubard 544:9e3d053ad4ec 126
vcoubard 549:3f782c64d014 127 characteristicIndex++;
vcoubard 541:884f95bf5351 128 }
vcoubard 541:884f95bf5351 129
vcoubard 549:3f782c64d014 130 /* Relaunch discovery of new characteristics beyond the last entry cached in characteristics[]. */
vcoubard 549:3f782c64d014 131 if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) {
vcoubard 549:3f782c64d014 132 /* Determine the ending handle of the last cached characteristic. */
vcoubard 549:3f782c64d014 133 Gap::Handle_t startHandle = characteristics[characteristicIndex - 1].getValueHandle() + 1;
vcoubard 549:3f782c64d014 134 Gap::Handle_t endHandle = services[serviceIndex].getEndHandle();
vcoubard 549:3f782c64d014 135 resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */
vcoubard 541:884f95bf5351 136
vcoubard 549:3f782c64d014 137 if (startHandle < endHandle) {
vcoubard 549:3f782c64d014 138 ble_gattc_handle_range_t handleRange = {
vcoubard 549:3f782c64d014 139 .start_handle = startHandle,
vcoubard 549:3f782c64d014 140 .end_handle = endHandle
vcoubard 549:3f782c64d014 141 };
vcoubard 549:3f782c64d014 142 if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) {
vcoubard 549:3f782c64d014 143 terminateCharacteristicDiscovery();
vcoubard 549:3f782c64d014 144 }
vcoubard 549:3f782c64d014 145 } else {
vcoubard 549:3f782c64d014 146 terminateCharacteristicDiscovery();
vcoubard 541:884f95bf5351 147 }
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 555:dc3945bd78d7 254 memcpy(uuid, response->handle_value[0].p_value, UUID::LENGTH_OF_LONG_UUID);
vcoubard 541:884f95bf5351 255
vcoubard 541:884f95bf5351 256 unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 257 services[serviceIndex].setupLongUUID(uuid);
vcoubard 541:884f95bf5351 258
vcoubard 541:884f95bf5351 259 serviceUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 260 } else {
vcoubard 541:884f95bf5351 261 serviceUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 262 }
vcoubard 541:884f95bf5351 263 } else if (state == DISCOVER_CHARACTERISTIC_UUIDS) {
vcoubard 541:884f95bf5351 264 if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) {
vcoubard 541:884f95bf5351 265 UUID::LongUUIDBytes_t uuid;
vcoubard 555:dc3945bd78d7 266
vcoubard 555:dc3945bd78d7 267 memcpy(uuid, &(response->handle_value[0].p_value[3]), UUID::LENGTH_OF_LONG_UUID);
vcoubard 541:884f95bf5351 268
vcoubard 541:884f95bf5351 269 unsigned charIndex = charUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 270 characteristics[charIndex].setupLongUUID(uuid);
vcoubard 541:884f95bf5351 271
vcoubard 541:884f95bf5351 272 charUUIDDiscoveryQueue.triggerFirst();
vcoubard 541:884f95bf5351 273 } else {
vcoubard 541:884f95bf5351 274 charUUIDDiscoveryQueue.dequeue();
vcoubard 541:884f95bf5351 275 }
vcoubard 541:884f95bf5351 276 }
rgrover1 393:0f7c5048efb3 277 }