Beispiel #1
0
uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas)
{
    uint32_t err_code;

    // Send value if connected
    if (p_bps->conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        uint8_t                encoded_bps_meas[MAX_BPM_LEN];
        uint16_t               len;
        uint16_t               hvx_len;
        ble_gatts_hvx_params_t hvx_params;
        
        len     = bps_measurement_encode(p_bps, p_bps_meas, encoded_bps_meas);
        hvx_len = len;

        memset(&hvx_params, 0, sizeof(hvx_params));
        
        hvx_params.handle = p_bps->meas_handles.value_handle;
        hvx_params.type   = BLE_GATT_HVX_INDICATION;
        hvx_params.offset = 0;
        hvx_params.p_len  = &hvx_len;
        hvx_params.p_data = encoded_bps_meas;
        
        err_code = sd_ble_gatts_hvx(p_bps->conn_handle, &hvx_params);
        if ((err_code == NRF_SUCCESS) && (hvx_len != len))
        {
            err_code = NRF_ERROR_DATA_SIZE;
        }
    }
    else
    {
        err_code = NRF_ERROR_INVALID_STATE;
    }

    return err_code;
}
Beispiel #2
0
uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate)
{
    uint32_t err_code;

    // Send value if connected and notifying
    if (p_hrs->conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        uint8_t                encoded_hrm[MAX_HRM_LEN];
        uint16_t               len;
        uint16_t               hvx_len;
        ble_gatts_hvx_params_t hvx_params;

        len     = hrm_encode(p_hrs, heart_rate, encoded_hrm);
        hvx_len = len;

        memset(&hvx_params, 0, sizeof(hvx_params));

        hvx_params.handle = p_hrs->hrm_handles.value_handle;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset = 0;
        hvx_params.p_len  = &hvx_len;
        hvx_params.p_data = encoded_hrm;

        err_code = sd_ble_gatts_hvx(p_hrs->conn_handle, &hvx_params);
        if ((err_code == NRF_SUCCESS) && (hvx_len != len))
        {
            err_code = NRF_ERROR_DATA_SIZE;
        }
    }
    else
    {
        err_code = NRF_ERROR_INVALID_STATE;
    }

    return err_code;
}
Beispiel #3
0
uint32_t ble_dfu_bytes_rcvd_report(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd)
{
    if (p_dfu == NULL)
    {
        return NRF_ERROR_NULL;
    }
    
    if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }
    
    ble_gatts_hvx_params_t hvx_params;
    uint16_t               index = 0;

    // Encode the Op Code.
    m_notif_buffer[index++] = OP_CODE_RESPONSE;

    // Encode the Reqest Op Code.
    m_notif_buffer[index++] = OP_CODE_IMAGE_SIZE_REQ;

    // Encode the Response Value.
    m_notif_buffer[index++] = (uint8_t)BLE_DFU_RESP_VAL_SUCCESS;

    index += uint32_encode(num_of_firmware_bytes_rcvd, &m_notif_buffer[index]);

    memset(&hvx_params, 0, sizeof(hvx_params));

    hvx_params.handle   = p_dfu->dfu_ctrl_pt_handles.value_handle;
    hvx_params.type     = BLE_GATT_HVX_NOTIFICATION;
    hvx_params.offset   = 0;
    hvx_params.p_len    = &index;
    hvx_params.p_data   = m_notif_buffer;

    return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}
