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.
Fork of nRF51822 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 #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 ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) 00281 { 00282 /* Forward the call with the default connection handle. */ 00283 nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); 00284 return areUpdatesEnabled(gap.getConnectionHandle(), characteristic, enabledP); 00285 } 00286 00287 ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) 00288 { 00289 int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle()); 00290 if (characteristicIndex == -1) { 00291 return BLE_ERROR_INVALID_PARAM; 00292 } 00293 00294 /* Read the cccd value from the GATT server. */ 00295 GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle; 00296 uint16_t cccdValue; 00297 uint16_t length = sizeof(cccdValue); 00298 ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast<uint8_t *>(&cccdValue), &length); 00299 if (rc != BLE_ERROR_NONE) { 00300 return rc; 00301 } 00302 if (length != sizeof(cccdValue)) { 00303 return BLE_ERROR_INVALID_STATE; 00304 } 00305 00306 /* Check for NOTFICATION or INDICATION in CCCD. */ 00307 if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) { 00308 *enabledP = true; 00309 } 00310 00311 return BLE_ERROR_NONE; 00312 } 00313 00314 /**************************************************************************/ 00315 /*! 00316 @brief Clear nRF5xGattServer's state. 00317 00318 @returns ble_error_t 00319 00320 @retval BLE_ERROR_NONE 00321 Everything executed properly 00322 */ 00323 /**************************************************************************/ 00324 ble_error_t nRF5xGattServer::reset(void) 00325 { 00326 /* Clear all state that is from the parent, including private members */ 00327 if (GattServer::reset() != BLE_ERROR_NONE) { 00328 return BLE_ERROR_INVALID_STATE; 00329 } 00330 00331 /* Clear derived class members */ 00332 memset(p_characteristics, 0, sizeof(p_characteristics)); 00333 memset(p_descriptors, 0, sizeof(p_descriptors)); 00334 memset(nrfCharacteristicHandles, 0, sizeof(ble_gatts_char_handles_t)); 00335 memset(nrfDescriptorHandles, 0, sizeof(nrfDescriptorHandles)); 00336 descriptorCount = 0; 00337 00338 return BLE_ERROR_NONE; 00339 } 00340 00341 /**************************************************************************/ 00342 /*! 00343 @brief Callback handler for events getting pushed up from the SD 00344 */ 00345 /**************************************************************************/ 00346 void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt) 00347 { 00348 GattAttribute::Handle_t handle_value; 00349 GattServerEvents::gattEvent_t eventType; 00350 const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt; 00351 00352 switch (p_ble_evt->header.evt_id) { 00353 case BLE_GATTS_EVT_WRITE: { 00354 /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */ 00355 00356 /* 1.) Handle CCCD changes */ 00357 handle_value = gattsEventP->params.write.handle; 00358 int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value); 00359 if ((characteristicIndex != -1) && 00360 (p_characteristics[characteristicIndex]->getProperties() & 00361 (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { 00362 00363 uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */ 00364 00365 if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) || 00366 ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) { 00367 eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED; 00368 } else { 00369 eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED; 00370 } 00371 00372 handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle()); 00373 return; 00374 } 00375 00376 /* 2.) Changes to the characteristic value will be handled with other events below */ 00377 eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN; 00378 } 00379 break; 00380 00381 case BLE_GATTS_EVT_HVC: 00382 /* Indication confirmation received */ 00383 eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED; 00384 handle_value = gattsEventP->params.hvc.handle; 00385 break; 00386 00387 case BLE_EVT_TX_COMPLETE: { 00388 handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count); 00389 return; 00390 } 00391 00392 case BLE_GATTS_EVT_SYS_ATTR_MISSING: 00393 sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0); 00394 return; 00395 00396 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: 00397 switch (gattsEventP->params.authorize_request.type) { 00398 case BLE_GATTS_AUTHORIZE_TYPE_READ: 00399 eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ; 00400 handle_value = gattsEventP->params.authorize_request.request.read.handle; 00401 break; 00402 case BLE_GATTS_AUTHORIZE_TYPE_WRITE: 00403 eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ; 00404 handle_value = gattsEventP->params.authorize_request.request.write.handle; 00405 break; 00406 default: 00407 return; 00408 } 00409 break; 00410 00411 default: 00412 return; 00413 } 00414 00415 int characteristicIndex = resolveValueHandleToCharIndex(handle_value); 00416 if (characteristicIndex == -1) { 00417 return; 00418 } 00419 00420 /* Find index (charHandle) in the pool */ 00421 switch (eventType) { 00422 case GattServerEvents::GATT_EVENT_DATA_WRITTEN: { 00423 GattWriteCallbackParams cbParams = { 00424 .connHandle = gattsEventP->conn_handle, 00425 .handle = handle_value, 00426 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op), 00427 .offset = gattsEventP->params.write.offset, 00428 .len = gattsEventP->params.write.len, 00429 .data = gattsEventP->params.write.data 00430 }; 00431 handleDataWrittenEvent(&cbParams); 00432 break; 00433 } 00434 case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: { 00435 GattWriteAuthCallbackParams cbParams = { 00436 .connHandle = gattsEventP->conn_handle, 00437 .handle = handle_value, 00438 .offset = gattsEventP->params.authorize_request.request.write.offset, 00439 .len = gattsEventP->params.authorize_request.request.write.len, 00440 .data = gattsEventP->params.authorize_request.request.write.data, 00441 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member 00442 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client 00443 * request is to proceed. */ 00444 }; 00445 ble_gatts_rw_authorize_reply_params_t reply = { 00446 .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, 00447 .params = { 00448 .write = { 00449 .gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams) 00450 } 00451 } 00452 }; 00453 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); 00454 00455 /* 00456 * If write-authorization is enabled for a characteristic, 00457 * AUTHORIZATION_REQ event (if replied with true) is *not* 00458 * followed by another DATA_WRITTEN event; so we still need 00459 * to invoke handleDataWritten(), much the same as we would 00460 * have done if write-authorization had not been enabled. 00461 */ 00462 if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { 00463 GattWriteCallbackParams cbParams = { 00464 .connHandle = gattsEventP->conn_handle, 00465 .handle = handle_value, 00466 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op), 00467 .offset = gattsEventP->params.authorize_request.request.write.offset, 00468 .len = gattsEventP->params.authorize_request.request.write.len, 00469 .data = gattsEventP->params.authorize_request.request.write.data, 00470 }; 00471 handleDataWrittenEvent(&cbParams); 00472 } 00473 break; 00474 } 00475 case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { 00476 GattReadAuthCallbackParams cbParams = { 00477 .connHandle = gattsEventP->conn_handle, 00478 .handle = handle_value, 00479 .offset = gattsEventP->params.authorize_request.request.read.offset, 00480 .len = 0, 00481 .data = NULL, 00482 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member 00483 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client 00484 * request is to proceed. */ 00485 }; 00486 00487 ble_gatts_rw_authorize_reply_params_t reply = { 00488 .type = BLE_GATTS_AUTHORIZE_TYPE_READ, 00489 .params = { 00490 .read = { 00491 .gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams) 00492 } 00493 } 00494 }; 00495 00496 if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) { 00497 if (cbParams.data != NULL) { 00498 reply.params.read.update = 1; 00499 reply.params.read.offset = cbParams.offset; 00500 reply.params.read.len = cbParams.len; 00501 reply.params.read.p_data = cbParams.data; 00502 } 00503 } 00504 00505 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); 00506 break; 00507 } 00508 00509 default: 00510 handleEvent(eventType, handle_value); 00511 break; 00512 } 00513 }
Generated on Tue Jul 12 2022 18:30:03 by
1.7.2
