<?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>Discovery in nRF Connect/Zephyr as *discovery*</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/93368/discovery-in-nrf-connect-zephyr-as-discovery</link><description>Hi, I&amp;#39;m new to nRF Connect, coming from the SDK. I&amp;#39;m building a Central/Peripheral system and I&amp;#39;ve got to the point where the Central is discovering what services and attributes the Peripheral provides. 
 The only Zephyr samples in which discovery is</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Wed, 21 May 2025 17:39:55 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/93368/discovery-in-nrf-connect-zephyr-as-discovery" /><item><title>RE: Discovery in nRF Connect/Zephyr as *discovery*</title><link>https://devzone.nordicsemi.com/thread/536507?ContentTypeID=1</link><pubDate>Wed, 21 May 2025 17:39:55 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:93772af1-8f01-4196-9e32-ed8b952529fb</guid><dc:creator>ScottOnDevZone</dc:creator><description>&lt;p&gt;You rock! Thank you.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Discovery in nRF Connect/Zephyr as *discovery*</title><link>https://devzone.nordicsemi.com/thread/471761?ContentTypeID=1</link><pubDate>Fri, 01 Mar 2024 11:20:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:cd1793a8-f383-4c6c-b405-0b7488c83333</guid><dc:creator>upupsky</dc:creator><description>&lt;p&gt;yes, it solve my problems. thanks!!!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Discovery in nRF Connect/Zephyr as *discovery*</title><link>https://devzone.nordicsemi.com/thread/464495?ContentTypeID=1</link><pubDate>Wed, 17 Jan 2024 02:46:09 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:96a46bf8-371f-4480-898e-fc57b6ea2863</guid><dc:creator>alessandra_rivera</dc:creator><description>&lt;p&gt;This was my exact problem with the discover function. I am also new to nRF Connect and I&amp;#39;ve been trying to figure out how to get this done. You have saved me a lot of time my friend. thank you. &lt;span class="emoticon" data-url="https://devzone.nordicsemi.com/cfs-file/__key/system/emoji/1f642.svg" title="Slight smile"&gt;&amp;#x1f642;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Discovery in nRF Connect/Zephyr as *discovery*</title><link>https://devzone.nordicsemi.com/thread/393089?ContentTypeID=1</link><pubDate>Fri, 28 Oct 2022 21:24:23 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b26983bd-ad11-4b7a-8a6c-b47b87053373</guid><dc:creator>David Ormand</dc:creator><description>&lt;p&gt;Answer to my own question.&lt;/p&gt;
&lt;p&gt;If I continue doing bt_gatt_discover() calls, the first&amp;nbsp;BT_UUID_GATT_PRIMARY object has a UUID of 0x1801 (&amp;nbsp;BT_UUID_GATT).&amp;nbsp; After the next call, I get a&amp;nbsp;&lt;span&gt;BT_UUID_GATT_PRIMARY&amp;nbsp;with UUID of 0x1800 (BT_UUID_GAP).&amp;nbsp; After the next call, I get a&amp;nbsp;BT_UUID_GATT_PRIMARY&amp;nbsp;with the UUID of my custom service.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;So it is in fact there.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Another interesting thing is, my custom service has one Notify characteristic with an associated CCCD.&amp;nbsp; The first&amp;nbsp;bt_gatt_discover() looking for&amp;nbsp;&lt;/span&gt;BT_GATT_DISCOVER_DESCRIPTOR, I get an attr-&amp;gt;uuid which is the UUID of this Notify characteristic.&amp;nbsp; After the next call, I get a 16-bit UUID with value 0x2902, which is&amp;nbsp;BT_UUID_GATT_CCC.&amp;nbsp; These two return episodes have different handles, and I&amp;#39;m thinking the first one is the one to use to subscribe to the notification, because that&amp;#39;s what central_ht does.&lt;/p&gt;
&lt;p&gt;My working code now looks like:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;enum DISCOVER_PHASE {
    DISC_PHASE_SERVICE,        /* Looking for Service UUIDs */
    DISC_PHASE_CHRC,           /* Looking for Characteristic UUIDs */
    DISC_PHASE_CCCD,           /* Looking for CCCDs */
};
typedef enum DISCOVER_PHASE discover_phase_t;
/* Phase of attribute discovery process */
static discover_phase_t discover_phase;
static uint16_t cccd_handle;   /* Handle to Notify CCCD for Report */
static uint16_t ctrl_handle;   /* Handle for Control Characteristic */
static uint16_t rpt_handle;    /* Handle for Report Characteristic */
.
.
.
static uint8_t discover_func(struct bt_conn *conn,
			     const struct bt_gatt_attr *attr,
			     struct bt_gatt_discover_params *params)
{
    static uint16_t last_handle;
	int err;

