| // 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/gatt-helpers.h" |
| #include "src/shared/micp.h" |
| |
| struct test_data_mics { |
| 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_data_micp { |
| struct gatt_db *db; |
| struct bt_micp *micp; |
| struct bt_gatt_client *client; |
| size_t iovcnt; |
| struct iovec *iov; |
| }; |
| |
| 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 MICP_GATT_CLIENT_MTU 64 |
| |
| #define iov_data(args...) ((const struct iovec[]) { args }) |
| |
| #define define_test_mics(name, function, _cfg, args...) \ |
| do { \ |
| const struct iovec iov[] = { args }; \ |
| static struct test_data_mics data; \ |
| 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_mics); \ |
| } while (0) |
| |
| #define define_test_micp(name, function, _cfg, args...) \ |
| do { \ |
| const struct iovec iov[] = { args }; \ |
| static struct test_data_micp data; \ |
| 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_micp); \ |
| } 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_mics(const void *user_data) |
| { |
| struct test_data_mics *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_teardown_micp(const void *user_data) |
| { |
| struct test_data_micp *data = (void *)user_data; |
| |
| bt_micp_unref(data->micp); |
| 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_write_cb(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); |
| } |
| |
| static 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; |
| uint16_t value = cpu_to_le16(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_cb, NULL, NULL); |
| |
| if (!ret) |
| printf("bt_gatt_client_write_value() : Write FAILED"); |
| } |
| |
| 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_micp *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_micp: ", NULL); |
| |
| bt_micp_ready_register(data->micp, micp_ready, data, NULL); |
| |
| bt_micp_attach(data->micp, data->client); |
| } |
| |
| 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_mics *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_mics *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_mics *data = user_data; |
| struct notify notify; |
| |
| memset(¬ify, 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_mics *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_mics *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); |
| } |
| |
| /* |
| * ATT: Exchange MTU Request (0x02) len 2 |
| * Client RX MTU: 64 |
| * |
| * ATT: Exchange MTU Response (0x03) len 2 |
| * Server 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) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Type Request (0x08) |
| * Handle: 0x0001 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #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: 0x0001-0x0004 |
| * UUID: Microphone Control (0x184d) |
| * |
| * ATT: Read By Group Type Request (0x10) len 6 |
| * Handle range: 0x0005-0xffff |
| * Attribute group type: Primary Service (0x2800) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Group Type Request (0x10) |
| * Handle: 0x0006 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #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) |
| */ |
| #define MICP_READ_REQ_SECOND_SERVICE \ |
| IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), \ |
| IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a) |
| |
| /* |
| * ATT: Read By Type Request (0x08) len 6 |
| * Handle range: 0x0001-0x0004 |
| * Attribute type: Include (0x2802) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Type Request (0x08) |
| * Handle: 0x0001 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #define MICP_READ_REQ_INCLUDE_SERVICE \ |
| IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28), \ |
| IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a) |
| |
| /* 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) |
| * |
| * ATT: Read By Type Response (0x09) len 8 |
| * Attribute data length: 7 |
| * Attribute data list: 1 entry |
| * Handle: 0x0002 |
| * Value: 1a0300c32b |
| * |
| * ATT: Read By Type Request (0x08) len 6 |
| * Handle range: 0x0003-0x0004 |
| * Attribute type: Characteristic (0x2803) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Type Request (0x08) |
| * Handle: 0x0004 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #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) |
| /* |
| * ATT: Read Request (0x0a) len 2 |
| * Handle: 0x0003 |
| * |
| * ATT: Read Response (0x0b) len 1 |
| */ |
| #define MICS_MUTE_READ \ |
| IOV_DATA(0x0a, 0x03, 0x00), \ |
| IOV_DATA(0x0b, 0x01) |
| |
| /* |
| * ATT: Write Request (0x12) len 4 |
| * Handle: 0x0004 |
| * Data: 0100 |
| * ATT: Write Response (0x13) len 0 |
| */ |
| #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, 0x01, 0x00), \ |
| IOV_DATA(0x013) |
| |
| #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_micp *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); |
| } |
| |
| /* |
| * ATT: Write Request (0x12) len 3 |
| * Handle: 0x0003 |
| * Data: 00 |
| * |
| * ATT: Write Response (0x13) len 0 |
| */ |
| #define MICS_MUTE_WRITE_VAL_00 \ |
| IOV_DATA(0x12, 0x03, 0x00, 0x00), \ |
| IOV_DATA(0x13) |
| |
| /* |
| * ATT: Write Request (0x12) len 3 |
| * Handle: 0x0003 |
| * Data: 01 |
| * |
| * ATT: Write Response (0x13) len 0 |
| */ |
| #define MICS_MUTE_WRITE_VAL_01 \ |
| IOV_DATA(0x12, 0x03, 0x00, 0x01), \ |
| IOV_DATA(0x13) |
| /* |
| * ATT: Read Request (0x0a) len 2 |
| * Handle: 0x0003 |
| * |
| * ATT: Read Response (0x0b) len 1 |
| */ |
| #define MICS_MUTE_READ \ |
| IOV_DATA(0x0a, 0x03, 0x00), \ |
| IOV_DATA(0x0b, 0x01) |
| |
| /* |
| * 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: 0x0001-0x0004 |
| * UUID: Microphone Control (0x184d) |
| * |
| * ATT: Read By Group Type Request (0x10) len 6 |
| * Handle range: 0x0005-0xffff |
| * Attribute group type: Primary Service (0x2800) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Group Type Request (0x10) |
| * Handle: 0x0005 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #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-0x0005 |
| * Attribute type: Characteristic (0x2803) |
| * |
| * ATT: Read By Type Response (0x09) len 8 |
| * Attribute data length: 7 |
| * Attribute data list: 1 entry |
| * Handle: 0x0002 |
| * Value: 1a0300c32b |
| * |
| * ATT: Read By Type Request (0x08) len 6 |
| * Handle range: 0x0005-0x0005 |
| * Attribute type: Characteristic (0x2803) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Type Request (0x08) |
| * Handle: 0x0005 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #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) |
| |
| /* |
| * ATT: Find By Type Value Request (0x06) len 8 |
| * Handle range: 0x0001-0xffff |
| * Attribute type: Primary Service (0x2800) |
| * UUID: Microphone Control (0x184d) |
| * |
| * ATT: Find By Type Value Response (0x07) len 4 |
| * Handle range: 0x0001-0x0004 |
| * |
| * ATT: Find By Type Value Request (0x06) len 8 |
| * Handle range: 0x0005-0xffff |
| * Attribute type: Primary Service (0x2800) |
| * UUID: Microphone Control (0x184d) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Find By Type Value Request (0x06) |
| * Handle: 0x0005 |
| * Error: Attribute Not Found (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) |
| |
| /* |
| * ATT: Read By Type Request (0x08) len 6 |
| * Handle range: 0x0001-0x0005 |
| * Attribute type: Characteristic (0x2803) |
| * |
| * ATT: Read By Type Response (0x09) len 8 |
| * Attribute data length: 7 |
| * Attribute data list: 1 entry |
| * Handle: 0x0002 |
| * Value: 1a0300c32b |
| * |
| * ATT: Read By Type Request (0x08) len 6 |
| * Handle range: 0x0003-0x0005 |
| * Attribute type: Characteristic (0x2803) |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Read By Type Request (0x08) |
| * Handle: 0x0003 |
| * Error: Attribute Not Found (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) |
| |
| /* |
| * ATT: Write Request (0x12) len 4 |
| * Handle: 0x0004 |
| * Data: 0000 |
| * |
| * ATT: Write Response (0x13) len 0 |
| * |
| * ATT: Write Request (0x12) len 4 |
| * Handle: 0x0004 |
| * Data: 0100 |
| * |
| * ATT: Write Response (0x13) len 0 |
| */ |
| #define MICS_WRITE_CCD \ |
| IOV_DATA(0x12, 0x04, 0x00, 0x00, 0x00), \ |
| IOV_DATA(0x13), \ |
| IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \ |
| IOV_DATA(0x13) |
| |
| /* |
| * ATT: Find Information Request (0x04) len 4 |
| * Handle range: 0x0004-0x0005 |
| * |
| * ATT: Find Information Response (0x05) len 5 |
| * Format: UUID-16 (0x01) |
| * Handle: 0x0004 |
| * UUID: Client Characteristic Configuration (0x2902) |
| * |
| * ATT: Find Information Request (0x04) len 4 |
| * Handle range: 0x0005-0x0005 |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Find Information Request (0x04) |
| * Handle: 0x0005 |
| * Error: Attribute Not Found (0x0a) |
| */ |
| #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) |
| |
| /* |
| * 1.reads the characteristic value for the |
| * Mute characteristic |
| * 2.update the Mute characteristic to 0 or 1 |
| * 3.sends a notification containing the updated value |
| * of the Mute characteristic |
| * 4.update the Mute characteristic to 0 or 1 which ever |
| * different than step 2 |
| * 5.sends a notification containing the updated value of |
| * the Mute characteristic |
| */ |
| #define MICS_SR_SPN_BV_01_C \ |
| ATT_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 \ |
| ATT_EXCHANGE_MTU, \ |
| DISCOVER_PRIM_SERV_NOTIF, \ |
| MICS_FIND_BY_TYPE_VALUE |
| |
| #define MICS_SR_SGGIT_CHA_BV_01_C \ |
| ATT_EXCHANGE_MTU, \ |
| DISCOVER_PRIM_SERV_NOTIF, \ |
| MICS_FIND_BY_TYPE_VALUE, \ |
| DISC_MICS_CHAR_AFTER_TYPE |
| |
| /* |
| * ATT: Write Request (0x12) len 3 |
| * Handle: 0x0003 |
| * Data: 02 |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Write Request (0x12) |
| * Handle: 0x0003 |
| * Error: Value Not Allowed (0x13) |
| * |
| * ATT: Write Request (0x12) len 3 |
| * Handle: 0x0003 |
| * Data: 05 |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Write Request (0x12) |
| * Handle: 0x0003 |
| * Error: Value Not Allowed (0x13) |
| */ |
| #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 \ |
| ATT_EXCHANGE_MTU, \ |
| DISCOVER_PRIM_SERV_NOTIF, \ |
| MICS_FIND_BY_TYPE_VALUE, \ |
| MICS_WRITE_MUTE_CHAR_INVALID |
| |
| /* |
| * ATT: Read Request (0x0a) len 2 |
| * Handle: 0x0003 |
| * |
| * ATT: Read Response (0x0b) len 1 |
| */ |
| #define MICS_MUTE_READ_INVALID \ |
| IOV_DATA(0x0a, 0x03, 0x00), \ |
| IOV_DATA(0x0b, 0x02) |
| |
| /* |
| * ATT: Write Request (0x12) len 3 |
| * Handle: 0x0003 |
| * Data: 01 |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Write Request (0x12) |
| * Handle: 0x0003 |
| * Error: Reserved (0x80) |
| */ |
| #define MICS_MUTE_WRITE_1 \ |
| IOV_DATA(0x12, 0x03, 0x00, 0x01), \ |
| IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80) |
| |
| /* |
| * ATT: Write Request (0x12) len 3 |
| * Handle: 0x0003 |
| * Data: 00 |
| * |
| * ATT: Error Response (0x01) len 4 |
| * Write Request (0x12) |
| * Handle: 0x0003 |
| * Error: Reserved (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 \ |
| ATT_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); |
| |
| /* MICS Testcases */ |
| define_test_mics("MICS/SR/SGGIT/SER/BV-01-C", test_server, NULL, |
| MICS_SR_SGGIT_SER_BV_01_C); |
| define_test_mics("MICS/SR/SGGIT/CHA/BV-01-C", test_server, NULL, |
| MICS_SR_SGGIT_CHA_BV_01_C); |
| define_test_mics("MICS/SR/SPE/BI-01-C", test_server, NULL, |
| MICS_SR_SPE_BI_1_C); |
| |
| /* MICS/SR/SPE/BI-02-C: |
| * In function *mics_new(struct gatt_db *db)[src/shared/micp.c] |
| * by default the mics->mute_stat is set to MICS_MUTED[0x01]. |
| * As per test specs, Testcase MICS/SR/SPE/BI-02-C, Initial |
| * condition of mute state should be MICS_DISABLED[0x02]. |
| * To verify this Unit test case we have to modify the initial |
| * state of mics->mute_stat to MICS_DISABLED in code |
| * [in func mics_new()], build it and run bluetoothd. Then run |
| * this unit test case and this test case will Pass. |
| */ |
| /* define_test_mics("MICS/SR/SPE/BI-02-C", test_server, NULL, |
| * MICS_SR_SPE_BI_02_C); |
| */ |
| define_test_mics("MICS/SR/SPN/BV-01-C", test_server, NULL, |
| MICS_SR_SPN_BV_01_C); |
| |
| /* MICP Testcases */ |
| define_test_micp("MICP/CL/CGGIT/SER/BV-01-C", test_client, NULL, |
| MICP_CL_CGGIT_SER_BV_01_C); |
| define_test_micp("MICP/CL/CGGIT/CHA/BV-01-C", test_client, NULL, |
| MICP_CL_CGGIT_CHA_BV_01_C); |
| define_test_micp("MICP/CL/SPE/BI-01-C", test_client, NULL, |
| MICP_CL_SPE_BI_01_C); |
| |
| return tester_run(); |
| } |