<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Disconnection between &amp;quot;ble_app_hrs&amp;quot; example in SDK 15.2.0 and &amp;quot;heart_rate_collector&amp;quot; example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/44172/disconnection-between-ble_app_hrs-example-in-sdk-15-2-0-and-heart_rate_collector-example-with-pc-ble-driver-c-c</link><description>Hello, this is Kwonjoon Lee, beginner of BLE development. 
 I successfully installed pc-ble-driver (c/c++) in accordance with Git-Hub guide ( https://github.com/NordicSemiconductor/pc-ble-driver ), and I would like to ask about disconnection between </description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Thu, 07 Mar 2019 06:52:26 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/44172/disconnection-between-ble_app_hrs-example-in-sdk-15-2-0-and-heart_rate_collector-example-with-pc-ble-driver-c-c" /><item><title>RE: Disconnection between "ble_app_hrs" example in SDK 15.2.0 and "heart_rate_collector" example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/thread/174704?ContentTypeID=1</link><pubDate>Thu, 07 Mar 2019 06:52:26 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5a451237-5bc9-4dce-958f-c5cfd67d7a04</guid><dc:creator>kwonjoon</dc:creator><description>&lt;p&gt;Hello, Sigurd, this is Kwonjoon Lee. &lt;br /&gt;I&amp;nbsp;always appreciate your kind answer, and I would like to get some more comments on my work.&lt;/p&gt;
&lt;p&gt;Actually, I am trying to implement Bluetooth5 communication with maximum throughput.&lt;br /&gt;(between the heart_rate_collector_v6 of &amp;quot;pc-ble-driver&amp;quot; and the ble_app_hrs of &amp;quot;nRF5 sdk 15.2.0&amp;quot;)&amp;nbsp;&lt;br /&gt;&lt;br /&gt;For that, I am attempting following three methods:&lt;br /&gt;1) Using uncoded 2M PHY (in my opinion, this is successful)&lt;br /&gt;2) Increasing LL data channel PDU payload length (is it so-called data length extension, DLE??)&lt;br /&gt;3) Increasing maximum transmission unit (MTU) of 247 (Max)&lt;/p&gt;
&lt;p&gt;My major problem and question are about 2) (increasing data length), and &lt;br /&gt;please see the following figures and my working history.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figures and Working History :&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/680x480/__key/communityserver-discussions-components-files/4/pastedimage1551938009315v1.png" /&gt;&lt;/p&gt;
&lt;p&gt;First, in my the ble_app_hrs example, sdk_config.h defines NRF_SDH_BLE_GAP_DATA_LENGTH&lt;br /&gt;as following code so that ble_app_hrs example (BLE peri) sends heart_rate_collector_v6 example&lt;br /&gt;(BLE master)&amp;nbsp;data_length_update_request of TX/RX bytes == 251/251 bytes.&lt;br /&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// &amp;lt;o&amp;gt; NRF_SDH_BLE_GAP_DATA_LENGTH   &amp;lt;27-251&amp;gt; 

// &amp;lt;i&amp;gt; Requested BLE GAP data length to be negotiated.

