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