library for BLE_GAP_backpack

Dependencies:   nrf51-sdk

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nRF5xServiceDiscovery.cpp Source File

nRF5xServiceDiscovery.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "nRF5xServiceDiscovery.h"
00018 
00019 ble_error_t
00020 nRF5xServiceDiscovery::launchCharacteristicDiscovery(Gap::Handle_t connectionHandle,
00021                                                      Gap::Handle_t startHandle,
00022                                                      Gap::Handle_t endHandle)
00023 {
00024     characteristicDiscoveryStarted(connectionHandle);
00025 
00026     ble_gattc_handle_range_t handleRange = {
00027         .start_handle = startHandle,
00028         .end_handle   = endHandle
00029     };
00030     uint32_t rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange);
00031     ble_error_t err = BLE_ERROR_NONE;
00032 
00033     switch (rc) {
00034         case NRF_SUCCESS:
00035             err = BLE_ERROR_NONE;
00036             break;
00037         case BLE_ERROR_INVALID_CONN_HANDLE:
00038         case NRF_ERROR_INVALID_ADDR:
00039             err = BLE_ERROR_INVALID_PARAM;
00040             break;
00041         case NRF_ERROR_BUSY:
00042             err = BLE_STACK_BUSY;
00043             break;
00044         case NRF_ERROR_INVALID_STATE:
00045             err = BLE_ERROR_INVALID_STATE;
00046             break;
00047         default:
00048             err = BLE_ERROR_UNSPECIFIED;
00049             break;
00050     }
00051 
00052     if (err) {
00053         terminateCharacteristicDiscovery(err);
00054     }
00055     return err;
00056 }
00057 
00058 void
00059 nRF5xServiceDiscovery::setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response)
00060 {
00061     serviceIndex = 0;
00062     numServices  = response->count;
00063 
00064     /* Account for the limitation on the number of discovered services we can handle at a time. */
00065     if (numServices > BLE_DB_DISCOVERY_MAX_SRV) {
00066         numServices = BLE_DB_DISCOVERY_MAX_SRV;
00067     }
00068 
00069     serviceUUIDDiscoveryQueue.reset();
00070     for (unsigned serviceIndex = 0; serviceIndex < numServices; serviceIndex++) {
00071         if (response->services[serviceIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
00072             serviceUUIDDiscoveryQueue.enqueue(serviceIndex);
00073             services[serviceIndex].setup(response->services[serviceIndex].handle_range.start_handle,
00074                                          response->services[serviceIndex].handle_range.end_handle);
00075         } else {
00076             services[serviceIndex].setup(response->services[serviceIndex].uuid.uuid,
00077                                          response->services[serviceIndex].handle_range.start_handle,
00078                                          response->services[serviceIndex].handle_range.end_handle);
00079         }
00080     }
00081 
00082     /* Trigger discovery of service UUID if necessary. */
00083     if (serviceUUIDDiscoveryQueue.getCount()) {
00084         serviceUUIDDiscoveryQueue.triggerFirst();
00085     }
00086 }
00087 
00088 void
00089 nRF5xServiceDiscovery::setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response)
00090 {
00091     numCharacteristics  = response->count;
00092 
00093     /* Account for the limitation on the number of discovered characteristics we can handle at a time. */
00094     if (numCharacteristics > BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) {
00095         numCharacteristics = BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV;
00096     }
00097 
00098     charUUIDDiscoveryQueue.reset();
00099     for (unsigned charIndex = 0; charIndex < numCharacteristics; charIndex++) {
00100         if (response->chars[charIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
00101             charUUIDDiscoveryQueue.enqueue(charIndex);
00102             characteristics[charIndex].setup(gattc,
00103                                              connHandle,
00104                                              response->chars[charIndex].char_props,
00105                                              response->chars[charIndex].handle_decl,
00106                                              response->chars[charIndex].handle_value);
00107         } else {
00108             characteristics[charIndex].setup(gattc,
00109                                              connHandle,
00110                                              response->chars[charIndex].uuid.uuid,
00111                                              response->chars[charIndex].char_props,
00112                                              response->chars[charIndex].handle_decl,
00113                                              response->chars[charIndex].handle_value);
00114         }
00115     }
00116 
00117     /* Trigger discovery of char UUID if necessary. */
00118     if (charUUIDDiscoveryQueue.getCount()) {
00119         charUUIDDiscoveryQueue.triggerFirst();
00120     }
00121 }
00122 
00123 void
00124 nRF5xServiceDiscovery::progressCharacteristicDiscovery(void)
00125 {
00126     if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
00127         return;
00128     }
00129 
00130     if ((discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) && (numCharacteristics > 0)) {
00131         discoveredCharacteristic.setLastHandle(characteristics[0].getDeclHandle() - 1);
00132 
00133         if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
00134             ((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) &&
00135              (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
00136             if (characteristicCallback) {
00137                 characteristicCallback(&discoveredCharacteristic);
00138             }
00139         }
00140     }
00141 
00142     for (uint8_t i = 0; i < numCharacteristics; ++i) {
00143         if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
00144             return;
00145         }
00146 
00147         if (i == (numCharacteristics - 1)) {
00148             discoveredCharacteristic = characteristics[i];
00149             break;
00150         } else {
00151             characteristics[i].setLastHandle(characteristics[i + 1].getDeclHandle() - 1);
00152         }
00153 
00154         if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
00155             ((matchingCharacteristicUUID == characteristics[i].getUUID()) &&
00156              (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
00157             if (characteristicCallback) {
00158                 characteristicCallback(&characteristics[i]);
00159             }
00160         }
00161     }
00162 
00163     if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
00164         return;
00165     }
00166 
00167     Gap::Handle_t startHandle = (numCharacteristics > 0) ? characteristics[numCharacteristics - 1].getValueHandle() + 1 : SRV_DISC_END_HANDLE;
00168     Gap::Handle_t endHandle   = services[serviceIndex].getEndHandle();
00169     resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */
00170 
00171     if (startHandle < endHandle) {
00172         ble_gattc_handle_range_t handleRange = {
00173             .start_handle = startHandle,
00174             .end_handle   = endHandle
00175         };
00176         if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) {
00177             terminateCharacteristicDiscovery(BLE_ERROR_UNSPECIFIED);
00178         }
00179     } else {
00180         terminateCharacteristicDiscovery(BLE_ERROR_NONE);
00181     }
00182 }
00183 
00184 void
00185 nRF5xServiceDiscovery::progressServiceDiscovery(void)
00186 {
00187     /* Iterate through the previously discovered services cached in services[]. */
00188     while ((state == SERVICE_DISCOVERY_ACTIVE) && (serviceIndex < numServices)) {
00189         if ((matchingServiceUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
00190             (matchingServiceUUID == services[serviceIndex].getUUID())) {
00191 
00192             if (serviceCallback && (matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN))) {
00193                 serviceCallback(&services[serviceIndex]);
00194             }
00195 
00196             if ((state == SERVICE_DISCOVERY_ACTIVE) && characteristicCallback) {
00197                 launchCharacteristicDiscovery(connHandle, services[serviceIndex].getStartHandle(), services[serviceIndex].getEndHandle());
00198             } else {
00199                 serviceIndex++;
00200             }
00201         } else {
00202             serviceIndex++;
00203         }
00204     }
00205 
00206     /* Relaunch discovery of new services beyond the last entry cached in services[]. */
00207     if ((state == SERVICE_DISCOVERY_ACTIVE) && (numServices > 0) && (serviceIndex > 0)) {
00208         /* Determine the ending handle of the last cached service. */
00209         Gap::Handle_t endHandle = services[serviceIndex - 1].getEndHandle();
00210         resetDiscoveredServices(); /* Note: resetDiscoveredServices() must come after fetching endHandle. */
00211 
00212         if (endHandle == SRV_DISC_END_HANDLE) {
00213             terminateServiceDiscovery();
00214         } else {
00215             if (sd_ble_gattc_primary_services_discover(connHandle, endHandle, NULL) != NRF_SUCCESS) {
00216                 terminateServiceDiscovery();
00217             }
00218         }
00219     }
00220 }
00221 
00222 void
00223 nRF5xServiceDiscovery::ServiceUUIDDiscoveryQueue::triggerFirst(void)
00224 {
00225     while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
00226         parentDiscoveryObject->state = DISCOVER_SERVICE_UUIDS;
00227 
00228         unsigned serviceIndex = getFirst();
00229         ble_uuid_t uuid = {
00230             .uuid = BLE_UUID_SERVICE_PRIMARY,
00231             .type = BLE_UUID_TYPE_BLE,
00232         };
00233         ble_gattc_handle_range_t handleRange = {
00234             .start_handle = parentDiscoveryObject->services[serviceIndex].getStartHandle(),
00235             .end_handle   = parentDiscoveryObject->services[serviceIndex].getEndHandle(),
00236         };
00237         if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
00238             return;
00239         }
00240 
00241         /* Skip this service if we fail to launch a read for its service-declaration
00242          * attribute. Its UUID will remain INVALID, and it may not match any filters. */
00243         dequeue();
00244     }
00245 
00246     /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
00247     if (parentDiscoveryObject->state == DISCOVER_SERVICE_UUIDS) {
00248         parentDiscoveryObject->state = SERVICE_DISCOVERY_ACTIVE;
00249     }
00250 }
00251 
00252 void
00253 nRF5xServiceDiscovery::CharUUIDDiscoveryQueue::triggerFirst(void)
00254 {
00255     while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
00256         parentDiscoveryObject->state = DISCOVER_CHARACTERISTIC_UUIDS;
00257 
00258         unsigned charIndex = getFirst();
00259         ble_uuid_t uuid = {
00260             .uuid = BLE_UUID_CHARACTERISTIC,
00261             .type = BLE_UUID_TYPE_BLE,
00262         };
00263         ble_gattc_handle_range_t handleRange = { };
00264         handleRange.start_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle();
00265         handleRange.end_handle   = parentDiscoveryObject->characteristics[charIndex].getDeclHandle() + 1;
00266         if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
00267             return;
00268         }
00269 
00270         /* Skip this service if we fail to launch a read for its service-declaration
00271          * attribute. Its UUID will remain INVALID, and it may not match any filters. */
00272         dequeue();
00273     }
00274 
00275     /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
00276     if (parentDiscoveryObject->state == DISCOVER_CHARACTERISTIC_UUIDS) {
00277         parentDiscoveryObject->state = CHARACTERISTIC_DISCOVERY_ACTIVE;
00278     }
00279 }
00280 
00281 void
00282 nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response)
00283 {
00284     if (state == DISCOVER_SERVICE_UUIDS) {
00285         if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID)) {
00286             UUID::LongUUIDBytes_t uuid;
00287             memcpy(uuid, response->handle_value[0].p_value, UUID::LENGTH_OF_LONG_UUID);
00288 
00289             unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue();
00290             services[serviceIndex].setupLongUUID(uuid, UUID::LSB);
00291 
00292             serviceUUIDDiscoveryQueue.triggerFirst();
00293         } else {
00294             serviceUUIDDiscoveryQueue.dequeue();
00295         }
00296     } else if (state == DISCOVER_CHARACTERISTIC_UUIDS) {
00297         if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) {
00298             UUID::LongUUIDBytes_t uuid;
00299 
00300             memcpy(uuid, &(response->handle_value[0].p_value[3]), UUID::LENGTH_OF_LONG_UUID);
00301 
00302             unsigned charIndex = charUUIDDiscoveryQueue.dequeue();
00303             characteristics[charIndex].setupLongUUID(uuid, UUID::LSB);
00304 
00305             charUUIDDiscoveryQueue.triggerFirst();
00306         } else {
00307             charUUIDDiscoveryQueue.dequeue();
00308         }
00309     }
00310 }