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.
Dependencies: nRF51_Vdd TextLCD BME280
GenericGattClient.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017-2017 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 <stdio.h> 00018 #include <stdlib.h> 00019 00020 #include <ble/DiscoveredService.h> 00021 #include <ble/DiscoveredCharacteristic.h> 00022 #include "ble/generic/GenericGattClient.h" 00023 #include "ble/blecommon.h" 00024 #include "ble/BLEInstanceBase.h " 00025 #include "ble/generic/GenericSecurityManager.h" 00026 #include <algorithm> 00027 00028 using ble::pal::AttServerMessage; 00029 using ble::pal::AttReadResponse; 00030 using ble::pal::AttReadBlobResponse; 00031 using ble::pal::AttReadByTypeResponse; 00032 using ble::pal::AttReadByGroupTypeResponse; 00033 using ble::pal::AttFindByTypeValueResponse; 00034 using ble::pal::AttErrorResponse; 00035 using ble::pal::AttributeOpcode; 00036 using ble::pal::AttWriteResponse; 00037 using ble::pal::AttPrepareWriteResponse; 00038 using ble::pal::AttExecuteWriteResponse; 00039 using ble::pal::AttHandleValueIndication; 00040 using ble::pal::AttHandleValueNotification; 00041 using ble::pal::AttFindInformationResponse; 00042 00043 #define PREPARE_WRITE_HEADER_LENGTH 5 00044 #define WRITE_HEADER_LENGTH 3 00045 #define CMAC_LENGTH 8 00046 #define MAC_COUNTER_LENGTH 4 00047 00048 namespace ble { 00049 namespace generic { 00050 00051 /* 00052 * Type of procedures which can be launched by the client. 00053 */ 00054 enum procedure_type_t { 00055 COMPLETE_DISCOVERY_PROCEDURE, 00056 READ_PROCEDURE, 00057 WRITE_PROCEDURE, 00058 DESCRIPTOR_DISCOVERY_PROCEDURE 00059 }; 00060 00061 00062 /* 00063 * Base class for a procedure control block 00064 */ 00065 struct GenericGattClient::ProcedureControlBlock { 00066 /* 00067 * Base constructor for procedure control block. 00068 */ 00069 ProcedureControlBlock(procedure_type_t type, Gap::Handle_t handle) : 00070 type(type), connection_handle(handle), next(NULL) { } 00071 00072 virtual ~ProcedureControlBlock() { } 00073 00074 /* 00075 * Entry point of the control block stack machine. 00076 */ 00077 virtual void handle(GenericGattClient* client, const AttServerMessage& message) = 0; 00078 00079 /* 00080 * Function call in case of timeout 00081 */ 00082 virtual void handle_timeout_error(GenericGattClient* client) = 0; 00083 00084 /** 00085 * Function called when the procedure is aborted 00086 */ 00087 virtual void abort(GenericGattClient *client) = 0; 00088 00089 procedure_type_t type; 00090 Gap::Handle_t connection_handle; 00091 ProcedureControlBlock* next; 00092 }; 00093 00094 00095 /* 00096 * Procedure control block for the discovery process. 00097 */ 00098 struct GenericGattClient::DiscoveryControlBlock : public ProcedureControlBlock { 00099 DiscoveryControlBlock( 00100 Gap::Handle_t handle, 00101 ServiceDiscovery::ServiceCallback_t service_callback, 00102 ServiceDiscovery::CharacteristicCallback_t characteristic_callback, 00103 UUID matching_service_uuid, 00104 UUID matching_characteristic_uuid 00105 ) : ProcedureControlBlock(COMPLETE_DISCOVERY_PROCEDURE, handle), 00106 service_callback(service_callback), 00107 characteristic_callback(characteristic_callback), 00108 matching_service_uuid(matching_service_uuid), 00109 matching_characteristic_uuid(matching_characteristic_uuid), 00110 services_discovered(NULL), 00111 done(false) { 00112 } 00113 00114 virtual ~DiscoveryControlBlock() { 00115 while(services_discovered) { 00116 service_t* tmp = services_discovered->next; 00117 delete services_discovered; 00118 services_discovered = tmp; 00119 } 00120 } 00121 00122 virtual void handle_timeout_error(GenericGattClient* client) { 00123 terminate(client); 00124 } 00125 00126 virtual void abort(GenericGattClient *client) { 00127 terminate(client); 00128 } 00129 00130 virtual void handle(GenericGattClient* client, const AttServerMessage& message) { 00131 // if end of discovery has been requested, ends it immediately 00132 if (done) { 00133 terminate(client); 00134 return; 00135 } 00136 00137 switch(message.opcode) { 00138 case AttributeOpcode::READ_BY_GROUP_TYPE_RESPONSE: 00139 handle_service_discovered( 00140 client, static_cast<const AttReadByGroupTypeResponse&>(message) 00141 ); 00142 break; 00143 case AttributeOpcode::FIND_BY_VALUE_TYPE_RESPONSE: 00144 handle_service_discovered( 00145 client, static_cast<const AttFindByTypeValueResponse&>(message) 00146 ); 00147 break; 00148 case AttributeOpcode::READ_BY_TYPE_RESPONSE: 00149 handle_characteristic_discovered( 00150 client, static_cast<const AttReadByTypeResponse&>(message) 00151 ); 00152 break; 00153 case AttributeOpcode::ERROR_RESPONSE: { 00154 const AttErrorResponse& error = static_cast<const AttErrorResponse&>(message); 00155 if (error.error_code != AttErrorResponse::ATTRIBUTE_NOT_FOUND) { 00156 terminate(client); 00157 return; 00158 } 00159 00160 switch (error.request_opcode) { 00161 case AttributeOpcode::READ_BY_GROUP_TYPE_REQUEST: 00162 case AttributeOpcode::FIND_BY_TYPE_VALUE_REQUEST: 00163 start_characteristic_discovery(client); 00164 break; 00165 case AttributeOpcode::READ_BY_TYPE_REQUEST: 00166 handle_all_characteristics_discovered(client); 00167 break; 00168 default: 00169 // error 00170 break; 00171 } 00172 } break; 00173 default: 00174 // error 00175 break; 00176 } 00177 } 00178 00179 template<typename Response> 00180 void handle_service_discovered(GenericGattClient* client, const Response& response) { 00181 if (!response.size()) { 00182 terminate(client); 00183 return; 00184 } 00185 00186 uint16_t end_handle = 0x0000; 00187 for (size_t i = 0; i < response.size(); ++i) { 00188 uint16_t start_handle = get_start_handle(response[i]); 00189 end_handle = get_end_handle(response[i]); 00190 UUID uuid = get_uuid(response[i]); 00191 00192 if (!characteristic_callback) { 00193 DiscoveredService discovered_service; 00194 discovered_service.setup(uuid, start_handle, end_handle); 00195 service_callback(&discovered_service); 00196 } else { 00197 service_t* discovered_service = new (std::nothrow) service_t( 00198 start_handle, end_handle, uuid 00199 ); 00200 00201 if (discovered_service == NULL) { 00202 terminate(client); 00203 return; 00204 } 00205 00206 insert_service(discovered_service); 00207 } 00208 } 00209 00210 if (end_handle == 0xFFFF) { 00211 start_characteristic_discovery(client); 00212 } else { 00213 ble_error_t err = client->_pal_client->discover_primary_service( 00214 connection_handle, end_handle + 1 00215 ); 00216 00217 if (err) { 00218 terminate(client); 00219 } 00220 } 00221 } 00222 00223 void start_characteristic_discovery(GenericGattClient* client) { 00224 if (!services_discovered) { 00225 terminate(client); 00226 return; 00227 } 00228 00229 if (!characteristic_callback) { 00230 terminate(client); 00231 return; 00232 } 00233 00234 if (service_callback) { 00235 DiscoveredService discovered_service; 00236 discovered_service.setup( 00237 services_discovered->uuid, 00238 services_discovered->begin, 00239 services_discovered->end 00240 ); 00241 service_callback(&discovered_service); 00242 } 00243 00244 last_characteristic = characteristic_t(); 00245 client->_pal_client->discover_characteristics_of_a_service( 00246 connection_handle, 00247 attribute_handle_range( 00248 services_discovered->begin, 00249 services_discovered->end 00250 ) 00251 ); 00252 } 00253 00254 void handle_characteristic_discovered(GenericGattClient* client, const AttReadByTypeResponse& response) { 00255 for (size_t i = 0; i < response.size(); ++i) { 00256 if (last_characteristic.is_valid() == false) { 00257 last_characteristic.set_last_handle(response[i].handle - 1); 00258 if (matching_characteristic_uuid == UUID() 00259 || last_characteristic.getUUID() == matching_characteristic_uuid) { 00260 characteristic_callback(&last_characteristic); 00261 } 00262 } 00263 00264 last_characteristic = characteristic_t( 00265 client, connection_handle, response[i].handle, response[i].value 00266 ); 00267 } 00268 00269 // check if all the characteristics of the service has been discovered 00270 if (last_characteristic.getValueHandle() == services_discovered->end) { 00271 handle_all_characteristics_discovered(client); 00272 } else { 00273 ble_error_t err = client->_pal_client->discover_characteristics_of_a_service( 00274 connection_handle, 00275 attribute_handle_range( 00276 last_characteristic.getValueHandle() + 1, 00277 services_discovered->end 00278 ) 00279 ); 00280 00281 if (err) { 00282 terminate(client); 00283 } 00284 } 00285 } 00286 00287 void handle_all_characteristics_discovered(GenericGattClient* client) { 00288 if (last_characteristic.is_valid() == false) { 00289 if (matching_characteristic_uuid == UUID() 00290 || matching_characteristic_uuid == last_characteristic.getUUID()) { 00291 last_characteristic.set_last_handle(services_discovered->end); 00292 characteristic_callback(&last_characteristic); 00293 } 00294 } 00295 00296 service_t* old = services_discovered; 00297 services_discovered = services_discovered->next; 00298 delete old; 00299 00300 if (!services_discovered) { 00301 terminate(client); 00302 } else { 00303 start_characteristic_discovery(client); 00304 } 00305 } 00306 00307 void terminate(GenericGattClient* client) { 00308 // unknown error, terminate the procedure immediately 00309 client->remove_control_block(this); 00310 Gap::Handle_t handle = connection_handle; 00311 delete this; 00312 client->on_termination(handle); 00313 } 00314 00315 uint16_t get_start_handle(const AttReadByGroupTypeResponse::attribute_data_t& data) { 00316 return data.group_range.begin; 00317 } 00318 00319 uint16_t get_start_handle(const attribute_handle_range_t& range) { 00320 return range.begin; 00321 } 00322 00323 uint16_t get_end_handle(const AttReadByGroupTypeResponse::attribute_data_t& data) { 00324 return data.group_range.end; 00325 } 00326 00327 uint16_t get_end_handle(const attribute_handle_range_t& range) { 00328 return range.end; 00329 } 00330 00331 UUID get_uuid(const AttReadByGroupTypeResponse::attribute_data_t& data) { 00332 if (data.value.size() == 2) { 00333 return UUID(data.value[0] | data.value[1] << 8); 00334 } else { 00335 return UUID(data.value.data(), UUID::LSB); 00336 } 00337 } 00338 00339 UUID get_uuid(const attribute_handle_range_t& range) { 00340 return matching_service_uuid; 00341 } 00342 00343 struct service_t { 00344 service_t(uint16_t begin, uint16_t end, const UUID& uuid) : 00345 begin(begin), end(end), uuid(uuid), next(NULL) { } 00346 uint16_t begin; 00347 uint16_t end; 00348 UUID uuid; 00349 service_t* next; 00350 }; 00351 00352 struct characteristic_t : DiscoveredCharacteristic { 00353 characteristic_t() : DiscoveredCharacteristic() { 00354 lastHandle = 0x0001; 00355 } 00356 00357 characteristic_t( 00358 GattClient* client, 00359 Gap::Handle_t connection_handle, 00360 uint16_t decl_handle, 00361 const ArrayView<const uint8_t> value 00362 ) : DiscoveredCharacteristic() { 00363 gattc = client; 00364 uuid = get_uuid(value); 00365 props = get_properties(value); 00366 declHandle = decl_handle; 00367 valueHandle = get_value_handle(value); 00368 lastHandle = 0x0000; 00369 connHandle = connection_handle; 00370 } 00371 00372 static UUID get_uuid(const ArrayView<const uint8_t>& value) { 00373 if (value.size() == 5) { 00374 return UUID(value[3] | (value[4] << 8)); 00375 } else { 00376 return UUID(value.data() + 3, UUID::LSB); 00377 } 00378 } 00379 00380 static DiscoveredCharacteristic::Properties_t get_properties(const ArrayView<const uint8_t>& value) { 00381 uint8_t raw_properties = value[0]; 00382 DiscoveredCharacteristic::Properties_t result; 00383 result._broadcast = (raw_properties & (1 << 0)) ? true : false; 00384 result._read = (raw_properties & (1 << 1)) ? true : false; 00385 result._writeWoResp = (raw_properties & (1 << 2)) ? true : false; 00386 result._write = (raw_properties & (1 << 3)) ? true : false; 00387 result._notify = (raw_properties & (1 << 4)) ? true : false; 00388 result._indicate = (raw_properties & (1 << 5)) ? true : false; 00389 result._authSignedWrite = (raw_properties & (1 << 6)) ? true : false; 00390 return result; 00391 } 00392 00393 static uint16_t get_value_handle(const ArrayView<const uint8_t>& value) { 00394 return value[1] | (value[2] << 8); 00395 } 00396 00397 void set_last_handle(uint16_t last_handle) { 00398 lastHandle = last_handle; 00399 } 00400 00401 bool is_valid() const { 00402 return lastHandle != 0x0000; 00403 } 00404 }; 00405 00406 void insert_service(service_t* service) { 00407 if (services_discovered == NULL) { 00408 services_discovered = service; 00409 return; 00410 } 00411 00412 service_t* current = services_discovered; 00413 while (current->next) { 00414 current = current->next; 00415 } 00416 current->next = service; 00417 } 00418 00419 ServiceDiscovery::ServiceCallback_t service_callback; 00420 ServiceDiscovery::CharacteristicCallback_t characteristic_callback; 00421 UUID matching_service_uuid; 00422 UUID matching_characteristic_uuid; 00423 service_t* services_discovered; 00424 characteristic_t last_characteristic; 00425 bool done; 00426 }; 00427 00428 00429 struct GenericGattClient::ReadControlBlock : public ProcedureControlBlock { 00430 ReadControlBlock( 00431 Gap::Handle_t connection_handle, uint16_t attribute_handle, uint16_t offset 00432 ) : ProcedureControlBlock(READ_PROCEDURE, connection_handle), 00433 attribute_handle(attribute_handle), 00434 offset(offset), current_offset(offset), data(NULL) { 00435 } 00436 00437 virtual ~ReadControlBlock() { 00438 if (data != NULL) { 00439 free(data); 00440 } 00441 } 00442 00443 virtual void handle_timeout_error(GenericGattClient* client) { 00444 GattReadCallbackParams response = { 00445 connection_handle, 00446 attribute_handle, 00447 offset, 00448 0, // size of 0 00449 NULL, // no data 00450 BLE_ERROR_UNSPECIFIED, 00451 00452 }; 00453 terminate(client, response); 00454 } 00455 00456 virtual void abort(GenericGattClient *client) { 00457 GattReadCallbackParams response = { 00458 connection_handle, 00459 attribute_handle, 00460 offset, 00461 0, // size of 0 00462 NULL, // no data 00463 BLE_ERROR_INVALID_STATE, 00464 00465 }; 00466 terminate(client, response); 00467 } 00468 00469 void terminate(GenericGattClient* client, const GattReadCallbackParams& response) { 00470 client->remove_control_block(this); 00471 client->processReadResponse(&response); 00472 delete this; 00473 } 00474 00475 virtual void handle(GenericGattClient* client, const AttServerMessage& message) { 00476 switch(message.opcode) { 00477 case AttributeOpcode::ERROR_RESPONSE: 00478 handle_error(client, static_cast<const AttErrorResponse&>(message)); 00479 break; 00480 00481 case AttributeOpcode::READ_RESPONSE: 00482 handle_read_response(client, static_cast<const AttReadResponse&>(message)); 00483 break; 00484 00485 case AttributeOpcode::READ_BLOB_RESPONSE: 00486 handle_read_response(client, static_cast<const AttReadBlobResponse&>(message)); 00487 break; 00488 00489 default: { 00490 // should not happen, terminate the procedure and notify client with an error 00491 // in such case 00492 GattReadCallbackParams response = { 00493 connection_handle, 00494 attribute_handle, 00495 AttErrorResponse::UNLIKELY_ERROR, 00496 0, // size of 0 00497 NULL, // no data 00498 BLE_ERROR_UNSPECIFIED, 00499 00500 }; 00501 terminate(client, response); 00502 } break; 00503 } 00504 } 00505 00506 template<typename ResponseType> 00507 void handle_read_response(GenericGattClient* client, const ResponseType& read_response) { 00508 uint16_t mtu_size = client->get_mtu(connection_handle); 00509 00510 // end of responses ? 00511 if ((uint16_t) read_response.size() < (mtu_size - 1)) { 00512 GattReadCallbackParams response = { 00513 connection_handle, 00514 attribute_handle, 00515 offset, 00516 0, // size of 0 00517 NULL, // no data 00518 BLE_ERROR_NONE, 00519 }; 00520 00521 // is it the first response, or is there any other response already 00522 // in the object ? 00523 if (data == NULL) { 00524 response.len = (uint16_t) read_response.size(); 00525 response.data = read_response.data(); 00526 } else { 00527 // copy the data in the existing buffer 00528 memcpy(data + (current_offset - offset), read_response.data(), read_response.size()); 00529 response.len = (current_offset + read_response.size()) - offset; 00530 response.data = data; 00531 } 00532 terminate(client, response); 00533 } else { 00534 // allocation which will contain the response data plus the next one. 00535 data = (uint8_t*) realloc(data, (current_offset - offset) + ((mtu_size - 1) * 2)); 00536 if (data == NULL) { 00537 GattReadCallbackParams response = { 00538 connection_handle, 00539 attribute_handle, 00540 offset, 00541 AttErrorResponse::INSUFFICIENT_RESOURCES, 00542 NULL, 00543 BLE_ERROR_NO_MEM, 00544 }; 00545 terminate(client, response); 00546 return; 00547 } 00548 00549 memcpy(data + (current_offset - offset), read_response.data(), read_response.size()); 00550 current_offset = current_offset + read_response.size(); 00551 ble_error_t err = client->_pal_client->read_attribute_blob( 00552 connection_handle, 00553 attribute_handle, 00554 current_offset 00555 ); 00556 00557 if (err) { 00558 GattReadCallbackParams response = { 00559 connection_handle, 00560 attribute_handle, 00561 AttErrorResponse::UNLIKELY_ERROR, 00562 0, // size of 0 00563 NULL, // no data 00564 BLE_ERROR_UNSPECIFIED, 00565 00566 }; 00567 terminate(client, response); 00568 } 00569 } 00570 } 00571 00572 void handle_error(GenericGattClient* client, const AttErrorResponse& error) { 00573 ble_error_t status = BLE_ERROR_UNSPECIFIED; 00574 00575 switch (error.error_code) { 00576 case AttErrorResponse::INVALID_HANDLE: 00577 status = BLE_ERROR_INVALID_PARAM; 00578 break; 00579 case AttErrorResponse::INSUFFICIENT_AUTHORIZATION: 00580 status = BLE_ERROR_INVALID_STATE; 00581 break; 00582 case AttErrorResponse::INSUFFICIENT_AUTHENTICATION: 00583 status = BLE_ERROR_INVALID_STATE; 00584 break; 00585 case AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: 00586 status = BLE_ERROR_INVALID_STATE; 00587 break; 00588 case AttErrorResponse::INSUFFICIENT_ENCRYPTION: 00589 status = BLE_ERROR_INVALID_STATE; 00590 break; 00591 case AttErrorResponse::READ_NOT_PERMITTED: 00592 status = BLE_ERROR_OPERATION_NOT_PERMITTED; 00593 break; 00594 case AttErrorResponse::INVALID_OFFSET: 00595 status = BLE_ERROR_PARAM_OUT_OF_RANGE; 00596 break; 00597 case AttErrorResponse::ATTRIBUTE_NOT_LONG: 00598 status = BLE_ERROR_PARAM_OUT_OF_RANGE; 00599 break; 00600 default: 00601 status = BLE_ERROR_UNSPECIFIED; 00602 break; 00603 } 00604 00605 GattReadCallbackParams response = { 00606 connection_handle, 00607 attribute_handle, 00608 offset, 00609 error.error_code, 00610 /* data */ NULL, 00611 status 00612 }; 00613 00614 terminate(client, response); 00615 } 00616 00617 uint16_t attribute_handle; 00618 uint16_t offset; 00619 uint16_t current_offset; 00620 uint8_t* data; 00621 }; 00622 00623 /* 00624 * Control block for the write process 00625 */ 00626 struct GenericGattClient::WriteControlBlock : public ProcedureControlBlock { 00627 WriteControlBlock( 00628 Gap::Handle_t connection_handle, uint16_t attribute_handle, 00629 uint8_t* data, uint16_t len 00630 ) : ProcedureControlBlock(WRITE_PROCEDURE, connection_handle), 00631 attribute_handle(attribute_handle), len(len), offset(0), data(data), 00632 prepare_success(false), status(BLE_ERROR_UNSPECIFIED), error_code(0xFF) { 00633 } 00634 00635 virtual ~WriteControlBlock() { 00636 free(data); 00637 } 00638 00639 virtual void handle_timeout_error(GenericGattClient* client) { 00640 GattWriteCallbackParams response = { 00641 connection_handle, 00642 attribute_handle, 00643 GattWriteCallbackParams::OP_WRITE_REQ, 00644 BLE_ERROR_UNSPECIFIED, 00645 0x00 00646 }; 00647 terminate(client, response); 00648 } 00649 00650 virtual void abort(GenericGattClient *client) { 00651 GattWriteCallbackParams response = { 00652 connection_handle, 00653 attribute_handle, 00654 GattWriteCallbackParams::OP_WRITE_REQ, 00655 BLE_ERROR_INVALID_STATE, 00656 0x00 00657 }; 00658 terminate(client, response); 00659 } 00660 00661 void terminate(GenericGattClient* client, const GattWriteCallbackParams& response) { 00662 client->remove_control_block(this); 00663 client->processWriteResponse(&response); 00664 delete this; 00665 } 00666 00667 virtual void handle(GenericGattClient* client, const AttServerMessage& message) { 00668 switch(message.opcode) { 00669 case AttributeOpcode::ERROR_RESPONSE: 00670 handle_error(client, static_cast<const AttErrorResponse&>(message)); 00671 break; 00672 00673 case AttributeOpcode::WRITE_RESPONSE: 00674 handle_write_response(client, static_cast<const AttWriteResponse&>(message)); 00675 break; 00676 00677 case AttributeOpcode::PREPARE_WRITE_RESPONSE: 00678 handle_prepare_write_response(client, static_cast<const AttPrepareWriteResponse&>(message)); 00679 break; 00680 00681 case AttributeOpcode::EXECUTE_WRITE_RESPONSE: 00682 handle_execute_write_response(client, static_cast<const AttExecuteWriteResponse&>(message)); 00683 break; 00684 00685 default: { 00686 GattWriteCallbackParams response = { 00687 connection_handle, 00688 attribute_handle, 00689 GattWriteCallbackParams::OP_WRITE_REQ, 00690 BLE_ERROR_UNSPECIFIED, 00691 AttErrorResponse::UNLIKELY_ERROR 00692 }; 00693 00694 terminate(client, response); 00695 } break; 00696 } 00697 } 00698 00699 void handle_write_response(GenericGattClient* client, const AttWriteResponse& write_response) { 00700 GattWriteCallbackParams response = { 00701 connection_handle, attribute_handle, 00702 GattWriteCallbackParams::OP_WRITE_REQ, 00703 BLE_ERROR_NONE, 0x00 00704 }; 00705 00706 terminate(client, response); 00707 } 00708 00709 void handle_prepare_write_response(GenericGattClient* client, const AttPrepareWriteResponse& write_response) { 00710 ble_error_t err = BLE_ERROR_UNSPECIFIED; 00711 00712 uint16_t mtu_size = client->get_mtu(connection_handle); 00713 offset = write_response.offset + write_response.partial_value.size(); 00714 if (offset < len) { 00715 err = client->_pal_client->queue_prepare_write( 00716 connection_handle, attribute_handle, 00717 make_const_ArrayView( 00718 data + offset, 00719 std::min((len - offset), (mtu_size - 5)) 00720 ), 00721 offset 00722 ); 00723 } else { 00724 err = client->_pal_client->execute_write_queue( 00725 connection_handle, true 00726 ); 00727 } 00728 00729 if (err) { 00730 clear_prepare_queue(client, err, AttErrorResponse::UNLIKELY_ERROR); 00731 } 00732 } 00733 00734 void handle_execute_write_response(GenericGattClient* client, const AttExecuteWriteResponse& execute_response) { 00735 if (prepare_success) { 00736 status = BLE_ERROR_NONE; 00737 error_code = 0x00; 00738 } 00739 00740 GattWriteCallbackParams response = { 00741 connection_handle, 00742 attribute_handle, 00743 GattWriteCallbackParams::OP_WRITE_REQ, 00744 status, 00745 error_code 00746 }; 00747 00748 terminate(client, response); 00749 } 00750 00751 void clear_prepare_queue(GenericGattClient* client, ble_error_t s, uint8_t e) { 00752 prepare_success = false; 00753 status = s; 00754 error_code = e; 00755 ble_error_t err = client->_pal_client->execute_write_queue( 00756 connection_handle, false 00757 ); 00758 00759 if (err) { 00760 GattWriteCallbackParams response = { 00761 connection_handle, 00762 attribute_handle, 00763 GattWriteCallbackParams::OP_WRITE_REQ, 00764 err, 00765 AttErrorResponse::UNLIKELY_ERROR 00766 }; 00767 00768 terminate(client, response); 00769 } 00770 } 00771 00772 void handle_error(GenericGattClient* client, const AttErrorResponse& error) { 00773 ble_error_t status = BLE_ERROR_UNSPECIFIED; 00774 00775 switch (error.error_code) { 00776 case AttErrorResponse::INVALID_HANDLE: 00777 status = BLE_ERROR_INVALID_PARAM; 00778 break; 00779 case AttErrorResponse::INVALID_ATTRIBUTE_VALUE_LENGTH: 00780 status = BLE_ERROR_INVALID_PARAM; 00781 break; 00782 case AttErrorResponse::INSUFFICIENT_AUTHORIZATION: 00783 status = BLE_ERROR_INVALID_STATE; 00784 break; 00785 case AttErrorResponse::INSUFFICIENT_AUTHENTICATION: 00786 status = BLE_ERROR_INVALID_STATE; 00787 break; 00788 case AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: 00789 status = BLE_ERROR_INVALID_STATE; 00790 break; 00791 case AttErrorResponse::INSUFFICIENT_ENCRYPTION: 00792 status = BLE_ERROR_INVALID_STATE; 00793 break; 00794 case AttErrorResponse::WRITE_NOT_PERMITTED: 00795 status = BLE_ERROR_OPERATION_NOT_PERMITTED; 00796 break; 00797 default: 00798 status = BLE_ERROR_UNSPECIFIED; 00799 break; 00800 } 00801 00802 if (error.request_opcode == AttributeOpcode(AttributeOpcode::PREPARE_WRITE_REQUEST)) { 00803 clear_prepare_queue(client, status, error.error_code); 00804 } else { 00805 GattWriteCallbackParams response = { 00806 connection_handle, 00807 attribute_handle, 00808 GattWriteCallbackParams::OP_WRITE_REQ, 00809 status, 00810 error.error_code 00811 }; 00812 00813 terminate(client, response); 00814 } 00815 } 00816 00817 uint16_t attribute_handle; 00818 uint16_t len; 00819 uint16_t offset; 00820 uint8_t* data; 00821 bool prepare_success; 00822 ble_error_t status; 00823 uint8_t error_code; 00824 }; 00825 00826 /* 00827 * Control block for the descriptor discovery process 00828 */ 00829 struct GenericGattClient::DescriptorDiscoveryControlBlock : public ProcedureControlBlock { 00830 DescriptorDiscoveryControlBlock( 00831 const DiscoveredCharacteristic& characteristic, 00832 const CharacteristicDescriptorDiscovery::DiscoveryCallback_t & discoveryCallback, 00833 const CharacteristicDescriptorDiscovery::TerminationCallback_t & terminationCallback 00834 ) : ProcedureControlBlock(DESCRIPTOR_DISCOVERY_PROCEDURE, characteristic.getConnectionHandle()), 00835 characteristic(characteristic), 00836 discovery_cb(discoveryCallback), 00837 termination_cb(terminationCallback), 00838 next_handle(characteristic.getValueHandle() + 1), 00839 done(false) { 00840 } 00841 00842 virtual ~DescriptorDiscoveryControlBlock() { } 00843 00844 ble_error_t start(GenericGattClient* client) { 00845 return client->_pal_client->discover_characteristics_descriptors( 00846 connection_handle, 00847 attribute_handle_range( 00848 next_handle, 00849 characteristic.getLastHandle() 00850 ) 00851 ); 00852 } 00853 00854 virtual void handle_timeout_error(GenericGattClient* client) { 00855 terminate(client, BLE_ERROR_UNSPECIFIED); 00856 } 00857 00858 virtual void abort(GenericGattClient *client) { 00859 terminate(client, BLE_ERROR_INVALID_STATE); 00860 } 00861 00862 virtual void handle(GenericGattClient* client, const AttServerMessage& message) { 00863 if (done) { 00864 terminate(client, BLE_ERROR_NONE); 00865 return; 00866 } 00867 00868 switch(message.opcode) { 00869 case AttributeOpcode::ERROR_RESPONSE: 00870 handle_error(client, static_cast<const AttErrorResponse&>(message)); 00871 return; 00872 00873 case AttributeOpcode::FIND_INFORMATION_RESPONSE: 00874 handle_response(client, static_cast<const AttFindInformationResponse&>(message)); 00875 return; 00876 00877 default: 00878 break; 00879 } 00880 } 00881 00882 void handle_error(GenericGattClient* client, const AttErrorResponse& error) { 00883 if (error.error_code == AttErrorResponse::ATTRIBUTE_NOT_FOUND) { 00884 terminate(client, BLE_ERROR_NONE); 00885 } else { 00886 terminate(client, BLE_ERROR_UNSPECIFIED, error.error_code); 00887 } 00888 } 00889 00890 void handle_response(GenericGattClient* client, const AttFindInformationResponse& response) { 00891 for (size_t i = 0; i < response.size(); ++i) { 00892 DiscoveredCharacteristicDescriptor descriptor( 00893 client, connection_handle, response[i].handle, response[i].uuid 00894 ); 00895 CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t params = { 00896 characteristic, 00897 descriptor 00898 }; 00899 discovery_cb(¶ms); 00900 if (done) { 00901 terminate(client, BLE_ERROR_NONE); 00902 return; 00903 } 00904 00905 if (response[i].handle == characteristic.getLastHandle()) { 00906 terminate(client, BLE_ERROR_NONE); 00907 return; 00908 } 00909 next_handle = response[i].handle + 1; 00910 } 00911 00912 ble_error_t err = start(client); 00913 if (err) { 00914 terminate(client, err, AttErrorResponse::UNLIKELY_ERROR); 00915 } 00916 } 00917 00918 void terminate(GenericGattClient* client, ble_error_t status, uint8_t error_code = 0x00) { 00919 client->remove_control_block(this); 00920 CharacteristicDescriptorDiscovery::TerminationCallbackParams_t params = { 00921 characteristic, 00922 status, 00923 error_code 00924 }; 00925 termination_cb(¶ms); 00926 delete this; 00927 } 00928 00929 DiscoveredCharacteristic characteristic; 00930 CharacteristicDescriptorDiscovery::DiscoveryCallback_t discovery_cb; 00931 CharacteristicDescriptorDiscovery::TerminationCallback_t termination_cb; 00932 uint16_t next_handle; 00933 bool done; 00934 }; 00935 00936 00937 GenericGattClient::GenericGattClient(pal::GattClient* pal_client) : 00938 _pal_client(pal_client), 00939 _termination_callback(), 00940 _signing_event_handler(NULL), 00941 control_blocks(NULL), 00942 _is_reseting(false) { 00943 _pal_client->when_server_message_received( 00944 mbed::callback(this, &GenericGattClient::on_server_message_received) 00945 ); 00946 _pal_client->when_transaction_timeout( 00947 mbed::callback(this, &GenericGattClient::on_transaction_timeout) 00948 ); 00949 } 00950 00951 ble_error_t GenericGattClient::launchServiceDiscovery ( 00952 Gap::Handle_t connection_handle, 00953 ServiceDiscovery::ServiceCallback_t service_callback, 00954 ServiceDiscovery::CharacteristicCallback_t characteristic_callback, 00955 const UUID& matching_service_uuid, 00956 const UUID& matching_characteristic_uuid 00957 ) { 00958 // verify that there is no other procedures going on this connection 00959 if (_is_reseting || get_control_block(connection_handle)) { 00960 return BLE_ERROR_INVALID_STATE; 00961 } 00962 00963 // terminate and return if there is no callback to call 00964 if (!service_callback && !characteristic_callback) { 00965 on_termination(connection_handle); 00966 return BLE_ERROR_NONE; 00967 } 00968 00969 DiscoveryControlBlock* discovery_pcb = new(std::nothrow) DiscoveryControlBlock( 00970 connection_handle, 00971 service_callback, 00972 characteristic_callback, 00973 matching_service_uuid, 00974 matching_characteristic_uuid 00975 ); 00976 00977 if (discovery_pcb == NULL) { 00978 return BLE_ERROR_NO_MEM; 00979 } 00980 00981 // note: control block inserted prior the request because they are part of 00982 // of the transaction and the callback can be call synchronously 00983 insert_control_block(discovery_pcb); 00984 00985 // launch the request 00986 ble_error_t err = BLE_ERROR_UNSPECIFIED; 00987 if (matching_service_uuid == UUID()) { 00988 err = _pal_client->discover_primary_service( 00989 connection_handle, 00990 0x0001 00991 ); 00992 } else { 00993 err = _pal_client->discover_primary_service_by_service_uuid( 00994 connection_handle, 00995 0x0001, 00996 matching_service_uuid 00997 ); 00998 } 00999 01000 if (err) { 01001 remove_control_block(discovery_pcb); 01002 delete discovery_pcb; 01003 } 01004 01005 return err; 01006 } 01007 01008 bool GenericGattClient::isServiceDiscoveryActive () const { 01009 ProcedureControlBlock* pcb = control_blocks; 01010 01011 while (pcb) { 01012 if (pcb->type == COMPLETE_DISCOVERY_PROCEDURE) { 01013 return true; 01014 } 01015 pcb = pcb->next; 01016 } 01017 01018 return false; 01019 } 01020 01021 void GenericGattClient::terminateServiceDiscovery () 01022 { 01023 ProcedureControlBlock* pcb = control_blocks; 01024 while (pcb) { 01025 if (pcb->type == COMPLETE_DISCOVERY_PROCEDURE) { 01026 static_cast<DiscoveryControlBlock*>(pcb)->done = true; 01027 } 01028 pcb = pcb->next; 01029 } 01030 } 01031 01032 ble_error_t GenericGattClient::read ( 01033 Gap::Handle_t connection_handle, 01034 GattAttribute::Handle_t attribute_handle, 01035 uint16_t offset) const 01036 { 01037 // verify that there is no other procedures going on this connection 01038 if (_is_reseting || get_control_block(connection_handle)) { 01039 return BLE_ERROR_INVALID_STATE; 01040 } 01041 01042 ReadControlBlock* read_pcb = new(std::nothrow) ReadControlBlock( 01043 connection_handle, 01044 attribute_handle, 01045 offset 01046 ); 01047 01048 if (read_pcb == NULL) { 01049 return BLE_ERROR_NO_MEM; 01050 } 01051 01052 insert_control_block(read_pcb); 01053 01054 ble_error_t err = BLE_ERROR_NONE; 01055 01056 if (offset == 0) { 01057 err = _pal_client->read_attribute_value( 01058 connection_handle, attribute_handle 01059 ); 01060 } else { 01061 err = _pal_client->read_attribute_blob( 01062 connection_handle, attribute_handle, offset 01063 ); 01064 } 01065 01066 if (err) { 01067 remove_control_block(read_pcb); 01068 delete read_pcb; 01069 } 01070 01071 return err; 01072 } 01073 01074 ble_error_t GenericGattClient::write ( 01075 GattClient::WriteOp_t cmd, 01076 Gap::Handle_t connection_handle, 01077 GattAttribute::Handle_t attribute_handle, 01078 size_t length, 01079 const uint8_t* value 01080 ) const { 01081 // verify that there is no other procedures going on this connection 01082 if (_is_reseting || get_control_block(connection_handle)) { 01083 return BLE_ERROR_INVALID_STATE; 01084 } 01085 01086 uint16_t mtu = get_mtu(connection_handle); 01087 01088 /* if link is encrypted signed writes should be normal writes */ 01089 if (cmd == GattClient::GATT_OP_SIGNED_WRITE_CMD) { 01090 ble::link_encryption_t encryption(ble::link_encryption_t::NOT_ENCRYPTED); 01091 SecurityManager &sm = createBLEInstance()->getSecurityManager(); 01092 ble_error_t status = sm.getLinkEncryption(connection_handle, &encryption); 01093 if (status == BLE_ERROR_NONE && 01094 (encryption == link_encryption_t::ENCRYPTED || 01095 encryption == link_encryption_t::ENCRYPTED_WITH_MITM || 01096 encryption == link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM) 01097 ) { 01098 cmd = GattClient::GATT_OP_WRITE_CMD; 01099 } 01100 } 01101 01102 if (cmd == GattClient::GATT_OP_WRITE_CMD) { 01103 if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH)) { 01104 return BLE_ERROR_PARAM_OUT_OF_RANGE; 01105 } 01106 return _pal_client->write_without_response( 01107 connection_handle, 01108 attribute_handle, 01109 make_const_ArrayView(value, length) 01110 ); 01111 } else if (cmd == GattClient::GATT_OP_SIGNED_WRITE_CMD) { 01112 if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH - CMAC_LENGTH - MAC_COUNTER_LENGTH)) { 01113 return BLE_ERROR_PARAM_OUT_OF_RANGE; 01114 } 01115 ble_error_t status = _pal_client->signed_write_without_response( 01116 connection_handle, 01117 attribute_handle, 01118 make_const_ArrayView(value, length) 01119 ); 01120 if (_signing_event_handler && (status == BLE_ERROR_NONE)) { 01121 _signing_event_handler->on_signed_write(); 01122 } 01123 return status; 01124 } else { 01125 uint8_t* data = NULL; 01126 01127 if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH)) { 01128 data = (uint8_t*) malloc(length); 01129 if (data == NULL) { 01130 return BLE_ERROR_NO_MEM; 01131 } 01132 memcpy(data, value, length); 01133 } 01134 01135 WriteControlBlock* write_pcb = new (std::nothrow) WriteControlBlock( 01136 connection_handle, 01137 attribute_handle, 01138 data, 01139 length 01140 ); 01141 01142 if (write_pcb == NULL) { 01143 free(data); 01144 return BLE_ERROR_NO_MEM; 01145 } 01146 01147 insert_control_block(write_pcb); 01148 01149 ble_error_t err = BLE_ERROR_UNSPECIFIED; 01150 if (data) { 01151 err = _pal_client->queue_prepare_write( 01152 connection_handle, 01153 attribute_handle, 01154 make_const_ArrayView(value, mtu - PREPARE_WRITE_HEADER_LENGTH), 01155 /* offset */0 01156 ); 01157 } else { 01158 err = _pal_client->write_attribute( 01159 connection_handle, 01160 attribute_handle, 01161 make_const_ArrayView(value, length) 01162 ); 01163 } 01164 01165 if (err) { 01166 remove_control_block(write_pcb); 01167 delete write_pcb; 01168 } 01169 01170 return err; 01171 } 01172 01173 return BLE_ERROR_NOT_IMPLEMENTED; 01174 } 01175 01176 void GenericGattClient::onServiceDiscoveryTermination ( 01177 ServiceDiscovery::TerminationCallback_t callback 01178 ) { 01179 _termination_callback = callback; 01180 } 01181 01182 ble_error_t GenericGattClient::discoverCharacteristicDescriptors ( 01183 const DiscoveredCharacteristic& characteristic, 01184 const CharacteristicDescriptorDiscovery::DiscoveryCallback_t & discoveryCallback, 01185 const CharacteristicDescriptorDiscovery::TerminationCallback_t & terminationCallback 01186 ) { 01187 // verify that there is no other procedures going on this connection 01188 if (_is_reseting || get_control_block(characteristic.getConnectionHandle())) { 01189 return BLE_ERROR_INVALID_STATE; 01190 } 01191 01192 if (characteristic.getValueHandle() == characteristic.getLastHandle()) { 01193 CharacteristicDescriptorDiscovery::TerminationCallbackParams_t params = { 01194 characteristic, 01195 BLE_ERROR_NONE, 01196 /* error code */ 0x00 01197 }; 01198 01199 terminationCallback(¶ms); 01200 return BLE_ERROR_NONE; 01201 } 01202 01203 DescriptorDiscoveryControlBlock* discovery_pcb = 01204 new(std::nothrow) DescriptorDiscoveryControlBlock( 01205 characteristic, 01206 discoveryCallback, 01207 terminationCallback 01208 ); 01209 01210 if (discovery_pcb == NULL) { 01211 return BLE_ERROR_NO_MEM; 01212 } 01213 01214 insert_control_block(discovery_pcb); 01215 01216 ble_error_t err = discovery_pcb->start(this); 01217 01218 if (err) { 01219 remove_control_block(discovery_pcb); 01220 delete discovery_pcb; 01221 } 01222 01223 return err; 01224 } 01225 01226 bool GenericGattClient::isCharacteristicDescriptorDiscoveryActive ( 01227 const DiscoveredCharacteristic& characteristic 01228 ) const { 01229 ProcedureControlBlock* pcb = control_blocks; 01230 01231 while (pcb) { 01232 if (pcb->type == DESCRIPTOR_DISCOVERY_PROCEDURE && 01233 static_cast<DescriptorDiscoveryControlBlock*>(pcb)->characteristic == characteristic) { 01234 return true; 01235 } 01236 pcb = pcb->next; 01237 } 01238 01239 return false; 01240 } 01241 01242 void GenericGattClient::terminateCharacteristicDescriptorDiscovery ( 01243 const DiscoveredCharacteristic& characteristic 01244 ) { 01245 ProcedureControlBlock* pcb = control_blocks; 01246 01247 while (pcb) { 01248 if (pcb->type == DESCRIPTOR_DISCOVERY_PROCEDURE) { 01249 DescriptorDiscoveryControlBlock* dpcb = 01250 static_cast<DescriptorDiscoveryControlBlock*>(pcb); 01251 if (dpcb->characteristic == characteristic) { 01252 dpcb->done = true; 01253 return; 01254 } 01255 } 01256 01257 pcb = pcb->next; 01258 } 01259 01260 } 01261 01262 ble_error_t GenericGattClient::reset (void) { 01263 01264 // _is_reseting prevent executions of new procedure while the instance resets. 01265 // otherwise new procedures can be launched from callbacks generated by the 01266 // reset. 01267 _is_reseting = true; 01268 while (control_blocks) { 01269 control_blocks->abort(this); 01270 } 01271 _is_reseting = false; 01272 01273 return BLE_ERROR_NONE; 01274 } 01275 01276 void GenericGattClient::set_signing_event_handler ( 01277 EventHandler *signing_event_handler 01278 ) { 01279 _signing_event_handler = signing_event_handler; 01280 } 01281 01282 void GenericGattClient::on_termination(Gap::Handle_t connection_handle) { 01283 if (_termination_callback) { 01284 _termination_callback(connection_handle); 01285 } 01286 } 01287 01288 void GenericGattClient::on_server_message_received( 01289 connection_handle_t connection_handle, 01290 const AttServerMessage& message 01291 ) { 01292 switch(message.opcode) { 01293 case AttributeOpcode::ERROR_RESPONSE: 01294 case AttributeOpcode::EXCHANGE_MTU_RESPONSE: 01295 case AttributeOpcode::FIND_INFORMATION_RESPONSE: 01296 case AttributeOpcode::FIND_BY_VALUE_TYPE_RESPONSE: 01297 case AttributeOpcode::READ_BY_TYPE_RESPONSE: 01298 case AttributeOpcode::READ_RESPONSE: 01299 case AttributeOpcode::READ_BLOB_RESPONSE: 01300 case AttributeOpcode::READ_MULTIPLE_RESPONSE: 01301 case AttributeOpcode::READ_BY_GROUP_TYPE_RESPONSE: 01302 case AttributeOpcode::WRITE_RESPONSE: 01303 case AttributeOpcode::PREPARE_WRITE_RESPONSE: 01304 case AttributeOpcode::EXECUTE_WRITE_RESPONSE: { 01305 on_server_response(connection_handle, message); 01306 } break; 01307 01308 case AttributeOpcode::HANDLE_VALUE_INDICATION: 01309 case AttributeOpcode::HANDLE_VALUE_NOTIFICATION: { 01310 on_server_event(connection_handle, message); 01311 } break; 01312 01313 default: 01314 // invalid message receive 01315 return; 01316 } 01317 } 01318 01319 void GenericGattClient::on_server_response( 01320 connection_handle_t connection, 01321 const AttServerMessage& message 01322 ) { 01323 ProcedureControlBlock* pcb = get_control_block(connection); 01324 if (pcb == NULL) { 01325 return; 01326 } 01327 01328 pcb->handle(this, message); 01329 } 01330 01331 void GenericGattClient::on_server_event(connection_handle_t connection, const AttServerMessage& message) { 01332 GattHVXCallbackParams callbacks_params = { 01333 (Gap::Handle_t) connection, 0 01334 }; 01335 01336 switch (message.opcode) { 01337 case AttributeOpcode::HANDLE_VALUE_NOTIFICATION: { 01338 const AttHandleValueNotification& notification = 01339 static_cast<const AttHandleValueNotification&>(message); 01340 callbacks_params.handle = notification.attribute_handle; 01341 callbacks_params.type = BLE_HVX_NOTIFICATION; 01342 callbacks_params.len = notification.attribute_value.size(); 01343 callbacks_params.data = notification.attribute_value.data(); 01344 } break; 01345 01346 case AttributeOpcode::HANDLE_VALUE_INDICATION: { 01347 const AttHandleValueIndication& indication = 01348 static_cast<const AttHandleValueIndication&>(message); 01349 callbacks_params.handle = indication.attribute_handle; 01350 callbacks_params.type = BLE_HVX_INDICATION; 01351 callbacks_params.len = indication.attribute_value.size(); 01352 callbacks_params.data = indication.attribute_value.data(); 01353 } break; 01354 01355 default: 01356 return; 01357 } 01358 01359 processHVXEvent(&callbacks_params); 01360 } 01361 01362 void GenericGattClient::on_transaction_timeout(connection_handle_t connection) { 01363 ProcedureControlBlock* pcb = get_control_block(connection); 01364 if (pcb == NULL) { 01365 return; 01366 } 01367 01368 pcb->handle_timeout_error(this); 01369 } 01370 01371 GenericGattClient::ProcedureControlBlock* GenericGattClient::get_control_block(Gap::Handle_t connection) { 01372 ProcedureControlBlock* it = control_blocks; 01373 while (it && it->connection_handle != connection) { 01374 it = it->next; 01375 } 01376 return it; 01377 } 01378 01379 const GenericGattClient::ProcedureControlBlock* GenericGattClient::get_control_block(Gap::Handle_t connection) const { 01380 ProcedureControlBlock* it = control_blocks; 01381 while (it && it->connection_handle != connection) { 01382 it = it->next; 01383 } 01384 return it; 01385 } 01386 01387 void GenericGattClient::insert_control_block(ProcedureControlBlock* cb) const { 01388 if (control_blocks == NULL) { 01389 control_blocks = cb; 01390 return; 01391 } 01392 01393 ProcedureControlBlock* current = control_blocks; 01394 while (current->next) { 01395 current = current->next; 01396 } 01397 current->next = cb; 01398 } 01399 01400 void GenericGattClient::remove_control_block(ProcedureControlBlock* cb) const { 01401 if (control_blocks == NULL) { 01402 return; 01403 } 01404 01405 if (cb == control_blocks) { 01406 control_blocks = control_blocks->next; 01407 return; 01408 } 01409 01410 ProcedureControlBlock* current = control_blocks; 01411 while (current->next && current->next != cb) { 01412 current = current->next; 01413 } 01414 01415 if (current->next == NULL) { 01416 return; 01417 } 01418 01419 current->next = cb->next; 01420 cb->next = NULL; 01421 } 01422 01423 uint16_t GenericGattClient::get_mtu(Gap::Handle_t connection) const { 01424 uint16_t result = 23; 01425 if(_pal_client->get_mtu_size((connection_handle_t) connection, result) != BLE_ERROR_NONE) { 01426 result = 23; 01427 } 01428 return result; 01429 } 01430 01431 } // namespace pal 01432 } // namespace ble
Generated on Tue Jul 12 2022 15:15:46 by
