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.
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 Aug 9 2022 00:37:08 by
