1 /*
2 * Copyright (c) 2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8
9 #include <zephyr/bluetooth/bluetooth.h>
10 #include <zephyr/bluetooth/conn.h>
11 #include <zephyr/bluetooth/att.h>
12 #include <zephyr/bluetooth/gatt.h>
13
14 #include <zephyr/settings/settings.h>
15
16 #include <zephyr/logging/log.h>
17
18 #include "testlib/adv.h"
19 #include "testlib/att.h"
20 #include "testlib/att_read.h"
21 #include "testlib/att_write.h"
22 #include "testlib/conn.h"
23
24 #include "babblekit/flags.h"
25 #include "babblekit/sync.h"
26 #include "babblekit/testcase.h"
27
28 #include "common.h"
29
30 LOG_MODULE_REGISTER(client, LOG_LEVEL_DBG);
31
32 DEFINE_FLAG_STATIC(client_security_changed_flag);
33
34 static struct bt_conn_cb client_conn_cb;
35
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)36 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
37 {
38 char addr_str[BT_ADDR_LE_STR_LEN];
39
40 bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
41
42 TEST_ASSERT(err == 0, "Security update failed: %s level %u err %d", addr_str, level, err);
43
44 LOG_DBG("Security changed: %s level %u", addr_str, level);
45 SET_FLAG(client_security_changed_flag);
46 }
47
init_client_conn_callbacks(void)48 static void init_client_conn_callbacks(void)
49 {
50 int err;
51
52 client_conn_cb.connected = NULL;
53 client_conn_cb.disconnected = NULL;
54 client_conn_cb.security_changed = security_changed;
55
56 err = bt_conn_cb_register(&client_conn_cb);
57 TEST_ASSERT(err == 0, "Failed to set client conn callbacks (err %d)", err);
58 }
59
find_characteristic(struct bt_conn * conn,const struct bt_uuid * svc,const struct bt_uuid * chrc,uint16_t * chrc_value_handle)60 void find_characteristic(struct bt_conn *conn, const struct bt_uuid *svc,
61 const struct bt_uuid *chrc, uint16_t *chrc_value_handle)
62 {
63 int err;
64 uint16_t svc_handle;
65 uint16_t svc_end_handle;
66 uint16_t chrc_end_handle;
67
68 err = bt_testlib_gatt_discover_primary(&svc_handle, &svc_end_handle, conn, svc,
69 BT_ATT_FIRST_ATTRIBUTE_HANDLE,
70 BT_ATT_LAST_ATTRIBUTE_HANDLE);
71 TEST_ASSERT(err == 0, "Failed to discover service: %d", err);
72
73 LOG_DBG("svc_handle: %u, svc_end_handle: %u", svc_handle, svc_end_handle);
74
75 err = bt_testlib_gatt_discover_characteristic(chrc_value_handle, &chrc_end_handle, NULL,
76 conn, chrc, (svc_handle + 1), svc_end_handle);
77 TEST_ASSERT(err == 0, "Failed to get value handle: %d", err);
78
79 LOG_DBG("chrc_value_handle: %u, chrc_end_handle: %u", *chrc_value_handle, chrc_end_handle);
80 }
81
client_procedure(void)82 void client_procedure(void)
83 {
84 int err;
85 struct bt_conn *conn;
86 uint16_t handle;
87
88 char server_new_name[CONFIG_BT_DEVICE_NAME_MAX];
89
90 NET_BUF_SIMPLE_DEFINE(attr_value_buf, BT_ATT_MAX_ATTRIBUTE_LEN);
91
92 generate_name(server_new_name, CONFIG_BT_DEVICE_NAME_MAX);
93
94 TEST_START("client");
95
96 bk_sync_init();
97
98 err = bt_enable(NULL);
99 TEST_ASSERT(err == 0, "Cannot enable Bluetooth (err %d)", err);
100
101 LOG_DBG("Bluetooth initialized");
102
103 init_client_conn_callbacks();
104
105 err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, ADVERTISER_NAME);
106 TEST_ASSERT(err == 0, "Failed to start connectable advertising (err %d)", err);
107
108 err = bt_testlib_att_exchange_mtu(conn);
109 TEST_ASSERT(err == 0, "Failed to update MTU (err %d)", err);
110
111 find_characteristic(conn, BT_UUID_GAP, BT_UUID_GAP_DEVICE_NAME, &handle);
112
113 err = bt_testlib_att_read_by_handle_sync(&attr_value_buf, NULL, NULL, conn,
114 BT_ATT_CHAN_OPT_UNENHANCED_ONLY, handle, 0);
115 TEST_ASSERT(err == 0, "Failed to read characteristic (err %d)", err);
116
117 LOG_DBG("Device Name of the server: %.*s", attr_value_buf.len, attr_value_buf.data);
118
119 err = bt_testlib_att_write(conn, BT_ATT_CHAN_OPT_UNENHANCED_ONLY, handle, server_new_name,
120 sizeof(server_new_name));
121 TEST_ASSERT(err == BT_ATT_ERR_SUCCESS, "Got ATT error: %d", err);
122
123 bk_sync_send();
124
125 TEST_PASS("client");
126 }
127