Marco Zecchini
/
Example_RTOS
Rtos API example
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 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 Sun Jul 17 2022 08:25:23 by 1.7.2