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 #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 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 p_characteristics[characteristicCount] = p_char; 00107 p_char->getValueAttribute().setHandle(nrfCharacteristicHandles[characteristicCount].value_handle); 00108 characteristicCount++; 00109 00110 /* Add optional descriptors if any */ 00111 /* ToDo: Make sure we don't overflow the array */ 00112 for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) { 00113 GattAttribute *p_desc = p_char->getDescriptor(j); 00114 /* skip the user-description-descriptor here; this has already been handled when adding the characteristic (above). */ 00115 if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) { 00116 continue; 00117 } 00118 00119 nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID()); 00120 00121 ASSERT(ERROR_NONE == 00122 custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID, 00123 &nordicUUID, 00124 p_desc->getValuePtr(), 00125 p_desc->getInitialLength(), 00126 p_desc->getMaxLength(), 00127 &nrfDescriptorHandles[descriptorCount]), 00128 BLE_ERROR_PARAM_OUT_OF_RANGE); 00129 00130 p_descriptors[descriptorCount++] = p_desc; 00131 p_desc->setHandle(nrfDescriptorHandles[descriptorCount]); 00132 } 00133 } 00134 00135 serviceCount++; 00136 00137 return BLE_ERROR_NONE; 00138 } 00139 00140 /**************************************************************************/ 00141 /*! 00142 @brief Reads the value of a characteristic, based on the service 00143 and characteristic index fields 00144 00145 @param[in] attributeHandle 00146 The handle of the GattCharacteristic to read from 00147 @param[in] buffer 00148 Buffer to hold the the characteristic's value 00149 (raw byte array in LSB format) 00150 @param[in/out] len 00151 input: Length in bytes to be read. 00152 output: Total length of attribute value upon successful return. 00153 00154 @returns ble_error_t 00155 00156 @retval BLE_ERROR_NONE 00157 Everything executed properly 00158 */ 00159 /**************************************************************************/ 00160 ble_error_t nRF5xGattServer::read(GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) 00161 { 00162 return read(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, lengthP); 00163 } 00164 00165 ble_error_t nRF5xGattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) 00166 { 00167 ble_gatts_value_t value = { 00168 .len = *lengthP, 00169 .offset = 0, 00170 .p_value = buffer, 00171 }; 00172 00173 ASSERT( ERROR_NONE == 00174 sd_ble_gatts_value_get(connectionHandle, attributeHandle, &value), 00175 BLE_ERROR_PARAM_OUT_OF_RANGE); 00176 *lengthP = value.len; 00177 00178 return BLE_ERROR_NONE; 00179 } 00180 00181 /**************************************************************************/ 00182 /*! 00183 @brief Updates the value of a characteristic, based on the service 00184 and characteristic index fields 00185 00186 @param[in] charHandle 00187 The handle of the GattCharacteristic to write to 00188 @param[in] buffer 00189 Data to use when updating the characteristic's value 00190 (raw byte array in LSB format) 00191 @param[in] len 00192 The number of bytes in buffer 00193 00194 @returns ble_error_t 00195 00196 @retval BLE_ERROR_NONE 00197 Everything executed properly 00198 */ 00199 /**************************************************************************/ 00200 ble_error_t nRF5xGattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) 00201 { 00202 return write(BLE_CONN_HANDLE_INVALID, attributeHandle, buffer, len, localOnly); 00203 } 00204 00205 ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) 00206 { 00207 ble_error_t returnValue = BLE_ERROR_NONE; 00208 00209 ble_gatts_value_t value = { 00210 .len = len, 00211 .offset = 0, 00212 .p_value = const_cast<uint8_t *>(buffer), 00213 }; 00214 00215 if (localOnly) { 00216 /* Only update locally regardless of notify/indicate */ 00217 ASSERT_INT( ERROR_NONE, 00218 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), 00219 BLE_ERROR_PARAM_OUT_OF_RANGE ); 00220 return BLE_ERROR_NONE; 00221 } 00222 00223 int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); 00224 if ((characteristicIndex != -1) && 00225 (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { 00226 /* HVX update for the characteristic value */ 00227 ble_gatts_hvx_params_t hvx_params; 00228 00229 hvx_params.handle = attributeHandle; 00230 hvx_params.type = 00231 (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION; 00232 hvx_params.offset = 0; 00233 hvx_params.p_data = const_cast<uint8_t *>(buffer); 00234 hvx_params.p_len = &len; 00235 00236 if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */ 00237 connectionHandle = nRF5xGap::getInstance().getConnectionHandle(); 00238 } 00239 error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); 00240 if (error != ERROR_NONE) { 00241 switch (error) { 00242 case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */ 00243 case ERROR_BUSY: 00244 returnValue = BLE_STACK_BUSY; 00245 break; 00246 00247 case ERROR_INVALID_STATE: 00248 case ERROR_BLEGATTS_SYS_ATTR_MISSING: 00249 returnValue = BLE_ERROR_INVALID_STATE; 00250 break; 00251 00252 default : 00253 ASSERT_INT( ERROR_NONE, 00254 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), 00255 BLE_ERROR_PARAM_OUT_OF_RANGE ); 00256 00257 /* Notifications consume application buffers. The return value can 00258 * be used for resending notifications. */ 00259 returnValue = BLE_STACK_BUSY; 00260 break; 00261 } 00262 } 00263 } else { 00264 returnValue = BLE_ERROR_INVALID_STATE; // if assert is not used 00265 ASSERT_INT( ERROR_NONE, 00266 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), 00267 BLE_ERROR_PARAM_OUT_OF_RANGE ); 00268 } 00269 00270 return returnValue; 00271 } 00272 00273 ble_error_t nRF5xGattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) 00274 { 00275 /* Forward the call with the default connection handle. */ 00276 return areUpdatesEnabled(nRF5xGap::getInstance().getConnectionHandle(), characteristic, enabledP); 00277 } 00278 00279 ble_error_t nRF5xGattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) 00280 { 00281 int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle()); 00282 if (characteristicIndex == -1) { 00283 return BLE_ERROR_INVALID_PARAM; 00284 } 00285 00286 /* Read the cccd value from the GATT server. */ 00287 GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle; 00288 uint16_t cccdValue; 00289 uint16_t length = sizeof(cccdValue); 00290 ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast<uint8_t *>(&cccdValue), &length); 00291 if (rc != BLE_ERROR_NONE) { 00292 return rc; 00293 } 00294 if (length != sizeof(cccdValue)) { 00295 return BLE_ERROR_INVALID_STATE; 00296 } 00297 00298 /* Check for NOTFICATION or INDICATION in CCCD. */ 00299 if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) { 00300 *enabledP = true; 00301 } 00302 00303 return BLE_ERROR_NONE; 00304 } 00305 00306 /**************************************************************************/ 00307 /*! 00308 @brief Callback handler for events getting pushed up from the SD 00309 */ 00310 /**************************************************************************/ 00311 void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt) 00312 { 00313 GattAttribute::Handle_t handle_value; 00314 GattServerEvents::gattEvent_t eventType; 00315 const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt; 00316 00317 switch (p_ble_evt->header.evt_id) { 00318 case BLE_GATTS_EVT_WRITE: { 00319 /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */ 00320 00321 /* 1.) Handle CCCD changes */ 00322 handle_value = gattsEventP->params.write.handle; 00323 int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value); 00324 if ((characteristicIndex != -1) && 00325 (p_characteristics[characteristicIndex]->getProperties() & 00326 (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { 00327 00328 uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */ 00329 00330 if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) || 00331 ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) { 00332 eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED; 00333 } else { 00334 eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED; 00335 } 00336 00337 handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle()); 00338 return; 00339 } 00340 00341 /* 2.) Changes to the characteristic value will be handled with other events below */ 00342 eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN; 00343 } 00344 break; 00345 00346 case BLE_GATTS_EVT_HVC: 00347 /* Indication confirmation received */ 00348 eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED; 00349 handle_value = gattsEventP->params.hvc.handle; 00350 break; 00351 00352 case BLE_EVT_TX_COMPLETE: { 00353 handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count); 00354 return; 00355 } 00356 00357 case BLE_GATTS_EVT_SYS_ATTR_MISSING: 00358 sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0); 00359 return; 00360 00361 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: 00362 switch (gattsEventP->params.authorize_request.type) { 00363 case BLE_GATTS_AUTHORIZE_TYPE_READ: 00364 eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ; 00365 handle_value = gattsEventP->params.authorize_request.request.read.handle; 00366 break; 00367 case BLE_GATTS_AUTHORIZE_TYPE_WRITE: 00368 eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ; 00369 handle_value = gattsEventP->params.authorize_request.request.write.handle; 00370 break; 00371 default: 00372 return; 00373 } 00374 break; 00375 00376 default: 00377 return; 00378 } 00379 00380 int characteristicIndex = resolveValueHandleToCharIndex(handle_value); 00381 if (characteristicIndex == -1) { 00382 return; 00383 } 00384 00385 /* Find index (charHandle) in the pool */ 00386 switch (eventType) { 00387 case GattServerEvents::GATT_EVENT_DATA_WRITTEN: { 00388 GattWriteCallbackParams cbParams = { 00389 .connHandle = gattsEventP->conn_handle, 00390 .handle = handle_value, 00391 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op), 00392 .offset = gattsEventP->params.write.offset, 00393 .len = gattsEventP->params.write.len, 00394 .data = gattsEventP->params.write.data 00395 }; 00396 handleDataWrittenEvent(&cbParams); 00397 break; 00398 } 00399 case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: { 00400 GattWriteAuthCallbackParams cbParams = { 00401 .connHandle = gattsEventP->conn_handle, 00402 .handle = handle_value, 00403 .offset = gattsEventP->params.authorize_request.request.write.offset, 00404 .len = gattsEventP->params.authorize_request.request.write.len, 00405 .data = gattsEventP->params.authorize_request.request.write.data, 00406 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member 00407 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client 00408 * request is to proceed. */ 00409 }; 00410 ble_gatts_rw_authorize_reply_params_t reply = { 00411 .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, 00412 .params = { 00413 .write = { 00414 .gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams) 00415 } 00416 } 00417 }; 00418 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); 00419 00420 /* 00421 * If write-authorization is enabled for a characteristic, 00422 * AUTHORIZATION_REQ event (if replied with true) is *not* 00423 * followed by another DATA_WRITTEN event; so we still need 00424 * to invoke handleDataWritten(), much the same as we would 00425 * have done if write-authorization had not been enabled. 00426 */ 00427 if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { 00428 GattWriteCallbackParams cbParams = { 00429 .connHandle = gattsEventP->conn_handle, 00430 .handle = handle_value, 00431 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op), 00432 .offset = gattsEventP->params.authorize_request.request.write.offset, 00433 .len = gattsEventP->params.authorize_request.request.write.len, 00434 .data = gattsEventP->params.authorize_request.request.write.data, 00435 }; 00436 handleDataWrittenEvent(&cbParams); 00437 } 00438 break; 00439 } 00440 case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { 00441 GattReadAuthCallbackParams cbParams = { 00442 .connHandle = gattsEventP->conn_handle, 00443 .handle = handle_value, 00444 .offset = gattsEventP->params.authorize_request.request.read.offset, 00445 .len = 0, 00446 .data = NULL, 00447 .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member 00448 * set to AUTH_CALLBACK_REPLY_SUCCESS if the client 00449 * request is to proceed. */ 00450 }; 00451 00452 ble_gatts_rw_authorize_reply_params_t reply = { 00453 .type = BLE_GATTS_AUTHORIZE_TYPE_READ, 00454 .params = { 00455 .read = { 00456 .gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams) 00457 } 00458 } 00459 }; 00460 00461 if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) { 00462 if (cbParams.data != NULL) { 00463 reply.params.read.update = 1; 00464 reply.params.read.offset = cbParams.offset; 00465 reply.params.read.len = cbParams.len; 00466 reply.params.read.p_data = cbParams.data; 00467 } 00468 } 00469 00470 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); 00471 break; 00472 } 00473 00474 default: 00475 handleEvent(eventType, handle_value); 00476 break; 00477 } 00478 }
Generated on Tue Jul 12 2022 21:00:16 by
