Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

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