Clone of the nRF51822 repository from github The correct home is https://github.com/lancaster-university/nRF51822

Dependencies:   nrf51-sdk

Dependents:   microbit-dal microbit-ble-open microbit-dal-eddystone microbit-dal-ble-accelerometer-example ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nRF5xGattServer.cpp Source File

nRF5xGattServer.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 "nRF5xGattServer.h"
00018 #ifdef YOTTA_CFG_MBED_OS
00019     #include "mbed-drivers/mbed.h"
00020 #else
00021     #include "mbed.h"
00022 #endif
00023 
00024 #include "common/common.h "
00025 #include "btle/custom/custom_helper.h"
00026 
00027 #include "nRF5xn.h"
00028 
00029 /**************************************************************************/
00030 /*!
00031     @brief  Adds a new service to the GATT table on the peripheral
00032 
00033     @returns    ble_error_t
00034 
00035     @retval     BLE_ERROR_NONE
00036                 Everything executed properly
00037 
00038     @section EXAMPLE
00039 
00040     @code
00041 
00042     @endcode
00043 */
00044 /**************************************************************************/
00045 ble_error_t nRF5xGattServer::addService(GattService &service)
00046 {
00047     /* ToDo: Make sure this service UUID doesn't already exist (?) */
00048     /* ToDo: Basic validation */
00049 
00050     /* Add the service to the nRF51 */
00051     ble_uuid_t nordicUUID;
00052     nordicUUID = custom_convert_to_nordic_uuid(service.getUUID());
00053 
00054     uint16_t serviceHandle;
00055     ASSERT( ERROR_NONE ==
00056             sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
00057                                      &nordicUUID,
00058                                      &serviceHandle),
00059             BLE_ERROR_PARAM_OUT_OF_RANGE );
00060     service.setHandle(serviceHandle);
00061 
00062     /* Add characteristics to the service */
00063     for (uint8_t i = 0; i < service.getCharacteristicCount(); i++) {
00064         if (characteristicCount >= BLE_TOTAL_CHARACTERISTICS) {
00065             return BLE_ERROR_NO_MEM;
00066         }
00067         GattCharacteristic *p_char = service.getCharacteristic(i);
00068 
00069         /* Skip any incompletely defined, read-only characteristics. */
00070         if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
00071             (p_char->getValueAttribute().getLength() == 0) &&
00072             (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) {
00073             continue;
00074         }
00075 
00076         nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID());
00077 
00078         /* The user-description descriptor is a special case which needs to be
00079          * handled at the time of adding the characteristic. The following block
00080          * is meant to discover its presence. */
00081         const uint8_t *userDescriptionDescriptorValuePtr = NULL;
00082         uint16_t userDescriptionDescriptorValueLen = 0;
00083         for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
00084             GattAttribute *p_desc = p_char->getDescriptor(j);
00085             if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
00086                 userDescriptionDescriptorValuePtr = p_desc->getValuePtr();
00087                 userDescriptionDescriptorValueLen = p_desc->getLength();
00088             }
00089         }
00090 
00091         ASSERT ( ERROR_NONE ==
00092                  custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
00093                                               &nordicUUID,
00094                                               p_char->getProperties(),
00095                                               p_char->getRequiredSecurity(),
00096                                               p_char->getValueAttribute().getValuePtr(),
00097                                               p_char->getValueAttribute().getLength(),
00098                                               p_char->getValueAttribute().getMaxLength(),
00099                                               p_char->getValueAttribute().hasVariableLength(),
00100                                               userDescriptionDescriptorValuePtr,
00101                                               userDescriptionDescriptorValueLen,
00102                                               p_char->isReadAuthorizationEnabled(),
00103                                               p_char->isWriteAuthorizationEnabled(),
00104                                               &nrfCharacteristicHandles[characteristicCount]),
00105                  BLE_ERROR_PARAM_OUT_OF_RANGE );
00106 
00107         /* Update the characteristic handle */
00108         p_characteristics[characteristicCount] = p_char;
00109         p_char->getValueAttribute().setHandle(nrfCharacteristicHandles[characteristicCount].value_handle);
00110         characteristicCount++;
00111 
00112         /* Add optional descriptors if any */
00113         for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
00114             if (descriptorCount >= BLE_TOTAL_DESCRIPTORS) {
00115                 return BLE_ERROR_NO_MEM;
00116             }
00117 
00118             GattAttribute *p_desc = p_char->getDescriptor(j);
00119             /* skip the user-description-descriptor here; this has already been handled when adding the characteristic (above). */
00120             if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
00121                 continue;
00122             }
00123 
00124             nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID());
00125 
00126             ASSERT(ERROR_NONE ==
00127                    custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID,
00128                                             &nordicUUID,
00129                                             p_desc->getValuePtr(),
00130                                             p_desc->getLength(),
00131                                             p_desc->getMaxLength(),
00132                                             p_desc->hasVariableLength(),
00133                                             &nrfDescriptorHandles[descriptorCount]),
00134                 BLE_ERROR_PARAM_OUT_OF_RANGE);
00135 
00136             p_descriptors[descriptorCount++] = p_desc;
00137             p_desc->setHandle(nrfDescriptorHandles[descriptorCount]);
00138         }
00139     }
00140 
00141     serviceCount++;
00142 
00143     return BLE_ERROR_NONE;
00144 }
00145 
00146 /**************************************************************************/
00147 /*!
00148     @brief  Reads the value of a characteristic, based on the service
00149             and characteristic index fields
00150 
00151     @param[in]  attributeHandle
00152                 The handle of the GattCharacteristic to read from
00153     @param[in]  buffer
00154                 Buffer to hold the the characteristic's value
00155                 (raw byte array in LSB format)
00156     @param[in/out] len
00157                 input:  Length in bytes to be read.
00158                 output: Total length of attribute value upon successful return.
00159 
00160     @returns    ble_error_t
00161 
00162     @retval     BLE_ERROR_NONE
00163                 Everything executed properly
00164 */
00165 /**************************************************************************/
00166 ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
00167 {
00168     return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP);
00169 }
00170 
00171 ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
00172 {
00173     ble_gatts_value_t value = {
00174         .len     = *lengthP,
00175         .offset  = 0,
00176         .p_value = buffer,
00177     };
00178 
00179     ASSERT( ERROR_NONE ==
00180             sd_ble_gatts_value_get(connectionHandle, attributeHandle, &value),
00181             BLE_ERROR_PARAM_OUT_OF_RANGE);
00182     *lengthP = value.len;
00183 
00184     return BLE_ERROR_NONE;
00185 }
00186 
00187 /**************************************************************************/
00188 /*!
00189     @brief  Updates the value of a characteristic, based on the service
00190             and characteristic index fields
00191 
00192     @param[in]  charHandle
00193                 The handle of the GattCharacteristic to write to
00194     @param[in]  buffer
00195                 Data to use when updating the characteristic's value
00196                 (raw byte array in LSB format)
00197     @param[in]  len
00198                 The number of bytes in buffer
00199 
00200     @returns    ble_error_t
00201 
00202     @retval     BLE_ERROR_NONE
00203                 Everything executed properly
00204 */
00205 /**************************************************************************/
00206 ble_error_t nRF5xGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
00207 {
00208     return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly);
00209 }
00210 
00211 ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
00212 {
00213     ble_error_t returnValue = BLE_ERROR_NONE;
00214 
00215     ble_gatts_value_t value = {
00216         .len     = len,
00217         .offset  = 0,
00218         .p_value = const_cast<uint8_t *>(buffer),
00219     };
00220 
00221     if (localOnly) {
00222         /* Only update locally regardless of notify/indicate */
00223         ASSERT_INT( ERROR_NONE,
00224                     sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
00225                     BLE_ERROR_PARAM_OUT_OF_RANGE );
00226         return BLE_ERROR_NONE;
00227     }
00228 
00229     int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
00230     if ((characteristicIndex != -1) &&
00231         (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
00232         /* HVX update for the characteristic value */
00233         ble_gatts_hvx_params_t hvx_params;
00234 
00235         hvx_params.handle = attributeHandle;
00236         hvx_params.type   =
00237             (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
00238         hvx_params.offset = 0;
00239         hvx_params.p_data = const_cast<uint8_t *>(buffer);
00240         hvx_params.p_len  = &len;
00241 
00242         if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */
00243             nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
00244             connectionHandle = gap.getConnectionHandle();
00245         }
00246         error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
00247         if (error != ERROR_NONE) {
00248             switch (error) {
00249                 case ERROR_BLE_NO_TX_BUFFERS: /*  Notifications consume application buffers. The return value can be used for resending notifications. */
00250                 case ERROR_BUSY:
00251                     returnValue = BLE_STACK_BUSY;
00252                     break;
00253 
00254                 case ERROR_INVALID_STATE:
00255                 case ERROR_BLEGATTS_SYS_ATTR_MISSING:
00256                     returnValue = BLE_ERROR_INVALID_STATE;
00257                     break;
00258 
00259                 default :
00260                     ASSERT_INT( ERROR_NONE,
00261                                 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
00262                                 BLE_ERROR_PARAM_OUT_OF_RANGE );
00263 
00264                     /* Notifications consume application buffers. The return value can
00265                      * be used for resending notifications. */
00266                     returnValue = BLE_STACK_BUSY;
00267                     break;
00268             }
00269         }
00270     } else {
00271         returnValue = BLE_ERROR_INVALID_STATE; // if assert is not used
00272         ASSERT_INT( ERROR_NONE,
00273                     sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
00274                     BLE_ERROR_PARAM_OUT_OF_RANGE );
00275     }
00276 
00277     return returnValue;
00278 }
00279 
00280 /**
00281  * Perform an explicit BLE notification of a given attribute.
00282  *
00283  * @param[in] attributeHandle
00284  *              Handle for the value attribute of the Characteristic.
00285  * @param[in] value
00286  *              A pointer to a buffer holding the new value
00287  * @param[in] size
00288  *              Size of the new value (in bytes).
00289  *
00290  * @return BLE_ERROR_NONE if we have successfully set the value of the attribute.
00291  */
00292 ble_error_t nRF5xGattServer::notify(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len)
00293 {
00294     uint16_t gapConnectionHandle = ((nRF5xGap &)nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap()).getConnectionHandle();
00295     ble_gatts_hvx_params_t hvx_params;
00296 
00297     hvx_params.handle = attributeHandle;
00298     hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
00299     hvx_params.offset = 0;
00300     hvx_params.p_data = const_cast<uint8_t *>(buffer);
00301     hvx_params.p_len  = &len;
00302 
00303     error_t error = (error_t) sd_ble_gatts_hvx(gapConnectionHandle, &hvx_params);
00304 
00305     if (error == ERROR_NONE)  
00306         return BLE_ERROR_NONE;
00307     else
00308         return BLE_STACK_BUSY;
00309 }
00310 
00311 
00312 ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
00313 {
00314     /* Forward the call with the default connection handle. */
00315     nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
00316     return areUpdatesEnabled(gap.getConnectionHandle(), characteristic, enabledP);
00317 }
00318 
00319 ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP)
00320 {
00321     int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle());
00322     if (characteristicIndex == -1) {
00323         return BLE_ERROR_INVALID_PARAM;
00324     }
00325 
00326     /* Read the cccd value from the GATT server. */
00327     GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle;
00328     uint16_t cccdValue;
00329     uint16_t length = sizeof(cccdValue);
00330     ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast<uint8_t *>(&cccdValue), &length);
00331     if (rc != BLE_ERROR_NONE) {
00332         return rc;
00333     }
00334     if (length != sizeof(cccdValue)) {
00335         return BLE_ERROR_INVALID_STATE;
00336     }
00337 
00338     /* Check for NOTFICATION or INDICATION in CCCD. */
00339     if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) {
00340         *enabledP = true;
00341     }
00342 
00343     return BLE_ERROR_NONE;
00344 }
00345 
00346 /**************************************************************************/
00347 /*!
00348     @brief  Clear nRF5xGattServer's state.
00349 
00350     @returns    ble_error_t
00351 
00352     @retval     BLE_ERROR_NONE
00353                 Everything executed properly
00354 */
00355 /**************************************************************************/
00356 ble_error_t nRF5xGattServer::reset(void)
00357 {
00358     /* Clear all state that is from the parent, including private members */
00359     if (GattServer::reset() != BLE_ERROR_NONE) {
00360         return BLE_ERROR_INVALID_STATE;
00361     }
00362 
00363     /* Clear derived class members */
00364     memset(p_characteristics,        0, sizeof(p_characteristics));
00365     memset(p_descriptors,            0, sizeof(p_descriptors));
00366     memset(nrfCharacteristicHandles, 0, sizeof(ble_gatts_char_handles_t));
00367     memset(nrfDescriptorHandles,     0, sizeof(nrfDescriptorHandles));
00368     descriptorCount = 0;
00369 
00370     return BLE_ERROR_NONE;
00371 }
00372 
00373 /**************************************************************************/
00374 /*!
00375     @brief  Callback handler for events getting pushed up from the SD
00376 */
00377 /**************************************************************************/
00378 void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
00379 {
00380     GattAttribute::Handle_t        handle_value;
00381     GattServerEvents::gattEvent_t  eventType;
00382     const ble_gatts_evt_t         *gattsEventP = &p_ble_evt->evt.gatts_evt;
00383 
00384     switch (p_ble_evt->header.evt_id) {
00385         case BLE_GATTS_EVT_WRITE: {
00386                 /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */
00387 
00388                 /* 1.) Handle CCCD changes */
00389                 handle_value = gattsEventP->params.write.handle;
00390                 int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value);
00391                 if ((characteristicIndex != -1) &&
00392                     (p_characteristics[characteristicIndex]->getProperties() &
00393                         (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
00394 
00395                     uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */
00396 
00397                     if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) ||
00398                         ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) {
00399                         eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
00400                     } else {
00401                         eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
00402                     }
00403 
00404                     handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle());
00405                     return;
00406                 }
00407 
00408                 /* 2.) Changes to the characteristic value will be handled with other events below */
00409                 eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
00410             }
00411             break;
00412 
00413         case BLE_GATTS_EVT_HVC:
00414             /* Indication confirmation received */
00415             eventType    = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
00416             handle_value = gattsEventP->params.hvc.handle;
00417             break;
00418 
00419         case BLE_EVT_TX_COMPLETE: {
00420             handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count);
00421             return;
00422         }
00423 
00424         case BLE_GATTS_EVT_SYS_ATTR_MISSING: 
00425         case BLE_GAP_EVT_CONN_SEC_UPDATE:
00426         {
00427             GattSysAttrMissingCallbackParams cbParams = {gattsEventP->conn_handle};
00428             handleSysAttrMissingEvent(&cbParams);
00429             return;
00430         }
00431 
00432         case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
00433             switch (gattsEventP->params.authorize_request.type) {
00434                 case BLE_GATTS_AUTHORIZE_TYPE_READ:
00435                     eventType    = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ;
00436                     handle_value = gattsEventP->params.authorize_request.request.read.handle;
00437                     break;
00438                 case BLE_GATTS_AUTHORIZE_TYPE_WRITE:
00439                     eventType    = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ;
00440                     handle_value = gattsEventP->params.authorize_request.request.write.handle;
00441                     break;
00442                 default:
00443                     return;
00444             }
00445             break;
00446 
00447         default:
00448             return;
00449     }
00450 
00451     int characteristicIndex = resolveValueHandleToCharIndex(handle_value);
00452     if (characteristicIndex == -1) {
00453         return;
00454     }
00455 
00456     /* Find index (charHandle) in the pool */
00457     switch (eventType) {
00458         case GattServerEvents::GATT_EVENT_DATA_WRITTEN: {
00459             GattWriteCallbackParams cbParams = {
00460                 .connHandle = gattsEventP->conn_handle,
00461                 .handle     = handle_value,
00462                 .writeOp    = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op),
00463                 .offset     = gattsEventP->params.write.offset,
00464                 .len        = gattsEventP->params.write.len,
00465                 .data       = gattsEventP->params.write.data
00466             };
00467             handleDataWrittenEvent(&cbParams);
00468             break;
00469         }
00470         case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: {
00471             GattWriteAuthCallbackParams cbParams = {
00472                 .connHandle = gattsEventP->conn_handle,
00473                 .handle     = handle_value,
00474                 .offset     = gattsEventP->params.authorize_request.request.write.offset,
00475                 .len        = gattsEventP->params.authorize_request.request.write.len,
00476                 .data       = gattsEventP->params.authorize_request.request.write.data,
00477                 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
00478                                                                    * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
00479                                                                    * request is to proceed. */
00480             };
00481             ble_gatts_rw_authorize_reply_params_t reply = {
00482                 .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
00483                 .params = {
00484                     .write = {
00485                         .gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams)
00486                     }
00487                 }
00488             };
00489             sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
00490 
00491             /*
00492              * If write-authorization is enabled for a characteristic,
00493              * AUTHORIZATION_REQ event (if replied with true) is *not*
00494              * followed by another DATA_WRITTEN event; so we still need
00495              * to invoke handleDataWritten(), much the same as we would
00496              * have done if write-authorization had not been enabled.
00497              */
00498             if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) {
00499                 GattWriteCallbackParams cbParams = {
00500                     .connHandle = gattsEventP->conn_handle,
00501                     .handle     = handle_value,
00502                     .writeOp    = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op),
00503                     .offset     = gattsEventP->params.authorize_request.request.write.offset,
00504                     .len        = gattsEventP->params.authorize_request.request.write.len,
00505                     .data       = gattsEventP->params.authorize_request.request.write.data,
00506                 };
00507                 handleDataWrittenEvent(&cbParams);
00508             }
00509             break;
00510         }
00511         case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
00512             GattReadAuthCallbackParams cbParams = {
00513                 .connHandle         = gattsEventP->conn_handle,
00514                 .handle             = handle_value,
00515                 .offset             = gattsEventP->params.authorize_request.request.read.offset,
00516                 .len                = 0,
00517                 .data               = NULL,
00518                 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
00519                                                                    * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
00520                                                                    * request is to proceed. */
00521             };
00522 
00523             ble_gatts_rw_authorize_reply_params_t reply = {
00524                 .type = BLE_GATTS_AUTHORIZE_TYPE_READ,
00525                 .params = {
00526                     .read = {
00527                         .gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams)
00528                     }
00529                 }
00530             };
00531 
00532             if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) {
00533                 if (cbParams.data != NULL) {
00534                     reply.params.read.update = 1;
00535                     reply.params.read.offset = cbParams.offset;
00536                     reply.params.read.len    = cbParams.len;
00537                     reply.params.read.p_data = cbParams.data;
00538                 }
00539             }
00540 
00541             sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
00542             break;
00543         }
00544 
00545         default:
00546             handleEvent(eventType, handle_value);
00547             break;
00548     }
00549 }