xref: /btstack/src/ble/gatt-service/battery_service_v1_server.c (revision 7b782c70a1cff7fb8440b3f63128cc5bc9076402)
1 /*
2  * Copyright (C) 2014 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__ "battery_service_v1_server.c"
39 
40 /**
41  * Implementation of the GATT Battery Service Server
42  * To use with your application, add `#import <battery_service.gatt>` to your .gatt file
43  */
44 #include <stdio.h>
45 #include "btstack_defines.h"
46 #include "ble/att_db.h"
47 #include "ble/att_server.h"
48 #include "btstack_util.h"
49 #include "bluetooth_gatt.h"
50 #include "btstack_debug.h"
51 
52 #include "ble/gatt-service/battery_service_v1_server.h"
53 #include "hci_event_builder.h"
54 #include "bluetooth_data_types.h"
55 
56 #define BAS_TASK_BATTERY_LEVEL_CHANGED                                  0x0001
57 #define BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED                           0x0002
58 #define BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED                         0x0004
59 #define BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED                         0x0008
60 #define BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED                          0x0010
61 #define BAS_TASK_BATTERY_TIME_STATUS_CHANGED                            0x0020
62 #define BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED                          0x0040
63 #define BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED                     0x0080
64 #define BAS_TASK_BATTERY_INFORMATION_CHANGED                            0x0100
65 #define BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED                       0x0200
66 #define BAS_TASK_MODEL_NUMBER_STRING_CHANGED                            0x0400
67 #define BAS_TASK_SERIAL_NUMBER_STRING_CHANGED                           0x0800
68 
69 // list of uuids
70 static const uint16_t bas_uuid16s[BAS_CHARACTERISTIC_INDEX_NUM] = {
71     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL,
72     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS,
73     ORG_BLUETOOTH_CHARACTERISTIC_ESTIMATED_SERVICE_DATE,
74     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_CRITCAL_STATUS,
75     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_ENERGY_STATUS,
76     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_TIME_STATUS,
77     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_STATUS,
78     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_INFORMATION,
79     ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_INFORMATION,
80     ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING,
81     ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING,
82     ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING,
83 };
84 
85 static const char * bas_uuid16_name[BAS_CHARACTERISTIC_INDEX_NUM] = {
86     "BATTERY_LEVEL",
87     "BATTERY_LEVEL_STATUS",
88     "ESTIMATED_SERVICE_DATE",
89     "BATTERY_CRITCAL_STATUS",
90     "BATTERY_ENERGY_STATUS",
91     "BATTERY_TIME_STATUS",
92     "BATTERY_HEALTH_STATUS",
93     "BATTERY_HEALTH_INFORMATION",
94     "BATTERY_INFORMATION",
95     "MANUFACTURER_NAME_STRING",
96     "MODEL_NUMBER_STRING",
97     "SERIAL_NUMBER_STRING",
98 };
99 
100 static uint16_t bas_service_id_counter = 0;
101 static btstack_linked_list_t battery_services;
102 static btstack_packet_handler_t battery_service_app_callback;
103 
104 #define MEDFLOAT16_POSITIVE_INFINITY            0x07FE
105 #define MEDFLOAT16_NOT_A_NUMBER                 0x07FF
106 #define MEDFLOAT16_NOT_AT_THIS_RESOLUTION       0x0800
107 #define MEDFLOAT16_RFU                          0x0801
108 #define MEDFLOAT16_NEGATIVE_INFINITY            0x0802
109 
110 static bool bas_server_medfloat16_is_real_number(uint16_t value_medfloat16){
111     switch (value_medfloat16){
112         case MEDFLOAT16_POSITIVE_INFINITY:
113         case MEDFLOAT16_NOT_A_NUMBER:
114         case MEDFLOAT16_NOT_AT_THIS_RESOLUTION:
115         case MEDFLOAT16_RFU:
116         case MEDFLOAT16_NEGATIVE_INFINITY:
117             return false;
118         default:
119             return true;
120     }
121 }
122 
123 static uint16_t bas_server_get_task_for_characteristic_index(bas_characteristic_index_t index){
124     switch (index){
125         case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL:
126             return BAS_TASK_BATTERY_LEVEL_CHANGED;
127         case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS:
128             return BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED;
129         case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE:
130             return BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED;
131         case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS:
132             return BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED;
133         case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS:
134             return BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED;
135         case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS:
136             return BAS_TASK_BATTERY_TIME_STATUS_CHANGED;
137         case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS:
138             return BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED;
139         case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION:
140             return BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED;
141         case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION:
142             return BAS_TASK_BATTERY_INFORMATION_CHANGED;
143         case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING:
144             return BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED;
145         case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING:
146             return BAS_TASK_MODEL_NUMBER_STRING_CHANGED;
147         case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING:
148             return BAS_TASK_SERIAL_NUMBER_STRING_CHANGED;
149         default:
150             btstack_assert(false);
151             return 0;
152     }
153 }
154 
155 static battery_service_v1_server_connection_t * battery_service_server_connection_for_con_handle(battery_service_v1_t * service, hci_con_handle_t con_handle){
156     if (service == NULL){
157         return NULL;
158     }
159 
160     uint8_t i;
161     for (i = 0; i < service->connections_max_num; i++){
162         if (service->connections[i].con_handle == con_handle){
163             return &service->connections[i];
164         }
165     }
166     return NULL;
167 }
168 
169 static battery_service_v1_server_connection_t * battery_service_server_add_connection_for_con_handle(battery_service_v1_t * service, hci_con_handle_t con_handle){
170     if (service == NULL){
171         return NULL;
172     }
173 
174     uint8_t i;
175     for (i = 0; i < service->connections_max_num; i++){
176         if (service->connections[i].con_handle == HCI_CON_HANDLE_INVALID){
177             service->connections[i].con_handle = con_handle;
178             service->connections[i].service = service;
179             return &service->connections[i];
180         }
181     }
182     return NULL;
183 }
184 
185 
186 static battery_service_v1_t * battery_service_service_for_attribute_handle(uint16_t attribute_handle){
187     btstack_linked_list_iterator_t it;
188     btstack_linked_list_iterator_init(&it, &battery_services);
189     while (btstack_linked_list_iterator_has_next(&it)){
190         battery_service_v1_t * item = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
191         if (attribute_handle < item->service_handler.start_handle) continue;
192         if (attribute_handle > item->service_handler.end_handle)   continue;
193         return item;
194     }
195     return NULL;
196 }
197 
198 
199 static battery_service_v1_t * battery_service_service_for_con_handle(hci_con_handle_t con_handle){
200     btstack_linked_list_iterator_t it;
201     btstack_linked_list_iterator_init(&it, &battery_services);
202     while (btstack_linked_list_iterator_has_next(&it)){
203         battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
204         uint8_t i;
205         for (i = 0; i < service->connections_max_num; i++){
206             if (service->connections[i].con_handle == con_handle){
207                 return service;
208             }
209         }
210     }
211     return NULL;
212 }
213 
214 static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_characteristic_index_t index, uint8_t * buffer, uint8_t buffer_size){
215     uint8_t pos = 0;
216     switch ((bas_characteristic_index_t) index){
217         case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL:
218             buffer[pos++] = service->battery_level;
219             break;
220 
221         case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS:
222             if (service->level_status == NULL){
223                 return 0;
224             }
225             buffer[pos++] = service->level_status->flags;
226             little_endian_store_16(buffer, pos, service->level_status->power_state_flags);
227             pos += 2;
228             if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_IDENTIFIER_PRESENT) > 0u){
229                 little_endian_store_16(buffer, pos, service->level_status->identifier);
230                 pos += 2;
231             }
232             if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_BATTERY_LEVEL_PRESENT) > 0u){
233                 buffer[pos++] = service->level_status->battery_level;
234             }
235             if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){
236                 buffer[pos++] = service->level_status->additional_status_flags;
237             }
238             break;
239 
240         case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE:
241             little_endian_store_24(buffer, pos, service->estimated_service_date_days);
242             pos += 3;
243             break;
244 
245         case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS:
246             buffer[pos++] = service->critical_status_flags;
247             break;
248 
249         case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS:
250             if (service->energy_status == NULL){
251                 return 0;
252             }
253             buffer[pos++] = service->energy_status->flags;
254             if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_EXTERNAL_SOURCE_POWER_PRESENT) > 0u){
255                 little_endian_store_16(buffer, pos, service->energy_status->external_source_power_medfloat16);
256                 pos += 2;
257             }
258             if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_PRESENT_VOLTAGE_PRESENT) > 0u){
259                 little_endian_store_16(buffer, pos, service->energy_status->present_voltage_medfloat16);
260                 pos += 2;
261             }
262             if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_ENERGY_PRESENT) > 0u){
263                 little_endian_store_16(buffer, pos, service->energy_status->available_energy_medfloat16);
264                 pos += 2;
265             }
266             if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_BATTERY_CAPACITY_PRESENT) > 0u){
267                 little_endian_store_16(buffer, pos, service->energy_status->available_battery_capacity_medfloat16);
268                 pos += 2;
269             }
270             if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_CHARGE_RATE_PRESENT) > 0u){
271                 little_endian_store_16(buffer, pos, service->energy_status->charge_rate_medfloat16);
272                 pos += 2;
273             }
274             if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_ENERGY_AT_LAST_CHARGE_PRESENT) > 0u){
275                 little_endian_store_16(buffer, pos, service->energy_status->available_energy_at_last_charge_medfloat16);
276                 pos += 2;
277             }
278             break;
279 
280         case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS:
281             if (service->time_status == NULL){
282                 return 0;
283             }
284             buffer[pos++] = service->time_status->flags;
285             little_endian_store_24(buffer, pos, service->time_status->time_until_discharged_minutes);
286             pos += 3;
287             if ((service->time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_DISCHARGED_ON_STANDBY_PRESENT) > 0u){
288                 little_endian_store_24(buffer, pos, service->time_status->time_until_discharged_on_standby_minutes);
289                 pos += 3;
290             }
291             if ((service->time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_RECHARGED_PRESENT) > 0u){
292                 little_endian_store_24(buffer, pos, service->time_status->time_until_recharged_minutes);
293                 pos += 3;
294             }
295             break;
296 
297         case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS:
298             if (service->health_status == NULL){
299                 return 0;
300             }
301             buffer[pos++] = service->health_status->flags;
302             if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){
303                 buffer[pos++] = service->health_status->summary;
304             }
305             if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CYCLE_COUNT_PRESENT) > 0u){
306                 little_endian_store_16(buffer, pos, service->health_status->cycle_count);
307                 pos += 2;
308             }
309             if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CURRENT_TEMPERATURE_PRESENT) > 0u){
310                 buffer[pos++] = service->health_status->current_temperature_degree_celsius;
311             }
312             if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_DEEP_DISCHARGE_COUNT_PRESENT) > 0u){
313                 little_endian_store_16(buffer, pos, service->health_status->deep_discharge_count);
314                 pos += 2;
315             }
316             break;
317 
318         case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION:
319             if (service->health_information == NULL){
320                 return 0;
321             }
322             buffer[pos++] = service->health_information->flags;
323             if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_CYCLE_COUNT_DESIGNED_LIFETIME_PRESENT) > 0u){
324                 little_endian_store_16(buffer, pos, service->health_information->cycle_count_designed_lifetime);
325                 pos += 2;
326             }
327             if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_DESIGNED_OPERATING_TEMPERATURE_PRESENT) > 0u){
328                 buffer[pos++] = service->health_information->min_designed_operating_temperature_degree_celsius;
329             }
330             if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_DESIGNED_OPERATING_TEMPERATURE_PRESENT) > 0u){
331                 buffer[pos++] = service->health_information->max_designed_operating_temperature_degree_celsius;
332             }
333             break;
334 
335         case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION:
336             if (service->information == NULL){
337                 return 0;
338             }
339             little_endian_store_16(buffer, pos, service->information->flags);
340             pos += 2;
341             buffer[pos++] = service->information->features;
342             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_MANUFACTURE_DATE_PRESENT) > 0u){
343                 little_endian_store_24(buffer, pos, service->information->manufacture_date_days);
344                 pos += 3;
345             }
346             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){
347                 little_endian_store_24(buffer, pos, service->information->expiration_date_days);
348                 pos += 3;
349             }
350             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_DESIGNED_CAPACITY_PRESENT) > 0u){
351                 little_endian_store_16(buffer, pos, service->information->designed_capacity_kWh_medfloat16);
352                 pos += 2;
353             }
354             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_LOW_ENERGY_PRESENT) > 0u){
355                 little_endian_store_16(buffer, pos, service->information->low_energy_kWh_medfloat16);
356                 pos += 2;
357             }
358             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CRITICAL_ENERGY_PRESENT) > 0u){
359                 little_endian_store_16(buffer, pos, service->information->critical_energy_kWh_medfloat16);
360                 pos += 2;
361             }
362             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){
363                 buffer[pos++] = service->information->chemistry;
364             }
365             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_NOMINAL_VOLTAGE_PRESENT) > 0u){
366                 little_endian_store_16(buffer, pos, service->information->nominal_voltage_medfloat16);
367                 pos += 2;
368             }
369             if ((service->information->flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){
370                 buffer[pos++] = service->information->aggregation_group;
371             }
372             break;
373         default:
374             break;
375     }
376     return pos;
377 }
378 
379 static uint16_t battery_service_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
380     UNUSED(con_handle);
381 
382     battery_service_v1_t * service = battery_service_service_for_attribute_handle(attribute_handle);
383     if (service == NULL){
384         return 0;
385     }
386 
387     battery_service_v1_server_connection_t * connection = battery_service_server_connection_for_con_handle(service, con_handle);
388     if (connection == NULL){
389         connection = battery_service_server_add_connection_for_con_handle(service, con_handle);
390         if (connection == NULL){
391             return 0;
392         }
393     }
394 
395     uint8_t index;
396     uint8_t event[19];
397     uint8_t pos = 0;
398 
399     for (index = 0; index < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; index++){
400         if (attribute_handle != service->characteristics[index].value_handle){
401             continue;
402         }
403 
404         switch ((bas_characteristic_index_t) index){
405             case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING:
406                 if (service->manufacturer_name == NULL){
407                     return 0;
408                 }
409                 return att_read_callback_handle_blob((uint8_t *)service->manufacturer_name, strlen(service->manufacturer_name), offset, buffer, buffer_size);
410 
411             case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING:
412                 if (service->model_number == NULL){
413                     return 0;
414                 }
415                 return att_read_callback_handle_blob((uint8_t *)service->model_number, strlen(service->model_number), offset, buffer, buffer_size);
416 
417             case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING:
418                 if (service->serial_number == NULL){
419                     return 0;
420                 }
421                 return att_read_callback_handle_blob((uint8_t *)service->serial_number, strlen(service->serial_number), offset, buffer, buffer_size);
422 
423             default:
424                 pos = bas_serialize_characteristic(service, index, event, sizeof(event));
425                 if (pos == 1u){
426                     return att_read_callback_handle_byte(event[0], offset, buffer, buffer_size);
427                 }
428                 if (pos > 1u){
429                     return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
430                 }
431                 return 0;
432         }
433     }
434 
435     if (attribute_handle == service->battery_level_status_broadcast_configuration_handle){
436         return att_read_callback_handle_little_endian_16(service->battery_level_status_broadcast_configuration, offset, buffer, buffer_size);
437     }
438 
439     for (index = 0; index < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; index++){
440         if (attribute_handle != service->characteristics[index].client_configuration_handle){
441             continue;
442         }
443         return att_read_callback_handle_little_endian_16(connection->configurations[index], offset, buffer, buffer_size);
444     }
445     return 0;
446 }
447 
448 static int battery_service_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){
449     UNUSED(offset);
450     UNUSED(buffer_size);
451 
452     if (transaction_mode != ATT_TRANSACTION_MODE_NONE){
453         return 0;
454     }
455 
456     battery_service_v1_t * service = battery_service_service_for_attribute_handle(attribute_handle);
457     if (service == NULL){
458         return 0;
459     }
460 
461     battery_service_v1_server_connection_t * connection = battery_service_server_connection_for_con_handle(service, con_handle);
462     if (connection == NULL){
463         connection = battery_service_server_add_connection_for_con_handle(service, con_handle);
464         if (connection == NULL){
465             return 0;
466         }
467     }
468 
469     if (attribute_handle == service->battery_level_status_broadcast_configuration_handle){
470         uint8_t new_value = little_endian_read_16(buffer, 0);
471         bool broadcast_old = (service->battery_level_status_broadcast_configuration & 1) != 0;
472         bool broadcast_new = (new_value & 1) != 0;
473         service->battery_level_status_broadcast_configuration = new_value;
474         if (broadcast_old != broadcast_new){
475             // emit broadcast start/stop based on value of broadcast_new
476             uint8_t event[5];
477             hci_event_builder_context_t context;
478             uint8_t subevent_type = broadcast_new ? GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL_BROADCAST_START : GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL_BROADCAST_STOP;
479             hci_event_builder_init(&context, event, sizeof(buffer), HCI_EVENT_GATTSERVICE_META, subevent_type);
480             hci_event_builder_add_16(&context, service->service_id);
481             if (battery_service_app_callback != NULL){
482                 (*battery_service_app_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
483             }
484         }
485         return 0;
486     }
487 
488     uint8_t index;
489     for (index = 0; index < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; index++){
490         if (attribute_handle != service->characteristics[index].client_configuration_handle){
491             continue;
492         }
493         connection->configurations[index] = little_endian_read_16(buffer, 0);
494         return 0;
495     }
496     return 0;
497 }
498 
499 
500 static bool bas_characteristic_notify_configured(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index){
501     return (connection->configurations[index] & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) != 0u;
502 }
503 static bool bas_characteristic_indicate_configured(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index){
504     return (connection->configurations[index] & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION) != 0u;
505 }
506 
507 static void battery_service_can_send_now(void * context){
508     battery_service_v1_server_connection_t * connection = (battery_service_v1_server_connection_t *) context;
509     if (connection == NULL){
510         return;
511     }
512     battery_service_v1_t * service = connection->service;
513     if (service == NULL){
514         return;
515     }
516 
517     // if battery is removed, no indications or notification should be sent
518 //    if ( (service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_BATTERY_LEVEL_PRESENT) == 0u){
519 //        return;
520 //    }
521 
522     bas_characteristic_index_t index;
523     uint8_t event[19];
524     uint8_t pos = 0;
525     bool task_valid = true;
526 
527 
528     if ((connection->scheduled_tasks & BAS_TASK_BATTERY_LEVEL_CHANGED) > 0u){
529         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_LEVEL_CHANGED;
530         index = BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL;
531 
532     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED) > 0u){
533         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED;
534         index = BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS;
535 
536     } else if ((connection->scheduled_tasks & BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED) > 0u){
537         connection->scheduled_tasks &= ~BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED;
538         index = BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE;
539 
540     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED) > 0u){
541         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED;
542         index = BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS;
543 
544     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED) > 0u){
545         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED;
546         index = BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS;
547 
548     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_TIME_STATUS_CHANGED) > 0u){
549         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_TIME_STATUS_CHANGED;
550         index = BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS;
551 
552     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED) > 0u){
553         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED;
554         index = BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS;
555 
556     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED) > 0u){
557         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED;
558         index = BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS;
559 
560     } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_INFORMATION_CHANGED) > 0u){
561         connection->scheduled_tasks &= ~BAS_TASK_BATTERY_INFORMATION_CHANGED;
562         index = BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION;
563 
564     } else {
565         // TODO  BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED
566         // TODO  BAS_TASK_MODEL_NUMBER_STRING_CHANGED
567         // TODO  BAS_TASK_SERIAL_NUMBER_STRING_CHANGED
568 
569         task_valid = false;
570     }
571 
572     if (task_valid){
573         pos = bas_serialize_characteristic(service, index, event, sizeof(event));
574 
575         if (bas_characteristic_notify_configured(connection, index)){
576             att_server_notify(connection->con_handle, service->characteristics[index].value_handle, event, pos);
577         } else if (bas_characteristic_indicate_configured(connection, index)){
578             att_server_notify(connection->con_handle, service->characteristics[index].value_handle, event, pos);
579         }
580     }
581 
582     if (connection->scheduled_tasks > 0u){
583         att_server_register_can_send_now_callback(&connection->scheduled_tasks_callback, connection->con_handle);
584     }
585 }
586 
587 void battery_service_v1_server_init(void){
588 
589 }
590 
591 void battery_service_v1_server_register(battery_service_v1_t *service, battery_service_v1_server_connection_t *connections, uint8_t connection_max_num, uint16_t * out_service_id){
592     btstack_assert(service != NULL);
593     btstack_assert(connections != NULL);
594     btstack_assert(connection_max_num > 0u);
595 
596     // get service handle range
597     uint16_t end_handle   = 0xffff;
598     uint16_t start_handle = 0;
599 
600     btstack_linked_list_iterator_t it;
601     btstack_linked_list_iterator_init(&it, &battery_services);
602     while (btstack_linked_list_iterator_has_next(&it)){
603         battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
604         if (service->service_handler.end_handle > start_handle){
605             start_handle = service->service_handler.end_handle + 1;
606         }
607     }
608 
609     int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE, &start_handle, &end_handle);
610     btstack_assert(service_found != 0);
611     UNUSED(service_found);
612 
613     // get next service id
614     bas_service_id_counter = btstack_next_cid_ignoring_zero(bas_service_id_counter);
615     service->service_id = bas_service_id_counter;
616     if (out_service_id != NULL) {
617         *out_service_id = bas_service_id_counter;
618     }
619 
620     service->service_handler.start_handle = start_handle;
621     service->service_handler.end_handle = end_handle;
622     printf("start handle 0x%04X, end0x%04X\n", service->service_handler.start_handle , service->service_handler.end_handle);
623     uint8_t i;
624     for (i = 0; i < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; i++){
625         // get characteristic value handle and client configuration handle
626         service->characteristics[i].value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, bas_uuid16s[i]);
627         service->characteristics[i].client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, bas_uuid16s[i]);
628         printf("%30s: 0x%04X, CCC 0x%04X\n", bas_uuid16_name[i], service->characteristics[i].value_handle , service->characteristics[i].client_configuration_handle );
629     }
630 
631     service->battery_level_status_broadcast_configuration_handle = gatt_server_get_server_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS);
632 
633     memset(connections, 0, sizeof(battery_service_v1_server_connection_t) * connection_max_num);
634     for (i = 0; i < connection_max_num; i++){
635         connections[i].con_handle = HCI_CON_HANDLE_INVALID;
636     }
637     service->connections_max_num = connection_max_num;
638     service->connections = connections;
639 
640     service->service_handler.start_handle = start_handle;
641     service->service_handler.end_handle = end_handle;
642     service->service_handler.read_callback  = &battery_service_read_callback;
643     service->service_handler.write_callback = &battery_service_write_callback;
644     att_server_register_service_handler(&service->service_handler);
645 
646     log_info("Found Battery Service 0x%02x-0x%02x", start_handle, end_handle);
647 
648     btstack_linked_list_add_tail(&battery_services, (btstack_linked_item_t *) service);
649 }
650 
651 
652 static void bas_server_set_callback_for_connection(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index, uint8_t task){
653     if (connection->con_handle == HCI_CON_HANDLE_INVALID){
654         connection->scheduled_tasks = 0;
655         return;
656     }
657 
658     uint8_t scheduled_tasks = connection->scheduled_tasks;
659     connection->scheduled_tasks |= task;
660     if (scheduled_tasks == 0){
661         connection->scheduled_tasks_callback.callback = &battery_service_can_send_now;
662         connection->scheduled_tasks_callback.context  = (void*) connection;
663         att_server_register_can_send_now_callback(&connection->scheduled_tasks_callback, connection->con_handle);
664     }
665 }
666 
667 static void bas_server_set_callback(battery_service_v1_t * service, bas_characteristic_index_t index){
668     // if battery is removed, no indications or notification should be sent
669 
670     if (service->level_status == NULL){
671         return;
672     }
673     if ((index != BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS) && (service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_BATTERY_LEVEL_PRESENT) == 0u){
674         return;
675     }
676     uint8_t task = bas_server_get_task_for_characteristic_index(index);
677     uint8_t i;
678     for (i = 0; i < service->connections_max_num; i++){
679         if (service->connections[i].configurations[index] > 0u){
680             bas_server_set_callback_for_connection(&service->connections[i], index, task);
681         }
682     }
683 }
684 
685 uint8_t battery_service_v1_server_set_battery_level(battery_service_v1_t * service, uint8_t battery_level){
686     btstack_assert(service != NULL);
687     if (battery_level > 100){
688         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
689     }
690     if (service->battery_level != battery_level){
691         service->battery_level = battery_level;
692         bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL);
693     }
694     return ERROR_CODE_SUCCESS;
695 }
696 
697 uint8_t battery_service_v1_server_set_battery_level_status(battery_service_v1_t * service, const battery_level_status_t * battery_level_status){
698     btstack_assert(service != NULL);
699     btstack_assert(battery_level_status != NULL);
700 
701     if ((battery_level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_RFU) != 0u){
702         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
703     }
704     if ((battery_level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){
705        if ((battery_level_status->additional_status_flags & BATTERY_LEVEL_ADDITIONAL_STATUS_BITMASK_RFU) != 0u){
706             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
707         }
708     }
709 
710     service->level_status = battery_level_status;
711     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS);
712     return ERROR_CODE_SUCCESS;
713 }
714 
715 uint8_t battery_service_v1_server_set_estimated_service_date_days(battery_service_v1_t * service, uint32_t estimated_service_date_days){
716     btstack_assert(service != NULL);
717 
718     if (estimated_service_date_days > 0xFFFFFF){
719         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
720     }
721 
722     service->estimated_service_date_days = estimated_service_date_days;
723     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE);
724     return ERROR_CODE_SUCCESS;
725 }
726 
727 uint8_t battery_service_v1_server_set_critcal_status_flags(battery_service_v1_t * service, uint8_t critcal_status_flags){
728     btstack_assert(service != NULL);
729 
730     if ((critcal_status_flags & BATTERY_CRITCAL_STATUS_BITMASK_RFU) != 0u){
731         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
732     }
733 
734     service->critical_status_flags = critcal_status_flags;
735     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS);
736     return ERROR_CODE_SUCCESS;
737 }
738 
739 uint8_t battery_service_v1_server_set_energy_status(battery_service_v1_t * service, const battery_energy_status_t * energy_status){
740     btstack_assert(service != NULL);
741     btstack_assert(energy_status != NULL);
742 
743     if ((energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_RFU) != 0u){
744         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
745     }
746 
747     service->energy_status = energy_status;
748     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS);
749     return ERROR_CODE_SUCCESS;
750 }
751 
752 uint8_t battery_service_v1_server_set_time_status(battery_service_v1_t * service, const battery_time_status_t * time_status){
753     btstack_assert(service != NULL);
754     btstack_assert(time_status != NULL);
755 
756     if ((time_status->flags & BATTERY_TIME_STATUS_BITMASK_RFU) != 0u){
757         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
758     }
759     if (time_status->time_until_discharged_minutes > 0xFFFFFF){
760         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
761     }
762     if ((time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_DISCHARGED_ON_STANDBY_PRESENT) > 0u){
763         if (time_status->time_until_discharged_on_standby_minutes > 0xFFFFFF){
764             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
765         }
766     }
767     if ((time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_RECHARGED_PRESENT) > 0u){
768         if (time_status->time_until_recharged_minutes > 0xFFFFFF){
769             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
770         }
771     }
772 
773     service->time_status = time_status;
774     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS);
775     return ERROR_CODE_SUCCESS;
776 }
777 
778 uint8_t battery_service_v1_server_set_health_status(battery_service_v1_t * service, const battery_health_status_t * health_status){
779     btstack_assert(service != NULL);
780     btstack_assert(health_status != NULL);
781 
782     if ((health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_RFU) != 0u){
783         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
784     }
785     if ((health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){
786         if (health_status->summary > 100){
787             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
788         }
789     }
790 
791     service->health_status = health_status;
792     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS);
793     return ERROR_CODE_SUCCESS;
794 }
795 
796 uint8_t battery_service_v1_server_set_health_information(battery_service_v1_t * service, const battery_health_information_t * health_information){
797     btstack_assert(service != NULL);
798     btstack_assert(health_information != NULL);
799 
800     if ((health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_RFU) != 0u){
801         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
802     }
803 
804     service->health_information = health_information;
805     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION);
806     return ERROR_CODE_SUCCESS;
807 }
808 
809 uint8_t battery_service_v1_server_set_information(battery_service_v1_t * service, const battery_information_t * information){
810     btstack_assert(service != NULL);
811     btstack_assert(information != NULL);
812 
813     if ((information->flags & BATTERY_INFORMATION_BITMASK_RFU) != 0u){
814         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
815     }
816     if ((information->flags & BATTERY_INFORMATION_BITMASK_MANUFACTURE_DATE_PRESENT) > 0u){
817         if (information->manufacture_date_days > 0xFFFFFF){
818             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
819         }
820     }
821     if ((information->flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){
822         if (information->expiration_date_days > 0xFFFFFF){
823             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
824         }
825     }
826     if ((information->flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){
827         if (information->chemistry >= BATTERY_CHEMISTRY_RFU_START && information->chemistry <= BATTERY_CHEMISTRY_RFU_END){
828             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
829         }
830     }
831     if ((information->flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){
832         if (information->aggregation_group == 0xFF){
833             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
834         }
835     }
836     if ((information->flags & BATTERY_INFORMATION_BITMASK_DESIGNED_CAPACITY_PRESENT) > 0u){
837         if (!bas_server_medfloat16_is_real_number(information->designed_capacity_kWh_medfloat16)){
838             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
839         }
840     }
841     if ((information->flags & BATTERY_INFORMATION_BITMASK_LOW_ENERGY_PRESENT) > 0u){
842         if (!bas_server_medfloat16_is_real_number(information->low_energy_kWh_medfloat16)){
843             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
844         }
845     }
846     if ((information->flags & BATTERY_INFORMATION_BITMASK_CRITICAL_ENERGY_PRESENT) > 0u){
847         if (!bas_server_medfloat16_is_real_number(information->critical_energy_kWh_medfloat16)){
848             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
849         }
850     }
851     if ((information->flags & BATTERY_INFORMATION_BITMASK_NOMINAL_VOLTAGE_PRESENT) > 0u){
852         if (!bas_server_medfloat16_is_real_number(information->nominal_voltage_medfloat16)){
853             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
854         }
855     }
856     service->information = information;
857     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION);
858     return ERROR_CODE_SUCCESS;
859 }
860 
861 uint8_t battery_service_v1_server_set_manufacturer_name(battery_service_v1_t * service, const char * manufacturer_name){
862     btstack_assert(service != NULL);
863     btstack_assert(manufacturer_name != NULL);
864 
865     service->manufacturer_name = manufacturer_name;
866     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING);
867     return ERROR_CODE_SUCCESS;
868 }
869 
870 uint8_t battery_service_v1_server_set_model_number(battery_service_v1_t * service, const char * model_number){
871     btstack_assert(service != NULL);
872     btstack_assert(model_number != NULL);
873 
874     service->model_number = model_number;
875     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING);
876     return ERROR_CODE_SUCCESS;
877 }
878 
879 uint8_t battery_service_v1_server_set_serial_number(battery_service_v1_t * service, const char * serial_number){
880     btstack_assert(service != NULL);
881     btstack_assert(serial_number != NULL);
882 
883     service->serial_number = serial_number;
884     bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING);
885     return ERROR_CODE_SUCCESS;
886 }
887 
888 void battery_service_v1_server_set_packet_handler(btstack_packet_handler_t callback){
889     btstack_assert(callback != NULL);
890     battery_service_app_callback = callback;
891 }
892 
893 void battery_service_v1_server_deregister(battery_service_v1_t *service){
894     btstack_linked_list_remove(&battery_services, (btstack_linked_item_t * )service);
895     // TODO cansel can send now
896 }
897 
898 void battery_service_v1_server_deinit(void){
899     // deregister listeners
900     // empty list
901     btstack_linked_list_iterator_t it;
902     btstack_linked_list_iterator_init(&it, &battery_services);
903     while (btstack_linked_list_iterator_has_next(&it)){
904         battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
905         battery_service_v1_server_deregister(service);
906     }
907 }
908 
909 uint16_t battery_service_v1_server_get_broadcast_advertisement(uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size){
910 
911     if (adv_size < 7) return 0u;
912 
913     uint16_t pos = 0;
914     // adv flags
915     adv_buffer[pos++] = 2;
916     adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_FLAGS;
917     adv_buffer[pos++] = 0x04;
918 
919     // adv interval
920     adv_buffer[pos++] = 3;
921     adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL;
922     little_endian_store_16(adv_buffer, pos, adv_interval);
923     pos += 2;
924 
925     uint16_t pos_without_data = pos;
926 
927     btstack_linked_list_iterator_t it;
928     btstack_linked_list_iterator_init(&it, &battery_services);
929     while (btstack_linked_list_iterator_has_next(&it)){
930         battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
931         if ((service->battery_level_status_broadcast_configuration & 1) != 0) {
932             uint8_t value_buffer[10];
933             uint16_t value_len = bas_serialize_characteristic(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS, value_buffer, sizeof(value_buffer));
934             if ((pos + 4 + value_len) <= adv_size) {
935                 adv_buffer[pos++] = 3 + value_len;
936                 adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID;
937                 little_endian_store_16(adv_buffer, pos, ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE);
938                 pos += 2;
939                 memcpy(&adv_buffer[pos], value_buffer, value_len);
940                 pos += value_len;
941             } else {
942                 break;
943             }
944         }
945     }
946 
947     // indicate nothing to broadcast
948     if (pos == pos_without_data) {
949         pos = 0;
950     }
951 
952     return pos;
953 }
954 
955 uint16_t battery_service_v1_server_get_broadcast_advertisement_single(battery_service_v1_t * service_single, uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size){
956 
957     if (adv_size < 7) return 0u;
958 
959     uint16_t pos = 0;
960     // adv flags
961     adv_buffer[pos++] = 2;
962     adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_FLAGS;
963     adv_buffer[pos++] = 0x04;
964 
965     // adv interval
966     adv_buffer[pos++] = 3;
967     adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL;
968     little_endian_store_16(adv_buffer, pos, adv_interval);
969     pos += 2;
970 
971     uint16_t pos_without_data = pos;
972 
973     btstack_linked_list_iterator_t it;
974     btstack_linked_list_iterator_init(&it, &battery_services);
975     while (btstack_linked_list_iterator_has_next(&it)){
976         battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
977         if (service == service_single) {
978             if ((service->battery_level_status_broadcast_configuration & 1) != 0) {
979                 uint8_t value_buffer[10];
980                 uint16_t value_len = bas_serialize_characteristic(service,
981                                                                   BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS,
982                                                                   value_buffer, sizeof(value_buffer));
983                 if ((pos + 4 + value_len) <= adv_size) {
984                     adv_buffer[pos++] = 3 + value_len;
985                     adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID;
986                     little_endian_store_16(adv_buffer, pos, ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE);
987                     pos += 2;
988                     memcpy(&adv_buffer[pos], value_buffer, value_len);
989                     pos += value_len;
990                 } else {
991                     break;
992                 }
993             }
994         }
995     }
996 
997     // indicate nothing to broadcast
998     if (pos == pos_without_data) {
999         pos = 0;
1000     }
1001 
1002     return pos;
1003 }
1004 
1005