uint32_t sendDataPHYSENS(ble_pss_t * p_pss)
{
    uint32_t err_code = NRF_SUCCESS;
    uint16_t len = (SENSOR_ROW_SIZE);
    uint8_t data[SENSOR_ROW_SIZE] = {0};
    uint8_t memory[6] = {0}; // 3 datas of 6 bytes each
    uint8_t iter, iter_data;
    uint16_t new_remember = 0;
    uint16_t add = 0;
    uint16_t skip = g_index_skip;

    if ((p_pss->conn_handle != BLE_CONN_HANDLE_INVALID) && p_pss->is_notification_supported)
    {


        ble_gatts_hvx_params_t hvx_params;

        memset(&hvx_params, 0, sizeof(hvx_params));

        hvx_params.handle   = p_pss->phy_sen_level_handles.value_handle;
        hvx_params.type     = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.p_len    = &len;
        switch (ble_mode) {

        case BLE_STICK_MODE:
            if (g_state == 2) {
                data[0] = STICK_MOMENT;
                data[1] = g_battery_int;
                data[2] = 1;
                for (iter=0; iter<10; iter++) {
                    data[3+iter] = g_data_send[iter];
                }
                g_state = 3;
            } else if (g_state == 3) {
                data[0] = STICK_MOMENT;
                data[1] = g_battery_int;
                data[2] = 2;
                for (iter=10; iter<22; iter++) {
                    data[3+iter-10] = g_data_send[iter];
                }
                g_state = 0; //RESTART

            } else {
                //TODO, put code from settings
                //Send settings
                /*data[0] = STICK_MOMENT;
                data[1] = g_battery_int;
                for (iter=0; iter<14; iter++) {
                    data[2+iter] = g_data_send[iter];
                }*/
                data[0] = SETTINGS_READ;
                data[1] = g_battery_int;
                for (iter=0; iter<18; iter++) {
                    data[2+iter] = g_settings[iter];
                }

            }
            break;

        case BLE_SETTINGS_MODE:
            data[0] = SETTINGS_READ;
            data[1] = g_battery_int;
            for (iter=0; iter<18; iter++) {
                data[2+iter] = g_settings[iter];
            }
            break;
        case BLE_CALIB_AXIS_MODE:
            data[0] = CALIB_OUTPUT;
            data[1] = g_battery_int;
            for (iter=0; iter<8; iter++) {
                data[2+iter] = g_calib_axis[iter];
            }
            for (iter=8; iter<18; iter++) {
                data[2+iter] = 0;
            }
            break;
        case BLE_FREE_MODE:
        case BLE_OTHER_MODE:
        case BLE_SHOT_MODE:
            // TODO mode magement
            // Draft mode and real mode mangement
            // Indexing later
            switch(g_state) {
            case 0:
            case 1:

                data[0] = DATA_DRAFT;
                data[1] = g_battery_int;

                for (iter_data = 0; iter_data<3; iter_data++) {
                    for (iter=0; iter<6; iter++) {
                        data[2+iter + (iter_data*6)] = g_data_send[iter + (iter_data*6)];
                    }
                }
                break;
            case 2:
                data[0] = DATA_START;
                data[1] = g_battery_int;
                // 300 for 30, but 32 indexes system.
                // Take ratio (300 / (30/32))
                //TODO
                if (g_remember < 320) {
                    g_remember = BR25S_CIRCULAR_BUFFER - (320-g_remember);
                } else {
                    g_remember -= 320;
                }
                g_shot_br25s_index = 0;
                break;
            case 3:
                data[0] = DATA;
                data[1] = g_battery_int;
                break;
            case 4:
                data[0] = DATA_END;
                data[1] = g_battery_int;
                break;
            }

            if (g_state >= 2) {
                new_remember = g_remember;

                for (iter_data=0; iter_data<3; iter_data++) {

                    getDatas(memory, 6, new_remember);

                    new_remember += g_skip[g_index_skip % 5];
                    add += g_skip[g_index_skip % 5];
                    g_index_skip++;

                    if (new_remember >= BR25S_CIRCULAR_BUFFER) {
                        new_remember = 0;
                    }

                    for (iter=0; iter<6; iter++) {
                        data[2+iter + (iter_data*6)] = memory[iter];
                    }
                }
            }

            break;
        }
        hvx_params.p_data = data;

        err_code = sd_ble_gatts_hvx(p_pss->conn_handle, &hvx_params);



        if (ble_mode == BLE_STICK_MODE && g_state <= 1) {
            return NRF_ERROR_INVALID_STATE; // Send only one data
        } else if (ble_mode == BLE_STICK_MODE) {
            return err_code;
        }

        // Add only if complete data
        if (ble_mode == BLE_SHOT_MODE && err_code == NRF_SUCCESS && g_state >= 2) {

            if (g_state == 2) {
                g_state = 3;

            } else if (g_state == 4) {
                g_state = 0;
                g_real_index = 0; //Flush everything
                g_valid = 1;
                g_index_skip = 0;
            }

            g_remember = new_remember;
            g_shot_br25s_index += add;
            if (g_remember >= BR25S_CIRCULAR_BUFFER)
                g_remember == 0;

            if (g_state == 3) {
                // 18 left + 2 extra(Nothing)
                if (g_shot_br25s_index >= BR25S_CIRCULAR_BUFFER - 20) {
                    // This sample and the last one
                    g_state = 4;
                }
            }
        } else if (g_state >= 2) {
            // Reinit some value
            g_index_skip = skip;
        }
    }
    else
    {
        err_code = NRF_ERROR_INVALID_STATE;
    }


    if ((ble_mode == BLE_SHOT_MODE || ble_mode == BLE_FREE_MODE) && g_state <= 1) {
        return NRF_ERROR_INVALID_STATE; // Send only one data
    }

    return err_code;
}
Beispiel #5
0
/**@brief Function for sending response from Specific Operation Control Point.
 *
 * @param[in]   p_cgms        Service instance.
 * @param[in]   p_racp_val   RACP value to be sent.
 */