#ifndef NRF_SDH_BLE_GAP_DATA_LENGTH
#define NRF_SDH_BLE_GAP_DATA_LENGTH 251
#endif&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;After that, heart_rate_collector_v6 example (BLE master) responds with following&amp;nbsp;&amp;nbsp;&lt;br /&gt;the function call, sd_ble_gap_data_length_update (m_adapter, m_connection_handle, &amp;amp;dlp, &amp;amp;dll) &lt;br /&gt;as shown in the attached code. But, it makes NRF_ERROR_RESOURCE. &lt;br /&gt;So, currently, I changed the function call to&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;span&gt;sd_ble_gap_data_length_update (m_adapter, m_connection_handle, NULL, NULL) &lt;br /&gt;according to &lt;a href="https://www.nordicsemi.com/DocLib/Content/SoftDevice_API_Doc/S140/v6-1-0/group_ble_gap_data_length_update_procedure_msc"&gt;the link&lt;/a&gt;&amp;nbsp;(third case and picture), and the result is TX/RX bytes == 157/157 bytes.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// Added by Kwonjoon @ 20190228 in accordance with Sigurd&amp;#39;s Guide (Below)
static void on_conn_data_length_update_request(const ble_gap_evt_t * const p_ble_gap_evt)
{
	printf(&amp;quot;BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST : TX/RX bytes == %d/%d bytes and TX/RX us == %d/%d us \n&amp;quot;,
		p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_tx_octets,
		p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_rx_octets,
		p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_tx_time_us,
		p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_rx_time_us);

	ble_gap_data_length_params_t const dlp =
	{
		.max_rx_octets = 251, // Previous Value : 27
		.max_tx_octets = 251, // Previous Value : 27
		.max_rx_time_us = 2704, // BLE_GAP_DATA_LENGTH_AUTO
		.max_tx_time_us = 2704, // BLE_GAP_DATA_LENGTH_AUTO
	};

	ble_gap_data_length_limitation_t dll = { 0 };
	//uint32_t err_code = sd_ble_gap_data_length_update(m_adapter, m_connection_handle, &amp;amp;dlp, &amp;amp;dll);
	uint32_t err_code = sd_ble_gap_data_length_update(m_adapter, m_connection_handle, NULL, NULL);
	if (err_code != NRF_SUCCESS)
	{
		printf(&amp;quot;sd_ble_gap_data_length_update failed, err_code %d\n&amp;quot;, err_code);
	}

}
// Added by Kwonjoon @ 20190228 in accordance with Sigurd&amp;#39;s Guide (Above)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;To resolve the&amp;nbsp;&lt;span&gt;NRF_ERROR_RESOURCE, and increase data length up to 251 bytes,&lt;br /&gt;I found some comments about data length update procedure in the &lt;/span&gt;&lt;span&gt;ble_gap.h of the heart_rate_collector_v6&amp;nbsp;example (BLE master) as following text.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;@retval ::NRF_ERROR_RESOURCES 
The connection event length configured for this link is not sufficient for the requested parameters.
Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length.
Inspect p_dl_limitation to see where the limitation is.&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Accordingly, to increase connection event length, I changed ble_cfg_set() function&amp;nbsp;&lt;br /&gt;in the heart_rate_collector (BLE master), but I got the error message that &lt;br /&gt;sd_ble_cfg_set() is failed due to invalid parameter, which is expressed the first figure.&lt;br /&gt;(my connection interval is 7.5ms in both BLE master and BLE peri)&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;static uint32_t ble_cfg_set(uint8_t conn_cfg_tag)
{
    const uint32_t ram_start = 0; // Value is not used by ble-driver
    uint32_t error_code;
    ble_cfg_t ble_cfg;

    // Configure the connection roles.
    memset(&amp;amp;ble_cfg, 0, sizeof(ble_cfg));

#if NRF_SD_BLE_API &amp;gt;= 6
    ble_cfg.gap_cfg.role_count_cfg.adv_set_count        = BLE_GAP_ADV_SET_COUNT_DEFAULT;
#endif
    ble_cfg.gap_cfg.role_count_cfg.periph_role_count    = 0;
    ble_cfg.gap_cfg.role_count_cfg.central_role_count   = 1;
    ble_cfg.gap_cfg.role_count_cfg.central_sec_count    = 0;

    error_code = sd_ble_cfg_set(m_adapter, BLE_GAP_CFG_ROLE_COUNT, &amp;amp;ble_cfg, ram_start);
    if (error_code != NRF_SUCCESS)
    {
        printf(&amp;quot;sd_ble_cfg_set() failed when attempting to set BLE_GAP_CFG_ROLE_COUNT. Error code: 0x%02X\n&amp;quot;, error_code);
        fflush(stdout);
        return error_code;
    }

    memset(&amp;amp;ble_cfg, 0x00, sizeof(ble_cfg));
    ble_cfg.conn_cfg.conn_cfg_tag                 = conn_cfg_tag;
    ble_cfg.conn_cfg.params.gatt_conn_cfg.att_mtu = 247; // Changed by Kwonjoon @ 20190306, Previous Value : 150
	
    error_code = sd_ble_cfg_set(m_adapter, BLE_CONN_CFG_GATT, &amp;amp;ble_cfg, ram_start);
    if (error_code != NRF_SUCCESS)
    {
        printf(&amp;quot;sd_ble_cfg_set() failed when attempting to set BLE_CONN_CFG_GATT. Error code: 0x%02X\n&amp;quot;, error_code);
        fflush(stdout);
        return error_code;
    }

	// Added by Kwonjoon @ 20190306 for Increasing Connection Event Length &amp;amp; Increasing LL Payload (Below)
	memset(&amp;amp;ble_cfg, 0x00, sizeof(ble_cfg));
	ble_cfg.conn_cfg.params.gap_conn_cfg.event_length = MSEC_TO_UNITS(6.25, UNIT_1_25_MS); // 3
	
	error_code = sd_ble_cfg_set(m_adapter, BLE_CONN_CFG_GAP, &amp;amp;ble_cfg, ram_start);
	if (error_code != NRF_SUCCESS)
	{
		printf(&amp;quot;sd_ble_cfg_set() failed when attempting to set BLE_CONN_CFG_GAP. Error code: 0x%02X\n&amp;quot;, error_code);
		fflush(stdout);
		return error_code;
	}
	// Added by Kwonjoon @ 20190306 for Increasing Connection Event Length &amp;amp; Increasing LL Payload (Above)
    
	return NRF_SUCCESS;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Questions :&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(1) How can I increase connection event length &amp;amp; LL data channel PDU payload length (data length)??&lt;br /&gt;(2) Where can I set the MTU of 247 bytes?? in both BLE master and BLE peri&lt;/p&gt;
&lt;p&gt;I really appreciate for reading of long questions,&lt;br /&gt;If you give me some comments, it will be huge help for me.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;br /&gt;Kwonjoon Lee&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Disconnection between "ble_app_hrs" example in SDK 15.2.0 and "heart_rate_collector" example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/thread/174472?ContentTypeID=1</link><pubDate>Wed, 06 Mar 2019 09:17:15 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:fb744c76-449b-40ec-9119-f45e3aaa9351</guid><dc:creator>Chencheng</dc:creator><description>&lt;p&gt;Thank you Sigurd! max_rx/tx_oectets set to 27 works.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Disconnection between "ble_app_hrs" example in SDK 15.2.0 and "heart_rate_collector" example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/thread/174355?ContentTypeID=1</link><pubDate>Tue, 05 Mar 2019 16:18:23 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:f3d053d9-28f7-4a55-a3a7-5590cb437b33</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi&amp;nbsp;&lt;span&gt;Chencheng,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The&amp;nbsp;connectivity firmware is compiled with&amp;nbsp;NRF_SDH_BLE_GAP_DATA_LENGTH (sdk_config.h) set to 27.&amp;nbsp;That is the reason why I set&amp;nbsp;max_rx_octets and&amp;nbsp;max_tx_octets to 27 in the code I posted. You might be able to use higher&amp;nbsp;values if you compile the&amp;nbsp;connectivity firmware yourself with&amp;nbsp;NRF_SDH_BLE_GAP_DATA_LENGTH set to a higher value, but I cannot&amp;nbsp;guarantee that the rest of the&amp;nbsp;serialization library will support that change.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Disconnection between "ble_app_hrs" example in SDK 15.2.0 and "heart_rate_collector" example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/thread/174344?ContentTypeID=1</link><pubDate>Tue, 05 Mar 2019 15:52:48 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:1ab60baf-31bb-44d5-8043-d37bc423ab2c</guid><dc:creator>Chencheng</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I implemented according to this. But I get an error:&lt;/p&gt;
&lt;p&gt;BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST received: sd_ble_gap_data_length_update failed, err_code 19 NRF_ERROR_RESOURCES&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;My implementation is a bit difference:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#if NRF_SD_BLE_API &amp;gt;= 5
/**@brief Function called on BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event.
 *
 * @details Data length update request
 *
 * @param[in] p_ble_gap_evt Data length update request Event.
 */
static void on_conn_data_length_update_request(const ble_gap_evt_t * const p_ble_gap_evt)
{
	printf(&amp;quot;BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST received: &amp;quot;);

	ble_gap_data_length_params_t const dlp =
	{
		.max_rx_octets = p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_tx_octets,
		.max_tx_octets = p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_rx_octets,
		.max_rx_time_us = p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_rx_time_us,
		.max_tx_time_us = p_ble_gap_evt-&amp;gt;params.data_length_update_request.peer_params.max_tx_time_us
	};

	ble_gap_data_length_limitation_t dll = { 0 };

	uint32_t err_code = sd_ble_gap_data_length_update(m_adapter, m_connection_handle, &amp;amp;dlp, &amp;amp;dll);
	if (err_code != NRF_SUCCESS) 
	{
		printf(&amp;quot;sd_ble_gap_data_length_update failed, err_code %d\n&amp;quot;, err_code);
	}
    else
    {
		printf(&amp;quot;sd_ble_gap_data_length_update OK.\n&amp;quot;);
    }
    fflush(stdout);
}
#endif
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;BR/Chencheng&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Disconnection between "ble_app_hrs" example in SDK 15.2.0 and "heart_rate_collector" example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/thread/173348?ContentTypeID=1</link><pubDate>Thu, 28 Feb 2019 01:02:16 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:9937d3cc-83cc-4258-b3a0-bdf12d320154</guid><dc:creator>kwonjoon</dc:creator><description>&lt;p&gt;I really appreciate your kind and detailed answer!!. I will do my best to conduct your guide, and If another issue occur, I will let you know after serious consideration :)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Disconnection between "ble_app_hrs" example in SDK 15.2.0 and "heart_rate_collector" example with pc-ble-driver (c/c++)</title><link>https://devzone.nordicsemi.com/thread/173330?ContentTypeID=1</link><pubDate>Wed, 27 Feb 2019 21:58:37 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b84c47bf-88b1-48d5-bbd0-acdc05f52d33</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;&lt;span&gt;1) No, this is not the expected behavior. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;2) &amp;nbsp;Looking at the list &lt;a href="https://www.nordicsemi.com/DocLib/Content/SoftDevice_API_Doc/S140/v6-1-0/group_ble_gap_enumerations"&gt;here&lt;/a&gt;, we see that event 18 (0x12) is the same as BLE_GAP_EVT_CONN_PARAM_UPDATE. This is an event informing you that the connection parameters have been changed.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Disconnect reason 0x22 is &lt;a href="https://www.nordicsemi.com/DocLib/Content/SoftDevice_API_Doc/S140/v6-1-1/group_ble_hci_status_codes#ga91c40ef8a7c61f6a3a036eac70956491"&gt;BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;I see in the list that you also have another un-handled event with id=35, that is a BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. This event needs to handled, or else you will disconnect, so this is the event that is causing the disconnect. This is something that the pc-ble-driver examples should have handled.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Here is how you can handle the BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Snippet:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;pre class="ui-code" data-mode="text"&gt;static void on_conn_data_length_update_request(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	printf(&amp;quot;BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST received\n&amp;quot;);

	ble_gap_data_length_params_t const dlp =
	{
		.max_rx_octets = 27,
		.max_tx_octets = 27,
		.max_rx_time_us = BLE_GAP_DATA_LENGTH_AUTO,
		.max_tx_time_us = BLE_GAP_DATA_LENGTH_AUTO,
	};

	ble_gap_data_length_limitation_t dll = { 0 };

	uint32_t err_code = sd_ble_gap_data_length_update(m_adapter, m_connection_handle, &amp;amp;dlp, &amp;amp;dll);
	if (err_code != NRF_SUCCESS) 
	{
		printf(&amp;quot;sd_ble_gap_data_length_update failed, err_code %d\n&amp;quot;, err_code);
	}

}
&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;In&amp;nbsp;ble_evt_dispatch() you will need this:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;pre class="ui-code" data-mode="text"&gt;		case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
			on_conn_data_length_update_request(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
			break;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Complete main.c:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;pre class="ui-code" data-mode="text"&gt;/*
 * copyright (c) 2012 - 2018, nordic semiconductor asa
 * all rights reserved.
 *
 * redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. redistributions in binary form, except as embedded into a nordic
 *    semiconductor asa integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA &amp;quot;AS IS&amp;quot; AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**@example examples/heart_rate_collector
 *
 * @brief Heart Rate Collector Sample Application main file.
 *
 * This file contains the source code for a sample application that acts as a BLE Central device.
 * This application scans for a Heart Rate Sensor device and reads it&amp;#39;s heart rate data.
 * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
 *
 * Structure of this file
 * - Includes
 * - Definitions
 * - Global variables
 * - Global functions
 * - Event functions
 * - Event dispatcher
 * - Main
 */

/** Includes */
#include &amp;quot;ble.h&amp;quot;
#include &amp;quot;sd_rpc.h&amp;quot;

#include &amp;lt;stdbool.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;


/** Definitions */
#ifdef _WIN32
#define DEFAULT_UART_PORT_NAME &amp;quot;COM6&amp;quot;
#define DEFAULT_BAUD_RATE 1000000 /**&amp;lt; The baud rate to be used for serial communication with nRF5 device. */
#endif
#ifdef __APPLE__
#define DEFAULT_UART_PORT_NAME &amp;quot;/dev/tty.usbmodem00000&amp;quot;
#define DEFAULT_BAUD_RATE 115200 /* 1M baud rate is not supported on MacOS */
#endif
#ifdef __linux__
#define DEFAULT_UART_PORT_NAME &amp;quot;/dev/ttyACM0&amp;quot;
#define DEFAULT_BAUD_RATE 1000000
#endif

enum
{
    UNIT_0_625_MS = 625,  /**&amp;lt; Number of microseconds in 0.625 milliseconds. */
    UNIT_1_25_MS  = 1250, /**&amp;lt; Number of microseconds in 1.25 milliseconds. */
    UNIT_10_MS    = 10000 /**&amp;lt; Number of microseconds in 10 milliseconds. */
};

#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))

#define SCAN_INTERVAL 0x00A0 /**&amp;lt; Determines scan interval in units of 0.625 milliseconds. */
#define SCAN_WINDOW   0x0050 /**&amp;lt; Determines scan window in units of 0.625 milliseconds. */
#define SCAN_TIMEOUT  0x0    /**&amp;lt; Scan timeout between 0x01 and 0xFFFF in seconds, 0x0 disables timeout. */

#define MIN_CONNECTION_INTERVAL         MSEC_TO_UNITS(200, UNIT_1_25_MS) /**&amp;lt; Determines minimum connection interval in milliseconds. */
#define MAX_CONNECTION_INTERVAL         MSEC_TO_UNITS(300, UNIT_1_25_MS) /**&amp;lt; Determines maximum connection interval in milliseconds. */
#define SLAVE_LATENCY                   0                                /**&amp;lt; Slave Latency in number of connection events. */
#define CONNECTION_SUPERVISION_TIMEOUT  MSEC_TO_UNITS(4000, UNIT_10_MS)  /**&amp;lt; Determines supervision time-out in units of 10 milliseconds. */

#define TARGET_DEV_NAME &amp;quot;Nordic_HRM&amp;quot; /**&amp;lt; Connect to a peripheral using a given advertising name here. */
#define MAX_PEER_COUNT 1            /**&amp;lt; Maximum number of peer&amp;#39;s application intends to manage. */

#define BLE_UUID_HEART_RATE_SERVICE          0x180D /**&amp;lt; Heart Rate service UUID. */
#define BLE_UUID_HEART_RATE_MEASUREMENT_CHAR 0x2A37 /**&amp;lt; Heart Rate Measurement characteristic UUID. */
#define BLE_UUID_CCCD                        0x2902
#define BLE_CCCD_NOTIFY                      0x01

#define STRING_BUFFER_SIZE 50

typedef struct
{
    uint8_t *     p_data;   /**&amp;lt; Pointer to data. */
    uint16_t      data_len; /**&amp;lt; Length of data. */
} data_t;


/** Global variables */
static uint8_t     m_connected_devices          = 0;
static uint16_t    m_connection_handle          = 0;
static uint16_t    m_service_start_handle       = 0;
static uint16_t    m_service_end_handle         = 0;
static uint16_t    m_hrm_char_handle            = 0;
static uint16_t    m_hrm_cccd_handle            = 0;
static bool        m_connection_is_in_progress  = false;
static adapter_t * m_adapter                    = NULL;

#if NRF_SD_BLE_API &amp;gt;= 5
static uint32_t    m_config_id                  = 1;
#endif

#if NRF_SD_BLE_API &amp;gt;= 6
static uint8_t     mp_data[100]                 = { 0 };
static ble_data_t  m_adv_report_buffer;
#endif

static const ble_gap_scan_params_t m_scan_param =
{
#if NRF_SD_BLE_API &amp;gt;= 6
    0,                       // Set if accept extended advertising packetets.
    0,                       // Set if report inomplete reports.
#endif
    0,                       // Set if active scanning.
#if NRF_SD_BLE_API &amp;lt; 6
    0,                       // Set if selective scanning.
#endif
#if NRF_SD_BLE_API &amp;gt;= 6
    BLE_GAP_SCAN_FP_ACCEPT_ALL,
    BLE_GAP_PHY_1MBPS,
#endif
#if NRF_SD_BLE_API == 2
    NULL,                    // Set white-list.
#endif
#if NRF_SD_BLE_API == 3 || NRF_SD_BLE_API == 5
    0,                       // Set adv_dir_report.
#endif
    (uint16_t)SCAN_INTERVAL,
    (uint16_t)SCAN_WINDOW,
    (uint16_t)SCAN_TIMEOUT
#if NRF_SD_BLE_API &amp;gt;= 6
    , { 0 }                  // Set chennel mask.
#endif
};

static const ble_gap_conn_params_t m_connection_param =
{
    (uint16_t)MIN_CONNECTION_INTERVAL,
    (uint16_t)MAX_CONNECTION_INTERVAL,
    (uint16_t)SLAVE_LATENCY,
    (uint16_t)CONNECTION_SUPERVISION_TIMEOUT
};


/** Global functions */

/**@brief Function for handling error message events from sd_rpc.
 *
 * @param[in] adapter The transport adapter.
 * @param[in] code Error code that the error message is associated with.
 * @param[in] message The error message that the callback is associated with.
 */
static void status_handler(adapter_t * adapter, sd_rpc_app_status_t code, const char * message)
{
    printf(&amp;quot;Status: %d, message: %s\n&amp;quot;, (uint32_t)code, message);
    fflush(stdout);
}

/**@brief Function for handling the log message events from sd_rpc.
 *
 * @param[in] adapter The transport adapter.
 * @param[in] severity Level of severity that the log message is associated with.
 * @param[in] message The log message that the callback is associated with.
 */
static void log_handler(adapter_t * adapter, sd_rpc_log_severity_t severity, const char * message)
{
    switch (severity)
    {
        case SD_RPC_LOG_ERROR:
            printf(&amp;quot;Error: %s\n&amp;quot;, message);
            fflush(stdout);
            break;

        case SD_RPC_LOG_WARNING:
            printf(&amp;quot;Warning: %s\n&amp;quot;, message);
            fflush(stdout);
            break;

        case SD_RPC_LOG_INFO:
            printf(&amp;quot;Info: %s\n&amp;quot;, message);
            fflush(stdout);
            break;

        default:
            printf(&amp;quot;Log: %s\n&amp;quot;, message);
            fflush(stdout);
            break;
    }
}

/**@brief Function for initializing serial communication with the target nRF5 Bluetooth slave.
 *
 * @param[in] serial_port The serial port the target nRF5 device is connected to.
 *
 * @return The new transport adapter.
 */
static adapter_t * adapter_init(char * serial_port, uint32_t baud_rate)
{
    physical_layer_t  * phy;
    data_link_layer_t * data_link_layer;
    transport_layer_t * transport_layer;

    phy = sd_rpc_physical_layer_create_uart(serial_port,
                                            baud_rate,
                                            SD_RPC_FLOW_CONTROL_NONE,
                                            SD_RPC_PARITY_NONE);
    data_link_layer = sd_rpc_data_link_layer_create_bt_three_wire(phy, 100);
    transport_layer = sd_rpc_transport_layer_create(data_link_layer, 100);
    return sd_rpc_adapter_create(transport_layer);
}

/**@brief Function for converting a BLE address to a string.
 *
 * @param[in] address       Bluetooth Low Energy address.
 * @param[out] string_buffer The serial port the target nRF5 device is connected to.
 */
static void ble_address_to_string_convert(ble_gap_addr_t address, uint8_t * string_buffer)
{
    const int address_length = 6;
    char      temp_str[3];

    for (int i = address_length - 1; i &amp;gt;= 0; --i)
    {
        sprintf(temp_str, &amp;quot;%02X&amp;quot;, address.addr[i]);
        strcat((char *)string_buffer, temp_str);
    }
}

/**
 * @brief Parses advertisement data, providing length and location of the field in case
 *        matching data is found.
 *
 * @param[in]  Type of data to be looked for in advertisement data.
 * @param[in]  Advertisement report length and pointer to report.
 * @param[out] If data type requested is found in the data report, type data length and
 *             pointer to data will be populated here.
 *
 * @retval NRF_SUCCESS if the data type is found in the report.
 * @retval NRF_ERROR_NOT_FOUND if the data type could not be found.
 */
static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata)
{
    uint32_t  index = 0;
    uint8_t * p_data;

    p_data = p_advdata-&amp;gt;p_data;

    while (index &amp;lt; p_advdata-&amp;gt;data_len)
    {
        uint8_t field_length = p_data[index];
        uint8_t field_type   = p_data[index + 1];

        if (field_type == type)
        {
            p_typedata-&amp;gt;p_data   = &amp;amp;p_data[index + 2];
            p_typedata-&amp;gt;data_len = field_length - 1;
            return NRF_SUCCESS;
        }
        index += field_length + 1;
    }
    return NRF_ERROR_NOT_FOUND;
}

