Exemplo n.º 1
0
/**@brief     Function for handling service discovery completion.
 *
 * @details   This function will be used to determine if there are more services to be discovered,
 *            and if so, initiate the discovery of the next service.
 *
 * @param[in] p_db_discovery Pointer to the DB Discovery Structure.
 * @param[in] conn_handle    Connection Handle.
 */
static void on_srv_disc_completion(ble_db_discovery_t * p_db_discovery,
                                   uint16_t const       conn_handle)
{
    p_db_discovery->discoveries_count++;

    // Check if more services need to be discovered.
    if (p_db_discovery->discoveries_count < m_num_of_handlers_reg)
    {
        // Reset the current characteristic index since a new service discovery is about to start.
        p_db_discovery->curr_char_ind = 0;

        // Initiate discovery of the next service.
        p_db_discovery->curr_srv_ind++;

        ble_gatt_db_srv_t * p_srv_being_discovered;

        p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);

        p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind];

        // Reset the characteristic count in the current service to zero since a new service
        // discovery is about to start.
        p_srv_being_discovered->char_count = 0;

        NRF_LOG_INFO("Starting discovery of service with UUID 0x%x for Connection handle %d\r\n",
               p_srv_being_discovered->srv_uuid.uuid, conn_handle);

        uint32_t err_code;

        err_code = sd_ble_gattc_primary_services_discover
                   (
                   conn_handle,
                   SRV_DISC_START_HANDLE,
                   &(p_srv_being_discovered->srv_uuid)
                   );
        if (err_code != NRF_SUCCESS)
        {
            p_db_discovery->discovery_in_progress = false;

            // Error with discovering the service.
            // Indicate the error to the registered user application.
            discovery_error_evt_trigger(p_db_discovery, err_code, conn_handle);

            m_pending_user_evts[0].evt.evt_type    = BLE_DB_DISCOVERY_AVAILABLE;
            m_pending_user_evts[0].evt.conn_handle = conn_handle;
//            m_evt_handler(&m_pending_user_evts[0].evt);

            return;
        }
    }
    else
    {
        // No more service discovery is needed.
        p_db_discovery->discovery_in_progress  = false;
        m_pending_user_evts[0].evt.evt_type    = BLE_DB_DISCOVERY_AVAILABLE;
        m_pending_user_evts[0].evt.conn_handle = conn_handle;
        //m_evt_handler(&m_pending_user_evts[0].evt);
    }
}
Exemplo n.º 2
0
//Handle discovery is not currently used and should not be used during the discovery
//phase because it adds additional packets and time to the handshake. It is better
//To use the mesh write handle that is broadcasted in the join_me packet and
//is sent with the initial cluster_welcome packet
void GATTController::bleDiscoverHandles(u16 connectionHandle)
{
	u32 err = 0;

	//At first we need to enumerate the services
	err = sd_ble_gattc_primary_services_discover(connectionHandle, 0x0001, &meshService.serviceUuid);
	APP_ERROR_CHECK(err); //Currently Unhandeled
}
Exemplo n.º 3
0
/**@brief Function for handling the Connect event.
 *
 * @param[in]   p_ias_c     Immediate Alert Service client structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static uint32_t on_connect(ble_ias_c_t * p_ias_c, ble_evt_t const * p_ble_evt)
{
    ble_uuid_t ias_uuid;

    p_ias_c->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

    // Discover Immediate alert service
    BLE_UUID_BLE_ASSIGN(ias_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);

    return sd_ble_gattc_primary_services_discover(p_ias_c->conn_handle, START_HANDLE, &ias_uuid);
}
uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery,
                                uint16_t                   conn_handle)
{
    if (p_db_discovery == NULL)
    {
        return NRF_ERROR_NULL;
    }

    if (!m_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    if (m_num_of_handlers_reg == 0)
    {
        // No user modules were registered. There are no services to discover.
        return NRF_ERROR_INVALID_STATE;
    }

    if (p_db_discovery->discovery_in_progress)
    {
        return NRF_ERROR_BUSY;
    }

    ble_db_discovery_srv_t * p_srv_being_discovered;

    m_num_of_discoveries_made = 0;
    m_pending_usr_evt_index   = 0;

    p_db_discovery->curr_srv_ind = 0;
    p_db_discovery->conn_handle  = conn_handle;

    p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);

    p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind].srv_uuid;
    
    DB_LOG("[DB]: Starting discovery of service with UUID 0x%x for Connection handle %d\r\n",
           p_srv_being_discovered->srv_uuid.uuid, p_db_discovery->conn_handle);
    
    uint32_t err_code;

    err_code = sd_ble_gattc_primary_services_discover(p_db_discovery->conn_handle,
                                                      SRV_DISC_START_HANDLE,
                                                      &(p_srv_being_discovered->srv_uuid));
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
    p_db_discovery->discovery_in_progress = true;

    return NRF_SUCCESS;
}
/**@brief     Function for handling service discovery completion.
 *
 * @details   This function will be used to determine if there are more services to be discovered,
 *            and if so, initiate the discovery of the next service.
 *
 * @param[in] p_db_discovery Pointer to the DB Discovery Structure.
 */
