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 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 54 #define BAS_TASK_BATTERY_LEVEL_CHANGED 0x0001 55 #define BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED 0x0002 56 #define BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED 0x0004 57 #define BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED 0x0008 58 #define BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED 0x0010 59 #define BAS_TASK_BATTERY_TIME_STATUS_CHANGED 0x0020 60 #define BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED 0x0040 61 #define BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED 0x0080 62 #define BAS_TASK_BATTERY_INFORMATION_CHANGED 0x0100 63 #define BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED 0x0200 64 #define BAS_TASK_MODEL_NUMBER_STRING_CHANGED 0x0400 65 #define BAS_TASK_SERIAL_NUMBER_STRING_CHANGED 0x0800 66 67 // list of uuids 68 static const uint16_t bas_uuid16s[BAS_CHARACTERISTIC_INDEX_NUM] = { 69 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, 70 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS, 71 ORG_BLUETOOTH_CHARACTERISTIC_ESTIMATED_SERVICE_DATE, 72 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_CRITCAL_STATUS, 73 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_ENERGY_STATUS, 74 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_TIME_STATUS, 75 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_STATUS, 76 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_INFORMATION, 77 ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_INFORMATION, 78 ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, 79 ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, 80 ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, 81 }; 82 static btstack_linked_list_t battery_services; 83 84 static uint16_t bas_server_get_task_for_characteristic_index(bas_characteristic_index_t index){ 85 switch (index){ 86 case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL: 87 return BAS_TASK_BATTERY_LEVEL_CHANGED; 88 case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS: 89 return BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED; 90 case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE: 91 return BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED; 92 case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS: 93 return BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED; 94 case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS: 95 return BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED; 96 case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS: 97 return BAS_TASK_BATTERY_TIME_STATUS_CHANGED; 98 case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS: 99 return BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED; 100 case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION: 101 return BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED; 102 case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION: 103 return BAS_TASK_BATTERY_INFORMATION_CHANGED; 104 case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING: 105 return BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED; 106 case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING: 107 return BAS_TASK_MODEL_NUMBER_STRING_CHANGED; 108 case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING: 109 return BAS_TASK_SERIAL_NUMBER_STRING_CHANGED; 110 default: 111 btstack_assert(false); 112 } 113 } 114 115 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){ 116 if (service == NULL){ 117 return NULL; 118 } 119 120 uint8_t i; 121 for (i = 0; i < service->connections_max_num; i++){ 122 if (service->connections[i].con_handle == con_handle){ 123 return &service->connections[i]; 124 } 125 } 126 return NULL; 127 } 128 129 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){ 130 if (service == NULL){ 131 return NULL; 132 } 133 134 uint8_t i; 135 for (i = 0; i < service->connections_max_num; i++){ 136 if (service->connections[i].con_handle == HCI_CON_HANDLE_INVALID){ 137 service->connections[i].con_handle = con_handle; 138 service->connections[i].service = service; 139 return &service->connections[i]; 140 } 141 } 142 return NULL; 143 } 144 145 146 static battery_service_v1_t * battery_service_service_for_attribute_handle(uint16_t attribute_handle){ 147 btstack_linked_list_iterator_t it; 148 btstack_linked_list_iterator_init(&it, &battery_services); 149 while (btstack_linked_list_iterator_has_next(&it)){ 150 battery_service_v1_t * item = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it); 151 if (attribute_handle < item->start_handle) continue; 152 if (attribute_handle > item->end_handle) continue; 153 return item; 154 } 155 return NULL; 156 } 157 158 159 static battery_service_v1_t * battery_service_service_for_con_handle(hci_con_handle_t con_handle){ 160 btstack_linked_list_iterator_t it; 161 btstack_linked_list_iterator_init(&it, &battery_services); 162 while (btstack_linked_list_iterator_has_next(&it)){ 163 battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it); 164 uint8_t i; 165 for (i = 0; i < service->connections_max_num; i++){ 166 if (service->connections[i].con_handle == con_handle){ 167 return service; 168 } 169 } 170 } 171 return NULL; 172 } 173 174 static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_characteristic_index_t index, uint8_t * event, uint8_t event_size){ 175 uint8_t pos = 0; 176 switch ((bas_characteristic_index_t) index){ 177 case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL: 178 event[pos++] = service->battery_level; 179 break; 180 181 case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS: 182 if (service->level_status == NULL){ 183 return 0; 184 } 185 event[pos++] = service->level_status->flags; 186 little_endian_store_16(event, pos, service->level_status->power_state_flags); 187 pos += 2; 188 if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_IDENTIFIER_PRESENT) > 0u){ 189 little_endian_store_16(event, pos, service->level_status->identifier); 190 pos += 2; 191 } 192 if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_BATTERY_LEVEL_PRESENT) > 0u){ 193 event[pos++] = service->level_status->battery_level; 194 } 195 if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){ 196 event[pos++] = service->level_status->additional_status_flags; 197 } 198 break; 199 200 case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE: 201 little_endian_store_24(event, pos, service->estimated_service_date_days); 202 pos += 3; 203 break; 204 205 case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS: 206 event[pos++] = service->critcal_status_flags; 207 break; 208 209 case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS: 210 if (service->energy_status == NULL){ 211 return 0; 212 } 213 event[pos++] = service->energy_status->flags; 214 if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_EXTERNAL_SOURCE_POWER_PRESENT) > 0u){ 215 little_endian_store_16(event, pos, service->energy_status->external_source_power_medfloat16); 216 pos += 2; 217 } 218 if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_PRESENT_VOLTAGE_PRESENT) > 0u){ 219 little_endian_store_16(event, pos, service->energy_status->present_voltage_medfloat16); 220 pos += 2; 221 } 222 if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_ENERGY_PRESENT) > 0u){ 223 little_endian_store_16(event, pos, service->energy_status->available_energy_medfloat16); 224 pos += 2; 225 } 226 if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_BATTERY_CAPACITY_PRESENT) > 0u){ 227 little_endian_store_16(event, pos, service->energy_status->available_battery_capacity_medfloat16); 228 pos += 2; 229 } 230 if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_CHARGE_RATE_PRESENT) > 0u){ 231 little_endian_store_16(event, pos, service->energy_status->charge_rate_medfloat16); 232 pos += 2; 233 } 234 if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_ENERGY_AT_LAST_CHARGE_PRESENT) > 0u){ 235 little_endian_store_16(event, pos, service->energy_status->available_energy_at_last_charge_medfloat16); 236 pos += 2; 237 } 238 break; 239 240 case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS: 241 if (service->time_status == NULL){ 242 return 0; 243 } 244 event[pos++] = service->time_status->flags; 245 little_endian_store_24(event, pos, service->time_status->time_until_discharged_minutes); 246 pos += 3; 247 if ((service->time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_DISCHARGED_ON_STANDBY_PRESENT) > 0u){ 248 little_endian_store_24(event, pos, service->time_status->time_until_discharged_on_standby_minutes); 249 pos += 3; 250 } 251 if ((service->time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_RECHARGED_PRESENT) > 0u){ 252 little_endian_store_24(event, pos, service->time_status->time_until_recharged_minutes); 253 pos += 3; 254 } 255 break; 256 257 case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS: 258 if (service->health_status == NULL){ 259 return 0; 260 } 261 event[pos++] = service->health_status->flags; 262 if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){ 263 event[pos++] = service->health_status->summary; 264 } 265 if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CYCLE_COUNT_PRESENT) > 0u){ 266 little_endian_store_16(event, pos, service->health_status->cycle_count); 267 pos += 2; 268 } 269 if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CURRENT_TEMPERATURE_PRESENT) > 0u){ 270 event[pos++] = service->health_status->current_temperature_degree_celsius; 271 } 272 if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_DEEP_DISCHARGE_COUNT_PRESENT) > 0u){ 273 little_endian_store_16(event, pos, service->health_status->deep_discharge_count); 274 pos += 2; 275 } 276 break; 277 278 case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION: 279 if (service->health_information == NULL){ 280 return 0; 281 } 282 event[pos++] = service->health_information->flags; 283 if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_CYCLE_COUNT_DESIGNED_LIFETIME_PRESENT) > 0u){ 284 little_endian_store_16(event, pos, service->health_information->cycle_count_designed_lifetime); 285 pos += 2; 286 } 287 if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_DESIGNED_OPERATING_TEMPERATURE_PRESENT) > 0u){ 288 event[pos++] = service->health_information->min_designed_operating_temperature_degree_celsius; 289 } 290 if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_DESIGNED_OPERATING_TEMPERATURE_PRESENT) > 0u){ 291 event[pos++] = service->health_information->max_designed_operating_temperature_degree_celsius; 292 } 293 break; 294 295 case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION: 296 if (service->information == NULL){ 297 return 0; 298 } 299 little_endian_store_16(event, pos, service->information->flags); 300 pos += 2; 301 event[pos++] = service->information->features; 302 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_MANUFACTURE_DATE_PRESENT) > 0u){ 303 little_endian_store_24(event, pos, service->information->manufacture_date_days); 304 pos += 3; 305 } 306 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){ 307 little_endian_store_24(event, pos, service->information->expiration_date_days); 308 pos += 3; 309 } 310 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_DESIGNED_CAPACITY_PRESENT) > 0u){ 311 little_endian_store_16(event, pos, service->information->designed_capacity_kWh_medfloat16); 312 pos += 2; 313 } 314 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_LOW_ENERGY_PRESENT) > 0u){ 315 little_endian_store_16(event, pos, service->information->low_energy_kWh_medfloat16); 316 pos += 2; 317 } 318 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CRITICAL_ENERGY_PRESENT) > 0u){ 319 little_endian_store_16(event, pos, service->information->critical_energy_kWh_medfloat16); 320 pos += 2; 321 } 322 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){ 323 event[pos++] = service->information->chemistry; 324 } 325 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_NOMINAL_VOLTAGE_PRESENT) > 0u){ 326 little_endian_store_16(event, pos, service->information->nominal_voltage_medfloat16); 327 pos += 2; 328 } 329 if ((service->information->flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){ 330 event[pos++] = service->information->aggregation_group; 331 } 332 break; 333 default: 334 break; 335 } 336 return pos; 337 } 338 339 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){ 340 UNUSED(con_handle); 341 342 battery_service_v1_t * service = battery_service_service_for_attribute_handle(attribute_handle); 343 if (service == NULL){ 344 return 0; 345 } 346 347 battery_service_v1_server_connection_t * connection = battery_service_server_connection_for_con_handle(service, con_handle); 348 if (connection == NULL){ 349 connection = battery_service_server_add_connection_for_con_handle(service, con_handle); 350 if (connection == NULL){ 351 return 0; 352 } 353 } 354 355 uint8_t index; 356 uint8_t event[18]; 357 uint8_t pos = 0; 358 359 for (index = 0; index < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; index++){ 360 if (attribute_handle != service->characteristics[index].value_handle){ 361 continue; 362 } 363 364 switch ((bas_characteristic_index_t) index){ 365 case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING: 366 if (service->manufacturer_name == NULL){ 367 return 0; 368 } 369 return att_read_callback_handle_blob((uint8_t *)service->manufacturer_name, strlen(service->manufacturer_name), offset, buffer, buffer_size); 370 371 case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING: 372 if (service->model_number == NULL){ 373 return 0; 374 } 375 return att_read_callback_handle_blob((uint8_t *)service->model_number, strlen(service->model_number), offset, buffer, buffer_size); 376 377 case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING: 378 if (service->serial_number == NULL){ 379 return 0; 380 } 381 return att_read_callback_handle_blob((uint8_t *)service->serial_number, strlen(service->serial_number), offset, buffer, buffer_size); 382 383 default: 384 pos = bas_serialize_characteristic(service, index, event, sizeof(event)); 385 if (pos == 1u){ 386 return att_read_callback_handle_byte(event[0], offset, buffer, buffer_size); 387 } 388 if (pos > 1u){ 389 return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size); 390 } 391 return 0; 392 } 393 } 394 395 for (index = 0; index < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; index++){ 396 if (attribute_handle != service->characteristics[index].client_configuration_handle){ 397 continue; 398 } 399 return att_read_callback_handle_little_endian_16(connection->configurations[index], offset, buffer, buffer_size); 400 } 401 return 0; 402 } 403 404 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){ 405 UNUSED(offset); 406 UNUSED(buffer_size); 407 408 if (transaction_mode != ATT_TRANSACTION_MODE_NONE){ 409 return 0; 410 } 411 412 battery_service_v1_t * service = battery_service_service_for_attribute_handle(attribute_handle); 413 if (service == NULL){ 414 return 0; 415 } 416 417 battery_service_v1_server_connection_t * connection = battery_service_server_connection_for_con_handle(service, con_handle); 418 if (connection == NULL){ 419 connection = battery_service_server_add_connection_for_con_handle(service, con_handle); 420 if (connection == NULL){ 421 return 0; 422 } 423 } 424 425 uint8_t index; 426 for (index = 0; index < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; index++){ 427 if (attribute_handle != service->characteristics[index].client_configuration_handle){ 428 continue; 429 } 430 connection->configurations[index] = little_endian_read_16(buffer, 0); 431 } 432 return 0; 433 } 434 435 436 static bool bas_characteristic_notify_configured(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index){ 437 return (connection->configurations[index] & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) != 0u; 438 } 439 static bool bas_characteristic_indicate_configured(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index){ 440 return (connection->configurations[index] & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION) != 0u; 441 } 442 443 static void battery_service_can_send_now(void * context){ 444 battery_service_v1_server_connection_t * connection = (battery_service_v1_server_connection_t *) context; 445 if (connection == NULL){ 446 return; 447 } 448 battery_service_v1_t * service = connection->service; 449 if (service == NULL){ 450 return; 451 } 452 453 bas_characteristic_index_t index; 454 uint8_t event[18]; 455 uint8_t pos = 0; 456 bool task_valid = true; 457 458 459 if ((connection->scheduled_tasks & BAS_TASK_BATTERY_LEVEL_CHANGED) > 0u){ 460 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_LEVEL_CHANGED; 461 index = BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL; 462 463 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED) > 0u){ 464 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED; 465 index = BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS; 466 467 } else if ((connection->scheduled_tasks & BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED) > 0u){ 468 connection->scheduled_tasks &= ~BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED; 469 index = BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE; 470 471 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED) > 0u){ 472 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED; 473 index = BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS; 474 475 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED) > 0u){ 476 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED; 477 index = BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS; 478 479 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_TIME_STATUS_CHANGED) > 0u){ 480 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_TIME_STATUS_CHANGED; 481 index = BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS; 482 483 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED) > 0u){ 484 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED; 485 index = BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS; 486 487 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED) > 0u){ 488 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED; 489 index = BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS; 490 491 } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_INFORMATION_CHANGED) > 0u){ 492 connection->scheduled_tasks &= ~BAS_TASK_BATTERY_INFORMATION_CHANGED; 493 index = BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION; 494 495 } else { 496 // TODO BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED 497 // TODO BAS_TASK_MODEL_NUMBER_STRING_CHANGED 498 // TODO BAS_TASK_SERIAL_NUMBER_STRING_CHANGED 499 500 task_valid = false; 501 } 502 503 if (task_valid){ 504 pos = bas_serialize_characteristic(service, index, event, sizeof(event)); 505 506 if (bas_characteristic_notify_configured(connection, index)){ 507 att_server_notify(connection->con_handle, service->characteristics[index].value_handle, event, pos); 508 } else if (bas_characteristic_indicate_configured(connection, index)){ 509 att_server_notify(connection->con_handle, service->characteristics[index].value_handle, event, pos); 510 } 511 } 512 513 if (connection->scheduled_tasks > 0u){ 514 att_server_register_can_send_now_callback(&connection->scheduled_tasks_callback, connection->con_handle); 515 } 516 } 517 518 void battery_service_v1_server_init(void){ 519 520 } 521 522 void battery_service_v1_server_register(battery_service_v1_t *service, battery_service_v1_server_connection_t *connections, uint8_t connection_max_num){ 523 btstack_assert(service != NULL); 524 btstack_assert(connections != NULL); 525 btstack_assert(connection_max_num > 0u); 526 527 // get service handle range 528 uint16_t end_handle = 0xffff; 529 uint16_t start_handle = 0; 530 531 btstack_linked_list_iterator_t it; 532 btstack_linked_list_iterator_init(&it, &battery_services); 533 while (btstack_linked_list_iterator_has_next(&it)){ 534 battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it); 535 if (service->end_handle > start_handle){ 536 start_handle = service->end_handle + 1; 537 } 538 } 539 540 int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE, &start_handle, &end_handle); 541 btstack_assert(service_found != 0); 542 UNUSED(service_found); 543 544 service->start_handle = start_handle; 545 service->end_handle = end_handle; 546 547 uint8_t i; 548 for (i = 0; i < (uint8_t) BAS_CHARACTERISTIC_INDEX_NUM; i++){ 549 // get characteristic value handle and client configuration handle 550 service->characteristics[i].value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, bas_uuid16s[i]); 551 service->characteristics[i].client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, bas_uuid16s[i]); 552 } 553 554 memset(connections, 0, sizeof(battery_service_v1_server_connection_t) * connection_max_num); 555 for (i = 0; i < connection_max_num; i++){ 556 connections[i].con_handle = HCI_CON_HANDLE_INVALID; 557 } 558 service->connections_max_num = connection_max_num; 559 service->connections = connections; 560 561 service->service_handler.read_callback = &battery_service_read_callback; 562 service->service_handler.write_callback = &battery_service_write_callback; 563 att_server_register_service_handler(&service->service_handler); 564 565 log_info("Found Battery Service 0x%02x-0x%02x", start_handle, end_handle); 566 567 btstack_linked_list_add(&battery_services, (btstack_linked_item_t *) service); 568 } 569 570 571 static void bas_server_set_callback_for_connection(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index, uint8_t task){ 572 if (connection->con_handle == HCI_CON_HANDLE_INVALID){ 573 connection->scheduled_tasks = 0; 574 return; 575 } 576 577 uint8_t scheduled_tasks = connection->scheduled_tasks; 578 connection->scheduled_tasks |= task; 579 if (scheduled_tasks == 0){ 580 connection->scheduled_tasks_callback.callback = &battery_service_can_send_now; 581 connection->scheduled_tasks_callback.context = (void*) connection; 582 att_server_register_can_send_now_callback(&connection->scheduled_tasks_callback, connection->con_handle); 583 } 584 } 585 586 static void bas_server_set_callback(battery_service_v1_t * service, bas_characteristic_index_t index){ 587 uint8_t task = bas_server_get_task_for_characteristic_index(index); 588 uint8_t i; 589 for (i = 0; i < service->connections_max_num; i++){ 590 if (service->connections[i].configurations[index] > 0u){ 591 bas_server_set_callback_for_connection(&service->connections[i], index, task); 592 } 593 } 594 } 595 596 uint8_t battery_service_v1_server_set_battery_level(battery_service_v1_t * service, uint8_t battery_level){ 597 btstack_assert(service != NULL); 598 if (battery_level > 100){ 599 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 600 } 601 if (service->battery_level != battery_level){ 602 service->battery_level = battery_level; 603 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL); 604 } 605 return ERROR_CODE_SUCCESS; 606 } 607 608 uint8_t battery_service_v1_server_set_battery_level_status(battery_service_v1_t * service, const battery_level_status_t * battery_level_status){ 609 btstack_assert(service != NULL); 610 btstack_assert(battery_level_status != NULL); 611 612 if ((battery_level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_RFU) != 0u){ 613 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 614 } 615 if ((battery_level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){ 616 if ((battery_level_status->additional_status_flags & BATTERY_LEVEL_ADDITIONAL_STATUS_BITMASK_RFU) != 0u){ 617 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 618 } 619 } 620 621 service->level_status = battery_level_status; 622 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS); 623 return ERROR_CODE_SUCCESS; 624 } 625 626 uint8_t battery_service_v1_server_set_estimated_service_date_days(battery_service_v1_t * service, uint32_t estimated_service_date_days){ 627 btstack_assert(service != NULL); 628 629 if (estimated_service_date_days > 0xFFFFFF){ 630 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 631 } 632 633 service->estimated_service_date_days = estimated_service_date_days; 634 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE); 635 return ERROR_CODE_SUCCESS; 636 } 637 638 uint8_t battery_service_v1_server_set_critcal_status_flags(battery_service_v1_t * service, uint8_t critcal_status_flags){ 639 btstack_assert(service != NULL); 640 641 if ((critcal_status_flags & BATTERY_CRITCAL_STATUS_BITMASK_RFU) != 0u){ 642 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 643 } 644 645 service->critcal_status_flags = critcal_status_flags; 646 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS); 647 return ERROR_CODE_SUCCESS; 648 } 649 650 uint8_t battery_service_v1_server_set_energy_status(battery_service_v1_t * service, const battery_energy_status_t * energy_status){ 651 btstack_assert(service != NULL); 652 btstack_assert(energy_status != NULL); 653 654 if ((energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_RFU) != 0u){ 655 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 656 } 657 658 service->energy_status = energy_status; 659 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS); 660 return ERROR_CODE_SUCCESS; 661 } 662 663 uint8_t battery_service_v1_server_set_time_status(battery_service_v1_t * service, const battery_time_status_t * time_status){ 664 btstack_assert(service != NULL); 665 btstack_assert(time_status != NULL); 666 667 if ((time_status->flags & BATTERY_TIME_STATUS_BITMASK_RFU) != 0u){ 668 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 669 } 670 if (time_status->time_until_discharged_minutes > 0xFFFFFF){ 671 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 672 } 673 if ((time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_DISCHARGED_ON_STANDBY_PRESENT) > 0u){ 674 if (time_status->time_until_discharged_on_standby_minutes > 0xFFFFFF){ 675 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 676 } 677 } 678 if ((time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_RECHARGED_PRESENT) > 0u){ 679 if (time_status->time_until_recharged_minutes > 0xFFFFFF){ 680 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 681 } 682 } 683 684 service->time_status = time_status; 685 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS); 686 return ERROR_CODE_SUCCESS; 687 } 688 689 uint8_t battery_service_v1_server_set_health_status(battery_service_v1_t * service, const battery_health_status_t * health_status){ 690 btstack_assert(service != NULL); 691 btstack_assert(health_status != NULL); 692 693 if ((health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_RFU) != 0u){ 694 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 695 } 696 if ((health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){ 697 if (health_status->summary > 100){ 698 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 699 } 700 } 701 702 service->health_status = health_status; 703 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS); 704 return ERROR_CODE_SUCCESS; 705 } 706 707 uint8_t battery_service_v1_server_set_health_information(battery_service_v1_t * service, const battery_health_information_t * health_information){ 708 btstack_assert(service != NULL); 709 btstack_assert(health_information != NULL); 710 711 if ((health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_RFU) != 0u){ 712 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 713 } 714 715 service->health_information = health_information; 716 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION); 717 return ERROR_CODE_SUCCESS; 718 } 719 720 uint8_t battery_service_v1_server_set_information(battery_service_v1_t * service, const battery_information_t * information){ 721 btstack_assert(service != NULL); 722 btstack_assert(information != NULL); 723 724 if ((information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_RFU) != 0u){ 725 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 726 } 727 if ((information->flags & BATTERY_INFORMATION_BITMASK_MANUFACTURE_DATE_PRESENT) > 0u){ 728 if (information->manufacture_date_days > 0xFFFFFF){ 729 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 730 } 731 } 732 if ((information->flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){ 733 if (information->expiration_date_days > 0xFFFFFF){ 734 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 735 } 736 } 737 if ((information->flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){ 738 if (information->chemistry >= BATTERY_CHEMISTRY_RFU_START || information->chemistry <= BATTERY_CHEMISTRY_RFU_END){ 739 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 740 } 741 } 742 if ((information->flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){ 743 if (information->aggregation_group == 0xFF){ 744 return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 745 } 746 } 747 748 service->information = information; 749 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION); 750 return ERROR_CODE_SUCCESS; 751 } 752 753 uint8_t battery_service_v1_server_set_manufacturer_name(battery_service_v1_t * service, const char * manufacturer_name){ 754 btstack_assert(service != NULL); 755 btstack_assert(manufacturer_name != NULL); 756 757 service->manufacturer_name = manufacturer_name; 758 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING); 759 return ERROR_CODE_SUCCESS; 760 } 761 762 uint8_t battery_service_v1_server_set_model_number(battery_service_v1_t * service, const char * model_number){ 763 btstack_assert(service != NULL); 764 btstack_assert(model_number != NULL); 765 766 service->model_number = model_number; 767 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING); 768 return ERROR_CODE_SUCCESS; 769 } 770 771 uint8_t battery_service_v1_server_set_serial_number(battery_service_v1_t * service, const char * serial_number){ 772 btstack_assert(service != NULL); 773 btstack_assert(serial_number != NULL); 774 775 service->serial_number = serial_number; 776 bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING); 777 return ERROR_CODE_SUCCESS; 778 } 779 780 void battery_service_v1_server_deregister(battery_service_v1_t *service){ 781 btstack_linked_list_remove(&battery_services, (btstack_linked_item_t * )service); 782 // TODO cansel can send now 783 } 784 785 void battery_service_v1_server_deinit(void){ 786 // deregister listeners 787 // empty list 788 btstack_linked_list_iterator_t it; 789 btstack_linked_list_iterator_init(&it, &battery_services); 790 while (btstack_linked_list_iterator_has_next(&it)){ 791 battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it); 792 battery_service_v1_server_deregister(service); 793 } 794 } 795