test
Fork of nRF51822 by
Embed:
(wiki syntax)
Show/hide line numbers
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 1.7.2