static void on_srv_disc_completion(ble_db_discovery_t * p_db_discovery)
{
    m_num_of_discoveries_made++;

    // Check if more services need to be discovered.
    if (m_num_of_discoveries_made < m_num_of_handlers_reg)
    {
        // Reset the current characteristic index since a new service discovery is about to start.
        p_db_discovery->curr_char_ind = 0;

        // Initiate discovery of the next service.
        p_db_discovery->curr_srv_ind++;

        ble_db_discovery_srv_t * p_srv_being_discovered;

        p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);

        p_srv_being_discovered->srv_uuid =
            m_registered_handlers[p_db_discovery->curr_srv_ind].srv_uuid;

        // Reset the characteristic count in the current service to zero since a new service
        // discovery is about to start.
        p_srv_being_discovered->char_count = 0;

        DB_LOG("[DB]: Starting discovery of service with UUID 0x%x for Connection handle %d\r\n",
               p_srv_being_discovered->srv_uuid.uuid, p_db_discovery->conn_handle);

        uint32_t err_code;

        err_code = sd_ble_gattc_primary_services_discover
                   (
                   p_db_discovery->conn_handle,
                   SRV_DISC_START_HANDLE,
                   &(p_srv_being_discovered->srv_uuid)
                   );
        if (err_code != NRF_SUCCESS)
        {
            p_db_discovery->discovery_in_progress = false;

            // Error with discovering the service.
            // Indicate the error to the registered user application.
            discovery_error_evt_trigger(p_db_discovery, err_code);

            return;
        }
    }
    else
    {
        // No more service discovery is needed.
        p_db_discovery->discovery_in_progress = false;
    }
}
Exemplo n.º 6
0
uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery,
                                uint16_t                   conn_handle)
{
    VERIFY_PARAM_NOT_NULL(p_db_discovery);
    VERIFY_MODULE_INITIALIZED();

    if (m_num_of_handlers_reg == 0)
    {
        // No user modules were registered. There are no services to discover.
        return NRF_ERROR_INVALID_STATE;
    }

    if (p_db_discovery->discovery_in_progress)
    {
        return NRF_ERROR_BUSY;
    }

    p_db_discovery->conn_handle = conn_handle;
    ble_gatt_db_srv_t * p_srv_being_discovered;

    m_pending_usr_evt_index   = 0;

    p_db_discovery->discoveries_count = 0;
    p_db_discovery->curr_srv_ind      = 0;
    p_db_discovery->curr_char_ind     = 0;

    p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);

    p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind];

    NRF_LOG_INFO("Starting discovery of service with UUID 0x%x for Connection handle %d\r\n",
           p_srv_being_discovered->srv_uuid.uuid, conn_handle);

    uint32_t err_code;

    err_code = sd_ble_gattc_primary_services_discover(conn_handle,
                                                      SRV_DISC_START_HANDLE,
                                                      &(p_srv_being_discovered->srv_uuid));
    VERIFY_SUCCESS(err_code);
    p_db_discovery->discovery_in_progress = true;

    return NRF_SUCCESS;
}
Exemplo n.º 7
0
/**@brief Function for executing the Service Discovery Procedure.
 */
