/ 11111

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nRF51GattServer.cpp Source File

nRF51GattServer.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 "nRF51GattServer.h"
00018 #include "mbed.h"
00019 
00020 #include "common/common.h"
00021 #include "btle/custom/custom_helper.h"
00022 
00023 #include "nRF51Gap.h"
00024 
00025 nRF51GattServer &nRF51GattServer::getInstance(void) {
00026     static nRF51GattServer 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 nRF51GattServer::addService(GattService &service)
00047 {
00048     /* ToDo: Make sure we don't overflow the array, etc. */
00049     /* ToDo: Make sure this service UUID doesn't already exist (?) */
00050     /* ToDo: Basic validation */
00051 
00052     /* Add the service to the nRF51 */
00053     ble_uuid_t nordicUUID;
00054     nordicUUID = custom_convert_to_nordic_uuid(service.getUUID());
00055 
00056     uint16_t serviceHandle;
00057     ASSERT( ERROR_NONE ==
00058             sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
00059                                      &nordicUUID,
00060                                      &serviceHandle),
00061             BLE_ERROR_PARAM_OUT_OF_RANGE );
00062     service.setHandle(serviceHandle);
00063 
00064     /* Add characteristics to the service */
00065     for (uint8_t i = 0; i < service.getCharacteristicCount(); i++) {
00066         GattCharacteristic *p_char = service.getCharacteristic(i);
00067 
00068         /* Skip any incompletely defined, read-only characteristics. */
00069         if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
00070             (p_char->getValueAttribute().getInitialLength() == 0) &&
00071             (p_char->getProperties() == GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)) {
00072             continue;
00073         }
00074 
00075         nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID());
00076 
00077         /* The user-description descriptor is a special case which needs to be
00078          * handled at the time of adding the characteristic. The following block
00079          * is meant to discover its presence. */
00080         const uint8_t *userDescriptionDescriptorValuePtr = NULL;
00081         uint16_t userDescriptionDescriptorValueLen = 0;
00082         for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
00083             GattAttribute *p_desc = p_char->getDescriptor(j);
00084             if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
00085                 userDescriptionDescriptorValuePtr = p_desc->getValuePtr();
00086                 userDescriptionDescriptorValueLen = p_desc->getLength();
00087             }
00088         }
00089 
00090         ASSERT ( ERROR_NONE ==
00091                  custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
00092                                               &nordicUUID,
00093                                               p_char->getProperties(),
00094                                               p_char->getRequiredSecurity(),
00095                                               p_char->getValueAttribute().getValuePtr(),
00096                                               p_char->getValueAttribute().getInitialLength(),
00097                                               p_char->getValueAttribute().getMaxLength(),
00098                                               userDescriptionDescriptorValuePtr,
00099                                               userDescriptionDescriptorValueLen,
00100                                               p_char->isReadAuthorizationEnabled(),
00101                                               p_char->isWriteAuthorizationEnabled(),
00102                                               &nrfCharacteristicHandles[characteristicCount]),
00103                  BLE_ERROR_PARAM_OUT_OF_RANGE );
00104 
00105         /* Update the characteristic handle */
00106         uint16_t charHandle = characteristicCount;
00107         p_characteristics[characteristicCount++] = p_char;
00108 
00109         p_char->getValueAttribute().setHandle(charHandle);
00110 
00111         /* Add optional descriptors if any */
00112         /* ToDo: Make sure we don't overflow the array */
00113         for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
00114             GattAttribute *p_desc = p_char->getDescriptor(j);
00115             /* skip the user-description-descriptor here; this has already been handled when adding the characteristic (above). */
00116             if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
00117                 continue;
00118             }
00119 
00120             nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID());
00121 
00122             ASSERT(ERROR_NONE ==
00123                    custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID,
00124                                             &nordicUUID,
00125                                             p_desc->getValuePtr(),
00126                                             p_desc->getInitialLength(),
00127                                             p_desc->getMaxLength(),
00128                                             &nrfDescriptorHandles[descriptorCount]),
00129                 BLE_ERROR_PARAM_OUT_OF_RANGE);
00130 
00131             uint16_t descHandle = descriptorCount;
00132             p_descriptors[descriptorCount++] = p_desc;
00133             p_desc->setHandle(descHandle);
00134         }
00135     }
00136 
00137     serviceCount++;
00138 
00139     return BLE_ERROR_NONE;
00140 }
00141 
00142 /**************************************************************************/
00143 /*!
00144     @brief  Reads the value of a characteristic, based on the service
00145             and characteristic index fields
00146 
00147     @param[in]  attributeHandle
00148                 The handle of the GattCharacteristic to read from
00149     @param[in]  buffer
00150                 Buffer to hold the the characteristic's value
00151                 (raw byte array in LSB format)
00152     @param[in/out] len
00153                 input:  Length in bytes to be read.
00154                 output: Total length of attribute value upon successful return.
00155 
00156     @returns    ble_error_t
00157 
00158     @retval     BLE_ERROR_NONE
00159                 Everything executed properly
00160 */
00161 /**************************************************************************/
00162 ble_error_t nRF51GattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
00163 {
00164     return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP);
00165 }
00166 
00167 ble_error_t nRF51GattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP)
00168 {
00169     ble_gatts_value_t value = {
00170         .len     = *lengthP,
00171         .offset  = 0,
00172         .p_value = buffer,
00173     };
00174 
00175     ASSERT( ERROR_NONE ==
00176             sd_ble_gatts_value_get(connectionHandle, nrfCharacteristicHandles[attributeHandle].value_handle, &value),
00177             BLE_ERROR_PARAM_OUT_OF_RANGE);
00178     *lengthP = value.len;
00179 
00180     return BLE_ERROR_NONE;
00181 }
00182 
00183 /**************************************************************************/
00184 /*!
00185     @brief  Updates the value of a characteristic, based on the service
00186             and characteristic index fields
00187 
00188     @param[in]  charHandle
00189                 The handle of the GattCharacteristic to write to
00190     @param[in]  buffer
00191                 Data to use when updating the characteristic's value
00192                 (raw byte array in LSB format)
00193     @param[in]  len
00194                 The number of bytes in buffer
00195 
00196     @returns    ble_error_t
00197 
00198     @retval     BLE_ERROR_NONE
00199                 Everything executed properly
00200 */
00201 /**************************************************************************/
00202 ble_error_t nRF51GattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
00203 {
00204     return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly);
00205 }
00206 
00207 ble_error_t nRF51GattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
00208 {
00209     uint16_t gapConnectionHandle = nRF51Gap::getInstance().getConnectionHandle();
00210     ble_error_t returnValue = BLE_ERROR_NONE;
00211 
00212     ble_gatts_value_t value = {
00213         .len     = len,
00214         .offset  = 0,
00215         .p_value = const_cast<uint8_t *>(buffer),
00216     };
00217 
00218     if (localOnly) {
00219         /* Only update locally regardless of notify/indicate */
00220         ASSERT_INT( ERROR_NONE,
00221                     sd_ble_gatts_value_set(connectionHandle, nrfCharacteristicHandles[attributeHandle].value_handle, &value),
00222                     BLE_ERROR_PARAM_OUT_OF_RANGE );
00223         return BLE_ERROR_NONE;
00224     }
00225 
00226     if ((p_characteristics[attributeHandle]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)) &&
00227         (gapConnectionHandle != connectionHandle)) {
00228         /* HVX update for the characteristic value */
00229         ble_gatts_hvx_params_t hvx_params;
00230 
00231         hvx_params.handle = nrfCharacteristicHandles[attributeHandle].value_handle;
00232         hvx_params.type   =
00233             (p_characteristics[attributeHandle]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
00234         hvx_params.offset = 0;
00235         hvx_params.p_data = const_cast<uint8_t *>(buffer);
00236         hvx_params.p_len  = &len;
00237 
00238         error_t error = (error_t) sd_ble_gatts_hvx(gapConnectionHandle, &hvx_params);
00239 
00240         /* ERROR_INVALID_STATE, ERROR_BUSY, ERROR_GATTS_SYS_ATTR_MISSING and ERROR_NO_TX_BUFFERS the ATT table has been updated. */
00241         if ((error != ERROR_NONE) && (error != ERROR_INVALID_STATE) && (error != ERROR_BLE_NO_TX_BUFFERS) && (error != ERROR_BUSY) && (error != ERROR_BLEGATTS_SYS_ATTR_MISSING)) {
00242             ASSERT_INT( ERROR_NONE,
00243                         sd_ble_gatts_value_set(connectionHandle, nrfCharacteristicHandles[attributeHandle].value_handle, &value),
00244                         BLE_ERROR_PARAM_OUT_OF_RANGE );
00245         }
00246 
00247         /*  Notifications consume application buffers. The return value can
00248             be used for resending notifications.
00249         */
00250         if (error != ERROR_NONE) {
00251             returnValue = BLE_STACK_BUSY;
00252         }
00253     } else {
00254         ASSERT_INT( ERROR_NONE,
00255                     sd_ble_gatts_value_set(connectionHandle, nrfCharacteristicHandles[attributeHandle].value_handle, &value),
00256                     BLE_ERROR_PARAM_OUT_OF_RANGE );
00257     }
00258 
00259     return returnValue;
00260 }
00261 
00262 /**************************************************************************/
00263 /*!
00264     @brief  Callback handler for events getting pushed up from the SD
00265 */
00266 /**************************************************************************/
00267 void nRF51GattServer::hwCallback(ble_evt_t *p_ble_evt)
00268 {
00269     GattAttribute::Handle_t        handle_value;
00270     GattServerEvents::gattEvent_t  eventType;
00271     const ble_gatts_evt_t         *gattsEventP = &p_ble_evt->evt.gatts_evt;
00272 
00273     switch (p_ble_evt->header.evt_id) {
00274         case BLE_GATTS_EVT_WRITE:
00275             /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */
00276 
00277             /* 1.) Handle CCCD changes */
00278             handle_value = gattsEventP->params.write.handle;
00279             for (uint8_t i = 0; i < characteristicCount; i++) {
00280                 if ((p_characteristics[i]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)) &&
00281                     (nrfCharacteristicHandles[i].cccd_handle == handle_value)) {
00282                     uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */
00283 
00284                     if (((p_characteristics[i]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) ||
00285                         ((p_characteristics[i]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) {
00286                         eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
00287                     } else {
00288                         eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
00289                     }
00290 
00291                     handleEvent(eventType, handle_value);
00292                     return;
00293                 }
00294             }
00295 
00296             /* 2.) Changes to the characteristic value will be handled with other events below */
00297             eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
00298             break;
00299 
00300         case BLE_GATTS_EVT_HVC:
00301             /* Indication confirmation received */
00302             eventType    = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
00303             handle_value = gattsEventP->params.hvc.handle;
00304             break;
00305 
00306         case BLE_EVT_TX_COMPLETE: {
00307             handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count);
00308             return;
00309         }
00310 
00311         case BLE_GATTS_EVT_SYS_ATTR_MISSING:
00312             sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0);
00313             return;
00314 
00315         case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
00316             switch (gattsEventP->params.authorize_request.type) {
00317                 case BLE_GATTS_AUTHORIZE_TYPE_READ:
00318                     eventType    = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ;
00319                     handle_value = gattsEventP->params.authorize_request.request.read.handle;
00320                     break;
00321                 case BLE_GATTS_AUTHORIZE_TYPE_WRITE:
00322                     eventType    = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ;
00323                     handle_value = gattsEventP->params.authorize_request.request.write.handle;
00324                     break;
00325                 default:
00326                     return;
00327             }
00328             break;
00329 
00330         default:
00331             return;
00332     }
00333 
00334     /* Find index (charHandle) in the pool */
00335     for (uint8_t i = 0; i < characteristicCount; i++) {
00336         if (nrfCharacteristicHandles[i].value_handle == handle_value) {
00337             switch (eventType) {
00338                 case GattServerEvents::GATT_EVENT_DATA_WRITTEN: {
00339                     GattWriteCallbackParams cbParams = {
00340                         .handle  = i,
00341                         .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op),
00342                         .offset  = gattsEventP->params.write.offset,
00343                         .len     = gattsEventP->params.write.len,
00344                         .data    = gattsEventP->params.write.data
00345                     };
00346                     handleDataWrittenEvent(&cbParams);
00347                     break;
00348                 }
00349                 case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: {
00350                     GattWriteAuthCallbackParams cbParams = {
00351                         .handle  = i,
00352                         .offset  = gattsEventP->params.authorize_request.request.write.offset,
00353                         .len     = gattsEventP->params.authorize_request.request.write.len,
00354                         .data    = gattsEventP->params.authorize_request.request.write.data,
00355                     };
00356                     ble_gatts_rw_authorize_reply_params_t reply = {
00357                         .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
00358                         .params = {
00359                             .write = {
00360                                 .gatt_status = p_characteristics[i]->authorizeWrite(&cbParams)
00361                             }
00362                         }
00363                     };
00364                     sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
00365 
00366                     /*
00367                      * If write-authorization is enabled for a characteristic,
00368                      * AUTHORIZATION_REQ event (if replied with true) is *not*
00369                      * followed by another DATA_WRITTEN event; so we still need
00370                      * to invoke handleDataWritten(), much the same as we would
00371                      * have done if write-authorization had not been enabled.
00372                      */
00373                     if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) {
00374                         GattWriteCallbackParams cbParams = {
00375                             .handle  = i,
00376                             .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op),
00377                             .offset  = gattsEventP->params.authorize_request.request.write.offset,
00378                             .len     = gattsEventP->params.authorize_request.request.write.len,
00379                             .data    = gattsEventP->params.authorize_request.request.write.data,
00380                         };
00381                         handleDataWrittenEvent(&cbParams);
00382                     }
00383                     break;
00384                 }
00385                 case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: {
00386                     GattReadAuthCallbackParams cbParams = {
00387                         .handle = i,
00388                         .offset = gattsEventP->params.authorize_request.request.read.offset,
00389                         .len    = 0,
00390                         .data   = NULL
00391                     };
00392 
00393                     ble_gatts_rw_authorize_reply_params_t reply = {
00394                         .type = BLE_GATTS_AUTHORIZE_TYPE_READ,
00395                         .params = {
00396                             .read = {
00397                                 .gatt_status = p_characteristics[i]->authorizeRead(&cbParams)
00398                             }
00399                         }
00400                     };
00401 
00402                     if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) {
00403                         if (cbParams.data != NULL) {
00404                             reply.params.read.update = 1;
00405                             reply.params.read.offset = cbParams.offset;
00406                             reply.params.read.len    = cbParams.len;
00407                             reply.params.read.p_data = cbParams.data;
00408                         }
00409                     }
00410 
00411                     sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply);
00412                     break;
00413                 }
00414 
00415                 default:
00416                     handleEvent(eventType, handle_value);
00417                     break;
00418             }
00419         }
00420     }
00421 }