/**@brief Function for searching a given name in the advertisement packets.
 *
 * @details Use this function to parse received advertising data and to find a given
 * name in them either as &amp;#39;complete_local_name&amp;#39; or as &amp;#39;short_local_name&amp;#39;.
 *
 * @param[in]   p_adv_report   advertising data to parse.
 * @param[in]   name_to_find   name to search.
 * @return   true if the given name was found, false otherwise.
 */
static bool find_adv_name(const ble_gap_evt_adv_report_t *p_adv_report, const char * name_to_find)
{
    uint32_t err_code;
    data_t   adv_data;
    data_t   dev_name;

    // Initialize advertisement report for parsing
#if NRF_SD_BLE_API &amp;gt;= 6
    adv_data.p_data     = (uint8_t *)p_adv_report-&amp;gt;data.p_data;
    adv_data.data_len   = p_adv_report-&amp;gt;data.len;
#else
    adv_data.p_data     = (uint8_t *)p_adv_report-&amp;gt;data;
    adv_data.data_len   = p_adv_report-&amp;gt;dlen;
#endif

    //search for advertising names
    err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,
                                &amp;amp;adv_data,
                                &amp;amp;dev_name);
    if (err_code == NRF_SUCCESS)
    {
        if (memcmp(name_to_find, dev_name.p_data, dev_name.data_len )== 0)
        {
            return true;
        }
    }
    else
    {
        // Look for the short local name if it was not found as complete
        err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME,
                                    &amp;amp;adv_data,
                                    &amp;amp;dev_name);
        if (err_code != NRF_SUCCESS)
        {
            return false;
        }
        if (memcmp(name_to_find, dev_name.p_data, dev_name.data_len )== 0)
        {
            return true;
        }
    }
    return false;
}

