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