    /* @@@ */
    if(attr) {
        printk(&amp;quot;[ATTRIBUTE] handle %u\n&amp;quot;, attr-&amp;gt;handle);

        printk(&amp;quot;uuid type = %d, val=%x\n&amp;quot;, attr-&amp;gt;uuid-&amp;gt;type, BT_UUID_16(attr-&amp;gt;uuid)-&amp;gt;val);
    }
    /* @@@ */

    switch(discover_phase) {
        case DISC_PHASE_SERVICE:
            if(attr) {
                /* Getting here, attr-&amp;gt;uuid will be BT_UUID_GATT_PRIMARY */
                struct bt_gatt_service_val *svc_attr = attr-&amp;gt;user_data;
                printk(&amp;quot;attr is a primary service.  UUID type is %d, val = %x\n&amp;quot;,
                        svc_attr-&amp;gt;uuid-&amp;gt;type, BT_UUID_16(svc_attr-&amp;gt;uuid)-&amp;gt;val);
                if(!bt_uuid_cmp(svc_attr-&amp;gt;uuid, &amp;amp;cis_svc_uuid.uuid)) {
                    printk(&amp;quot;Found custom service\n&amp;quot;);
                }
                last_handle = attr-&amp;gt;handle;
            }
            else {
                /* No more service UUIDs.  Look for Characteristics. */
                printk(&amp;quot;No more services, looking for characteristics\n&amp;quot;);
                discover_params.uuid = NULL;
                discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
                discover_params.start_handle = last_handle + 1;

                err = bt_gatt_discover(conn, &amp;amp;discover_params);
                if (err) {
                    printk(&amp;quot;Discover failed - svc (err %d)\n&amp;quot;, err);
                }
                discover_phase = DISC_PHASE_CHRC;
                return BT_GATT_ITER_STOP;
            }

            break;

        case DISC_PHASE_CHRC:
            if(attr) {
                /* Getting here, attr-&amp;gt;uuid will be BT_UUID_GATT_CHRC */
                struct bt_gatt_chrc *chrc_attr = attr-&amp;gt;user_data;
                printk(&amp;quot;attr is a characteristic.  UUID type is %d, val = %x\n&amp;quot;,
                        chrc_attr-&amp;gt;uuid-&amp;gt;type, BT_UUID_16(chrc_attr-&amp;gt;uuid)-&amp;gt;val);
                if(!bt_uuid_cmp(chrc_attr-&amp;gt;uuid, &amp;amp;cis_control_char_uuid.uuid)) {
                    printk(&amp;quot;Found Control characteristic\n&amp;quot;);
                    ctrl_handle = attr-&amp;gt;handle;
                }
                if(!bt_uuid_cmp(chrc_attr-&amp;gt;uuid, &amp;amp;cis_report_char_uuid.uuid)) {
                    printk(&amp;quot;Found Report characteristic\n&amp;quot;);
                    rpt_handle = attr-&amp;gt;handle;
                }
                last_handle = attr-&amp;gt;handle;
            }
            else {
                /* Ran out of characteristics, look for CCCDs */
                printk(&amp;quot;No more characteristics, looking for CCCDs\n&amp;quot;);
                discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
        		discover_params.start_handle = attr-&amp;gt;handle + 1;
                discover_params.start_handle = last_handle + 1;

                err = bt_gatt_discover(conn, &amp;amp;discover_params);
                if (err) {
                    printk(&amp;quot;Discover failed - chrc (err %d)\n&amp;quot;, err);
                }
                discover_phase = DISC_PHASE_CCCD;
                return BT_GATT_ITER_STOP;
            }
            break;

        case DISC_PHASE_CCCD:
            if(attr) {
                printk(&amp;quot;attr is a CCCD.  UUID type is %d, val = %x\n&amp;quot;,
                        attr-&amp;gt;uuid-&amp;gt;type, BT_UUID_16(attr-&amp;gt;uuid)-&amp;gt;val);
                if(attr-&amp;gt;user_data == NULL) {
                    printk(&amp;quot;user_data is NULL\n&amp;quot;);
                }
                else {
                    struct bt_gatt_ccc *dope = attr-&amp;gt;user_data;
                    printk(&amp;quot;user data is %x\n&amp;quot;, dope-&amp;gt;flags);
                }
                /* Check if this CCCD is associated with Report charact */
                if(!bt_uuid_cmp(attr-&amp;gt;uuid, &amp;amp;cis_report_char_uuid.uuid)) {
                    printk(&amp;quot;Found CCCD for Report characteristic\n&amp;quot;);
                    cccd_handle = attr-&amp;gt;handle;
                }
                last_handle = attr-&amp;gt;handle;
            }
            else {
                printk(&amp;quot;Discovery complete\n&amp;quot;);
                /* If all the handles have been set, then all the expected
                 * attributes were found, and the Sensor is ready for duty */
                if(ctrl_handle &amp;amp;&amp;amp; rpt_handle &amp;amp;&amp;amp; cccd_handle) {
                    printk(&amp;quot;Sensor ready\n&amp;quot;);
                    is_ready = true;
                }
                else {
                    printk(&amp;quot;Sensor not found\n&amp;quot;);
                    is_ready = false;
                }
                when_sensor_ready();
            }
            break;
    }

