How can you add one CCC descriptor for every notification characteristic in a service?

Hello,

I am implementing the Physical Activity Monitor Service which looks like this:


/* Physical Activity Monitor Service Declaration */
BT_GATT_SERVICE_DEFINE(pam_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_PAMS),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_PHY_AMF, BT_GATT_CHRC_READ,
BT_GATT_PERM_READ, read_amf, NULL, NULL),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_GEN_AID, BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_NONE, NULL, NULL, NULL),
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_GEN_ASD, BT_GATT_CHRC_INDICATE,
BT_GATT_PERM_NONE, NULL, NULL, NULL), //TODO: Indication callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_CR_AID, BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_NONE, NULL, NULL, NULL),
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_CR_ASD, BT_GATT_CHRC_INDICATE,
BT_GATT_PERM_NONE, NULL, NULL, NULL), //TODO: Indication callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_SLP_AID, BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_NONE, NULL, NULL, NULL),
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_SC_ASD, BT_GATT_CHRC_INDICATE,
BT_GATT_PERM_NONE, NULL, NULL, NULL), //TODO: Indication callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_SLP_ASD, BT_GATT_CHRC_INDICATE,
BT_GATT_PERM_NONE, NULL, NULL, NULL), //TODO: Indication callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_PHY_AMCP, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE,
PAMS_GATT_PERM_DEFAULT & GATT_PERM_WRITE_MASK,
NULL, ctrl_point_write, NULL), //TODO: Test control point write callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_ACS, BT_GATT_CHRC_INDICATE | BT_GATT_CHRC_READ,
BT_GATT_PERM_NONE, read_acs, NULL, NULL), //TODO: Indication callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_PHY_ASDESC, BT_GATT_CHRC_INDICATE,
BT_GATT_PERM_NONE, NULL, NULL, NULL), //TODO: Indication callback
BT_GATT_CCC(pamc_ccc_cfg_changed, BT_GATT_PERM_WRITE | BT_GATT_PERM_READ),
}

Every notify or indicate characteristic needs a CCC according to The PAMS spec, but when I try to do this, I need to match every characteristic to its associated callback. Right now, using the HRS example, it simply iterates over every registered callback with a the notify boolean:

SYS_SLIST_FOR_EACH_CONTAINER(&hrs_cbs, listener, _node) {
if (listener->ctrl_point_write) {
err = listener->ctrl_point_write(*((uint8_t *)buf));
/* If we get an error other than ENOTSUP then immediately
* break the loop and return a generic gatt error, assuming this
* listener supports this request code, but failed to serve it
*/
if ((err != 0) && (err != -ENOTSUP)) {
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
}
}

I am now trying to match the GATT characteristic with the correct `_node` in order to turn on notifications on a per-characteristic basis as the spec says. 

However, the attribute passed into the ccc function is just the UUID of the CCC function. How can I know which function (below) to pass it to?

static void pams_gen_aid_ntf_changed(bool enabled)
{
pams_gen_aid_ntf_en = enabled;

LOG_INF("PAMS GEN AID notification status changed: %s\n",
enabled ? "enabled" : "disabled");
}

static struct bt_pams_cb pams_gen_aid_cb = {
.ntf_changed = pams_gen_aid_ntf_changed,
};

static void pams_cr_aid_ntf_changed(bool enabled)
{
pams_cr_aid_ntf_en = enabled;

LOG_INF("PAMS CR AID notification status changed: %s\n",
enabled ? "enabled" : "disabled");
}

static struct bt_pams_cb pams_cf_aid_cb = {
.ntf_changed = pams_cr_aid_ntf_changed,
};

static void pams_slp_aid_ntf_changed(bool enabled)
{
pams_slp_aid_ntf_en = enabled;

LOG_INF("PAMS SLEEP AID notification status changed: %s\n",
enabled ? "enabled" : "disabled");
}

static struct bt_pams_cb pams_slp_aid_cb = {
.ntf_changed = pams_slp_aid_ntf_changed,
};

static void pams_ctrl_point_ntf_changed(bool enabled)
{
pams_ctrl_point_ntf_en = enabled;

LOG_INF("PAMS CTRL Point notification status changed: %s\n",
enabled ? "enabled" : "disabled");
}

Do I have to make a separate CCC_changed function for every single characteristic?

Is there a way I can return a node of the desired callback and the attribute (uuid for example) of the clicked "notify" in the nrfConnect app? I am a bit stuck as a lot of the macros have less than ideal documentation. 

Thank you.

Related