static void racp_send(nrf_ble_cgms_t * p_cgms, ble_racp_value_t * p_racp_val)
{
    uint32_t               err_code;
    uint8_t                encoded_resp[25];
    uint8_t                len;
    uint16_t               hvx_len;
    ble_gatts_hvx_params_t hvx_params;

    if (
        (p_cgms->cgms_com_state != STATE_RACP_RESPONSE_PENDING)
        &&
        (p_cgms->racp_data.racp_proc_records_reported_since_txcomplete > 0)
       )
    {
        p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING;
        return;
    }

    // Send indication
    len     = ble_racp_encode(p_racp_val, encoded_resp);
    hvx_len = len;

    memset(&hvx_params, 0, sizeof(hvx_params));

    hvx_params.handle = p_cgms->char_handles.racp.value_handle;
    hvx_params.type   = BLE_GATT_HVX_INDICATION;
    hvx_params.offset = 0;
    hvx_params.p_len  = &hvx_len;
    hvx_params.p_data = encoded_resp;

    err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params);

    // Error handling
    if ((err_code == NRF_SUCCESS) && (hvx_len != len))
    {
        err_code = NRF_ERROR_DATA_SIZE;
    }

    switch (err_code)
    {
        case NRF_SUCCESS:
            // Wait for HVC event
            p_cgms->cgms_com_state = STATE_RACP_RESPONSE_IND_VERIF;
            break;

        case BLE_ERROR_NO_TX_PACKETS:
            // Wait for TX_COMPLETE event to retry transmission
            p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING;
            break;

        case NRF_ERROR_INVALID_STATE:
            // Make sure state machine returns to the default state
            p_cgms->cgms_com_state = STATE_NO_COMM;
            break;

        default:
            // Report error to application
            if (p_cgms->error_handler != NULL)
            {
                p_cgms->error_handler(err_code);
            }

            // Make sure state machine returns to the default state
            p_cgms->cgms_com_state = STATE_NO_COMM;
            break;
    }
}
Beispiel #6
0
/**@brief Function for handling the Disconnect event.
 *
 * @param[in] p_si7021  si7021 Service structure.
 * @param[in]   hum  Relative Humidity Raw 16-Bit.
 * @param[in]   temp Temperature Raw 16-Bit.
 */
