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