2023-08-03 07:25:31

by Mahesh Talewad

[permalink] [raw]
Subject: [PATCH BlueZ v1 3/3] unit/test-micp: Add unit test code for testing MICP-MICS

-Implemented UNIT Testcases for MICS[test-micp.c] and MICP[test-mics.c].
---
Makefile.am | 13 ++
src/shared/micp.c | 26 ++++
src/shared/micp.h | 2 +
unit/test-micp.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++
unit/test-mics.c | 290 +++++++++++++++++++++++++++++++++++++
5 files changed, 688 insertions(+)
create mode 100644 unit/test-micp.c
create mode 100644 unit/test-mics.c

diff --git a/Makefile.am b/Makefile.am
index 6f40f2a74..cde55bebf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -573,6 +573,19 @@ unit_test_gattrib_LDADD = src/libshared-glib.la \
lib/libbluetooth-internal.la \
$(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt

+unit_tests += unit/test-micp
+
+unit_test_micp_SOURCES = unit/test-micp.c
+
+unit_test_micp_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la $(GLIB_LIBS)
+
+unit_tests += unit/test-mics
+
+unit_test_mics_SOURCES = unit/test-mics.c
+unit_test_mics_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la $(GLIB_LIBS)
+
unit_tests += unit/test-bap

unit_test_bap_SOURCES = unit/test-bap.c
diff --git a/src/shared/micp.c b/src/shared/micp.c
index c5b814d98..bb71999be 100644
--- a/src/shared/micp.c
+++ b/src/shared/micp.c
@@ -1042,3 +1042,29 @@ void micp_char_write_value(uint16_t handle)

}
#endif /*MICP_MICS_PTS_FLAG*/
+
+static void micp_write_cb1(bool success, uint8_t att_ecode, void *user_data)
+{
+ if (success)
+ printf("MICP Write successful\n");
+ else
+ printf("\nWrite failed: 0x%02x\n", att_ecode);
+}
+
+void micp_write_value(struct bt_micp *micp, void *user_data)
+{
+ struct bt_mics *mics = micp_get_mics(micp);
+ uint16_t value_handle;
+ int ret;
+ const uint16_t value = 0x0001;
+
+ gatt_db_attribute_get_char_data(mics->ms, NULL, &value_handle,
+ NULL, NULL, NULL);
+
+ printf("%s handle: %x\n", __func__, value_handle);
+ ret = bt_gatt_client_write_value(micp->client, value_handle,
+ (void *)&value, sizeof(value), micp_write_cb1, NULL, NULL);
+ if (!ret)
+ printf("bt_gatt_client_write_value() : Write FAILED");
+
+}
diff --git a/src/shared/micp.h b/src/shared/micp.h
index 4a9807ed4..f20d46c9c 100644
--- a/src/shared/micp.h
+++ b/src/shared/micp.h
@@ -52,3 +52,5 @@ void micp_discover_mute_char(void);
void mics_mute_char_read(uint16_t handle);
void micp_char_write_value(uint16_t handle);
#endif /*MICP_MICS_PTS_FLAG*/
+
+void micp_write_value(struct bt_micp *micp, void *user_data);
diff --git a/unit/test-micp.c b/unit/test-micp.c
new file mode 100644
index 000000000..3db32a4f7
--- /dev/null
+++ b/unit/test-micp.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2023 NXP Semiconductors. All rights reserved.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+#include "src/shared/util.h"
+#include "src/shared/tester.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/micp.h"
+
+struct test_data {
+ struct gatt_db *db;
+ struct bt_micp *micp;
+ struct bt_gatt_server *server;
+ struct bt_gatt_client *client;
+ struct queue *ccc_states;
+ size_t iovcnt;
+ struct iovec *iov;
+ struct test_config *cfg;
+};
+
+struct ccc_state {
+ uint16_t handle;
+ uint16_t value;
+};
+
+struct notify {
+ uint16_t handle, ccc_handle;
+ uint8_t *value;
+ uint16_t len;
+ bt_gatt_server_conf_func_t conf;
+ void *user_data;
+};
+
+#define iov_data(args...) ((const struct iovec[]) { args })
+
+#define define_test(name, function, _cfg, args...) \
+ do { \
+ const struct iovec iov[] = { args }; \
+ static struct test_data data; \
+ data.cfg = _cfg; \
+ data.iovcnt = ARRAY_SIZE(iov_data(args)); \
+ data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
+ tester_add(name, &data, NULL, function, \
+ test_teardown); \
+ } while (0)
+
+static void print_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ if (tester_use_debug())
+ tester_debug("%s%s", prefix, str);
+}
+
+static void test_teardown(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+
+ bt_micp_unref(data->micp);
+ bt_gatt_server_unref(data->server);
+ util_iov_free(data->iov, data->iovcnt);
+ gatt_db_unref(data->db);
+
+ queue_destroy(data->ccc_states, free);
+
+ tester_teardown_complete();
+}
+
+static void test_complete_cb(const void *user_data)
+{
+ tester_test_passed();
+}
+
+static bool ccc_state_match(const void *a, const void *b)
+{
+ const struct ccc_state *ccc = a;
+ uint16_t handle = PTR_TO_UINT(b);
+
+ return ccc->handle == handle;
+}
+
+static struct ccc_state *find_ccc_state(struct test_data *data,
+ uint16_t handle)
+{
+ return queue_find(data->ccc_states, ccc_state_match,
+ UINT_TO_PTR(handle));
+}
+
+static struct ccc_state *get_ccc_state(struct test_data *data, uint16_t handle)
+{
+ struct ccc_state *ccc;
+
+ ccc = find_ccc_state(data, handle);
+ if (ccc)
+ return ccc;
+
+ ccc = new0(struct ccc_state, 1);
+ ccc->handle = handle;
+ queue_push_tail(data->ccc_states, ccc);
+
+ return ccc;
+}
+
+static void gatt_notify_cb(struct gatt_db_attribute *attrib,
+ struct gatt_db_attribute *ccc,
+ const uint8_t *value, size_t len,
+ struct bt_att *att, void *user_data)
+{
+ struct test_data *data = user_data;
+ struct notify notify;
+
+ memset(&notify, 0, sizeof(notify));
+
+ notify.handle = gatt_db_attribute_get_handle(attrib);
+ notify.ccc_handle = gatt_db_attribute_get_handle(ccc);
+ notify.value = (void *) value;
+ notify.len = len;
+
+ printf("%s: notify.value:%d notify->len:%d\n", __func__,
+ (int)*(notify.value), notify.len);
+ if (!bt_gatt_server_send_notification(data->server,
+ notify.handle, notify.value,
+ notify.len, false))
+ printf("%s: Failed to send notification\n", __func__);
+}
+
+static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct test_data *data = user_data;
+ struct ccc_state *ccc;
+ uint16_t handle;
+ uint8_t ecode = 0;
+ const uint8_t *value = NULL;
+ size_t len = 0;
+
+ handle = gatt_db_attribute_get_handle(attrib);
+
+ ccc = get_ccc_state(data, handle);
+ if (!ccc) {
+ ecode = BT_ATT_ERROR_UNLIKELY;
+ goto done;
+ }
+
+ len = sizeof(ccc->value);
+ value = (void *) &ccc->value;
+
+done:
+ gatt_db_attribute_read_result(attrib, id, ecode, value, len);
+}
+
+static void test_server(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+ struct bt_att *att;
+ struct io *io;
+
+ io = tester_setup_io(data->iov, data->iovcnt);
+ g_assert(io);
+
+ tester_io_set_complete_func(test_complete_cb);
+
+ att = bt_att_new(io_get_fd(io), false);
+ g_assert(att);
+
+ bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
+
+ data->db = gatt_db_new();
+ g_assert(data->db);
+
+ gatt_db_ccc_register(data->db, gatt_ccc_read_cb, NULL,
+ gatt_notify_cb, data);
+
+ data->micp = bt_micp_new(data->db, NULL);
+ g_assert(data->micp);
+
+ data->server = bt_gatt_server_new(data->db, att, 64, 0);
+ g_assert(data->server);
+
+ bt_gatt_server_set_debug(data->server, print_debug, "bt_gatt_server:",
+ NULL);
+
+ data->ccc_states = queue_new();
+
+ tester_io_send();
+
+ bt_att_unref(att);
+}
+
+#define EXCHANGE_MTU IOV_DATA(0x02, 0x40, 0x00), \
+ IOV_DATA(0x03, 0x40, 0x00)
+
+#define MICS_MUTE_WRITE_VAL_00 \
+ IOV_DATA(0x12, 0x03, 0x00, 0x00), \
+ IOV_DATA(0x13)
+
+#define MICS_MUTE_WRITE_VAL_01 \
+ IOV_DATA(0x12, 0x03, 0x00, 0x01), \
+ IOV_DATA(0x13)
+
+#define MICS_MUTE_READ \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x01)
+
+#define DISCOVER_PRIM_SERV_NOTIF \
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ IOV_DATA(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x4d, 0x18), \
+ IOV_DATA(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ IOV_DATA(0x01, 0x10, 0x05, 0x00, 0x0a)
+
+/* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0009
+ * Attribute type: Characteristic (0x2803)
+ * ATT: Read By Type Response (0x09) len 22
+ * Attribute data length: 7
+ * Handle: 0x0002
+ * Value: 1a0300c82b
+ * Properties: 0x1a
+ * Value Handle: 0x0003
+ * Value UUID: Mute (0x2bc3)
+ */
+#define DISC_MICS_CHAR_1 \
+ IOV_DATA(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28), \
+ IOV_DATA(0x09, 0x07, \
+ 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \
+ IOV_DATA(0x08, 0x05, 0x00, 0x05, 0x00, 0x03, 0x28), \
+ IOV_DATA(0x01, 0x08, 0x05, 0x00, 0x0a)
+
+
+#define MICS_FIND_BY_TYPE_VALUE \
+ IOV_DATA(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4d, 0x18), \
+ IOV_DATA(0x07, 0x01, 0x00, 0x04, 0x00), \
+ IOV_DATA(0x06, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4d, 0x18), \
+ IOV_DATA(0x01, 0x06, 0x05, 0x00, 0x0a)
+
+#define DISC_MICS_CHAR_AFTER_TYPE \
+ IOV_DATA(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28), \
+ IOV_DATA(0x09, 0x07, \
+ 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \
+ IOV_DATA(0x08, 0x03, 0x00, 0x05, 0x00, 0x03, 0x28), \
+ IOV_DATA(0x01, 0x08, 0x03, 0x00, 0x0a)
+
+#define MICS_WRITE_CCD \
+ IOV_DATA(0x12, 0x04, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13), \
+ IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13)
+
+#define MICS_FIND_INFO \
+ IOV_DATA(0x04, 0x04, 0x00, 0x05, 0x00), \
+ IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29), \
+ IOV_DATA(0x04, 0x05, 0x00, 0x05, 0x00), \
+ IOV_DATA(0x01, 0x04, 0x05, 0x00, 0x0a)
+
+#define MICS_SR_SPN_BV_01_C \
+ EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ DISC_MICS_CHAR_1, \
+ MICS_FIND_BY_TYPE_VALUE, \
+ DISC_MICS_CHAR_AFTER_TYPE, \
+ MICS_FIND_INFO, \
+ MICS_WRITE_CCD, \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x01), \
+ MICS_MUTE_WRITE_VAL_00, \
+ IOV_DATA(0x1b, 0x03, 0x00, 0x00), \
+ MICS_MUTE_WRITE_VAL_01, \
+ IOV_DATA(0x1b, 0x03, 0x00, 0x01), \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x01)
+
+#define MICS_SR_SGGIT_SER_BV_01_C \
+ EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ MICS_FIND_BY_TYPE_VALUE
+
+#define MICS_SR_SGGIT_CHA_BV_01_C \
+ EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ MICS_FIND_BY_TYPE_VALUE, \
+ DISC_MICS_CHAR_AFTER_TYPE
+
+#define MICS_WRITE_MUTE_CHAR_INVALID \
+ IOV_DATA(0x12, 0x03, 0x00, 0x02), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x13), \
+ IOV_DATA(0x12, 0x03, 0x00, 0x05), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x13)
+
+#define MICS_SR_SPE_BI_1_C \
+ EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ MICS_FIND_BY_TYPE_VALUE, \
+ MICS_WRITE_MUTE_CHAR_INVALID
+
+#define MICS_MUTE_READ_INVALID \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x02)
+
+#define MICS_MUTE_WRITE_1 \
+ IOV_DATA(0x12, 0x03, 0x00, 0x01), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80)
+
+#define MICS_MUTE_WRITE_0 \
+ IOV_DATA(0x12, 0x03, 0x00, 0x00), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80)
+
+#define MICS_SR_SPE_BI_02_C \
+ EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ MICS_FIND_BY_TYPE_VALUE, \
+ MICS_MUTE_READ_INVALID, \
+ MICS_MUTE_WRITE_0, \
+ MICS_MUTE_WRITE_1
+
+int main(int argc, char *argv[])
+{
+
+ tester_init(&argc, &argv);
+
+ define_test("MICS/SR/SGGIT/SER/BV-01-C", test_server, NULL,
+ MICS_SR_SGGIT_SER_BV_01_C);
+ define_test("MICS/SR/SGGIT/CHA/BV-01-C", test_server, NULL,
+ MICS_SR_SGGIT_CHA_BV_01_C);
+ define_test("MICS/SR/SPE/BI-01-C", test_server, NULL,
+ MICS_SR_SPE_BI_1_C);
+ define_test("MICS/SR/SPE/BI-02-C", test_server, NULL,
+ MICS_SR_SPE_BI_02_C);
+ define_test("MICS/SR/SPN/BV-01-C", test_server, NULL,
+ MICS_SR_SPN_BV_01_C);
+
+ return tester_run();
+}
diff --git a/unit/test-mics.c b/unit/test-mics.c
new file mode 100644
index 000000000..fe84fb02d
--- /dev/null
+++ b/unit/test-mics.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2023 NXP Semiconductors. All rights reserved.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+#include "btio/btio.h"
+#include "src/shared/util.h"
+#include "src/shared/tester.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-helpers.h"
+#include "src/shared/micp.h"
+
+struct test_data {
+ struct gatt_db *db;
+ struct bt_micp *micp;
+ struct bt_gatt_client *client;
+ size_t iovcnt;
+ struct iovec *iov;
+ struct test_config *cfg;
+};
+
+struct db_attribute_micp_test_data {
+ struct gatt_db_attribute *match;
+ bool found;
+};
+
+#define MICP_GATT_CLIENT_MTU 64
+#define iov_data(args...) ((const struct iovec[]) { args })
+
+#define define_test(name, function, _cfg, args...) \
+ do { \
+ const struct iovec iov[] = { args }; \
+ static struct test_data data; \
+ data.cfg = _cfg; \
+ data.iovcnt = ARRAY_SIZE(iov_data(args)); \
+ data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
+ tester_add(name, &data, test_setup, function, \
+ test_teardown); \
+ } while (0)
+
+static void print_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ if (tester_use_debug())
+ tester_debug("%s %s", prefix, str);
+}
+
+static void test_teardown(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+
+ bt_gatt_client_unref(data->client);
+ util_iov_free(data->iov, data->iovcnt);
+ gatt_db_unref(data->db);
+
+ tester_teardown_complete();
+}
+
+static void test_complete_cb(const void *user_data)
+{
+ tester_test_passed();
+}
+
+static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
+{
+
+ if (!success)
+ tester_setup_failed();
+ else
+ tester_setup_complete();
+}
+
+static void micp_ready(struct bt_micp *micp, void *user_data)
+{
+ micp_write_value(micp, user_data);
+}
+
+static void test_client(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+ struct io *io;
+
+ io = tester_setup_io(data->iov, data->iovcnt);
+ g_assert(io);
+
+ tester_io_set_complete_func(test_complete_cb);
+
+ data->db = gatt_db_new();
+ g_assert(data->db);
+
+ data->micp = bt_micp_new(data->db, bt_gatt_client_get_db(data->client));
+ g_assert(data->micp);
+
+ bt_micp_set_debug(data->micp, print_debug, "bt_mip: ", NULL);
+
+ bt_micp_ready_register(data->micp, micp_ready, data, NULL);
+
+ bt_micp_attach(data->micp, data->client);
+}
+
+ /* ATT: Exchange MTU Response (0x03) len 2
+ * Server RX MTU: 64
+ */
+ /* ATT: Exchange MTU Request (0x02) len 2
+ * Client RX MTU: 64
+ */
+#define ATT_EXCHANGE_MTU IOV_DATA(0x02, 0x40, 0x00), \
+ IOV_DATA(0x03, 0x40, 0x00)
+
+/*
+ * ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute type: Server Supported Features (0x2b3a)
+ */
+#define MICP_READ_SR_FEATURE IOV_DATA(0x08, 0x01, 0x00, 0Xff, 0xff, \
+ 0x3a, 0x2b), \
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a)
+
+ /*
+ * ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute group type: Primary Service (0x2800)
+ */
+
+/*
+ * ATT: Read By Group Type Response (0x11) len 7
+ * Attribute data length: 6
+ * Attribute group list: 1 entry
+ * Handle range: 0x00a0-0x00a4
+ * UUID: Microphone Control (0x184d)
+ */
+#define MICP_READ_GROUP_TYPE \
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ IOV_DATA(0x11, 0x06, \
+ 0x01, 0x00, 0x04, 0x00, 0x4d, 0x18), \
+ IOV_DATA(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ IOV_DATA(0x01, 0x10, 0x06, 0x00, 0x0a)
+
+ /* ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute group type: Secondary Service (0x2801)
+ */
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)08 01 00 05 00 02 28
+ */
+#define MICP_READ_REQ_SECOND_SERVICE \
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), \
+ IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a)
+
+#define MICP_READ_REQ_INCLUDE_SERVICE \
+ IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28), \
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a)
+
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0004
+ * Attribute type: Characteristic (0x2803)
+ */
+
+/* ATT: Find Information Request (0x04) len 4
+ * Handle range: 0x0004-0x0004
+ */
+#define MICP_FIND_INFO_REQ \
+ IOV_DATA(0x04, 0x04, 0x00, 0x04, 0x00), \
+ IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29)
+
+/*
+ * ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0004
+ * Attribute type: Characteristic (0x2803)
+ */
+#define MICP_READ_REQ_CHAR \
+ IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),\
+ IOV_DATA(0x09, 0x07, \
+ 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \
+ IOV_DATA(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28), \
+ IOV_DATA(0x01, 0x08, 0x04, 0x00, 0x0a)
+
+#define MICS_MUTE_READ \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x01)
+
+#define MICS_EN_MUTE_DISCPTR \
+ IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13)
+
+#define MICS_MUTE_WRITE \
+ IOV_DATA(0x12, 0x03, 0x00, 0x01),\
+ IOV_DATA(0x13)
+
+#define MICP_CL_CGGIT_SER_BV_01_C \
+ MICS_MUTE_READ, \
+ MICS_EN_MUTE_DISCPTR, \
+ IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x013)
+
+#define MICP_CL_CGGIT_CHA_BV_01_C \
+ MICS_MUTE_READ, \
+ MICS_EN_MUTE_DISCPTR, \
+ IOV_DATA(0x12, 0x03, 0x00, 0x06, 0x00), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x013), \
+ MICS_MUTE_READ
+
+#define MICP_CL_SPE_BI_01_C \
+ MICS_MUTE_READ, \
+ MICS_EN_MUTE_DISCPTR, \
+ IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80)
+
+/* GATT Discover All procedure */
+static const struct iovec setup_data[] = {
+ ATT_EXCHANGE_MTU,
+ MICP_READ_SR_FEATURE,
+ MICP_READ_GROUP_TYPE,
+ MICP_READ_REQ_SECOND_SERVICE,
+ MICP_READ_REQ_INCLUDE_SERVICE,
+ MICP_READ_REQ_CHAR,
+ MICP_FIND_INFO_REQ
+};
+
+static void test_setup(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+ struct bt_att *att;
+ struct gatt_db *db;
+ struct io *io;
+
+ io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data));
+ g_assert(io);
+
+ att = bt_att_new(io_get_fd(io), false);
+ g_assert(att);
+
+ bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
+
+ db = gatt_db_new();
+ g_assert(db);
+
+
+ data->client = bt_gatt_client_new(db, att, MICP_GATT_CLIENT_MTU, 0);
+ g_assert(data->client);
+
+ bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
+ NULL);
+
+ bt_gatt_client_ready_register(data->client, client_ready_cb, data,
+ NULL);
+
+ bt_att_unref(att);
+ gatt_db_unref(db);
+}
+
+
+int main(int argc, char *argv[])
+{
+
+ tester_init(&argc, &argv);
+
+ define_test("MICP/CL/CGGIT/SER/BV-01-C", test_client, NULL,
+ MICS_MUTE_READ);
+ define_test("MICP/CL/CGGIT/CHA/BV-01-C", test_client, NULL,
+ MICP_CL_CGGIT_SER_BV_01_C);
+ define_test("MICP/CL/SPE/BI-01-C", test_client, NULL,
+ MICP_CL_SPE_BI_01_C);
+
+ return tester_run();
+}
--
2.34.1