/**@brief Function for initializing the BLE stack.
 *
 * @return NRF_SUCCESS on success, otherwise an error code.
 */
static uint32_t ble_stack_init()
{
    uint32_t            err_code;
    uint32_t *          app_ram_base = NULL;

#if NRF_SD_BLE_API &amp;lt;= 3
    ble_enable_params_t ble_enable_params;
    memset(&amp;amp;ble_enable_params, 0, sizeof(ble_enable_params));
#endif

#if NRF_SD_BLE_API == 3
    ble_enable_params.gatt_enable_params.att_mtu = GATT_MTU_SIZE_DEFAULT;
#elif NRF_SD_BLE_API &amp;lt; 3
    ble_enable_params.gatts_enable_params.attr_tab_size     = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
    ble_enable_params.gatts_enable_params.service_changed   = false;
    ble_enable_params.common_enable_params.p_conn_bw_counts = NULL;
    ble_enable_params.common_enable_params.vs_uuid_count    = 1;
#endif

#if NRF_SD_BLE_API &amp;lt;= 3
    ble_enable_params.gap_enable_params.periph_conn_count   = 1;
    ble_enable_params.gap_enable_params.central_conn_count  = 1;
    ble_enable_params.gap_enable_params.central_sec_count   = 1;

    err_code = sd_ble_enable(m_adapter, &amp;amp;ble_enable_params, app_ram_base);
#else
    err_code = sd_ble_enable(m_adapter, app_ram_base);
#endif

    switch (err_code) {
        case NRF_SUCCESS:
            break;
        case NRF_ERROR_INVALID_STATE:
            printf(&amp;quot;BLE stack already enabled\n&amp;quot;);
            fflush(stdout);
            break;
        default:
            printf(&amp;quot;Failed to enable BLE stack. Error code: %d\n&amp;quot;, err_code);
            fflush(stdout);
            break;
    }

    return err_code;
}

