takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GenericGattClient.cpp Source File

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