static void service_disc_req_send(const ble_ans_c_t * p_ans)
{
    uint16_t   handle = START_HANDLE_DISCOVER;
    ble_uuid_t ans_uuid;
    uint32_t   err_code;

    // Discover services on uuid Alert Notification.
    BLE_UUID_BLE_ASSIGN(ans_uuid, BLE_UUID_ALERT_NOTIFICATION_SERVICE);

    err_code = sd_ble_gattc_primary_services_discover(p_ans->conn_handle, handle, &ans_uuid);
    if (err_code != NRF_SUCCESS)
    {
        handle_discovery_failure(p_ans, err_code);
    }
    else
    {
        m_client_state = STATE_DISC_SERV;
    }
}
Exemplo n.º 8
0
/**@brief Function for executing the Service Discovery Procedure.
 */
static void service_disc_req_send(const ble_ancs_c_t * p_ancs)
{
    uint16_t   handle = START_HANDLE_DISCOVER;
    ble_uuid_t ancs_uuid;
    uint32_t   err_code;

    // Discover services on uuid for ANCS.
    BLE_UUID_BLE_ASSIGN(ancs_uuid, BLE_UUID_APPLE_NOTIFICATION_CENTER_SERVICE);
    ancs_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN;

    err_code = sd_ble_gattc_primary_services_discover(p_ancs->conn_handle, handle, &ancs_uuid);
    if (err_code != NRF_SUCCESS)
    {
        handle_discovery_failure(p_ancs, err_code);
    }
    else
    {
        m_client_state = STATE_DISC_SERV;
    }
}
Exemplo n.º 9
0
uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery,
                                uint16_t                   conn_handle)
{
    if (p_db_discovery == NULL)
    {
        return NRF_ERROR_NULL;
    }

    if (!m_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    p_db_discovery->srv_being_discovered.srv_uuid = m_srv_uuid;
    p_db_discovery->conn_handle                   = conn_handle;
    
    DB_LOG("[DB]: Starting service discovery\r\n");
    
    return sd_ble_gattc_primary_services_discover(p_db_discovery->conn_handle,
                                                  SRV_DISC_START_HANDLE,
                                                  &m_srv_uuid);
}
Exemplo n.º 10
0
void nRF51822::poll() {
  uint32_t   evtBuf[BLE_STACK_EVT_MSG_BUF_SIZE] __attribute__ ((__aligned__(BLE_EVTS_PTR_ALIGNMENT)));
  uint16_t   evtLen = sizeof(evtBuf);
  ble_evt_t* bleEvt = (ble_evt_t*)evtBuf;

  if (sd_ble_evt_get((uint8_t*)evtBuf, &evtLen) == NRF_SUCCESS) {
    switch (bleEvt->header.evt_id) {
      case BLE_EVT_TX_COMPLETE:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt TX complete "));
        Serial.println(bleEvt->evt.common_evt.params.tx_complete.count);
#endif
        this->_txBufferCount++;
        break;

      case BLE_GAP_EVT_CONNECTED:
#ifdef NRF_51822_DEBUG
        char address[18];

        BLEUtil::addressToString(bleEvt->evt.gap_evt.params.connected.peer_addr.addr, address);

        Serial.print(F("Evt Connected "));
        Serial.println(address);
#endif

        this->_connectionHandle = bleEvt->evt.gap_evt.conn_handle;

        sd_ble_tx_buffer_count_get(&this->_txBufferCount);

        if (this->_eventListener) {
          this->_eventListener->BLEDeviceConnected(*this, bleEvt->evt.gap_evt.params.connected.peer_addr.addr);
        }

        if (this->_minimumConnectionInterval >= BLE_GAP_CP_MIN_CONN_INTVL_MIN &&
            this->_maximumConnectionInterval <= BLE_GAP_CP_MAX_CONN_INTVL_MAX) {
          ble_gap_conn_params_t gap_conn_params;

          gap_conn_params.min_conn_interval = this->_minimumConnectionInterval;  // in 1.25ms units
          gap_conn_params.max_conn_interval = this->_maximumConnectionInterval;  // in 1.25ms unit
          gap_conn_params.slave_latency     = 0;
          gap_conn_params.conn_sup_timeout  = 4000 / 10; // in 10ms unit

          sd_ble_gap_conn_param_update(this->_connectionHandle, &gap_conn_params);
        }

        if (this->_numRemoteServices > 0) {
          sd_ble_gattc_primary_services_discover(this->_connectionHandle, 1, NULL);
        }
        break;

      case BLE_GAP_EVT_DISCONNECTED:
#ifdef NRF_51822_DEBUG
        Serial.println(F("Evt Disconnected"));
#endif
        this->_connectionHandle = BLE_CONN_HANDLE_INVALID;
        this->_txBufferCount = 0;

        for (int i = 0; i < this->_numLocalCharacteristics; i++) {
          struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i];

          localCharacteristicInfo->notifySubscribed = false;
          localCharacteristicInfo->indicateSubscribed = false;

          if (localCharacteristicInfo->characteristic->subscribed()) {
            if (this->_eventListener) {
              this->_eventListener->BLEDeviceCharacteristicSubscribedChanged(*this, *localCharacteristicInfo->characteristic, false);
            }
          }
        }

        if (this->_eventListener) {
          this->_eventListener->BLEDeviceDisconnected(*this);
        }

        // clear remote handle info
        for (int i = 0; i < this->_numRemoteServices; i++) {
          memset(&this->_remoteServiceInfo[i].handlesRange, 0, sizeof(this->_remoteServiceInfo[i].handlesRange));
        }

        for (int i = 0; i < this->_numRemoteCharacteristics; i++) {
          memset(&this->_remoteCharacteristicInfo[i].properties, 0, sizeof(this->_remoteCharacteristicInfo[i].properties));
          this->_remoteCharacteristicInfo[i].valueHandle = 0;
        }

        this->_remoteRequestInProgress = false;

        this->startAdvertising();
        break;

      case BLE_GAP_EVT_CONN_PARAM_UPDATE:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Conn Param Update 0x"));
        Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval, HEX);
        Serial.print(F(" 0x"));
        Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval, HEX);
        Serial.print(F(" 0x"));
        Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.slave_latency, HEX);
        Serial.print(F(" 0x"));
        Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.conn_sup_timeout, HEX);
        Serial.println();
