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 LinkNode-Test 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 16:00:20 by
