init
Embed:
(wiki syntax)
Show/hide line numbers
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 13:24:43 by
1.7.2