1 /* btp_has.c - Bluetooth HAS Tester */
2
3 /*
4 * Copyright (c) 2023 Oticon
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8 #include <zephyr/bluetooth/audio/has.h>
9
10 #include "btp/btp.h"
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/arch/common/ffs.h>
13 #include <stdint.h>
14
15 #include <zephyr/logging/log.h>
16 #define LOG_MODULE_NAME bttester_has
17 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
18
has_supported_commands(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)19 static uint8_t has_supported_commands(const void *cmd, uint16_t cmd_len,
20 void *rsp, uint16_t *rsp_len)
21 {
22 struct btp_has_read_supported_commands_rp *rp = rsp;
23
24 tester_set_bit(rp->data, BTP_HAS_READ_SUPPORTED_COMMANDS);
25 tester_set_bit(rp->data, BTP_HAS_SET_ACTIVE_INDEX);
26 tester_set_bit(rp->data, BTP_HAS_SET_PRESET_NAME);
27 tester_set_bit(rp->data, BTP_HAS_REMOVE_PRESET);
28 tester_set_bit(rp->data, BTP_HAS_ADD_PRESET);
29 tester_set_bit(rp->data, BTP_HAS_SET_PROPERTIES);
30
31 *rsp_len = sizeof(*rp) + 1;
32
33 return BTP_STATUS_SUCCESS;
34 }
35
has_set_active_index(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)36 static uint8_t has_set_active_index(const void *cmd, uint16_t cmd_len,
37 void *rsp, uint16_t *rsp_len)
38 {
39 const struct btp_has_set_active_index_cmd *cp = cmd;
40 int err = bt_has_preset_active_set(cp->index);
41
42 return BTP_STATUS_VAL(err);
43 }
44
45 static uint16_t has_presets;
46 static char temp_name[BT_HAS_PRESET_NAME_MAX + 1];
47
has_set_preset_name(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)48 static uint8_t has_set_preset_name(const void *cmd, uint16_t cmd_len,
49 void *rsp, uint16_t *rsp_len)
50 {
51 const struct btp_has_set_preset_name_cmd *cp = cmd;
52 const uint16_t fixed_size = sizeof(*cp);
53 int err = -1;
54
55 if (cmd_len >= fixed_size && cmd_len >= (fixed_size + cp->length)) {
56 int name_len = MIN(cp->length, BT_HAS_PRESET_NAME_MAX);
57
58 memcpy(temp_name, cp->name, name_len);
59 temp_name[name_len] = '\0';
60 err = bt_has_preset_name_change(cp->index, temp_name);
61 }
62 return BTP_STATUS_VAL(err);
63 }
64
has_remove_preset(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)65 static uint8_t has_remove_preset(const void *cmd, uint16_t cmd_len,
66 void *rsp, uint16_t *rsp_len)
67 {
68 const struct btp_has_remove_preset_cmd *cp = cmd;
69 int err = 0;
70
71 if (cp->index == BT_HAS_PRESET_INDEX_NONE) {
72 while (has_presets) {
73 uint8_t index = find_lsb_set(has_presets);
74
75 err = bt_has_preset_unregister(index);
76 if (err) {
77 break;
78 }
79 has_presets &= ~(1 << (index - 1));
80 }
81 } else {
82 err = bt_has_preset_unregister(cp->index);
83 if (!err) {
84 has_presets &= ~(1 << (cp->index - 1));
85 }
86 }
87 return BTP_STATUS_VAL(err);
88 }
89
has_preset_selected(unsigned char index,bool sync)90 static int has_preset_selected(unsigned char index, bool sync)
91 {
92 return BTP_STATUS_SUCCESS;
93 }
94
95 static const struct bt_has_preset_ops has_preset_ops = {
96 has_preset_selected, NULL
97 };
98
has_add_preset(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)99 static uint8_t has_add_preset(const void *cmd, uint16_t cmd_len,
100 void *rsp, uint16_t *rsp_len)
101 {
102 const struct btp_has_add_preset_cmd *cp = cmd;
103 const uint16_t fixed_size = sizeof(*cp);
104 int err = -1;
105
106 if (cmd_len >= fixed_size && cmd_len >= (fixed_size + cp->length)) {
107 int name_len = MIN(cp->length, BT_HAS_PRESET_NAME_MAX);
108
109 memcpy(temp_name, cp->name, name_len);
110 temp_name[name_len] = '\0';
111 struct bt_has_preset_register_param preset_params = {
112 cp->index, cp->props, temp_name, &has_preset_ops
113 };
114 err = bt_has_preset_register(&preset_params);
115 if (!err) {
116 has_presets |= 1 << (cp->index - 1);
117 }
118 }
119 return BTP_STATUS_VAL(err);
120 }
121
has_set_properties(const void * cmd,uint16_t cmd_len,void * rsp,uint16_t * rsp_len)122 static uint8_t has_set_properties(const void *cmd, uint16_t cmd_len,
123 void *rsp, uint16_t *rsp_len)
124 {
125 const struct btp_has_set_properties_cmd *cp = cmd;
126 int err = (cp->props & BT_HAS_PROP_AVAILABLE) ?
127 bt_has_preset_available(cp->index) :
128 bt_has_preset_unavailable(cp->index);
129
130 return BTP_STATUS_VAL(err);
131 }
132
133 static const struct btp_handler has_handlers[] = {
134 {
135 .opcode = BTP_HAS_READ_SUPPORTED_COMMANDS,
136 .index = BTP_INDEX_NONE,
137 .expect_len = 0,
138 .func = has_supported_commands
139 },
140 {
141 .opcode = BTP_HAS_SET_ACTIVE_INDEX,
142 .expect_len = sizeof(struct btp_has_set_active_index_cmd),
143 .func = has_set_active_index
144 },
145 {
146 .opcode = BTP_HAS_SET_PRESET_NAME,
147 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
148 .func = has_set_preset_name
149 },
150 {
151 .opcode = BTP_HAS_REMOVE_PRESET,
152 .expect_len = sizeof(struct btp_has_remove_preset_cmd),
153 .func = has_remove_preset
154 },
155 {
156 .opcode = BTP_HAS_ADD_PRESET,
157 .expect_len = BTP_HANDLER_LENGTH_VARIABLE,
158 .func = has_add_preset
159 },
160 {
161 .opcode = BTP_HAS_SET_PROPERTIES,
162 .expect_len = sizeof(struct btp_has_set_properties_cmd),
163 .func = has_set_properties
164 }
165 };
166
tester_init_has(void)167 uint8_t tester_init_has(void)
168 {
169 tester_register_command_handlers(BTP_SERVICE_ID_HAS, has_handlers,
170 ARRAY_SIZE(has_handlers));
171
172 struct bt_has_features_param params = {
173 .type = BT_HAS_HEARING_AID_TYPE_BINAURAL,
174 .preset_sync_support = false,
175 .independent_presets = IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT)
176 };
177 int err = bt_has_register(¶ms);
178
179 return BTP_STATUS_VAL(err);
180 }
181
tester_unregister_has(void)182 uint8_t tester_unregister_has(void)
183 {
184 return BTP_STATUS_SUCCESS;
185 }
186