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