#if NRF_SD_BLE_API &amp;lt; 5
/**@brief Set BLE option for the BLE role and connection bandwidth.
 *
 * @return NRF_SUCCESS on option set successfully, otherwise an error code.
 */
static uint32_t ble_options_set()
{
#if NRF_SD_BLE_API &amp;lt;= 3
    ble_opt_t        opt;
    ble_common_opt_t common_opt;

    common_opt.conn_bw.role                 = BLE_GAP_ROLE_CENTRAL;
    common_opt.conn_bw.conn_bw.conn_bw_rx   = BLE_CONN_BW_HIGH;
    common_opt.conn_bw.conn_bw.conn_bw_tx   = BLE_CONN_BW_HIGH;
    opt.common_opt                          = common_opt;

    return sd_ble_opt_set(m_adapter, BLE_COMMON_OPT_CONN_BW, &amp;amp;opt);
#else
    return NRF_ERROR_NOT_SUPPORTED;
#endif
}
#endif

#if NRF_SD_BLE_API &amp;gt;= 5
/**@brief Function for setting configuration for the BLE stack.
 *
 * @return NRF_SUCCESS on success, otherwise an error code.
 */
static uint32_t ble_cfg_set(uint8_t conn_cfg_tag)
{
    const uint32_t ram_start = 0; // Value is not used by ble-driver
    uint32_t error_code;
    ble_cfg_t ble_cfg;

    // Configure the connection roles.
    memset(&amp;amp;ble_cfg, 0, sizeof(ble_cfg));

#if NRF_SD_BLE_API &amp;gt;= 6
    ble_cfg.gap_cfg.role_count_cfg.adv_set_count        = BLE_GAP_ADV_SET_COUNT_DEFAULT;
#endif
    ble_cfg.gap_cfg.role_count_cfg.periph_role_count    = 0;
    ble_cfg.gap_cfg.role_count_cfg.central_role_count   = 1;
    ble_cfg.gap_cfg.role_count_cfg.central_sec_count    = 0;

    error_code = sd_ble_cfg_set(m_adapter, BLE_GAP_CFG_ROLE_COUNT, &amp;amp;ble_cfg, ram_start);
    if (error_code != NRF_SUCCESS)
    {
        printf(&amp;quot;sd_ble_cfg_set() failed when attempting to set BLE_GAP_CFG_ROLE_COUNT. Error code: 0x%02X\n&amp;quot;, error_code);
        fflush(stdout);
        return error_code;
    }

    memset(&amp;amp;ble_cfg, 0x00, sizeof(ble_cfg));
    ble_cfg.conn_cfg.conn_cfg_tag                 = conn_cfg_tag;
    ble_cfg.conn_cfg.params.gatt_conn_cfg.att_mtu = 150;

    error_code = sd_ble_cfg_set(m_adapter, BLE_CONN_CFG_GATT, &amp;amp;ble_cfg, ram_start);
    if (error_code != NRF_SUCCESS)
    {
        printf(&amp;quot;sd_ble_cfg_set() failed when attempting to set BLE_CONN_CFG_GATT. Error code: 0x%02X\n&amp;quot;, error_code);
        fflush(stdout);
        return error_code;
    }

    return NRF_SUCCESS;
}
#endif

/**@brief Start scanning (GAP Discovery procedure, Observer Procedure).
 * *
 * @return NRF_SUCCESS on successfully initiating scanning procedure, otherwise an error code.
 */
static uint32_t scan_start()
{
#if NRF_SD_BLE_API &amp;gt;= 6
    m_adv_report_buffer.p_data = mp_data;
    m_adv_report_buffer.len = sizeof(mp_data);
#endif

    uint32_t error_code = sd_ble_gap_scan_start(m_adapter, &amp;amp;m_scan_param
#if NRF_SD_BLE_API &amp;gt;= 6
    , &amp;amp;m_adv_report_buffer
#endif
    );

    if (error_code != NRF_SUCCESS)
    {
        printf(&amp;quot;Scan start failed with error code: %d\n&amp;quot;, error_code);
        fflush(stdout);
    } else
    {
        printf(&amp;quot;Scan started\n&amp;quot;);
        fflush(stdout);
    }

    return error_code;
}

/**@brief Function called upon connecting to BLE peripheral.
 *
 * @details Initiates primary service discovery.
 *
 * @return NRF_SUCCESS on success, otherwise an error code.
 */
static uint32_t service_discovery_start()
{
    uint32_t   err_code;
    uint16_t   start_handle = 0x01;
    ble_uuid_t srvc_uuid;

    printf(&amp;quot;Discovering primary services\n&amp;quot;);
    fflush(stdout);

    srvc_uuid.type = BLE_UUID_TYPE_BLE;
    srvc_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;

    // Initiate procedure to find the primary BLE_UUID_HEART_RATE_SERVICE.
    err_code = sd_ble_gattc_primary_services_discover(m_adapter,
                                                      m_connection_handle, start_handle,
                                                      &amp;amp;srvc_uuid);
    if (err_code != NRF_SUCCESS)
    {
        printf(&amp;quot;Failed to initiate or continue a GATT Primary Service Discovery procedure\n&amp;quot;);
        fflush(stdout);
    }

    return err_code;
}

/**@brief Function called upon discovering a BLE peripheral&amp;#39;s primary service(s).
 *
 * @details Initiates service&amp;#39;s (m_service) characteristic discovery.
 *
 * @return NRF_SUCCESS on success, otherwise an error code.
 */
static uint32_t char_discovery_start()
{
    ble_gattc_handle_range_t handle_range;

    printf(&amp;quot;Discovering characteristics\n&amp;quot;);
    fflush(stdout);

    handle_range.start_handle = m_service_start_handle;
    handle_range.end_handle = m_service_end_handle;

    return sd_ble_gattc_characteristics_discover(m_adapter, m_connection_handle, &amp;amp;handle_range);
}