#endif
        break;

      case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Sec Params Request "));
#ifndef NRF51_S130
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.timeout);
        Serial.print(F(" "));
#endif
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.bond);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.mitm);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.io_caps);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.oob);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.min_key_size);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.max_key_size);
        Serial.println();
#endif

        if (this->_bondStore && !this->_bondStore->hasData()) {
          // only allow bonding if bond store exists and there is no data

          ble_gap_sec_params_t gapSecParams;

#ifdef NRF51_S130
          gapSecParams.kdist_periph.enc = 1;
#else
          gapSecParams.timeout          = 30; // must be 30s
#endif
          gapSecParams.bond             = true;
          gapSecParams.mitm             = false;
          gapSecParams.io_caps          = BLE_GAP_IO_CAPS_NONE;
          gapSecParams.oob              = false;
          gapSecParams.min_key_size     = 7;
          gapSecParams.max_key_size     = 16;

#ifdef NRF51_S130
          ble_gap_sec_keyset_t keyset;

          keyset.keys_central.p_enc_key  = NULL;
          keyset.keys_central.p_id_key   = NULL;
          keyset.keys_central.p_sign_key = NULL;
          keyset.keys_periph.p_enc_key   = this->_encKey;
          keyset.keys_periph.p_id_key    = NULL;
          keyset.keys_periph.p_sign_key  = NULL;

          sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_SUCCESS, &gapSecParams, &keyset);
#else
          sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_SUCCESS, &gapSecParams);
