test

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;
00031     if ((rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange)) != NRF_SUCCESS) {
00032         terminateCharacteristicDiscovery();
00033         switch (rc) {
00034             case BLE_ERROR_INVALID_CONN_HANDLE:
00035             case NRF_ERROR_INVALID_ADDR:
00036                 return BLE_ERROR_INVALID_PARAM;
00037             case NRF_ERROR_BUSY:
00038                 return BLE_STACK_BUSY;
00039             default:
00040             case NRF_ERROR_INVALID_STATE:
00041                 return BLE_ERROR_INVALID_STATE;
00042         }
00043     }
00044 
00045     return BLE_ERROR_NONE;
00046 }
00047 
00048 void
00049 nRF5xServiceDiscovery::setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response)
00050 {
00051     serviceIndex = 0;
00052     numServices  = response->count;
00053 
00054     /* Account for the limitation on the number of discovered services we can handle at a time. */
00055     if (numServices > BLE_DB_DISCOVERY_MAX_SRV) {
00056         numServices = BLE_DB_DISCOVERY_MAX_SRV;
00057     }
00058 
00059     serviceUUIDDiscoveryQueue.reset();
00060     for (unsigned serviceIndex = 0; serviceIndex < numServices; serviceIndex++) {
00061         if (response->services[serviceIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
00062             serviceUUIDDiscoveryQueue.enqueue(serviceIndex);
00063             services[serviceIndex].setup(response->services[serviceIndex].handle_range.start_handle,
00064                                          response->services[serviceIndex].handle_range.end_handle);
00065         } else {
00066             services[serviceIndex].setup(response->services[serviceIndex].uuid.uuid,
00067                                          response->services[serviceIndex].handle_range.start_handle,
00068                                          response->services[serviceIndex].handle_range.end_handle);
00069         }
00070     }
00071 
00072     /* Trigger discovery of service UUID if necessary. */
00073     if (serviceUUIDDiscoveryQueue.getCount()) {
00074         serviceUUIDDiscoveryQueue.triggerFirst();
00075     }
00076 }
00077 
00078 void
00079 nRF5xServiceDiscovery::setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response)
00080 {
00081     characteristicIndex = 0;
00082     numCharacteristics  = response->count;
00083 
00084     /* Account for the limitation on the number of discovered characteristics we can handle at a time. */
00085     if (numCharacteristics > BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) {
00086         numCharacteristics = BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV;
00087     }
00088 
00089     charUUIDDiscoveryQueue.reset();
00090     for (unsigned charIndex = 0; charIndex < numCharacteristics; charIndex++) {
00091         if (response->chars[charIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
00092             charUUIDDiscoveryQueue.enqueue(charIndex);
00093             characteristics[charIndex].setup(gattc,
00094                                              connHandle,
00095                                              response->chars[charIndex].char_props,
00096                                              response->chars[charIndex].handle_decl,
00097                                              response->chars[charIndex].handle_value);
00098         } else {
00099             characteristics[charIndex].setup(gattc,
00100                                              connHandle,
00101                                              response->chars[charIndex].uuid.uuid,
00102                                              response->chars[charIndex].char_props,
00103                                              response->chars[charIndex].handle_decl,
00104                                              response->chars[charIndex].handle_value);
00105         }
00106     }
00107 
00108     /* Trigger discovery of char UUID if necessary. */
00109     if (charUUIDDiscoveryQueue.getCount()) {
00110         charUUIDDiscoveryQueue.triggerFirst();
00111     }
00112 }
00113 
00114 void
00115 nRF5xServiceDiscovery::progressCharacteristicDiscovery(void)
00116 {
00117     /* Iterate through the previously discovered characteristics cached in characteristics[]. */
00118     while ((state == CHARACTERISTIC_DISCOVERY_ACTIVE) && (characteristicIndex < numCharacteristics)) {
00119         if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
00120             ((matchingCharacteristicUUID == characteristics[characteristicIndex].getUUID()) &&
00121              (matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
00122             if (characteristicCallback) {
00123                 characteristicCallback(&characteristics[characteristicIndex]);
00124             }
00125         }
00126 
00127         characteristicIndex++;
00128     }
00129 
00130     /* Relaunch discovery of new characteristics beyond the last entry cached in characteristics[]. */
00131     if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) {
00132         /* Determine the ending handle of the last cached characteristic. */
00133         Gap::Handle_t startHandle = characteristics[characteristicIndex - 1].getValueHandle() + 1;
00134         Gap::Handle_t endHandle   = services[serviceIndex].getEndHandle();
00135         resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */
00136 
00137         if (startHandle < endHandle) {
00138             ble_gattc_handle_range_t handleRange = {
00139                 .start_handle = startHandle,
00140                 .end_handle   = endHandle
00141             };
00142             if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) {
00143                 terminateCharacteristicDiscovery();
00144             }
00145         } else {
00146             terminateCharacteristicDiscovery();
00147         }
00148     }
00149 }
00150 
00151 void
00152 nRF5xServiceDiscovery::progressServiceDiscovery(void)
00153 {
00154     /* Iterate through the previously discovered services cached in services[]. */
00155     while ((state == SERVICE_DISCOVERY_ACTIVE) && (serviceIndex < numServices)) {
00156         if ((matchingServiceUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
00157             (matchingServiceUUID == services[serviceIndex].getUUID())) {
00158 
00159             if (serviceCallback && (matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN))) {
00160                 serviceCallback(&services[serviceIndex]);
00161             }
00162 
00163             if ((state == SERVICE_DISCOVERY_ACTIVE) && characteristicCallback) {
00164                 launchCharacteristicDiscovery(connHandle, services[serviceIndex].getStartHandle(), services[serviceIndex].getEndHandle());
00165             } else {
00166                 serviceIndex++;
00167             }
00168         } else {
00169             serviceIndex++;
00170         }
00171     }
00172 
00173     /* Relaunch discovery of new services beyond the last entry cached in services[]. */
00174     if ((state == SERVICE_DISCOVERY_ACTIVE) && (numServices > 0) && (serviceIndex > 0)) {
00175         /* Determine the ending handle of the last cached service. */
00176         Gap::Handle_t endHandle = services[serviceIndex - 1].getEndHandle();
00177         resetDiscoveredServices(); /* Note: resetDiscoveredServices() must come after fetching endHandle. */
00178 
00179         if (endHandle == SRV_DISC_END_HANDLE) {
00180             terminateServiceDiscovery();
00181         } else {
00182             if (sd_ble_gattc_primary_services_discover(connHandle, endHandle, NULL) != NRF_SUCCESS) {
00183                 terminateServiceDiscovery();
00184             }
00185         }
00186     }
00187 }
00188 
00189 void
00190 nRF5xServiceDiscovery::ServiceUUIDDiscoveryQueue::triggerFirst(void)
00191 {
00192     while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
00193         parentDiscoveryObject->state = DISCOVER_SERVICE_UUIDS;
00194 
00195         unsigned serviceIndex = getFirst();
00196         ble_uuid_t uuid = {
00197             .uuid = BLE_UUID_SERVICE_PRIMARY,
00198             .type = BLE_UUID_TYPE_BLE,
00199         };
00200         ble_gattc_handle_range_t handleRange = {
00201             .start_handle = parentDiscoveryObject->services[serviceIndex].getStartHandle(),
00202             .end_handle   = parentDiscoveryObject->services[serviceIndex].getEndHandle(),
00203         };
00204         if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
00205             return;
00206         }
00207 
00208         /* Skip this service if we fail to launch a read for its service-declaration
00209          * attribute. Its UUID will remain INVALID, and it may not match any filters. */
00210         dequeue();
00211     }
00212 
00213     /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
00214     if (parentDiscoveryObject->state == DISCOVER_SERVICE_UUIDS) {
00215         parentDiscoveryObject->state = SERVICE_DISCOVERY_ACTIVE;
00216     }
00217 }
00218 
00219 void
00220 nRF5xServiceDiscovery::CharUUIDDiscoveryQueue::triggerFirst(void)
00221 {
00222     while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
00223         parentDiscoveryObject->state = DISCOVER_CHARACTERISTIC_UUIDS;
00224 
00225         unsigned charIndex = getFirst();
00226         ble_uuid_t uuid = {
00227             .uuid = BLE_UUID_CHARACTERISTIC,
00228             .type = BLE_UUID_TYPE_BLE,
00229         };
00230         ble_gattc_handle_range_t handleRange = { };
00231         handleRange.start_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle();
00232         handleRange.end_handle   = parentDiscoveryObject->characteristics[charIndex].getDeclHandle() + 1;
00233         if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
00234             return;
00235         }
00236 
00237         /* Skip this service if we fail to launch a read for its service-declaration
00238          * attribute. Its UUID will remain INVALID, and it may not match any filters. */
00239         dequeue();
00240     }
00241 
00242     /* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
00243     if (parentDiscoveryObject->state == DISCOVER_CHARACTERISTIC_UUIDS) {
00244         parentDiscoveryObject->state = CHARACTERISTIC_DISCOVERY_ACTIVE;
00245     }
00246 }
00247 
00248 void
00249 nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_char_val_by_uuid_read_rsp_t *response)
00250 {
00251     if (state == DISCOVER_SERVICE_UUIDS) {
00252         if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID)) {
00253             UUID::LongUUIDBytes_t uuid;
00254             /* Switch longUUID bytes to MSB */
00255             for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
00256                 uuid[i] = response->handle_value[0].p_value[UUID::LENGTH_OF_LONG_UUID - 1 - i];
00257             }
00258 
00259             unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue();
00260             services[serviceIndex].setupLongUUID(uuid);
00261 
00262             serviceUUIDDiscoveryQueue.triggerFirst();
00263         } else {
00264             serviceUUIDDiscoveryQueue.dequeue();
00265         }
00266     } else if (state == DISCOVER_CHARACTERISTIC_UUIDS) {
00267         if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) {
00268             UUID::LongUUIDBytes_t uuid;
00269             /* Switch longUUID bytes to MSB */
00270             for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
00271                 uuid[i] = response->handle_value[0].p_value[3 + UUID::LENGTH_OF_LONG_UUID - 1 - i];
00272             }
00273 
00274             unsigned charIndex = charUUIDDiscoveryQueue.dequeue();
00275             characteristics[charIndex].setupLongUUID(uuid);
00276 
00277             charUUIDDiscoveryQueue.triggerFirst();
00278         } else {
00279             charUUIDDiscoveryQueue.dequeue();
00280         }
00281     }
00282 }