2023-08-07 23:41:07

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v1 3/3] unit/test-micp: Add unit test code for testing MICP-MICS

Hi Mahesh,

On Thu, Aug 3, 2023 at 12:21 AM Mahesh Talewad <[email protected]> wrote:
>
> -Implemented UNIT Testcases for MICS[test-micp.c] and MICP[test-mics.c].

Not sure why you had decided to go with 2 files instead of one, but
you can still test both server and client and possibly share some
definition between the 2 sides.

> ---
> Makefile.am | 13 ++
> src/shared/micp.c | 26 ++++
> src/shared/micp.h | 2 +
> unit/test-micp.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++
> unit/test-mics.c | 290 +++++++++++++++++++++++++++++++++++++
> 5 files changed, 688 insertions(+)
> create mode 100644 unit/test-micp.c
> create mode 100644 unit/test-mics.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 6f40f2a74..cde55bebf 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -573,6 +573,19 @@ unit_test_gattrib_LDADD = src/libshared-glib.la \
> lib/libbluetooth-internal.la \
> $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt
>
> +unit_tests += unit/test-micp
> +
> +unit_test_micp_SOURCES = unit/test-micp.c
> +
> +unit_test_micp_LDADD = src/libshared-glib.la \
> + lib/libbluetooth-internal.la $(GLIB_LIBS)
> +
> +unit_tests += unit/test-mics
> +
> +unit_test_mics_SOURCES = unit/test-mics.c
> +unit_test_mics_LDADD = src/libshared-glib.la \
> + lib/libbluetooth-internal.la $(GLIB_LIBS)
> +
> unit_tests += unit/test-bap
>
> unit_test_bap_SOURCES = unit/test-bap.c
> diff --git a/src/shared/micp.c b/src/shared/micp.c
> index c5b814d98..bb71999be 100644
> --- a/src/shared/micp.c
> +++ b/src/shared/micp.c
> @@ -1042,3 +1042,29 @@ void micp_char_write_value(uint16_t handle)
>
> }
> #endif /*MICP_MICS_PTS_FLAG*/
> +
> +static void micp_write_cb1(bool success, uint8_t att_ecode, void *user_data)
> +{
> + if (success)
> + printf("MICP Write successful\n");
> + else
> + printf("\nWrite failed: 0x%02x\n", att_ecode);
> +}
> +
> +void micp_write_value(struct bt_micp *micp, void *user_data)
> +{
> + struct bt_mics *mics = micp_get_mics(micp);
> + uint16_t value_handle;
> + int ret;
> + const uint16_t value = 0x0001;
> +
> + gatt_db_attribute_get_char_data(mics->ms, NULL, &value_handle,
> + NULL, NULL, NULL);
> +
> + printf("%s handle: %x\n", __func__, value_handle);
> + ret = bt_gatt_client_write_value(micp->client, value_handle,
> + (void *)&value, sizeof(value), micp_write_cb1, NULL, NULL);
> + if (!ret)
> + printf("bt_gatt_client_write_value() : Write FAILED");
> +
> +}

