Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API Buffer mbed
Fork of BLE_LEDBlinker by
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 }
Generated on Tue Jul 12 2022 19:00:01 by
1.7.2
