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
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 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 nRF51GattServer::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 nRF51GattServer::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 nRF51GattServer::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 nRF51GattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) 00206 { 00207 uint16_t gapConnectionHandle = nRF51Gap::getInstance().getConnectionHandle(); 00208 ble_error_t returnValue = BLE_ERROR_NONE; 00209 00210 ble_gatts_value_t value = { 00211 .len = len, 00212 .offset = 0, 00213 .p_value = const_cast<uint8_t *>(buffer), 00214 }; 00215 00216 if (localOnly) { 00217 /* Only update locally regardless of notify/indicate */ 00218 ASSERT_INT( ERROR_NONE, 00219 sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), 00220 BLE_ERROR_PARAM_OUT_OF_RANGE ); 00221 return BLE_ERROR_NONE; 00222 } 00223 00224 int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); 00225 if ((characteristicIndex != -1) && 00226 (p_characteristics[characteristicIndex]->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 = attributeHandle; 00232 hvx_params.type = 00233 (p_characteristics[characteristicIndex]->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, attributeHandle, &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, attributeHandle, &value), 00256 BLE_ERROR_PARAM_OUT_OF_RANGE ); 00257 } 00258 00259 return returnValue; 00260 } 00261 00262 ble_error_t nRF51GattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP) 00263 { 00264 /* Forward the call with the default connection handle. */ 00265 return areUpdatesEnabled(nRF51Gap::getInstance().getConnectionHandle(), characteristic, enabledP); 00266 } 00267 00268 ble_error_t nRF51GattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) 00269 { 00270 int characteristicIndex = resolveValueHandleToCharIndex(characteristic.getValueHandle()); 00271 if (characteristicIndex == -1) { 00272 return BLE_ERROR_INVALID_PARAM; 00273 } 00274 00275 /* Read the cccd value from the GATT server. */ 00276 GattAttribute::Handle_t cccdHandle = nrfCharacteristicHandles[characteristicIndex].cccd_handle; 00277 uint16_t cccdValue; 00278 uint16_t length = sizeof(cccdValue); 00279 ble_error_t rc = read(connectionHandle, cccdHandle, reinterpret_cast<uint8_t *>(&cccdValue), &length); 00280 if (rc != BLE_ERROR_NONE) { 00281 return rc; 00282 } 00283 if (length != sizeof(cccdValue)) { 00284 return BLE_ERROR_INVALID_STATE; 00285 } 00286 00287 /* Check for NOTFICATION or INDICATION in CCCD. */ 00288 if ((cccdValue & BLE_GATT_HVX_NOTIFICATION) || (cccdValue & BLE_GATT_HVX_INDICATION)) { 00289 *enabledP = true; 00290 } 00291 00292 return BLE_ERROR_NONE; 00293 } 00294 00295 /**************************************************************************/ 00296 /*! 00297 @brief Callback handler for events getting pushed up from the SD 00298 */ 00299 /**************************************************************************/ 00300 void nRF51GattServer::hwCallback(ble_evt_t *p_ble_evt) 00301 { 00302 GattAttribute::Handle_t handle_value; 00303 GattServerEvents::gattEvent_t eventType; 00304 const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt; 00305 00306 switch (p_ble_evt->header.evt_id) { 00307 case BLE_GATTS_EVT_WRITE: { 00308 /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */ 00309 00310 /* 1.) Handle CCCD changes */ 00311 handle_value = gattsEventP->params.write.handle; 00312 int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value); 00313 if ((characteristicIndex != -1) && 00314 (p_characteristics[characteristicIndex]->getProperties() & 00315 (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { 00316 00317 uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */ 00318 00319 if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) || 00320 ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) { 00321 eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED; 00322 } else { 00323 eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED; 00324 } 00325 00326 handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle()); 00327 return; 00328 } 00329 00330 /* 2.) Changes to the characteristic value will be handled with other events below */ 00331 eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN; 00332 } 00333 break; 00334 00335 case BLE_GATTS_EVT_HVC: 00336 /* Indication confirmation received */ 00337 eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED; 00338 handle_value = gattsEventP->params.hvc.handle; 00339 break; 00340 00341 case BLE_EVT_TX_COMPLETE: { 00342 handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count); 00343 return; 00344 } 00345 00346 case BLE_GATTS_EVT_SYS_ATTR_MISSING: 00347 sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0); 00348 return; 00349 00350 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: 00351 switch (gattsEventP->params.authorize_request.type) { 00352 case BLE_GATTS_AUTHORIZE_TYPE_READ: 00353 eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ; 00354 handle_value = gattsEventP->params.authorize_request.request.read.handle; 00355 break; 00356 case BLE_GATTS_AUTHORIZE_TYPE_WRITE: 00357 eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ; 00358 handle_value = gattsEventP->params.authorize_request.request.write.handle; 00359 break; 00360 default: 00361 return; 00362 } 00363 break; 00364 00365 default: 00366 return; 00367 } 00368 00369 int characteristicIndex = resolveValueHandleToCharIndex(handle_value); 00370 if (characteristicIndex == -1) { 00371 return; 00372 } 00373 00374 /* Find index (charHandle) in the pool */ 00375 switch (eventType) { 00376 case GattServerEvents::GATT_EVENT_DATA_WRITTEN: { 00377 GattWriteCallbackParams cbParams = { 00378 .handle = handle_value, 00379 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op), 00380 .offset = gattsEventP->params.write.offset, 00381 .len = gattsEventP->params.write.len, 00382 .data = gattsEventP->params.write.data 00383 }; 00384 handleDataWrittenEvent(&cbParams); 00385 break; 00386 } 00387 case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: { 00388 GattWriteAuthCallbackParams cbParams = { 00389 .handle = handle_value, 00390 .offset = gattsEventP->params.authorize_request.request.write.offset, 00391 .len = gattsEventP->params.authorize_request.request.write.len, 00392 .data = gattsEventP->params.authorize_request.request.write.data, 00393 }; 00394 ble_gatts_rw_authorize_reply_params_t reply = { 00395 .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, 00396 .params = { 00397 .write = { 00398 .gatt_status = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams) 00399 } 00400 } 00401 }; 00402 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); 00403 00404 /* 00405 * If write-authorization is enabled for a characteristic, 00406 * AUTHORIZATION_REQ event (if replied with true) is *not* 00407 * followed by another DATA_WRITTEN event; so we still need 00408 * to invoke handleDataWritten(), much the same as we would 00409 * have done if write-authorization had not been enabled. 00410 */ 00411 if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { 00412 GattWriteCallbackParams cbParams = { 00413 .handle = handle_value, 00414 .writeOp = static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op), 00415 .offset = gattsEventP->params.authorize_request.request.write.offset, 00416 .len = gattsEventP->params.authorize_request.request.write.len, 00417 .data = gattsEventP->params.authorize_request.request.write.data, 00418 }; 00419 handleDataWrittenEvent(&cbParams); 00420 } 00421 break; 00422 } 00423 case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { 00424 GattReadAuthCallbackParams cbParams = { 00425 .handle = handle_value, 00426 .offset = gattsEventP->params.authorize_request.request.read.offset, 00427 .len = 0, 00428 .data = NULL 00429 }; 00430 00431 ble_gatts_rw_authorize_reply_params_t reply = { 00432 .type = BLE_GATTS_AUTHORIZE_TYPE_READ, 00433 .params = { 00434 .read = { 00435 .gatt_status = p_characteristics[characteristicIndex]->authorizeRead(&cbParams) 00436 } 00437 } 00438 }; 00439 00440 if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) { 00441 if (cbParams.data != NULL) { 00442 reply.params.read.update = 1; 00443 reply.params.read.offset = cbParams.offset; 00444 reply.params.read.len = cbParams.len; 00445 reply.params.read.p_data = cbParams.data; 00446 } 00447 } 00448 00449 sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); 00450 break; 00451 } 00452 00453 default: 00454 handleEvent(eventType, handle_value); 00455 break; 00456 } 00457 }
Generated on Tue Jul 12 2022 18:08:54 by
1.7.2
