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(&params);
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