  	return BT_GATT_ITER_CONTINUE;
}

int start_discovery(struct bt_conn *conn)
{
    int err;

	if (conn == m_conn) {
		discover_params.uuid = NULL;
		discover_params.func = discover_func;
		discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
		discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
		discover_params.type = BT_GATT_DISCOVER_PRIMARY;
        discover_phase = DISC_PHASE_SERVICE;
        ctrl_handle = 0;
        rpt_handle  = 0;
        cccd_handle = 0;

		err = bt_gatt_discover(m_conn, &amp;amp;discover_params);
		if (err) {
			printk(&amp;quot;Discover failed - service (err %d)\n&amp;quot;, err);
			return err;
		}
	}
    return 0;
}
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The output looks like:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;[ATTRIBUTE] handle 1
uuid type = 0, val=2800
attr is a primary service.  UUID type is 0, val = 1801
[ATTRIBUTE] handle 9
uuid type = 0, val=2800
attr is a primary service.  UUID type is 0, val = 1800
[ATTRIBUTE] handle 16
uuid type = 0, val=2800
attr is a primary service.  UUID type is 2, val = 1200
Found custom service
No more services, looking for characteristics
[ATTRIBUTE] handle 17
uuid type = 0, val=2803
attr is a characteristic.  UUID type is 0, val = 1531
Found Control characteristic
[ATTRIBUTE] handle 19
uuid type = 0, val=2803
attr is a characteristic.  UUID type is 0, val = 1532
Found Report characteristic
No more characteristics, looking for CCCDs
[ATTRIBUTE] handle 20
uuid type = 0, val=1532
attr is a CCCD.  UUID type is 0, val = 1532
user_data is NULL
Found CCCD for Report characteristic
[ATTRIBUTE] handle 21
uuid type = 0, val=2902
attr is a CCCD.  UUID type is 0, val = 2902
user_data is NULL
Discovery complete
Sensor ready&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>