Subscribing to attributes in BLE service

Hello!

I am developing my own BLE solution where I have the different attributes in my service and I am connecting two different nrf52840, one to act as a GATTClient and one as a GATTServer

The code below is for my client where I am discovering the service and my attributes. 

All attributes can be found BUT I can not subscribe to them. What do I need to do because I am lost?

static uint8_t discover_func(struct bt_conn *conn,
			     const struct bt_gatt_attr *attr,
			     struct bt_gatt_discover_params *params)
{
	int err;

	if (!attr) {
		printk("Discover complete\n");
		(void)memset(params, 0, sizeof(*params));
		return BT_GATT_ITER_STOP;
	}

	printk("[ATTRIBUTE] handle %u\n", attr->handle);

	if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_FROG)) {
		printk("Discovering TxDATA\n");
		memcpy(&frog_discover_uuid, BT_UUID_TXDATA, sizeof(frog_discover_uuid));
		discover_params.uuid = &frog_discover_uuid.uuid;
		discover_params.start_handle = attr->handle + 1;
		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;

		err = bt_gatt_discover(conn, &discover_params);
		if (err) {
			printk("Discover failed (err %d)\n", err);
		}
	} else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_TXDATA)) {
		printk("Discovering RxCREDIT\n");
		memcpy(&frog_discover_uuid, BT_UUID_RXCREDIT, sizeof(frog_discover_uuid));
		discover_params.uuid = &frog_discover_uuid.uuid;
		discover_params.start_handle = attr->handle + 1;
		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;

		err = bt_gatt_discover(conn, &discover_params);
		if (err) {
			printk("Discover failed (err %d)\n", err);
		}
	} else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_RXCREDIT)) {
		printk("Discovering CCC TxData\n");
		//memcpy(&frog_discover_uuid, BT_UUID_GATT_CCC, sizeof(frog_discover_uuid));
		discover_params.uuid = ccc_uuid;
		ccc_uuid2 = ccc_uuid;
		discover_params.start_handle = attr->handle + 2;
		discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
		subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);

		err = bt_gatt_discover(conn, &discover_params);
		if (err) {
			printk("Discover failed (err %d)\n", err);
		}
	} else if (!bt_uuid_cmp(discover_params.uuid, ccc_uuid2)){
		printk("Discovering CCC RxCredit\n");
		//memcpy(&frog_discover_uuid, BT_UUID_GATT_CCC, sizeof(frog_discover_uuid));
		discover_params.uuid = ccc_uuid;
		discover_params.start_handle = attr->handle + 2;
		discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
		subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);

		err = bt_gatt_discover(conn, &discover_params);
		if (err) {
			printk("Discover failed (err %d)\n", err);
		}
	} else {
		subscribe_params.notify = notify_func;
		subscribe_params.value = BT_GATT_CCC_NOTIFY;
		subscribe_params.ccc_handle = attr->handle;

		err = bt_gatt_subscribe(conn, &subscribe_params);
		if (err && err != -EALREADY) {
			printk("Subscribe failed (err %d)\n", err);
		} else {
			printk("[SUBSCRIBED]\n");
		}

		return BT_GATT_ITER_CONTINUE;
	}

	return BT_GATT_ITER_STOP;
}



Regards,

Björn

  • Hello,

    I recommend including logs to verify and handle the discovery. You first need to discover the characteristic, then find the CCCD descriptor, and finally subscribe to notifications. You can follow this exercise from the Developer Academy course, which discusses something very similar.

    Kind regards,
    Abhijith

  • Hello! 
    Already find all the CCCD descriptors and the characteristics, I need to subscribe to them and I don't know how to add that when I have two different sets of CCCDs and characteristics.

    The question is fairly straight forward, if I have the code I have given in my post. In these two sections:

    } else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_RXCREDIT)) {
    		printk("Discovering CCC TxData\n");
    		//memcpy(&frog_discover_uuid, BT_UUID_GATT_CCC, sizeof(frog_discover_uuid));
    		discover_params.uuid = ccc_uuid;
    		ccc_uuid2 = ccc_uuid;
    		discover_params.start_handle = attr->handle + 2;
    		discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
    		subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
    
    		err = bt_gatt_discover(conn, &discover_params);
    		if (err) {
    			printk("Discover failed (err %d)\n", err);
    		}
    	} else if (!bt_uuid_cmp(discover_params.uuid, ccc_uuid2)){
    		printk("Discovering CCC RxCredit\n");
    		//memcpy(&frog_discover_uuid, BT_UUID_GATT_CCC, sizeof(frog_discover_uuid));
    		discover_params.uuid = ccc_uuid;
    		discover_params.start_handle = attr->handle + 2;
    		discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
    		subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
    
    		err = bt_gatt_discover(conn, &discover_params);
    		if (err) {
    			printk("Discover failed (err %d)\n", err);
    		}
    	}

    Do I need to add subscribing within each of those blocks? Or should it be done outside of those blocks?

  • Hello,

    You need to create a bt_gatt_subscribe_params for each CCCD and call bt_gatt_subscribe(). From the initial code you shared, it looks like you're only discovering the CCCD descriptors but never actually subscribing after discovery.

    Your discover_func() should first find all the handles and then subscribe only after the discovery is complete. Also, value_handle should be the characteristic's value handle, not the descriptor's handle.

    Instead of setting subscribe_params.value_handle like this:

    subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);

    You should store the characteristic's handle when you find it.

    Kind Regards,

    Abhijith

  • Why should I store the characteristics handle when the original code from one of the samples does like what I am doing?

    And which handle is that exactly if I shouldn't store the value_handle? Is it the ccc_handle?
    Isn't it like the code I have in the original snippet from row 62 onwards? Isn't that the correct subscription methodology?

    With the exception that I am only subscribing to one of the cccd:s at the moment?

    Regards,

    Björn


  • Hello,

    In your code, you are using the cccd_handle correctly, but you need to use the characteristic's value handle for subscribing. When subscribing to a characteristic, you need to provide both.

    Refer to the central_uart sample, where you can find discovery_complete(). If you check bt_nus_subscribe_receive under nus_client.c, you will see how both of these values are used.

    For example: See line 182, that is the characteristic's value handle. If you check line 183, that is the cccd_handle.

    Kind Regards,

    Abhijith

Related