xref: /btstack/src/le-audio/gatt-service/broadcast_audio_scan_service_server.c (revision 77bf845768a9c39a5561c69033c0112e62f08947)
1 /*
2  * Copyright (C) 2022 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "broadcast_audio_scan_service_server.c"
39 
40 #include <stdio.h>
41 
42 #include "ble/att_db.h"
43 #include "ble/att_server.h"
44 #include "bluetooth_gatt.h"
45 #include "btstack_debug.h"
46 #include "btstack_defines.h"
47 #include "btstack_event.h"
48 #include "btstack_util.h"
49 
50 #include "le-audio/gatt-service/broadcast_audio_scan_service_server.h"
51 #include "le-audio/le_audio_util.h"
52 
53 #ifdef ENABLE_TESTING_SUPPORT
54 #include <stdio.h>
55 #endif
56 
57 #define BASS_MAX_NOTIFY_BUFFER_SIZE                             200
58 #define BASS_INVALID_SOURCE_INDEX                               0xFF
59 
60 static att_service_handler_t    broadcast_audio_scan_service;
61 static btstack_packet_handler_t bass_server_event_callback;
62 
63 // characteristic: AUDIO_SCAN_CONTROL_POINT
64 static uint16_t bass_audio_scan_control_point_handle;
65 
66 static uint8_t  bass_logic_time = 0;
67 
68 static bass_server_source_t * bass_sources;
69 static uint8_t  bass_sources_num = 0;
70 static bass_server_connection_t * bass_clients;
71 static uint8_t  bass_clients_num = 0;
72 static btstack_context_callback_registration_t  scheduled_tasks_callback;
73 
74 static uint8_t bass_server_get_next_update_counter(void){
75     uint8_t next_update_counter;
76     if (bass_logic_time == 0xff) {
77         next_update_counter = 0;
78     } else {
79         next_update_counter = bass_logic_time + 1;
80     }
81     bass_logic_time = next_update_counter;
82     return next_update_counter;
83 }
84 
85 // returns positive number if counter a > b
86 static int8_t bass_server_counter_delta(uint8_t counter_a, uint8_t counter_b){
87     return (int8_t)(counter_a - counter_b);
88 }
89 
90 static uint8_t bass_server_find_empty_or_last_used_source_index(void){
91     bass_server_source_t * last_used_source = NULL;
92     uint8_t last_used_source_index = BASS_INVALID_SOURCE_INDEX;
93 
94     uint8_t i;
95     for (i = 0; i < bass_sources_num; i++){
96         if (!bass_sources[i].in_use){
97             return i;
98         }
99         if (last_used_source == NULL){
100             last_used_source = &bass_sources[i];
101             last_used_source_index = i;
102             continue;
103         }
104         if (bass_server_counter_delta(bass_sources[i].update_counter, last_used_source->update_counter) < 0 ){
105             last_used_source = &bass_sources[i];
106             last_used_source_index = i;
107         }
108     }
109     return last_used_source_index;
110 }
111 
112 static bass_server_source_t *  bass_server_find_empty_or_last_used_source(void){
113     uint8_t last_used_source_index = bass_server_find_empty_or_last_used_source_index();
114     if (last_used_source_index == BASS_INVALID_SOURCE_INDEX){
115         return NULL;
116     }
117     return &bass_sources[last_used_source_index];
118 }
119 
120 static bass_server_source_t * bass_server_find_receive_state_for_value_handle(uint16_t attribute_handle){
121     uint16_t i;
122     for (i = 0; i < bass_sources_num; i++){
123         if (attribute_handle == bass_sources[i].bass_receive_state_handle){
124             return &bass_sources[i];
125         }
126     }
127     return NULL;
128 }
129 
130 static bass_server_source_t * bass_server_find_receive_state_for_client_configuration_handle(uint16_t attribute_handle){
131     if (attribute_handle == 0){
132         return NULL;
133     }
134     uint8_t i;
135     for (i = 0; i < bass_sources_num; i++){
136         if (bass_sources[i].bass_receive_state_client_configuration_handle == attribute_handle){
137             return &bass_sources[i];
138         }
139     }
140     return NULL;
141 }
142 
143 static bass_server_source_t * bass_server_find_source_for_source_id(uint8_t source_id){
144     if (source_id < bass_sources_num){
145         return &bass_sources[source_id];
146     }
147     return NULL;
148 }
149 
150 static bass_server_connection_t * bass_server_find_client_for_con_handle(hci_con_handle_t con_handle){
151     uint16_t i;
152     for (i = 0; i < bass_clients_num; i++){
153         if (bass_clients[i].con_handle == con_handle) {
154             return &bass_clients[i];
155         }
156     }
157     return NULL;
158 }
159 
160 static void bass_server_register_con_handle(hci_con_handle_t con_handle, uint16_t client_configuration){
161     bass_server_connection_t * client = bass_server_find_client_for_con_handle(con_handle);
162     if (client == NULL){
163         client = bass_server_find_client_for_con_handle(HCI_CON_HANDLE_INVALID);
164         if (client == NULL){
165             return;
166         }
167 
168     }
169     client->con_handle = (client_configuration == 0) ? HCI_CON_HANDLE_INVALID : con_handle;
170 }
171 
172 static void bass_server_source_emit_scan_stoped(hci_con_handle_t con_handle){
173     btstack_assert(bass_server_event_callback != NULL);
174 
175     uint8_t event[5];
176     uint8_t pos = 0;
177     event[pos++] = HCI_EVENT_GATTSERVICE_META;
178     event[pos++] = sizeof(event) - 2;
179     event[pos++] = GATTSERVICE_SUBEVENT_BASS_SERVER_SCAN_STOPPED;
180     little_endian_store_16(event, pos, con_handle);
181     pos += 2;
182     (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
183 }
184 
185 static void bass_server_source_emit_scan_started(hci_con_handle_t con_handle){
186     btstack_assert(bass_server_event_callback != NULL);
187 
188     uint8_t event[5];
189     uint8_t pos = 0;
190     event[pos++] = HCI_EVENT_GATTSERVICE_META;
191     event[pos++] = sizeof(event) - 2;
192     event[pos++] = GATTSERVICE_SUBEVENT_BASS_SERVER_SCAN_STARTED;
193     little_endian_store_16(event, pos, con_handle);
194     pos += 2;
195     (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
196 }
197 
198 
199 static void bass_server_source_emit_source_state_changed(uint8_t subevent_id, hci_con_handle_t con_handle, uint8_t source_id, le_audio_pa_sync_t pa_sync){
200     btstack_assert(bass_server_event_callback != NULL);
201 
202     uint8_t event[7];
203     uint8_t pos = 0;
204     event[pos++] = HCI_EVENT_GATTSERVICE_META;
205     event[pos++] = sizeof(event) - 2;
206     event[pos++] = subevent_id;
207     little_endian_store_16(event, pos, con_handle);
208     pos += 2;
209     event[pos++] = source_id;
210     event[pos++] = (uint8_t)pa_sync;
211     (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
212 }
213 
214 static void bass_server_source_emit_source_added(hci_con_handle_t con_handle, bass_server_source_t * source){
215     bass_server_source_emit_source_state_changed(GATTSERVICE_SUBEVENT_BASS_SERVER_SOURCE_ADDED, con_handle, source->source_id, source->data.pa_sync);
216 }
217 
218 static void bass_server_source_emit_source_modified(hci_con_handle_t con_handle, bass_server_source_t * source){
219     bass_server_source_emit_source_state_changed(GATTSERVICE_SUBEVENT_BASS_SERVER_SOURCE_MODIFIED, con_handle, source->source_id, source->data.pa_sync);
220 }
221 
222 static void bass_server_source_emit_source_deleted(hci_con_handle_t con_handle, bass_server_source_t * source){
223     bass_server_source_emit_source_state_changed(GATTSERVICE_SUBEVENT_BASS_SERVER_SOURCE_DELETED, con_handle, source->source_id, LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA);
224 }
225 
226 static void bass_server_source_emit_broadcast_code(hci_con_handle_t con_handle, uint8_t source_id, const uint8_t * broadcast_code){
227     btstack_assert(bass_server_event_callback != NULL);
228 
229     uint8_t event[22];
230     uint8_t pos = 0;
231     event[pos++] = HCI_EVENT_GATTSERVICE_META;
232     event[pos++] = sizeof(event) - 2;
233     event[pos++] = GATTSERVICE_SUBEVENT_BASS_SERVER_BROADCAST_CODE;
234     little_endian_store_16(event, pos, con_handle);
235     pos += 2;
236     event[pos++] = source_id;
237     reverse_128(broadcast_code, &event[pos]);
238     pos += 16;
239     (*bass_server_event_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
240 }
241 
242 // offset gives position into fully serialized bass record
243 static uint16_t bass_server_copy_source_to_buffer(bass_server_source_t * source, uint16_t buffer_offset, uint8_t * buffer, uint16_t buffer_size){
244     uint8_t  field_data[16];
245     uint16_t source_offset = 0;
246     uint16_t stored_bytes = 0;
247     memset(buffer, 0, buffer_size);
248 
249     if (!source->in_use){
250         return 0;
251     }
252     field_data[0] = source->source_id;
253     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
254                                                         buffer_offset);
255     source_offset++;
256 
257     stored_bytes += bass_util_source_data_header_virtual_memcpy(&source->data, &source_offset, buffer_offset, buffer,
258                                                                 buffer_size);
259 
260     field_data[0] = (uint8_t)source->data.pa_sync_state;
261     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
262                                                         buffer_offset);
263     source_offset++;
264 
265     field_data[0] = (uint8_t)source->big_encryption;
266     stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 1, source_offset, buffer, buffer_size,
267                                                         buffer_offset);
268     source_offset++;
269 
270     if (source->big_encryption == LE_AUDIO_BIG_ENCRYPTION_BAD_CODE){
271         reverse_128(source->bad_code, &field_data[0]);
272         stored_bytes += le_audio_util_virtual_memcpy_helper(field_data, 16, source_offset, buffer, buffer_size,
273                                                             buffer_offset);
274         source_offset += 16;
275     }
276 
277     stored_bytes += bass_util_source_data_subgroups_virtual_memcpy(&source->data, true, &source_offset, buffer_offset,
278                                                                    buffer,
279                                                                    buffer_size);
280     return stored_bytes;
281 }
282 
283 static uint16_t bass_server_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
284     UNUSED(con_handle);
285 
286     bass_server_source_t * source = bass_server_find_receive_state_for_value_handle(attribute_handle);
287     if (source){
288         return bass_server_copy_source_to_buffer(source, offset, buffer, buffer_size);
289     }
290 
291     source = bass_server_find_receive_state_for_client_configuration_handle(attribute_handle);
292     if (source){
293         return att_read_callback_handle_little_endian_16(source->bass_receive_state_client_configuration, offset, buffer, buffer_size);
294     }
295 
296     return 0;
297 }
298 
299 static bool bass_server_source_remote_modify_source_buffer_valid(uint8_t *buffer, uint16_t buffer_size){
300     if (buffer_size < 5){
301         log_info("Modify Source opcode, buffer too small");
302         return false;
303     }
304 
305     uint8_t pos = 1; // source_id
306     return bass_util_pa_sync_state_and_subgroups_in_valid_range(buffer+pos, buffer_size-pos);
307 }
308 
309 static void bass_server_add_source_from_buffer(uint8_t *buffer, uint16_t buffer_size, bass_server_source_t * source){
310     UNUSED(buffer_size);
311 
312     source->update_counter = bass_server_get_next_update_counter();
313     source->in_use = true;
314 
315     bass_util_source_data_parse(buffer, buffer_size, &source->data, false);
316 }
317 
318 static bool bass_server_pa_synchronized(bass_server_source_t * source){
319     return source->data.pa_sync_state == LE_AUDIO_PA_SYNC_STATE_SYNCHRONIZED_TO_PA;
320 }
321 
322 
323 static bool bass_server_bis_synchronized(bass_server_source_t * source){
324     uint8_t i;
325     for (i = 0; i < source->data.subgroups_num; i++){
326         if ((source->data.subgroups[i].bis_sync_state > 0) && (source->data.subgroups[i].bis_sync_state < 0xFFFFFFFF)){
327             return true;
328         }
329     }
330     return false;
331 }
332 
333 
334 static void bass_server_reset_source(bass_server_source_t * source){
335     source->in_use = false;
336     source->data.address_type = BD_ADDR_TYPE_LE_PUBLIC;
337     memset(source->data.address, 0, sizeof(source->data.address));
338     source->data.adv_sid = 0;
339     source->data.broadcast_id = 0;
340     source->data.pa_sync = LE_AUDIO_PA_SYNC_DO_NOT_SYNCHRONIZE_TO_PA;
341     source->data.pa_sync_state = LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA;
342     source->big_encryption = LE_AUDIO_BIG_ENCRYPTION_NOT_ENCRYPTED;
343     memset(source->bad_code, 0, sizeof(source->bad_code));
344     source->data.pa_interval = 0;
345     source->data.subgroups_num = 0;
346     memset(source->data.subgroups, 0, sizeof(source->data.subgroups));
347 }
348 
349 static void bass_server_reset_client_long_write_buffer(bass_server_connection_t * client){
350     memset(client->long_write_buffer, 0, sizeof(client->long_write_buffer));
351     client->long_write_value_size = 0;
352 }
353 
354 static int bass_server_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
355     // printf("bass_server_write_callback con_handle 0x%02x, attr_handle 0x%02x \n", con_handle, attribute_handle);
356     if (attribute_handle != 0 && attribute_handle != bass_audio_scan_control_point_handle){
357         bass_server_source_t * source = bass_server_find_receive_state_for_client_configuration_handle(attribute_handle);
358         if (source){
359             source->bass_receive_state_client_configuration = little_endian_read_16(buffer, 0);
360             bass_server_register_con_handle(con_handle, source->bass_receive_state_client_configuration);
361         }
362         return 0;
363     }
364 
365     bass_server_connection_t * connection = bass_server_find_client_for_con_handle(con_handle);
366     if (connection == NULL){
367         return ATT_ERROR_WRITE_REQUEST_REJECTED;
368     }
369 
370     uint16_t total_value_len = buffer_size + offset;
371 
372     switch (transaction_mode){
373         case ATT_TRANSACTION_MODE_NONE:
374             if (buffer_size > sizeof(connection->long_write_buffer)){
375                 bass_server_reset_client_long_write_buffer(connection);
376                 return ATT_ERROR_WRITE_REQUEST_REJECTED;
377             }
378             memcpy(&connection->long_write_buffer[0], buffer, buffer_size);
379             connection->long_write_value_size = total_value_len;
380             break;
381 
382         case ATT_TRANSACTION_MODE_ACTIVE:
383             if (total_value_len > sizeof(connection->long_write_buffer)){
384                 bass_server_reset_client_long_write_buffer(connection);
385                 return ATT_ERROR_WRITE_REQUEST_REJECTED;
386             }
387             // allow overlapped and/or mixed order chunks
388             connection->long_write_attribute_handle = attribute_handle;
389 
390             memcpy(&connection->long_write_buffer[offset], buffer, buffer_size);
391             if (total_value_len > connection->long_write_value_size){
392                 connection->long_write_value_size = total_value_len;
393             }
394             return 0;
395 
396         case ATT_TRANSACTION_MODE_VALIDATE:
397             return 0;
398 
399         case ATT_TRANSACTION_MODE_EXECUTE:
400             attribute_handle = connection->long_write_attribute_handle;
401             break;
402 
403         default:
404             return 0;
405     }
406 
407     if (attribute_handle == bass_audio_scan_control_point_handle){
408         if (connection->long_write_value_size < 2){
409             return ATT_ERROR_WRITE_REQUEST_REJECTED;
410         }
411 
412         bass_opcode_t opcode = (bass_opcode_t)connection->long_write_buffer[0];
413         uint8_t  *remote_data = &connection->long_write_buffer[1];
414         uint16_t remote_data_size = connection->long_write_value_size - 1;
415 
416         bass_server_source_t * source;
417         uint8_t broadcast_code[16];
418         switch (opcode){
419             case BASS_OPCODE_REMOTE_SCAN_STOPPED:
420                 if (remote_data_size != 1){
421                     return ATT_ERROR_WRITE_REQUEST_REJECTED;
422                 }
423                 bass_server_source_emit_scan_stoped(con_handle);
424                 break;
425 
426             case BASS_OPCODE_REMOTE_SCAN_STARTED:
427                 if (remote_data_size != 1){
428                     return ATT_ERROR_WRITE_REQUEST_REJECTED;
429                 }
430                 bass_server_source_emit_scan_started(con_handle);
431                 break;
432 
433             case BASS_OPCODE_ADD_SOURCE:
434                 if (!bass_util_source_buffer_in_valid_range(remote_data, remote_data_size)){
435                     return ATT_ERROR_WRITE_REQUEST_REJECTED;
436                 }
437                 source = bass_server_find_empty_or_last_used_source();
438                 btstack_assert(source != NULL);
439                 log_info("add source %d", source->source_id);
440                 bass_server_add_source_from_buffer(remote_data, remote_data_size, source);
441                 bass_server_source_emit_source_added(con_handle, source);
442                 // server needs to trigger notification
443                 break;
444 
445             case BASS_OPCODE_MODIFY_SOURCE:
446                 if (!bass_server_source_remote_modify_source_buffer_valid(remote_data, remote_data_size)){
447                     return ATT_ERROR_WRITE_REQUEST_REJECTED;
448                 }
449 
450                 source = bass_server_find_source_for_source_id(remote_data[0]);
451                 if (source == NULL){
452                     return BASS_ERROR_CODE_INVALID_SOURCE_ID;
453                 }
454                 bass_util_pa_info_and_subgroups_parse(remote_data + 1, remote_data_size - 1, &source->data, false);
455                 bass_server_source_emit_source_modified(con_handle, source);
456                 // server needs to trigger notification
457                 break;
458 
459             case BASS_OPCODE_SET_BROADCAST_CODE:
460                 if (remote_data_size != 17){
461                     return ATT_ERROR_WRITE_REQUEST_REJECTED;
462                 }
463 
464                 source = bass_server_find_source_for_source_id(remote_data[0]);
465                 if (source == NULL){
466                     return BASS_ERROR_CODE_INVALID_SOURCE_ID;
467                 }
468                 reverse_128(&remote_data[1], broadcast_code);
469                 bass_server_source_emit_broadcast_code(con_handle, source->source_id, broadcast_code);
470                 break;
471 
472             case BASS_OPCODE_REMOVE_SOURCE:
473                 if (remote_data_size != 1){
474                     return ATT_ERROR_WRITE_REQUEST_REJECTED;
475                 }
476                 source = bass_server_find_source_for_source_id(remote_data[0]);
477                 if (source == NULL){
478                     return BASS_ERROR_CODE_INVALID_SOURCE_ID;
479                 }
480 
481                 if (bass_server_pa_synchronized(source)){
482                     log_info("remove source %d rejected, PA synchronised", source->source_id);
483                     return 0;
484                 }
485 
486                 if (bass_server_bis_synchronized(source)){
487                     log_info("remove source %d rejected, BIS synchronised", source->source_id);
488                     return 0;
489                 }
490 
491                 bass_server_reset_source(source);
492                 broadcast_audio_scan_service_server_set_pa_sync_state(source->source_id, LE_AUDIO_PA_SYNC_STATE_NOT_SYNCHRONIZED_TO_PA);
493                 bass_server_source_emit_source_deleted(con_handle, source);
494                 break;
495 
496             default:
497                 bass_server_reset_client_long_write_buffer(connection);
498                 return BASS_ERROR_CODE_OPCODE_NOT_SUPPORTED;
499         }
500         bass_server_reset_client_long_write_buffer(connection);
501     }
502     return 0;
503 }
504 
505 static void bass_server_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
506     UNUSED(channel);
507     UNUSED(packet);
508     UNUSED(size);
509 
510     if (packet_type != HCI_EVENT_PACKET){
511         return;
512     }
513 
514     hci_con_handle_t con_handle;
515     bass_server_connection_t * connection;
516 
517     switch (hci_event_packet_get_type(packet)) {
518         case HCI_EVENT_DISCONNECTION_COMPLETE:
519             con_handle = hci_event_disconnection_complete_get_connection_handle(packet);
520 
521             connection = bass_server_find_client_for_con_handle(con_handle);
522             if (connection == NULL){
523                 break;
524             }
525 
526             memset(connection, 0, sizeof(bass_server_connection_t));
527             connection->con_handle = HCI_CON_HANDLE_INVALID;
528             break;
529         default:
530             break;
531     }
532 }
533 
534 void broadcast_audio_scan_service_server_init(const uint8_t sources_num, bass_server_source_t * sources, const uint8_t clients_num, bass_server_connection_t * clients){
535     // get service handle range
536     btstack_assert(sources_num != 0);
537     btstack_assert(clients_num != 0);
538 
539     uint16_t start_handle = 0;
540     uint16_t end_handle   = 0xffff;
541     bool service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BROADCAST_AUDIO_SCAN_SERVICE, &start_handle, &end_handle);
542     btstack_assert(service_found);
543 
544     UNUSED(service_found);
545 
546     bass_audio_scan_control_point_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_AUDIO_SCAN_CONTROL_POINT);
547     bass_sources_num = 0;
548     bass_logic_time = 0;
549     bass_sources = sources;
550 
551 #ifdef ENABLE_TESTING_SUPPORT
552     printf("BASS 0x%02x - 0x%02x \n", start_handle, end_handle);
553 #endif
554     uint16_t start_chr_handle = start_handle;
555     while ( (start_chr_handle < end_handle) && (bass_sources_num < sources_num )) {
556         uint16_t chr_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE);
557         uint16_t chr_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BROADCAST_RECEIVE_STATE);
558 
559         if (chr_value_handle == 0){
560             break;
561         }
562         bass_server_source_t * source = &bass_sources[bass_sources_num];
563         bass_server_reset_source(source);
564 
565         source->source_id = bass_sources_num;
566         source->update_counter = bass_server_get_next_update_counter();
567         source->bass_receive_state_client_configuration = 0;
568 
569         source->bass_receive_state_handle = chr_value_handle;
570         source->bass_receive_state_client_configuration_handle = chr_client_configuration_handle;
571 
572 #ifdef ENABLE_TESTING_SUPPORT
573     printf("    bass_receive_state_%d                 0x%02x \n", bass_sources_num, source->bass_receive_state_handle);
574     printf("    bass_receive_state_%d CCC             0x%02x \n", bass_sources_num, source->bass_receive_state_client_configuration_handle);
575 #endif
576 
577         start_chr_handle = chr_client_configuration_handle + 1;
578         bass_sources_num++;
579     }
580 
581     bass_clients_num = clients_num;
582     bass_clients = clients;
583     memset(bass_clients, 0, sizeof(bass_server_connection_t) * bass_clients_num);
584     uint8_t i;
585     for (i = 0; i < bass_clients_num; i++){
586         bass_clients[i].con_handle = HCI_CON_HANDLE_INVALID;
587     }
588 
589     log_info("Found BASS service 0x%02x-0x%02x (num sources %d)", start_handle, end_handle, bass_sources_num);
590 
591     // register service with ATT Server
592     broadcast_audio_scan_service.start_handle   = start_handle;
593     broadcast_audio_scan_service.end_handle     = end_handle;
594     broadcast_audio_scan_service.read_callback  = &bass_server_read_callback;
595     broadcast_audio_scan_service.write_callback = &bass_server_write_callback;
596     broadcast_audio_scan_service.packet_handler = bass_server_packet_handler;
597     att_server_register_service_handler(&broadcast_audio_scan_service);
598 }
599 
600 void broadcast_audio_scan_service_server_register_packet_handler(btstack_packet_handler_t packet_handler){
601     btstack_assert(packet_handler != NULL);
602     bass_server_event_callback = packet_handler;
603 }
604 
605 static void bass_service_can_send_now(void * context){
606     bass_server_connection_t * client = (bass_server_connection_t *) context;
607     btstack_assert(client != NULL);
608 
609     uint8_t source_index;
610     for (source_index = 0; source_index < bass_sources_num; source_index++){
611         uint8_t task = (1 << source_index);
612         if ((client->sources_to_notify & task) != 0){
613             client->sources_to_notify &= ~task;
614             uint8_t  buffer[BASS_MAX_NOTIFY_BUFFER_SIZE];
615             uint16_t bytes_copied = bass_server_copy_source_to_buffer(&bass_sources[source_index], 0, buffer, sizeof(buffer));
616             att_server_notify(client->con_handle, bass_sources[source_index].bass_receive_state_handle, &buffer[0], bytes_copied);
617             return;
618         }
619     }
620 
621     uint8_t i;
622     for (i = 0; i < bass_clients_num; i++){
623         client = &bass_clients[i];
624 
625         if (client->sources_to_notify != 0){
626             scheduled_tasks_callback.callback = &bass_service_can_send_now;
627             scheduled_tasks_callback.context  = (void*) client;
628             att_server_register_can_send_now_callback(&scheduled_tasks_callback, client->con_handle);
629             return;
630         }
631     }
632 }
633 
634 static void bass_server_set_callback(uint8_t source_index){
635     // there is only one type of task: notify on source state change
636     // as task we register which source is changed, and the change will be propagated to all clients
637     uint8_t i;
638     uint8_t task = (1 << source_index);
639 
640     uint8_t scheduled_tasks = 0;
641 
642     for (i = 0; i < bass_clients_num; i++){
643         bass_server_connection_t * connection = &bass_clients[i];
644 
645         if (connection->con_handle == HCI_CON_HANDLE_INVALID){
646             connection->sources_to_notify &= ~task;
647             return;
648         }
649 
650         scheduled_tasks |= connection->sources_to_notify;
651         connection->sources_to_notify |= task;
652 
653         if (scheduled_tasks == 0){
654             scheduled_tasks_callback.callback = &bass_service_can_send_now;
655             scheduled_tasks_callback.context  = (void*) connection;
656             att_server_register_can_send_now_callback(&scheduled_tasks_callback, connection->con_handle);
657         }
658     }
659 }
660 
661 void broadcast_audio_scan_service_server_set_pa_sync_state(uint8_t source_index, le_audio_pa_sync_state_t sync_state){
662     btstack_assert(source_index < bass_sources_num);
663 
664     bass_server_source_t * source = &bass_sources[source_index];
665     source->data.pa_sync_state = sync_state;
666 
667     if (source->bass_receive_state_client_configuration != 0){
668         bass_server_set_callback(source_index);
669     }
670 }
671 
672 void broadcast_audio_scan_service_server_add_source(const bass_source_data_t *source_data, uint8_t * source_index){
673     *source_index = bass_server_find_empty_or_last_used_source_index();
674     if (*source_index == BASS_INVALID_SOURCE_INDEX){
675         return;
676     }
677     bass_server_source_t * last_used_source = &bass_sources[*source_index];
678     last_used_source->update_counter = bass_server_get_next_update_counter();
679     last_used_source->in_use = true;
680     last_used_source->source_id = *source_index;
681     memcpy(&last_used_source->data, source_data, sizeof(bass_source_data_t));
682 }
683 
684 void broadcast_audio_scan_service_server_deinit(void){
685     bass_server_event_callback = NULL;
686 }
687