Rtos API example

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