/**@brief Function called upon discovering service&amp;#39;s characteristics.
 *
 * @details Initiates heart rate monitor (m_hrm_char_handle) characteristic&amp;#39;s descriptor discovery.
 *
 * @return NRF_SUCCESS on success, otherwise an error code.
 */
static uint32_t descr_discovery_start()
{
    ble_gattc_handle_range_t handle_range;

    printf(&amp;quot;Discovering characteristic&amp;#39;s descriptors\n&amp;quot;);
    fflush(stdout);

    if (m_hrm_char_handle == 0)
    {
        printf(&amp;quot;No heart rate measurement characteristic handle found\n&amp;quot;);
        fflush(stdout);
        return NRF_ERROR_INVALID_STATE;
    }

    handle_range.start_handle   = m_hrm_char_handle;
    handle_range.end_handle     = m_service_end_handle;

    return sd_ble_gattc_descriptors_discover(m_adapter, m_connection_handle, &amp;amp;handle_range);
}

/**@brief Function that write&amp;#39;s the HRM characteristic&amp;#39;s CCCD.
 * *
 * @return NRF_SUCCESS on success, otherwise an error code.
 */
static uint32_t hrm_cccd_set(uint8_t value)
{
    ble_gattc_write_params_t write_params;
    uint8_t                  cccd_value[2] = {value, 0};

    printf(&amp;quot;Setting HRM CCCD\n&amp;quot;);
    fflush(stdout);

    if (m_hrm_cccd_handle == 0)
    {
        printf(&amp;quot;Error. No CCCD handle has been found\n&amp;quot;);
        fflush(stdout);
        return NRF_ERROR_INVALID_STATE;
    }

    write_params.handle     = m_hrm_cccd_handle;
    write_params.len        = 2;
    write_params.p_value    = cccd_value;
    write_params.write_op   = BLE_GATT_OP_WRITE_REQ;
    write_params.offset     = 0;

    return sd_ble_gattc_write(m_adapter, m_connection_handle, &amp;amp;write_params);
}


/** Event functions */

/**@brief Function called on BLE_GAP_EVT_CONNECTED event.
 *
 * @details Update connection state and proceed to discovering the peer&amp;#39;s GATT services.
 *
 * @param[in] p_ble_gap_evt GAP event.
 */
static void on_connected(const ble_gap_evt_t * const p_ble_gap_evt)
{
    printf(&amp;quot;Connection established\n&amp;quot;);
    fflush(stdout);

    m_connected_devices++;
    m_connection_handle         = p_ble_gap_evt-&amp;gt;conn_handle;
    m_connection_is_in_progress = false;

    service_discovery_start();
}

/**@brief Function called on BLE_GAP_EVT_ADV_REPORT event.
 *
 * @details Create a connection if received advertising packet corresponds to desired BLE device.
 *
 * @param[in] p_ble_gap_evt Advertising Report Event.
 */
static void on_adv_report(const ble_gap_evt_t * const p_ble_gap_evt)
{
    uint32_t err_code;
    uint8_t  str[STRING_BUFFER_SIZE] = {0};

    // Log the Bluetooth device address of advertisement packet received.
    ble_address_to_string_convert(p_ble_gap_evt-&amp;gt;params.adv_report.peer_addr, str);
    printf(&amp;quot;Received advertisement report with device address: 0x%s\n&amp;quot;, str);
    fflush(stdout);

    if (find_adv_name(&amp;amp;p_ble_gap_evt-&amp;gt;params.adv_report, TARGET_DEV_NAME))
    {
        if (m_connected_devices &amp;gt;= MAX_PEER_COUNT || m_connection_is_in_progress)
        {
            return;
        }

        err_code = sd_ble_gap_connect(m_adapter,
                                      &amp;amp;(p_ble_gap_evt-&amp;gt;params.adv_report.peer_addr),
                                      &amp;amp;m_scan_param,
                                      &amp;amp;m_connection_param
#if NRF_SD_BLE_API &amp;gt;= 5
                                     , m_config_id
#endif
                                     );
        if (err_code != NRF_SUCCESS)
        {
            printf(&amp;quot;Connection Request Failed, reason %d\n&amp;quot;, err_code);
            fflush(stdout);
            return;
        }

        m_connection_is_in_progress = true;
    }
#if NRF_SD_BLE_API &amp;gt;= 6
    else {
        err_code = sd_ble_gap_scan_start(m_adapter, NULL, &amp;amp;m_adv_report_buffer);

        if (err_code != NRF_SUCCESS)
        {
            printf(&amp;quot;Scan start failed with error code: %d\n&amp;quot;, err_code);
            fflush(stdout);
        }
        else
        {
            printf(&amp;quot;Scan started\n&amp;quot;);
            fflush(stdout);
        }
    }
#endif

}

/**@brief Function called on BLE_GAP_EVT_TIMEOUT event.
 *
 * @param[in] ble_gap_evt_t Timeout Event.
 */
static void on_timeout(const ble_gap_evt_t * const p_ble_gap_evt)
{
    if (p_ble_gap_evt-&amp;gt;params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
    {
        m_connection_is_in_progress = false;
    }
    else if (p_ble_gap_evt-&amp;gt;params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
    {
        scan_start();
    }
}

/**@brief Function called on BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP event.
 *
 * @details Update service state and proceed to discovering the service&amp;#39;s GATT characteristics.
 *
 * @param[in] p_ble_gattc_evt Primary Service Discovery Response Event.
 */
static void on_service_discovery_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    int count;
    int service_index;
    const ble_gattc_service_t * service;

    printf(&amp;quot;Received service discovery response\n&amp;quot;);
    fflush(stdout);

    if (p_ble_gattc_evt-&amp;gt;gatt_status != NRF_SUCCESS)
    {
        printf(&amp;quot;Service discovery failed. Error code 0x%X\n&amp;quot;, p_ble_gattc_evt-&amp;gt;gatt_status);
        fflush(stdout);
        return;
    }

    count = p_ble_gattc_evt-&amp;gt;params.prim_srvc_disc_rsp.count;

    if (count == 0)
    {
        printf(&amp;quot;Service not found\n&amp;quot;);
        fflush(stdout);
        return;
    }

    if (count &amp;gt; 1)
    {
        printf(&amp;quot;Warning, discovered multiple primary services. Ignoring all but the first\n&amp;quot;);
    }

    service_index = 0; /* We expect to discover only the Heart Rate service as requested. */
    service = &amp;amp;(p_ble_gattc_evt-&amp;gt;params.prim_srvc_disc_rsp.services[service_index]);

    if (service-&amp;gt;uuid.uuid != BLE_UUID_HEART_RATE_SERVICE)
    {
        printf(&amp;quot;Unknown service discovered with UUID: 0x%04X\n&amp;quot;, service-&amp;gt;uuid.uuid);
        fflush(stdout);
        return;
    }

    m_service_start_handle  = service-&amp;gt;handle_range.start_handle;
    m_service_end_handle    = service-&amp;gt;handle_range.end_handle;

    printf(&amp;quot;Discovered heart rate service. UUID: 0x%04X, &amp;quot;
                   &amp;quot;start handle: 0x%04X, end handle: 0x%04X\n&amp;quot;,
        service-&amp;gt;uuid.uuid, m_service_start_handle, m_service_end_handle);
    fflush(stdout);

    char_discovery_start();
}

/**@brief Function called on BLE_GATTC_EVT_CHAR_DISC_RSP event.
 *
 * @details Update characteristic state and proceed to discovering the characteristicss descriptors.
 *
 * @param[in] p_ble_gattc_evt Characteristic Discovery Response Event.
 */
static void on_characteristic_discovery_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    int count = p_ble_gattc_evt-&amp;gt;params.char_disc_rsp.count;

    if (p_ble_gattc_evt-&amp;gt;gatt_status != NRF_SUCCESS)
    {
        printf(&amp;quot;Characteristic discovery failed. Error code 0x%X\n&amp;quot;, p_ble_gattc_evt-&amp;gt;gatt_status);
        fflush(stdout);
        return;
    }

    printf(&amp;quot;Received characteristic discovery response, characteristics count: %d\n&amp;quot;, count);
    fflush(stdout);

    for (int i = 0; i &amp;lt; count; i++)
    {
        printf(&amp;quot;Characteristic handle: 0x%04X, UUID: 0x%04X\n&amp;quot;,
               p_ble_gattc_evt-&amp;gt;params.char_disc_rsp.chars[i].handle_decl,
               p_ble_gattc_evt-&amp;gt;params.char_disc_rsp.chars[i].uuid.uuid);
        fflush(stdout);

        if (p_ble_gattc_evt-&amp;gt;params.char_disc_rsp.chars[i].uuid.uuid ==
            BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)
        {
            m_hrm_char_handle = p_ble_gattc_evt-&amp;gt;params.char_disc_rsp.chars[i].handle_decl;
        }
    }

    descr_discovery_start();
}

/**@brief Function called on BLE_GATTC_EVT_DESC_DISC_RSP event.
 *
 * @details Update CCCD descriptor state and proceed to prompting user to toggle notifications.
 *
 * @param[in] p_ble_gattc_evt Descriptor Discovery Response Event.
 */
static void on_descriptor_discovery_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    int count = p_ble_gattc_evt-&amp;gt;params.desc_disc_rsp.count;

    if (p_ble_gattc_evt-&amp;gt;gatt_status != NRF_SUCCESS)
    {
        printf(&amp;quot;Descriptor discovery failed. Error code 0x%X\n&amp;quot;, p_ble_gattc_evt-&amp;gt;gatt_status);
        fflush(stdout);
        return;
    }

    printf(&amp;quot;Received descriptor discovery response, descriptor count: %d\n&amp;quot;, count);
    fflush(stdout);

    for (int i = 0; i &amp;lt; count; i++)
    {
        printf(&amp;quot;Descriptor handle: 0x%04X, UUID: 0x%04X\n&amp;quot;,
               p_ble_gattc_evt-&amp;gt;params.desc_disc_rsp.descs[i].handle,
               p_ble_gattc_evt-&amp;gt;params.desc_disc_rsp.descs[i].uuid.uuid);
        fflush(stdout);

        if (p_ble_gattc_evt-&amp;gt;params.desc_disc_rsp.descs[i].uuid.uuid == BLE_UUID_CCCD)
        {
            m_hrm_cccd_handle = p_ble_gattc_evt-&amp;gt;params.desc_disc_rsp.descs[i].handle;
            printf(&amp;quot;Press enter to toggle notifications on the HRM characteristic\n&amp;quot;);
            fflush(stdout);
        }
    }
}

