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