#endif
        } else {
#ifdef NRF51_S130
          sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
#else
          sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL);
#endif
        }
        break;

      case BLE_GAP_EVT_SEC_INFO_REQUEST:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Sec Info Request "));
        // Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.peer_addr);
        // Serial.print(F(" "));
#ifdef NRF51_S130
        Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.master_id.ediv);
#else
        Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.div);
#endif
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.enc_info);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.id_info);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.sign_info);
        Serial.println();
#endif
#ifdef NRF51_S130
        if (this->_encKey->master_id.ediv == bleEvt->evt.gap_evt.params.sec_info_request.master_id.ediv) {
          sd_ble_gap_sec_info_reply(this->_connectionHandle, &this->_encKey->enc_info, NULL, NULL);
        } else {
          sd_ble_gap_sec_info_reply(this->_connectionHandle, NULL, NULL, NULL);
        }
#else
        if (this->_authStatus->periph_keys.enc_info.div == bleEvt->evt.gap_evt.params.sec_info_request.div) {
          sd_ble_gap_sec_info_reply(this->_connectionHandle, &this->_authStatus->periph_keys.enc_info, NULL);
        } else {
          sd_ble_gap_sec_info_reply(this->_connectionHandle, NULL, NULL);
        }
#endif
        break;

      case BLE_GAP_EVT_AUTH_STATUS:
#ifdef NRF_51822_DEBUG
        Serial.println(F("Evt Auth Status"));
        Serial.println(bleEvt->evt.gap_evt.params.auth_status.auth_status);
#endif
        if (BLE_GAP_SEC_STATUS_SUCCESS == bleEvt->evt.gap_evt.params.auth_status.auth_status) {
#ifndef NRF51_S130
          *this->_authStatus = bleEvt->evt.gap_evt.params.auth_status;
#endif
          if (this->_bondStore) {
#ifdef NRF_51822_DEBUG
            Serial.println(F("Storing bond data"));
#endif
#ifdef NRF51_S130
            this->_bondStore->putData(this->_bondData, 0, sizeof(this->_bondData));
#else
            this->_bondStore->putData(this->_authStatusBuffer, 0, sizeof(this->_authStatusBuffer));
#endif
          }

          if (this->_eventListener) {
            this->_eventListener->BLEDeviceBonded(*this);
          }
        }
        break;

      case BLE_GAP_EVT_CONN_SEC_UPDATE:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Conn Sec Update "));
        Serial.print(bleEvt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.sm);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv);
        Serial.print(F(" "));
        Serial.print(bleEvt->evt.gap_evt.params.conn_sec_update.conn_sec.encr_key_size);
        Serial.println();
#endif
        break;

      case BLE_GATTS_EVT_WRITE: {
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Write, handle = "));
        Serial.println(bleEvt->evt.gatts_evt.params.write.handle, DEC);

        BLEUtil::printBuffer(bleEvt->evt.gatts_evt.params.write.data, bleEvt->evt.gatts_evt.params.write.len);
#endif

        uint16_t handle = bleEvt->evt.gatts_evt.params.write.handle;

        for (int i = 0; i < this->_numLocalCharacteristics; i++) {
          struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i];

          if (localCharacteristicInfo->handles.value_handle == handle) {
            if (this->_eventListener) {
              this->_eventListener->BLEDeviceCharacteristicValueChanged(*this, *localCharacteristicInfo->characteristic, bleEvt->evt.gatts_evt.params.write.data, bleEvt->evt.gatts_evt.params.write.len);
            }
            break;
          } else if (localCharacteristicInfo->handles.cccd_handle == handle) {
            uint16_t value = bleEvt->evt.gatts_evt.params.write.data[0] | (bleEvt->evt.gatts_evt.params.write.data[1] << 8);

            localCharacteristicInfo->notifySubscribed = (value & 0x0001);
            localCharacteristicInfo->indicateSubscribed = (value & 0x0002);

            bool subscribed = (localCharacteristicInfo->notifySubscribed || localCharacteristicInfo->indicateSubscribed);

            if (subscribed != localCharacteristicInfo->characteristic->subscribed()) {
              if (this->_eventListener) {
                this->_eventListener->BLEDeviceCharacteristicSubscribedChanged(*this, *localCharacteristicInfo->characteristic, subscribed);
              }
              break;
            }
          }
        }
        break;
      }

      case BLE_GATTS_EVT_SYS_ATTR_MISSING:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Sys Attr Missing "));
        Serial.println(bleEvt->evt.gatts_evt.params.sys_attr_missing.hint);