I'd expect you to fixup the original commit when introducing changes
to the shared library, that said I am not sure what this is for?

> diff --git a/src/shared/micp.h b/src/shared/micp.h
> index 4a9807ed4..f20d46c9c 100644
> --- a/src/shared/micp.h
> +++ b/src/shared/micp.h
> @@ -52,3 +52,5 @@ void micp_discover_mute_char(void);
> void mics_mute_char_read(uint16_t handle);
> void micp_char_write_value(uint16_t handle);
> #endif /*MICP_MICS_PTS_FLAG*/
> +
> +void micp_write_value(struct bt_micp *micp, void *user_data);

This should probably start with bt_ prefix, also I do expect that
anything that is needed by the tests shall also be available to the
likes of MediaTransport.Volume, but I haven't found any change
handling the Volume changes.

> diff --git a/unit/test-micp.c b/unit/test-micp.c
> new file mode 100644
> index 000000000..3db32a4f7
> --- /dev/null
> +++ b/unit/test-micp.c
> @@ -0,0 +1,357 @@
> +// SPDX-License-Identifier: LGPL-2.1-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2023 NXP Semiconductors. All rights reserved.
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/socket.h>
> +#include <fcntl.h>
> +
> +
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +#include "lib/uuid.h"
> +#include "src/shared/util.h"
> +#include "src/shared/tester.h"
> +#include "src/shared/queue.h"
> +#include "src/shared/att.h"
> +#include "src/shared/gatt-db.h"
> +#include "src/shared/gatt-server.h"
> +#include "src/shared/micp.h"
> +
> +struct test_data {
> + struct gatt_db *db;
> + struct bt_micp *micp;
> + struct bt_gatt_server *server;
> + struct bt_gatt_client *client;
> + struct queue *ccc_states;
> + size_t iovcnt;
> + struct iovec *iov;
> + struct test_config *cfg;
> +};
> +
> +struct ccc_state {
> + uint16_t handle;
> + uint16_t value;
> +};
> +
> +struct notify {
> + uint16_t handle, ccc_handle;
> + uint8_t *value;
> + uint16_t len;
> + bt_gatt_server_conf_func_t conf;
> + void *user_data;
> +};
> +
> +#define iov_data(args...) ((const struct iovec[]) { args })
> +
> +#define define_test(name, function, _cfg, args...) \
> + do { \
> + const struct iovec iov[] = { args }; \
> + static struct test_data data; \
> + data.cfg = _cfg; \
> + data.iovcnt = ARRAY_SIZE(iov_data(args)); \
> + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
> + tester_add(name, &data, NULL, function, \
> + test_teardown); \
> + } while (0)
> +
> +static void print_debug(const char *str, void *user_data)
> +{
> + const char *prefix = user_data;
> +
> + if (tester_use_debug())
> + tester_debug("%s%s", prefix, str);
> +}
> +
> +static void test_teardown(const void *user_data)
> +{
> + struct test_data *data = (void *)user_data;
> +
> + bt_micp_unref(data->micp);
> + bt_gatt_server_unref(data->server);
> + util_iov_free(data->iov, data->iovcnt);
> + gatt_db_unref(data->db);
> +
> + queue_destroy(data->ccc_states, free);
> +
> + tester_teardown_complete();
> +}
> +
> +static void test_complete_cb(const void *user_data)
> +{
> + tester_test_passed();
> +}
> +
> +static bool ccc_state_match(const void *a, const void *b)
> +{
> + const struct ccc_state *ccc = a;
> + uint16_t handle = PTR_TO_UINT(b);
> +
> + return ccc->handle == handle;
> +}
> +
> +static struct ccc_state *find_ccc_state(struct test_data *data,
> + uint16_t handle)
> +{
> + return queue_find(data->ccc_states, ccc_state_match,
> + UINT_TO_PTR(handle));
> +}
> +
> +static struct ccc_state *get_ccc_state(struct test_data *data, uint16_t handle)
> +{
> + struct ccc_state *ccc;
> +
> + ccc = find_ccc_state(data, handle);
> + if (ccc)
> + return ccc;
> +
> + ccc = new0(struct ccc_state, 1);
> + ccc->handle = handle;
> + queue_push_tail(data->ccc_states, ccc);
> +
> + return ccc;
> +}
> +
> +static void gatt_notify_cb(struct gatt_db_attribute *attrib,
> + struct gatt_db_attribute *ccc,
> + const uint8_t *value, size_t len,
> + struct bt_att *att, void *user_data)
> +{
> + struct test_data *data = user_data;
> + struct notify notify;
> +
> + memset(&notify, 0, sizeof(notify));
> +
> + notify.handle = gatt_db_attribute_get_handle(attrib);
> + notify.ccc_handle = gatt_db_attribute_get_handle(ccc);
> + notify.value = (void *) value;
> + notify.len = len;
> +
> + printf("%s: notify.value:%d notify->len:%d\n", __func__,
> + (int)*(notify.value), notify.len);
> + if (!bt_gatt_server_send_notification(data->server,
> + notify.handle, notify.value,
> + notify.len, false))
> + printf("%s: Failed to send notification\n", __func__);
> +}
> +
> +static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
> + unsigned int id, uint16_t offset,
> + uint8_t opcode, struct bt_att *att,
> + void *user_data)
> +{
> + struct test_data *data = user_data;
> + struct ccc_state *ccc;
> + uint16_t handle;
> + uint8_t ecode = 0;
> + const uint8_t *value = NULL;
> + size_t len = 0;
> +
> + handle = gatt_db_attribute_get_handle(attrib);
> +
> + ccc = get_ccc_state(data, handle);
> + if (!ccc) {
> + ecode = BT_ATT_ERROR_UNLIKELY;
> + goto done;
> + }
> +
> + len = sizeof(ccc->value);
> + value = (void *) &ccc->value;
> +
> +done:
> + gatt_db_attribute_read_result(attrib, id, ecode, value, len);
> +}
> +
> +static void test_server(const void *user_data)
> +{
> + struct test_data *data = (void *)user_data;
> + struct bt_att *att;
> + struct io *io;
> +
> + io = tester_setup_io(data->iov, data->iovcnt);
> + g_assert(io);
> +
> + tester_io_set_complete_func(test_complete_cb);
> +
> + att = bt_att_new(io_get_fd(io), false);
> + g_assert(att);
> +
> + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
> +
> + data->db = gatt_db_new();
> + g_assert(data->db);
> +
> + gatt_db_ccc_register(data->db, gatt_ccc_read_cb, NULL,
> + gatt_notify_cb, data);
> +
> + data->micp = bt_micp_new(data->db, NULL);
> + g_assert(data->micp);
> +
> + data->server = bt_gatt_server_new(data->db, att, 64, 0);
> + g_assert(data->server);
> +
> + bt_gatt_server_set_debug(data->server, print_debug, "bt_gatt_server:",
> + NULL);
> +
> + data->ccc_states = queue_new();
> +
> + tester_io_send();
> +
> + bt_att_unref(att);
> +}
> +
> +#define EXCHANGE_MTU IOV_DATA(0x02, 0x40, 0x00), \
> + IOV_DATA(0x03, 0x40, 0x00)
> +
> +#define MICS_MUTE_WRITE_VAL_00 \
> + IOV_DATA(0x12, 0x03, 0x00, 0x00), \
> + IOV_DATA(0x13)
> +
> +#define MICS_MUTE_WRITE_VAL_01 \
> + IOV_DATA(0x12, 0x03, 0x00, 0x01), \
> + IOV_DATA(0x13)
> +
> +#define MICS_MUTE_READ \
> + IOV_DATA(0x0a, 0x03, 0x00), \
> + IOV_DATA(0x0b, 0x01)
> +
> +#define DISCOVER_PRIM_SERV_NOTIF \
> + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
> + IOV_DATA(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x4d, 0x18), \
> + IOV_DATA(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28), \
> + IOV_DATA(0x01, 0x10, 0x05, 0x00, 0x0a)
> +
> +/* ATT: Read By Type Request (0x08) len 6
> + * Handle range: 0x0001-0x0009
> + * Attribute type: Characteristic (0x2803)
> + * ATT: Read By Type Response (0x09) len 22
> + * Attribute data length: 7
> + * Handle: 0x0002
> + * Value: 1a0300c82b
> + * Properties: 0x1a
> + * Value Handle: 0x0003
> + * Value UUID: Mute (0x2bc3)
> + */
> +#define DISC_MICS_CHAR_1 \
> + IOV_DATA(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28), \
> + IOV_DATA(0x09, 0x07, \
> + 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \
> + IOV_DATA(0x08, 0x05, 0x00, 0x05, 0x00, 0x03, 0x28), \
> + IOV_DATA(0x01, 0x08, 0x05, 0x00, 0x0a)
> +
> +
> +#define MICS_FIND_BY_TYPE_VALUE \
> + IOV_DATA(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4d, 0x18), \
> + IOV_DATA(0x07, 0x01, 0x00, 0x04, 0x00), \
> + IOV_DATA(0x06, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4d, 0x18), \
> + IOV_DATA(0x01, 0x06, 0x05, 0x00, 0x0a)
> +
> +#define DISC_MICS_CHAR_AFTER_TYPE \
> + IOV_DATA(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28), \
> + IOV_DATA(0x09, 0x07, \
> + 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \
> + IOV_DATA(0x08, 0x03, 0x00, 0x05, 0x00, 0x03, 0x28), \
> + IOV_DATA(0x01, 0x08, 0x03, 0x00, 0x0a)
> +
> +#define MICS_WRITE_CCD \
> + IOV_DATA(0x12, 0x04, 0x00, 0x00, 0x00), \
> + IOV_DATA(0x13), \
> + IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \
> + IOV_DATA(0x13)
> +
> +#define MICS_FIND_INFO \
> + IOV_DATA(0x04, 0x04, 0x00, 0x05, 0x00), \
> + IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29), \
> + IOV_DATA(0x04, 0x05, 0x00, 0x05, 0x00), \
> + IOV_DATA(0x01, 0x04, 0x05, 0x00, 0x0a)
> +
> +#define MICS_SR_SPN_BV_01_C \
> + EXCHANGE_MTU, \
> + DISCOVER_PRIM_SERV_NOTIF, \
> + DISC_MICS_CHAR_1, \
> + MICS_FIND_BY_TYPE_VALUE, \
> + DISC_MICS_CHAR_AFTER_TYPE, \
> + MICS_FIND_INFO, \
> + MICS_WRITE_CCD, \
> + IOV_DATA(0x0a, 0x03, 0x00), \
> + IOV_DATA(0x0b, 0x01), \
> + MICS_MUTE_WRITE_VAL_00, \
> + IOV_DATA(0x1b, 0x03, 0x00, 0x00), \
> + MICS_MUTE_WRITE_VAL_01, \
> + IOV_DATA(0x1b, 0x03, 0x00, 0x01), \
> + IOV_DATA(0x0a, 0x03, 0x00), \
> + IOV_DATA(0x0b, 0x01)
> +
> +#define MICS_SR_SGGIT_SER_BV_01_C \
> + EXCHANGE_MTU, \
> + DISCOVER_PRIM_SERV_NOTIF, \
> + MICS_FIND_BY_TYPE_VALUE
> +
> +#define MICS_SR_SGGIT_CHA_BV_01_C \
> + EXCHANGE_MTU, \
> + DISCOVER_PRIM_SERV_NOTIF, \
> + MICS_FIND_BY_TYPE_VALUE, \
> + DISC_MICS_CHAR_AFTER_TYPE
> +
> +#define MICS_WRITE_MUTE_CHAR_INVALID \
> + IOV_DATA(0x12, 0x03, 0x00, 0x02), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x13), \
> + IOV_DATA(0x12, 0x03, 0x00, 0x05), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x13)
> +
> +#define MICS_SR_SPE_BI_1_C \
> + EXCHANGE_MTU, \
> + DISCOVER_PRIM_SERV_NOTIF, \
> + MICS_FIND_BY_TYPE_VALUE, \
> + MICS_WRITE_MUTE_CHAR_INVALID
> +
> +#define MICS_MUTE_READ_INVALID \
> + IOV_DATA(0x0a, 0x03, 0x00), \
> + IOV_DATA(0x0b, 0x02)
> +
> +#define MICS_MUTE_WRITE_1 \
> + IOV_DATA(0x12, 0x03, 0x00, 0x01), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80)
> +
> +#define MICS_MUTE_WRITE_0 \
> + IOV_DATA(0x12, 0x03, 0x00, 0x00), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80)
> +
> +#define MICS_SR_SPE_BI_02_C \
> + EXCHANGE_MTU, \
> + DISCOVER_PRIM_SERV_NOTIF, \
> + MICS_FIND_BY_TYPE_VALUE, \
> + MICS_MUTE_READ_INVALID, \
> + MICS_MUTE_WRITE_0, \
> + MICS_MUTE_WRITE_1
> +
> +int main(int argc, char *argv[])
> +{
> +
> + tester_init(&argc, &argv);
> +
> + define_test("MICS/SR/SGGIT/SER/BV-01-C", test_server, NULL,
> + MICS_SR_SGGIT_SER_BV_01_C);
> + define_test("MICS/SR/SGGIT/CHA/BV-01-C", test_server, NULL,
> + MICS_SR_SGGIT_CHA_BV_01_C);
> + define_test("MICS/SR/SPE/BI-01-C", test_server, NULL,
> + MICS_SR_SPE_BI_1_C);
> + define_test("MICS/SR/SPE/BI-02-C", test_server, NULL,
> + MICS_SR_SPE_BI_02_C);
> + define_test("MICS/SR/SPN/BV-01-C", test_server, NULL,
> + MICS_SR_SPN_BV_01_C);
> +
> + return tester_run();
> +}
> diff --git a/unit/test-mics.c b/unit/test-mics.c
> new file mode 100644
> index 000000000..fe84fb02d
> --- /dev/null
> +++ b/unit/test-mics.c
> @@ -0,0 +1,290 @@
> +// SPDX-License-Identifier: LGPL-2.1-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2023 NXP Semiconductors. All rights reserved.
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/socket.h>
> +#include <fcntl.h>
> +
> +
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +#include "lib/uuid.h"
> +#include "btio/btio.h"
> +#include "src/shared/util.h"
> +#include "src/shared/tester.h"
> +#include "src/shared/queue.h"
> +#include "src/shared/att.h"
> +#include "src/shared/gatt-db.h"
> +#include "src/shared/gatt-helpers.h"
> +#include "src/shared/micp.h"
> +
> +struct test_data {
> + struct gatt_db *db;
> + struct bt_micp *micp;
> + struct bt_gatt_client *client;
> + size_t iovcnt;
> + struct iovec *iov;
> + struct test_config *cfg;
> +};
> +
> +struct db_attribute_micp_test_data {
> + struct gatt_db_attribute *match;
> + bool found;
> +};
> +
> +#define MICP_GATT_CLIENT_MTU 64
> +#define iov_data(args...) ((const struct iovec[]) { args })
> +
> +#define define_test(name, function, _cfg, args...) \
> + do { \
> + const struct iovec iov[] = { args }; \
> + static struct test_data data; \
> + data.cfg = _cfg; \
> + data.iovcnt = ARRAY_SIZE(iov_data(args)); \
> + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
> + tester_add(name, &data, test_setup, function, \
> + test_teardown); \
> + } while (0)
> +
> +static void print_debug(const char *str, void *user_data)
> +{
> + const char *prefix = user_data;
> +
> + if (tester_use_debug())
> + tester_debug("%s %s", prefix, str);
> +}
> +
> +static void test_teardown(const void *user_data)
> +{
> + struct test_data *data = (void *)user_data;
> +
> + bt_gatt_client_unref(data->client);
> + util_iov_free(data->iov, data->iovcnt);
> + gatt_db_unref(data->db);
> +
> + tester_teardown_complete();
> +}
> +
> +static void test_complete_cb(const void *user_data)
> +{
> + tester_test_passed();
> +}
> +
> +static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
> +{
> +
> + if (!success)
> + tester_setup_failed();
> + else
> + tester_setup_complete();
> +}
> +
> +static void micp_ready(struct bt_micp *micp, void *user_data)
> +{
> + micp_write_value(micp, user_data);
> +}
> +
> +static void test_client(const void *user_data)
> +{
> + struct test_data *data = (void *)user_data;
> + struct io *io;
> +
> + io = tester_setup_io(data->iov, data->iovcnt);
> + g_assert(io);
> +
> + tester_io_set_complete_func(test_complete_cb);
> +
> + data->db = gatt_db_new();
> + g_assert(data->db);
> +
> + data->micp = bt_micp_new(data->db, bt_gatt_client_get_db(data->client));
> + g_assert(data->micp);
> +
> + bt_micp_set_debug(data->micp, print_debug, "bt_mip: ", NULL);
> +
> + bt_micp_ready_register(data->micp, micp_ready, data, NULL);
> +
> + bt_micp_attach(data->micp, data->client);
> +}
> +
> + /* ATT: Exchange MTU Response (0x03) len 2
> + * Server RX MTU: 64
> + */
> + /* ATT: Exchange MTU Request (0x02) len 2
> + * Client RX MTU: 64
> + */
> +#define ATT_EXCHANGE_MTU IOV_DATA(0x02, 0x40, 0x00), \
> + IOV_DATA(0x03, 0x40, 0x00)
> +
> +/*
> + * ATT: Read By Type Request (0x08) len 6
> + * Handle range: 0x0001-0xffff
> + * Attribute type: Server Supported Features (0x2b3a)
> + */
> +#define MICP_READ_SR_FEATURE IOV_DATA(0x08, 0x01, 0x00, 0Xff, 0xff, \
> + 0x3a, 0x2b), \
> + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a)
> +
> + /*
> + * ATT: Read By Group Type Request (0x10) len 6
> + * Handle range: 0x0001-0xffff
> + * Attribute group type: Primary Service (0x2800)
> + */
> +
> +/*
> + * ATT: Read By Group Type Response (0x11) len 7
> + * Attribute data length: 6
> + * Attribute group list: 1 entry
> + * Handle range: 0x00a0-0x00a4
> + * UUID: Microphone Control (0x184d)
> + */
> +#define MICP_READ_GROUP_TYPE \
> + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
> + IOV_DATA(0x11, 0x06, \
> + 0x01, 0x00, 0x04, 0x00, 0x4d, 0x18), \
> + IOV_DATA(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28), \
> + IOV_DATA(0x01, 0x10, 0x06, 0x00, 0x0a)
> +
> + /* ATT: Read By Group Type Request (0x10) len 6
> + * Handle range: 0x0001-0xffff
> + * Attribute group type: Secondary Service (0x2801)
> + */
> + /* ATT: Error Response (0x01) len 4
> + * Read By Group Type Request (0x10)
> + * Handle: 0x0001
> + * Error: Attribute Not Found (0x0a)08 01 00 05 00 02 28
> + */
> +#define MICP_READ_REQ_SECOND_SERVICE \
> + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), \
> + IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a)
> +
> +#define MICP_READ_REQ_INCLUDE_SERVICE \
> + IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28), \
> + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a)
> +
> + /* ATT: Read By Type Request (0x08) len 6
> + * Handle range: 0x0001-0x0004
> + * Attribute type: Characteristic (0x2803)
> + */
> +
> +/* ATT: Find Information Request (0x04) len 4
> + * Handle range: 0x0004-0x0004
> + */
> +#define MICP_FIND_INFO_REQ \
> + IOV_DATA(0x04, 0x04, 0x00, 0x04, 0x00), \
> + IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29)
> +
> +/*
> + * ATT: Read By Type Request (0x08) len 6
> + * Handle range: 0x0001-0x0004
> + * Attribute type: Characteristic (0x2803)
> + */
> +#define MICP_READ_REQ_CHAR \
> + IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),\
> + IOV_DATA(0x09, 0x07, \
> + 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \
> + IOV_DATA(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28), \
> + IOV_DATA(0x01, 0x08, 0x04, 0x00, 0x0a)
> +
> +#define MICS_MUTE_READ \
> + IOV_DATA(0x0a, 0x03, 0x00), \
> + IOV_DATA(0x0b, 0x01)
> +
> +#define MICS_EN_MUTE_DISCPTR \
> + IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \
> + IOV_DATA(0x13)
> +
> +#define MICS_MUTE_WRITE \
> + IOV_DATA(0x12, 0x03, 0x00, 0x01),\
> + IOV_DATA(0x13)
> +
> +#define MICP_CL_CGGIT_SER_BV_01_C \
> + MICS_MUTE_READ, \
> + MICS_EN_MUTE_DISCPTR, \
> + IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x013)
> +
> +#define MICP_CL_CGGIT_CHA_BV_01_C \
> + MICS_MUTE_READ, \
> + MICS_EN_MUTE_DISCPTR, \
> + IOV_DATA(0x12, 0x03, 0x00, 0x06, 0x00), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x013), \
> + MICS_MUTE_READ
> +
> +#define MICP_CL_SPE_BI_01_C \
> + MICS_MUTE_READ, \
> + MICS_EN_MUTE_DISCPTR, \
> + IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \
> + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80)
> +
> +/* GATT Discover All procedure */
> +static const struct iovec setup_data[] = {
> + ATT_EXCHANGE_MTU,
> + MICP_READ_SR_FEATURE,
> + MICP_READ_GROUP_TYPE,
> + MICP_READ_REQ_SECOND_SERVICE,
> + MICP_READ_REQ_INCLUDE_SERVICE,
> + MICP_READ_REQ_CHAR,
> + MICP_FIND_INFO_REQ
> +};
> +
> +static void test_setup(const void *user_data)
> +{
> + struct test_data *data = (void *)user_data;
> + struct bt_att *att;
> + struct gatt_db *db;
> + struct io *io;
> +
> + io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data));
> + g_assert(io);
> +
> + att = bt_att_new(io_get_fd(io), false);
> + g_assert(att);
> +
> + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
> +
> + db = gatt_db_new();
> + g_assert(db);
> +
> +
> + data->client = bt_gatt_client_new(db, att, MICP_GATT_CLIENT_MTU, 0);
> + g_assert(data->client);
> +
> + bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
> + NULL);
> +
> + bt_gatt_client_ready_register(data->client, client_ready_cb, data,
> + NULL);
> +
> + bt_att_unref(att);
> + gatt_db_unref(db);
> +}
> +
> +
> +int main(int argc, char *argv[])
> +{
> +
> + tester_init(&argc, &argv);
> +
> + define_test("MICP/CL/CGGIT/SER/BV-01-C", test_client, NULL,
> + MICS_MUTE_READ);
> + define_test("MICP/CL/CGGIT/CHA/BV-01-C", test_client, NULL,
> + MICP_CL_CGGIT_SER_BV_01_C);
> + define_test("MICP/CL/SPE/BI-01-C", test_client, NULL,
> + MICP_CL_SPE_BI_01_C);
> +
> + return tester_run();
> +}
> --
> 2.34.1
>


--
Luiz Augusto von Dentz