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