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