#endif
#ifdef NRF51_S130
        sd_ble_gatts_sys_attr_set(this->_connectionHandle, NULL, 0, 0);
#else
        sd_ble_gatts_sys_attr_set(this->_connectionHandle, NULL, 0);
#endif
        break;

      case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Prim Srvc Disc Rsp 0x"));
        Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX);
#endif
        if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS) {
          uint16_t count = bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.count;
          for (int i = 0; i < count; i++) {
            for (int j = 0; j < this->_numRemoteServices; j++) {
              if ((bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i].uuid.type == this->_remoteServiceInfo[j].uuid.type) &&
                  (bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i].uuid.uuid == this->_remoteServiceInfo[j].uuid.uuid)) {
                this->_remoteServiceInfo[j].handlesRange = bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i].handle_range;
                break;
              }
            }
          }

          uint16_t startHandle = bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[count - 1].handle_range.end_handle + 1;

          sd_ble_gattc_primary_services_discover(this->_connectionHandle, startHandle, NULL);
        } else {
          // done discovering services
          for (int i = 0; i < this->_numRemoteServices; i++) {
            if (this->_remoteServiceInfo[i].handlesRange.start_handle != 0 && this->_remoteServiceInfo[i].handlesRange.end_handle != 0) {
              this->_remoteServiceDiscoveryIndex = i;

              sd_ble_gattc_characteristics_discover(this->_connectionHandle, &this->_remoteServiceInfo[i].handlesRange);
              break;
            }
          }
        }
        break;

      case BLE_GATTC_EVT_CHAR_DISC_RSP:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Char Disc Rsp 0x"));
        Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX);
#endif
        if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS) {
          ble_gattc_handle_range_t serviceHandlesRange = this->_remoteServiceInfo[this->_remoteServiceDiscoveryIndex].handlesRange;

          uint16_t count = bleEvt->evt.gattc_evt.params.char_disc_rsp.count;

          for (int i = 0; i < count; i++) {
            for (int j = 0; j < this->_numRemoteCharacteristics; j++) {
              if ((this->_remoteServiceInfo[this->_remoteServiceDiscoveryIndex].service == this->_remoteCharacteristicInfo[j].service) &&
                  (bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].uuid.type == this->_remoteCharacteristicInfo[j].uuid.type) &&
                  (bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].uuid.uuid == this->_remoteCharacteristicInfo[j].uuid.uuid)) {
                this->_remoteCharacteristicInfo[j].properties = bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].char_props;
                this->_remoteCharacteristicInfo[j].valueHandle = bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].handle_value;
              }
            }

            serviceHandlesRange.start_handle = bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].handle_value;
          }

          sd_ble_gattc_characteristics_discover(this->_connectionHandle, &serviceHandlesRange);
        } else {
          bool discoverCharacteristics = false;

          for (int i = this->_remoteServiceDiscoveryIndex + 1; i < this->_numRemoteServices; i++) {
            if (this->_remoteServiceInfo[i].handlesRange.start_handle != 0 && this->_remoteServiceInfo[i].handlesRange.end_handle != 0) {
              this->_remoteServiceDiscoveryIndex = i;

              sd_ble_gattc_characteristics_discover(this->_connectionHandle, &this->_remoteServiceInfo[i].handlesRange);
              discoverCharacteristics = true;
              break;
            }
          }

          if (!discoverCharacteristics) {
            if (this->_eventListener) {
              this->_eventListener->BLEDeviceRemoteServicesDiscovered(*this);
            }
          }
        }
        break;

      case BLE_GATTC_EVT_READ_RSP: {
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Read Rsp 0x"));
        Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX);
        Serial.println(bleEvt->evt.gattc_evt.params.read_rsp.handle, DEC);
        BLEUtil::printBuffer(bleEvt->evt.gattc_evt.params.read_rsp.data, bleEvt->evt.gattc_evt.params.read_rsp.len);
