Skip to content

Commit c21e2c4

Browse files
olivier-le-sagecarlescufi
authored andcommitted
[nrf fromtree] bluetooth: gatt: Add BT_GATT_CCC_WITH_WRITE_CB()
Add simple helper macro so users can define a CCCD with a write cb without having to combine BT_GATT_CCC_MANAGED() and BT_GATT_CCC_INITIALIZER() themselves. Unlike the changed callback the write callback has a return value that can be used to reject the write request. Signed-off-by: Olivier Lesage <[email protected]> (cherry picked from commit 7b61bd6) (cherry picked from commit 336b11a)
1 parent 256ac2a commit c21e2c4

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

include/zephyr/bluetooth/gatt.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,20 @@ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn,
11671167
BT_GATT_CCC_MANAGED(((struct _bt_gatt_ccc[]) \
11681168
{BT_GATT_CCC_INITIALIZER(_changed, NULL, NULL)}), _perm)
11691169

1170+
/**
1171+
* @brief Client Characteristic Configuration Declaration Macro with write callback.
1172+
*
1173+
* Helper macro to declare a CCC attribute with a write callback.
1174+
*
1175+
* @param _changed Configuration changed callback.
1176+
* @param _write Configuration write callback.
1177+
* @param _perm CCC access permissions,
1178+
* a bitmap of @ref bt_gatt_perm values.
1179+
*/
1180+
#define BT_GATT_CCC_WITH_WRITE_CB(_changed, _write, _perm) \
1181+
BT_GATT_CCC_MANAGED(((struct _bt_gatt_ccc[]) \
1182+
{BT_GATT_CCC_INITIALIZER(_changed, _write, NULL) }), _perm)
1183+
11701184
/** @brief Read Characteristic Extended Properties Attribute helper
11711185
*
11721186
* Read CEP attribute value from local database storing the result into buffer

tests/bluetooth/gatt/src/main.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ static void test1_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t valu
3939
nfy_enabled = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
4040
}
4141

42+
static ssize_t test1_ccc_cfg_write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, uint16_t value)
43+
{
44+
return sizeof(value);
45+
}
46+
4247
static ssize_t read_test(struct bt_conn *conn, const struct bt_gatt_attr *attr,
4348
void *buf, uint16_t len, uint16_t offset)
4449
{
@@ -507,3 +512,25 @@ ZTEST(test_gatt, test_bt_gatt_err_to_str)
507512
zassert_not_null(bt_gatt_err_to_str(-i), ": %d", i);
508513
}
509514
}
515+
516+
ZTEST(test_gatt, test_gatt_ccc_write_cb)
517+
{
518+
struct bt_gatt_attr test_write_cb_attrs[] = {
519+
/* Vendor Primary Service Declaration */
520+
BT_GATT_PRIMARY_SERVICE(&test1_uuid),
521+
522+
BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid,
523+
BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE,
524+
NULL, NULL, &nfy_enabled),
525+
BT_GATT_CCC_WITH_WRITE_CB(test1_ccc_cfg_changed,
526+
test1_ccc_cfg_write_cb,
527+
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
528+
};
529+
530+
struct bt_gatt_service test_write_cb_svc = BT_GATT_SERVICE(test_write_cb_attrs);
531+
532+
zassert_false(bt_gatt_service_register(&test_write_cb_svc),
533+
"Test service registration failed");
534+
zassert_false(bt_gatt_service_unregister(&test_write_cb_svc),
535+
"Test service1 unregister failed");
536+
}

tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static struct bt_conn *default_conn;
4141

4242
static struct bt_conn_cb central_cb;
4343

44+
DEFINE_FLAG_STATIC(gatt_subscribed_rejected_flag);
4445
DEFINE_FLAG_STATIC(gatt_subscribed_flag);
4546

4647
static uint8_t notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
@@ -69,6 +70,9 @@ static uint8_t notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *
6970
static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params)
7071
{
7172
if (err) {
73+
if (err == BT_ATT_ERR_WRITE_NOT_PERMITTED) {
74+
SET_FLAG(gatt_subscribed_rejected_flag);
75+
}
7276
return;
7377
}
7478

@@ -81,6 +85,7 @@ static void ccc_subscribe(void)
8185
{
8286
int err;
8387

88+
UNSET_FLAG(gatt_subscribed_rejected_flag);
8489
UNSET_FLAG(gatt_subscribed_flag);
8590

8691
subscribe_params.notify = notify_cb;
@@ -94,6 +99,13 @@ static void ccc_subscribe(void)
9499
TEST_FAIL("Failed to subscribe (att err %d)", err);
95100
}
96101

102+
WAIT_FOR_FLAG(gatt_subscribed_rejected_flag);
103+
104+
err = bt_gatt_subscribe(default_conn, &subscribe_params);
105+
if (err) {
106+
TEST_FAIL("Failed to subscribe (att err %d)", err);
107+
}
108+
97109
WAIT_FOR_FLAG(gatt_subscribed_flag);
98110
}
99111

tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ static struct bt_conn *default_conn;
4141

4242
static struct bt_conn_cb peripheral_cb;
4343

44+
static bool notif_write_allowed;
45+
4446
static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
4547
{
4648
ARG_UNUSED(attr);
@@ -52,10 +54,24 @@ static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
5254
SET_FLAG(ccc_cfg_changed_flag);
5355
}
5456

57+
static ssize_t ccc_cfg_write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, uint16_t value)
58+
{
59+
if (notif_write_allowed) {
60+
LOG_INF("CCC Write Request accepted.");
61+
return sizeof(value);
62+
} else {
63+
LOG_INF("CCC Write Request rejected.");
64+
notif_write_allowed = true;
65+
return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
66+
}
67+
}
68+
5569
BT_GATT_SERVICE_DEFINE(dummy_svc, BT_GATT_PRIMARY_SERVICE(&dummy_service),
5670
BT_GATT_CHARACTERISTIC(&notify_characteristic_uuid.uuid, BT_GATT_CHRC_NOTIFY,
5771
BT_GATT_PERM_NONE, NULL, NULL, NULL),
58-
BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
72+
BT_GATT_CCC_WITH_WRITE_CB(ccc_cfg_changed, ccc_cfg_write_cb,
73+
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
74+
);
5975

6076
static void create_adv(struct bt_le_ext_adv **adv)
6177
{

0 commit comments

Comments
 (0)