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