#endif
        this->_remoteRequestInProgress = false;

        if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION &&
            this->_bondStore) {
          ble_gap_sec_params_t gapSecParams;

#ifdef NRF51_S130
          gapSecParams.kdist_periph.enc = 1;
#else
          gapSecParams.timeout          = 30; // must be 30s
#endif
          gapSecParams.bond             = true;
          gapSecParams.mitm             = false;
          gapSecParams.io_caps          = BLE_GAP_IO_CAPS_NONE;
          gapSecParams.oob              = false;
          gapSecParams.min_key_size     = 7;
          gapSecParams.max_key_size     = 16;

          sd_ble_gap_authenticate(this->_connectionHandle, &gapSecParams);
        } else {
          uint16_t handle = bleEvt->evt.gattc_evt.params.read_rsp.handle;

          for (int i = 0; i < this->_numRemoteCharacteristics; i++) {
            if (this->_remoteCharacteristicInfo[i].valueHandle == handle) {
              if (this->_eventListener) {
                this->_eventListener->BLEDeviceRemoteCharacteristicValueChanged(*this, *this->_remoteCharacteristicInfo[i].characteristic, bleEvt->evt.gattc_evt.params.read_rsp.data, bleEvt->evt.gattc_evt.params.read_rsp. len);
              }
              break;
            }
          }
        }
        break;
      }

      case BLE_GATTC_EVT_WRITE_RSP:
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Write Rsp 0x"));
        Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX);
        Serial.println(bleEvt->evt.gattc_evt.params.write_rsp.handle, DEC);
#endif
        this->_remoteRequestInProgress = false;

        if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION &&
            this->_bondStore) {
          ble_gap_sec_params_t gapSecParams;

#ifdef NRF51_S130
          gapSecParams.kdist_periph.enc = 1;
#else
          gapSecParams.timeout          = 30; // must be 30s
#endif
          gapSecParams.bond             = true;
          gapSecParams.mitm             = false;
          gapSecParams.io_caps          = BLE_GAP_IO_CAPS_NONE;
          gapSecParams.oob              = false;
          gapSecParams.min_key_size     = 7;
          gapSecParams.max_key_size     = 16;

          sd_ble_gap_authenticate(this->_connectionHandle, &gapSecParams);
        }
        break;

      case BLE_GATTC_EVT_HVX: {
#ifdef NRF_51822_DEBUG
        Serial.print(F("Evt Hvx 0x"));
        Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX);
        Serial.println(bleEvt->evt.gattc_evt.params.hvx.handle, DEC);
#endif
        uint16_t handle = bleEvt->evt.gattc_evt.params.hvx.handle;

        if (bleEvt->evt.gattc_evt.params.hvx.type == BLE_GATT_HVX_INDICATION) {
          sd_ble_gattc_hv_confirm(this->_connectionHandle, handle);
        }

        for (int i = 0; i < this->_numRemoteCharacteristics; i++) {
          if (this->_remoteCharacteristicInfo[i].valueHandle == handle) {
            if (this->_eventListener) {
              this->_eventListener->BLEDeviceRemoteCharacteristicValueChanged(*this, *this->_remoteCharacteristicInfo[i].characteristic, bleEvt->evt.gattc_evt.params.read_rsp.data, bleEvt->evt.gattc_evt.params.read_rsp. len);
            }
            break;
          }
        }
        break;
      }

      default:
#ifdef NRF_51822_DEBUG
        Serial.print(F("bleEvt->header.evt_id = 0x"));
        Serial.print(bleEvt->header.evt_id, HEX);
        Serial.print(F(" "));
        Serial.println(bleEvt->header.evt_len);
#endif
        break;
    }
  }

  // sd_app_evt_wait();
}