uint32_t ble_si7021_sensor_update(ble_si7021_t * p_si7021, uint16_t hum, uint16_t temp) {
	uint8_t encoded_data[BLE_si7021_VALUE_MAX_LEN];
	//uint8_t len;

    if (p_si7021 == NULL) {
        return NRF_ERROR_NULL;
    }

    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    if ((hum != p_si7021->last_humraw && hum != 0) || (temp != p_si7021->last_tempraw && temp != 0)) {
    	NRF_LOG_DEBUG("ble_si7021_sensor_update %x,%x\n\r",hum,temp);

	    uint16_encode(hum,&encoded_data[0]);
	    uint16_encode(temp,&encoded_data[2]);

        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));

        gatts_value.len     = BLE_si7021_VALUE_MAX_LEN;
        gatts_value.offset  = 0;
        gatts_value.p_value = &encoded_data[0];

    	NRF_LOG_DEBUG("sd_ble_gatts_value_set %x,%x\n\r",p_si7021->conn_handle,p_si7021->value_char_handles.value_handle);
        // Update database. Set the value of a given attribute
        err_code = sd_ble_gatts_value_set(p_si7021->conn_handle,
        		                          p_si7021->value_char_handles.value_handle,
                                          &gatts_value);
    	NRF_LOG_DEBUG("sd_ble_gatts_value_set =%d\n\r",err_code);
        if (err_code == NRF_SUCCESS) {
            // save new temperature value.
        	p_si7021->last_humraw = hum;
        	p_si7021->last_tempraw = temp;
        } else {
            return err_code;
        }

        // Send value if connected and notifying.
        if (p_si7021->conn_handle != BLE_CONN_HANDLE_INVALID) {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));

            hvx_params.handle = p_si7021->value_char_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;

        	NRF_LOG_DEBUG("sd_ble_gatts_hvx\n\r");
            // Notify or Indicate an attribute value
            err_code = sd_ble_gatts_hvx(p_si7021->conn_handle, &hvx_params);
        	NRF_LOG_DEBUG("sd_ble_gatts_hvx =%d\n\r",err_code);
        } else {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }

    return err_code;
}
ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
{
    ble_error_t returnValue = BLE_ERROR_NONE;

    ble_gatts_value_t value = {
        /* .len     = */ len,
        /* .offset  = */ 0,
        /* .p_value = */ const_cast<uint8_t *>(buffer),
    };

    if (localOnly) {
        /* Only update locally regardless of notify/indicate */
        ASSERT_INT( ERROR_NONE,
                    sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
                    BLE_ERROR_PARAM_OUT_OF_RANGE );
        return BLE_ERROR_NONE;
    }

    int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle);
    if ((characteristicIndex != -1) &&
        (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) {
        /* HVX update for the characteristic value */
        ble_gatts_hvx_params_t hvx_params;

        hvx_params.handle = attributeHandle;
        hvx_params.type   =
            (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION;
        hvx_params.offset = 0;
        hvx_params.p_data = const_cast<uint8_t *>(buffer);
        hvx_params.p_len  = &len;

        if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */
            nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
            connectionHandle = gap.getConnectionHandle();
        }

        bool updatesEnabled = false;
        if (connectionHandle != BLE_CONN_HANDLE_INVALID) {
            ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled);

            // FIXME: The softdevice allocates and populates CCCD when the client
            // interract with them. Checking for updates may return an out of
            // range error in such case.
            if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) {
                return err;
            }
        }

        bool updates_permitted = false;
        ble_gap_conn_sec_t connection_security;
        uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security);
        if (!err &&
            (connection_security.sec_mode.sm == 1) &&
            (connection_security.sec_mode.lv >=  p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) {
            updates_permitted = true;
        }

        if (updatesEnabled && updates_permitted) {
            error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
            if (error != ERROR_NONE) {
                switch (error) {
                    case ERROR_BLE_NO_TX_BUFFERS: /*  Notifications consume application buffers. The return value can be used for resending notifications. */
                    case ERROR_BUSY:
                        returnValue = BLE_STACK_BUSY;
                        break;

                    case ERROR_INVALID_STATE:
                    case ERROR_BLEGATTS_SYS_ATTR_MISSING:
                        returnValue = BLE_ERROR_INVALID_STATE;
                        break;

                    default :
                        ASSERT_INT( ERROR_NONE,
                                    sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value),
                                    BLE_ERROR_PARAM_OUT_OF_RANGE );

                        /* Notifications consume application buffers. The return value can
                        * be used for resending notifications. */
                        returnValue = BLE_STACK_BUSY;
                        break;
                }
            }
        } else {
            returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
        }
    } else {
        returnValue = set_attribute_value(connectionHandle, attributeHandle, &value);
    }

    return returnValue;
}
uint32_t mesh_srv_char_val_set(uint8_t index, uint8_t* data, uint16_t len, bool update_sender)
{
    if (!is_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }
    
    if (index > g_mesh_service.value_count || index == 0)
    {
        return NRF_ERROR_INVALID_ADDR;
    }
    
    if (len > MAX_VALUE_LENGTH)
    {
        return NRF_ERROR_INVALID_LENGTH;
    }
    uint32_t error_code = 0;
    
    mesh_char_metadata_t* ch_md = &g_mesh_service.char_metadata[index - 1];
    
    /* this is now a new version of this data, signal to the rest of the mesh */
    ++ch_md->version_number;
    
    bool first_time = 
        (ch_md->flags & 
        (1 << MESH_MD_FLAGS_USED_POS)) == 0;
    
    if (first_time)
    {
        ch_md->flags |= 
            (1 << MESH_MD_FLAGS_INITIALIZED_POS) |
            (1 << MESH_MD_FLAGS_USED_POS);
        trickle_init(&ch_md->trickle);
    }
    else
    {
        trickle_rx_inconsistent(&ch_md->trickle);
    }
    
    if (update_sender || first_time)
    {
        ble_gap_addr_t my_addr;
        sd_ble_gap_address_get(&my_addr);
        memcpy(&ch_md->last_sender_addr, &my_addr, sizeof(ble_gap_addr_t));
        ch_md->flags |= (1 << MESH_MD_FLAGS_IS_ORIGIN_POS);
    }
        
    /* notify the connected central node, if any */
    if (g_active_conn_handle != CONN_HANDLE_INVALID)
    {
        ble_gatts_hvx_params_t notify_params;
        notify_params.handle = ch_md->char_value_handle;
        notify_params.offset = 0;
        notify_params.p_data = data;
        notify_params.p_len = &len;
        notify_params.type = BLE_GATT_HVX_NOTIFICATION;
        error_code = sd_ble_gatts_hvx(g_active_conn_handle, &notify_params);
        if (error_code != NRF_SUCCESS)
        {
            if (error_code == BLE_ERROR_INVALID_CONN_HANDLE)
            {
                g_active_conn_handle = CONN_HANDLE_INVALID;
            }
            else if (error_code == BLE_GATTS_EVT_SYS_ATTR_MISSING)
            {
                sd_ble_gatts_sys_attr_set(g_active_conn_handle, NULL, 0);
            }
            else
            {
                return NRF_ERROR_INTERNAL;
            }
        }
    }
    else
    {
        error_code = sd_ble_gatts_value_set(
            ch_md->char_value_handle, 
            0, &len, data);
        
        if (error_code != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    }
    
    return NRF_SUCCESS;
}
/**@brief Function for decoding a command packet with RPC_SD_BLE_GATTS_HVX opcode.
 *
 * This function will decode the command, call the BLE Stack API, and also send command response
 * to the peer through the the transport layer.
 *
 * @param[in] p_command         The encoded structure that needs to be decoded and passed on
 *                              to the BLE Stack API.
 * @param[in] command_len       The length of the encoded command read from transport layer.
 *
 * @retval NRF_SUCCESS               If the decoding of the command was successful, the SoftDevice
 *                                   API was called, and the command response was sent to peer,
 *                                   otherwise an error code.
 * @retval NRF_ERROR_INVALID_LENGTH  If the content length of the packet is not conforming to the
 *                                   codec specification.
 */
static uint32_t gatts_hvx_handle(uint8_t * const p_command, uint32_t command_len)
{
    uint32_t               err_code;
    uint16_t               conn_handle;
    ble_gatts_hvx_params_t hvx_params;
    uint8_t                resp_data[sizeof(uint16_t)];

    uint16_t                 hvx_params_data_length = 0;
    uint32_t                 index                  = 0;
    ble_gatts_hvx_params_t * p_hvx_params           = NULL;

    conn_handle  = uint16_decode(&p_command[index]);
    index       += sizeof(uint16_t);
    RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX);

    if (p_command[index++] == RPC_BLE_FIELD_PRESENT)
    {
        hvx_params.handle  = uint16_decode(&p_command[index]);
        index             += sizeof(uint16_t);
        hvx_params.type    = p_command[index++];
        hvx_params.offset  = uint16_decode(&p_command[index]);
        index             += sizeof(uint16_t);
        RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX);
        if (p_command[index++] == RPC_BLE_FIELD_PRESENT)
        {
            hvx_params_data_length  = uint16_decode(&p_command[index]);
            index                  += sizeof(uint16_t);
            hvx_params.p_len        = &hvx_params_data_length;
        }
        else
        {
            hvx_params.p_len = NULL;
        }
        RPC_DECODER_LENGTH_CHECK(command_len,
                                 (index + hvx_params_data_length),
                                 SD_BLE_GATTS_HVX);

        if (p_command[index++] == RPC_BLE_FIELD_PRESENT)
        {
            hvx_params.p_data = &(p_command[index]);
        }
        else
        {
            hvx_params.p_data = NULL;
        }
        p_hvx_params = &hvx_params;
    }

    RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX);

    err_code = sd_ble_gatts_hvx(conn_handle, p_hvx_params);

    if (err_code == NRF_SUCCESS)
    {
        if (p_hvx_params != NULL && p_hvx_params->p_len != NULL)
        {
            UNUSED_VARIABLE(uint16_encode(*(p_hvx_params->p_len), resp_data));
            return ble_rpc_cmd_resp_data_send(SD_BLE_GATTS_HVX,
                                              err_code,
                                              resp_data,
                                              sizeof(resp_data));
        }
    }

    return ble_rpc_cmd_resp_send(SD_BLE_GATTS_HVX, err_code);
}