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