Qi Yao / LinkNode---test123

Dependencies:   mbed

Fork of LinkNode-Test by Qi Yao

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