/**@brief Function called on BLE_GATTC_EVT_WRITE_RSP event.
 *
 * @param[in] p_ble_gattc_evt Write Response Event.
 */
static void on_write_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    printf(&amp;quot;Received write response.\n&amp;quot;);
    fflush(stdout);

    if (p_ble_gattc_evt-&amp;gt;gatt_status != NRF_SUCCESS)
    {
        printf(&amp;quot;Error. Write operation failed. Error code 0x%X\n&amp;quot;, p_ble_gattc_evt-&amp;gt;gatt_status);
        fflush(stdout);
    }
}

/**@brief Function called on BLE_GATTC_EVT_HVX event.
 *
 * @details Logs the received heart rate measurement.
 *
 * @param[in] p_ble_gattc_evt Handle Value Notification/Indication Event.
 */
static void on_hvx(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    if (p_ble_gattc_evt-&amp;gt;params.hvx.handle &amp;gt;= m_hrm_char_handle ||
            p_ble_gattc_evt-&amp;gt;params.hvx.handle &amp;lt;= m_hrm_cccd_handle) // Heart rate measurement.
    {
        // We know the heart rate reading is encoded as 2 bytes [flag, value].
        printf(&amp;quot;Received heart rate measurement: %d\n&amp;quot;, p_ble_gattc_evt-&amp;gt;params.hvx.data[1]);
    }
    else // Unknown data.
    {
        printf(&amp;quot;Un-parsed data received on handle: %04X\n&amp;quot;, p_ble_gattc_evt-&amp;gt;params.hvx.handle);
    }

    fflush(stdout);
}

/**@brief Function called on BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST event.
 *
 * @details Update GAP connection parameters.
 *
 * @param[in] p_ble_gap_evt Connection Parameter Update Event.
 */
static void on_conn_params_update_request(const ble_gap_evt_t * const p_ble_gap_evt)
{
    uint32_t err_code = sd_ble_gap_conn_param_update(m_adapter, m_connection_handle,
                                            &amp;amp;(p_ble_gap_evt-&amp;gt;
                                                    params.conn_param_update_request.conn_params));
    if (err_code != NRF_SUCCESS)
    {
        printf(&amp;quot;Conn params update failed, err_code %d\n&amp;quot;, err_code);
        fflush(stdout);
    }
}

#if NRF_SD_BLE_API &amp;gt;= 3
/**@brief Function called on BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event.
 *
 * @details Replies to an ATT_MTU exchange request by sending an Exchange MTU Response to the client.
 *
 * @param[in] p_ble_gatts_evt Exchange MTU Request Event.
 */
static void on_exchange_mtu_request(const ble_gatts_evt_t * const p_ble_gatts_evt)
{
    uint32_t err_code = sd_ble_gatts_exchange_mtu_reply(
        m_adapter,
        m_connection_handle,
#if NRF_SD_BLE_API &amp;lt; 5
        GATT_MTU_SIZE_DEFAULT);
#else
        BLE_GATT_ATT_MTU_DEFAULT);
#endif

    if (err_code != NRF_SUCCESS)
    {
        printf(&amp;quot;MTU exchange request reply failed, err_code %d\n&amp;quot;, err_code);
        fflush(stdout);
    }
}

/**@brief Function called on BLE_GATTC_EVT_EXCHANGE_MTU_RSP event.
 *
 * @details Logs the new BLE server RX MTU size.
 *
 * @param[in] p_ble_gattc_evt Exchange MTU Response Event.
 */
static void on_exchange_mtu_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
    uint16_t server_rx_mtu = p_ble_gattc_evt-&amp;gt;params.exchange_mtu_rsp.server_rx_mtu;

    printf(&amp;quot;MTU response received. New ATT_MTU is %d\n&amp;quot;, server_rx_mtu);
    fflush(stdout);
}
#endif


