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
bas_server_medfloat16_is_real_number(uint16_t value_medfloat16)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
bas_server_get_task_for_characteristic_index(bas_characteristic_index_t index)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
battery_service_server_connection_for_con_handle(battery_service_v1_t * service,hci_con_handle_t con_handle)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
battery_service_server_add_connection_for_con_handle(battery_service_v1_t * service,hci_con_handle_t con_handle)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
battery_service_service_for_attribute_handle(uint16_t attribute_handle)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
bas_serialize_characteristic(battery_service_v1_t * service,bas_characteristic_index_t index,uint8_t * buffer,uint8_t buffer_size)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
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 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
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 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
bas_characteristic_notify_configured(battery_service_v1_server_connection_t * connection,bas_characteristic_index_t index)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 }
bas_characteristic_indicate_configured(battery_service_v1_server_connection_t * connection,bas_characteristic_index_t index)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
battery_service_can_send_now(void * context)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
battery_service_v1_server_init(void)573 void battery_service_v1_server_init(void){
574
575 }
576
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 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
bas_server_set_callback_for_connection(battery_service_v1_server_connection_t * connection,bas_characteristic_index_t index,uint8_t task)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
bas_server_set_callback(battery_service_v1_t * service,bas_characteristic_index_t index)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
battery_service_v1_server_set_battery_level(battery_service_v1_t * service,uint8_t battery_level)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
battery_service_v1_server_set_battery_level_status(battery_service_v1_t * service,const battery_level_status_t * battery_level_status)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
battery_service_v1_server_set_estimated_service_date_days(battery_service_v1_t * service,uint32_t estimated_service_date_days)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
battery_service_v1_server_set_critcal_status_flags(battery_service_v1_t * service,uint8_t critcal_status_flags)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
battery_service_v1_server_set_energy_status(battery_service_v1_t * service,const battery_energy_status_t * energy_status)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
battery_service_v1_server_set_time_status(battery_service_v1_t * service,const battery_time_status_t * time_status)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
battery_service_v1_server_set_health_status(battery_service_v1_t * service,const battery_health_status_t * health_status)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
battery_service_v1_server_set_health_information(battery_service_v1_t * service,const battery_health_information_t * health_information)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
battery_service_v1_server_set_information(battery_service_v1_t * service,const battery_information_t * information)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
battery_service_v1_server_set_manufacturer_name(battery_service_v1_t * service,const char * manufacturer_name)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
battery_service_v1_server_set_model_number(battery_service_v1_t * service,const char * model_number)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
battery_service_v1_server_set_serial_number(battery_service_v1_t * service,const char * serial_number)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
battery_service_v1_server_set_packet_handler(btstack_packet_handler_t callback)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
battery_service_v1_server_deregister(battery_service_v1_t * service)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
battery_service_v1_server_deinit(void)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
battery_service_v1_server_get_broadcast_advertisement(uint16_t adv_interval,uint8_t * adv_buffer,uint16_t adv_size)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
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)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