static void on_conn_data_length_update_request(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	printf(&amp;quot;BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST received\n&amp;quot;);

	ble_gap_data_length_params_t const dlp =
	{
		.max_rx_octets = 27,
		.max_tx_octets = 27,
		.max_rx_time_us = BLE_GAP_DATA_LENGTH_AUTO,
		.max_tx_time_us = BLE_GAP_DATA_LENGTH_AUTO,
	};

	ble_gap_data_length_limitation_t dll = { 0 };

	uint32_t err_code = sd_ble_gap_data_length_update(m_adapter, m_connection_handle, &amp;amp;dlp, &amp;amp;dll);
	if (err_code != NRF_SUCCESS) 
	{
		printf(&amp;quot;sd_ble_gap_data_length_update failed, err_code %d\n&amp;quot;, err_code);
	}

}


/** Event dispatcher */

/**@brief Function for handling the Application&amp;#39;s BLE Stack events.
 *
 * @param[in] adapter The transport adapter.
 * @param[in] p_ble_evt Bluetooth stack event.
 */
static void ble_evt_dispatch(adapter_t * adapter, ble_evt_t * p_ble_evt)
{
    if (p_ble_evt == NULL)
    {
        printf(&amp;quot;Received an empty BLE event\n&amp;quot;);
        fflush(stdout);
        return;
    }



    switch (p_ble_evt-&amp;gt;header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connected(&amp;amp;(p_ble_evt-&amp;gt;evt.gap_evt));
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            printf(&amp;quot;Disconnected, reason: 0x%02X\n&amp;quot;,
                   p_ble_evt-&amp;gt;evt.gap_evt.params.disconnected.reason);
            fflush(stdout);
            m_connected_devices--;
            m_connection_handle = 0;
            break;

        case BLE_GAP_EVT_ADV_REPORT:
            on_adv_report(&amp;amp;(p_ble_evt-&amp;gt;evt.gap_evt));
            break;

        case BLE_GAP_EVT_TIMEOUT:
            on_timeout(&amp;amp;(p_ble_evt-&amp;gt;evt.gap_evt));
            break;

        case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
            on_service_discovery_response(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
            break;

        case BLE_GATTC_EVT_CHAR_DISC_RSP:
            on_characteristic_discovery_response(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
            break;

        case BLE_GATTC_EVT_DESC_DISC_RSP:
            on_descriptor_discovery_response(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
            break;

        case BLE_GATTC_EVT_WRITE_RSP:
            on_write_response(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
            break;

        case BLE_GATTC_EVT_HVX:
            on_hvx(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
            break;

        case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
            on_conn_params_update_request(&amp;amp;(p_ble_evt-&amp;gt;evt.gap_evt));
            break;

		case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
			on_conn_data_length_update_request(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
			break;

		case BLE_GAP_EVT_DATA_LENGTH_UPDATE:
			printf(&amp;quot;LL Data Channel PDU payload length updated\n&amp;quot;);	
			break;

		case BLE_GAP_EVT_CONN_PARAM_UPDATE:

			printf(&amp;quot;BLE_GAP_EVT_CONN_PARAM_UPDATE: max %d and min %d\n&amp;quot;,
				p_ble_evt-&amp;gt;evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval*UNIT_1_25_MS / 1000,
				p_ble_evt-&amp;gt;evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval*UNIT_1_25_MS / 1000);
			break;

    #if NRF_SD_BLE_API &amp;gt;= 3
        case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
            on_exchange_mtu_request(&amp;amp;(p_ble_evt-&amp;gt;evt.gatts_evt));
            break;

        case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
            on_exchange_mtu_response(&amp;amp;(p_ble_evt-&amp;gt;evt.gattc_evt));
            break;
    #endif

        default:
            printf(&amp;quot;Received an un-handled event with ID: %d\n&amp;quot;, p_ble_evt-&amp;gt;header.evt_id);
            fflush(stdout);
            break;
    }
}


/** Main */

/**@brief Function for application main entry.
 *
 * @param[in] argc Number of arguments (program expects 0 or 1 arguments).
 * @param[in] argv The serial port and baud rate of the target nRF5 device (Optional).
 */
int main(int argc, char * argv[])
{
    uint32_t error_code;
    char *   serial_port = DEFAULT_UART_PORT_NAME;
    uint32_t baud_rate = DEFAULT_BAUD_RATE;
    uint8_t  cccd_value = 0;

    if (argc &amp;gt; 2)
    {
        if (strcmp(argv[2], &amp;quot;1000000&amp;quot;) == 0)
        {
            baud_rate = 1000000;
        }
        else if (strcmp(argv[2], &amp;quot;115200&amp;quot;) == 0)
        {
            baud_rate = 115200;
        }
        else
        {
            printf(&amp;quot;Supported baud rate values are: 115200, 1000000\n&amp;quot;);
            fflush(stdout);
        }
    }

    if (argc &amp;gt; 1)
    {
        serial_port = argv[1];
    }

    printf(&amp;quot;Serial port used: %s\n&amp;quot;, serial_port);
    printf(&amp;quot;Baud rate used: %d\n&amp;quot;, baud_rate);
    fflush(stdout);

    m_adapter =  adapter_init(serial_port, baud_rate);
    sd_rpc_log_handler_severity_filter_set(m_adapter, SD_RPC_LOG_INFO);
    error_code = sd_rpc_open(m_adapter, status_handler, ble_evt_dispatch, log_handler);

    if (error_code != NRF_SUCCESS)
    {
        printf(&amp;quot;Failed to open nRF BLE Driver. Error code: 0x%02X\n&amp;quot;, error_code);
        fflush(stdout);
        return error_code;
    }

#if NRF_SD_BLE_API &amp;gt;= 5
    ble_cfg_set(m_config_id);
#endif

    error_code = ble_stack_init();

    if (error_code != NRF_SUCCESS)
    {
        return error_code;
    }

#if NRF_SD_BLE_API &amp;lt; 5
    error_code = ble_options_set();

    if (error_code != NRF_SUCCESS)
    {
        return error_code;
    }
#endif

    error_code = scan_start();

    if (error_code != NRF_SUCCESS)
    {
        return error_code;
    }

    // Endlessly loop.
    for (;;)
    {
        char c = (char)getchar();
        if (c == &amp;#39;q&amp;#39; || c == &amp;#39;Q&amp;#39;)
        {
            error_code = sd_rpc_close(m_adapter);

            if (error_code != NRF_SUCCESS)
            {
                printf(&amp;quot;Failed to close nRF BLE Driver. Error code: 0x%02X\n&amp;quot;, error_code);
                fflush(stdout);
                return error_code;
            }

            printf(&amp;quot;Closed\n&amp;quot;);
            fflush(stdout);

            return NRF_SUCCESS;
        }

        // Toggle notifications on the HRM characteristic every time user input is received.
        cccd_value ^= BLE_CCCD_NOTIFY;
        hrm_cccd_set(cccd_value);
    }
}
&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;3) You can find the documentation for the example &lt;a href="https://www.nordicsemi.com/DocLib/Content/SDK_Doc/nRF5_SDK/v15-2-0/ble_sdk_app_hrs"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>