From e16068db653dd2210a97cd71713bfb7a28f99458 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Wed, 25 Sep 2024 10:52:18 +0200 Subject: [PATCH] gatt-service/bas_server: implement set battery level status --- .../gatt-service/battery_service_v1_server.c | 192 +++++++++++++++--- .../gatt-service/battery_service_v1_server.h | 23 ++- 2 files changed, 174 insertions(+), 41 deletions(-) diff --git a/src/ble/gatt-service/battery_service_v1_server.c b/src/ble/gatt-service/battery_service_v1_server.c index f4b2e4710..94229c8b6 100644 --- a/src/ble/gatt-service/battery_service_v1_server.c +++ b/src/ble/gatt-service/battery_service_v1_server.c @@ -51,26 +51,66 @@ #include "ble/gatt-service/battery_service_v1_server.h" -#define BAS_NOTIFICATION_TASK_BATTERY_VALUE_CHANGED 0x0001 +#define BAS_TASK_BATTERY_LEVEL_CHANGED 0x0001 +#define BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED 0x0002 +#define BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED 0x0004 +#define BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED 0x0008 +#define BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED 0x0010 +#define BAS_TASK_BATTERY_TIME_STATUS_CHANGED 0x0020 +#define BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED 0x0040 +#define BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED 0x0080 +#define BAS_TASK_BATTERY_INFORMATION_CHANGED 0x0100 +#define BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED 0x0200 +#define BAS_TASK_MODEL_NUMBER_STRING_CHANGED 0x0400 +#define BAS_TASK_SERIAL_NUMBER_STRING_CHANGED 0x0800 // list of uuids static const uint16_t bas_uuid16s[BAS_CHARACTERISTIC_INDEX_NUM] = { - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS, - ORG_BLUETOOTH_CHARACTERISTIC_ESTIMATED_SERVICE_DATE, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_CRITCAL_STATUS, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_ENERGY_STATUS, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_TIME_STATUS, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_STATUS, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_INFORMATION, - ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_INFORMATION, - ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, - ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, - ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS, + ORG_BLUETOOTH_CHARACTERISTIC_ESTIMATED_SERVICE_DATE, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_CRITCAL_STATUS, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_ENERGY_STATUS, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_TIME_STATUS, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_STATUS, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_INFORMATION, + ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_INFORMATION, + ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING, + ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING, + ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING, }; - static btstack_linked_list_t battery_services; +static uint16_t bas_server_get_task_for_characteristic_index(bas_characteristic_index_t index){ + switch (index){ + case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL: + return BAS_TASK_BATTERY_LEVEL_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS: + return BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED; + case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE: + return BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS: + return BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS: + return BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS: + return BAS_TASK_BATTERY_TIME_STATUS_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS: + return BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION: + return BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED; + case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION: + return BAS_TASK_BATTERY_INFORMATION_CHANGED; + case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING: + return BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED; + case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING: + return BAS_TASK_MODEL_NUMBER_STRING_CHANGED; + case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING: + return BAS_TASK_SERIAL_NUMBER_STRING_CHANGED; + default: + btstack_assert(false); + } +} 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){ if (service == NULL){ @@ -135,7 +175,7 @@ static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_ uint8_t pos = 0; switch ((bas_characteristic_index_t) index){ case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL: - event[pos++] = service->battery_value; + event[pos++] = service->battery_level; break; case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS: @@ -392,6 +432,14 @@ static int battery_service_write_callback(hci_con_handle_t con_handle, uint16_t return 0; } + +static bool bas_characteristic_notify_configured(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index){ + return (connection->configurations[index] & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) != 0u; +} +static bool bas_characteristic_indicate_configured(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index){ + return (connection->configurations[index] & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION) != 0u; +} + static void battery_service_can_send_now(void * context){ battery_service_v1_server_connection_t * connection = (battery_service_v1_server_connection_t *) context; if (connection == NULL){ @@ -402,9 +450,64 @@ static void battery_service_can_send_now(void * context){ return; } - if ( (connection->scheduled_tasks & BAS_NOTIFICATION_TASK_BATTERY_VALUE_CHANGED) > 0u){ - connection->scheduled_tasks &= ~BAS_NOTIFICATION_TASK_BATTERY_VALUE_CHANGED; - att_server_notify(connection->con_handle, service->characteristics[BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL].value_handle, &service->battery_value, 1); + bas_characteristic_index_t index; + uint8_t event[18]; + uint8_t pos = 0; + bool task_valid = true; + + + if ((connection->scheduled_tasks & BAS_TASK_BATTERY_LEVEL_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_LEVEL_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS; + + } else if ((connection->scheduled_tasks & BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_ESTIMATED_SERVICE_DATE_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_CRITCAL_STATUS_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_ENERGY_STATUS_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_TIME_STATUS_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_TIME_STATUS_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_HEALTH_STATUS_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_HEALTH_INFORMATION_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS; + + } else if ((connection->scheduled_tasks & BAS_TASK_BATTERY_INFORMATION_CHANGED) > 0u){ + connection->scheduled_tasks &= ~BAS_TASK_BATTERY_INFORMATION_CHANGED; + index = BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION; + + } else { + // TODO BAS_TASK_MANUFACTURER_NAME_STRING_CHANGED + // TODO BAS_TASK_MODEL_NUMBER_STRING_CHANGED + // TODO BAS_TASK_SERIAL_NUMBER_STRING_CHANGED + + task_valid = false; + } + + if (task_valid){ + pos = bas_serialize_characteristic(service, index, event, sizeof(event)); + + if (bas_characteristic_notify_configured(connection, index)){ + att_server_notify(connection->con_handle, service->characteristics[index].value_handle, event, pos); + } else if (bas_characteristic_indicate_configured(connection, index)){ + att_server_notify(connection->con_handle, service->characteristics[index].value_handle, event, pos); + } } if (connection->scheduled_tasks > 0u){ @@ -465,12 +568,12 @@ void battery_service_v1_server_register(battery_service_v1_t *service, battery_s } -static void battery_service_set_callback(battery_service_v1_server_connection_t * connection, uint8_t task){ +static void bas_server_set_callback_for_connection(battery_service_v1_server_connection_t * connection, bas_characteristic_index_t index, uint8_t task){ if (connection->con_handle == HCI_CON_HANDLE_INVALID){ connection->scheduled_tasks = 0; return; } - + uint8_t scheduled_tasks = connection->scheduled_tasks; connection->scheduled_tasks |= task; if (scheduled_tasks == 0){ @@ -480,26 +583,49 @@ static void battery_service_set_callback(battery_service_v1_server_connection_t } } -uint8_t battery_service_v1_server_set_battery_value(battery_service_v1_t * service, uint8_t battery_value){ - btstack_assert(service != NULL); - if (service->battery_value == battery_value){ - return ERROR_CODE_REPEATED_ATTEMPTS; - } - if (battery_value > 100){ - return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; - } - service->battery_value = battery_value; - +static void bas_server_set_callback(battery_service_v1_t * service, bas_characteristic_index_t index){ + uint8_t task = bas_server_get_task_for_characteristic_index(index); uint8_t i; for (i = 0; i < service->connections_max_num; i++){ - battery_service_v1_server_connection_t * connection = &service->connections[i]; - if (connection->configurations[BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL] != 0){ - battery_service_set_callback(connection, BAS_NOTIFICATION_TASK_BATTERY_VALUE_CHANGED); + if (service->connections[i].configurations[index] > 0u){ + bas_server_set_callback_for_connection(&service->connections[i], index, task); } } +} + +uint8_t battery_service_v1_server_set_battery_level(battery_service_v1_t * service, uint8_t battery_level){ + btstack_assert(service != NULL); + if (battery_level > 100){ + return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; + } + + if (service->battery_level != battery_level){ + service->battery_level = battery_level; + bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL); + } return ERROR_CODE_SUCCESS; } +uint8_t battery_service_v1_server_set_battery_level_status(battery_service_v1_t * service, const battery_level_status_t * battery_level_status){ + btstack_assert(service != NULL); + btstack_assert(battery_level_status != NULL); + + if (battery_level_status->flags >= BATTERY_LEVEL_STATUS_BITMASK_RFU){ + return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; + } + + if ( (battery_level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){ + if (battery_level_status->additional_status_flags >= BATTERY_LEVEL_ADDITIONAL_STATUS_BITMASK_RFU){ + return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; + } + } + + service->level_status = battery_level_status; + bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS); + return ERROR_CODE_SUCCESS; +} + + void battery_service_v1_server_deregister(battery_service_v1_t *service){ btstack_linked_list_remove(&battery_services, (btstack_linked_item_t * )service); // TODO cansel can send now diff --git a/src/ble/gatt-service/battery_service_v1_server.h b/src/ble/gatt-service/battery_service_v1_server.h index 75e71d53e..cb0e79b27 100644 --- a/src/ble/gatt-service/battery_service_v1_server.h +++ b/src/ble/gatt-service/battery_service_v1_server.h @@ -228,7 +228,7 @@ typedef struct battery_service_v1 { bas_characteristic_t characteristics[BAS_CHARACTERISTIC_INDEX_NUM]; // ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL - uint8_t battery_value; + uint8_t battery_level; // ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS const battery_level_status_t * level_status; @@ -279,15 +279,22 @@ void battery_service_v1_server_register(battery_service_v1_t * service, battery_ void battery_service_v1_server_deregister(battery_service_v1_t * service); /** - * @brief Update battery value - * @note triggers notifications if subscribed + * @brief Update battery level + * @note Triggers notification if subscribed * @param service - * @param battery_value in range 0-100 - * @return ERROR_CODE_SUCCESS if value differs from old one, otherwise: - * - ERROR_CODE_REPEATED_ATTEMPTS, or - * - ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE + * @param battery_level in range 0-100 + * @return ERROR_CODE_SUCCESS if value is valid, otherwise ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE */ -uint8_t battery_service_v1_server_set_battery_value(battery_service_v1_t * service, uint8_t battery_value); +uint8_t battery_service_v1_server_set_battery_level(battery_service_v1_t * service, uint8_t battery_level); + +/** + * @brief Update battery level status + * @note Triggers notification or indication if subscribed + * @param service + * @param battery_level_status in range 0-100 + * @return ERROR_CODE_SUCCESS if value is valid, otherwise ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE + */ +uint8_t battery_service_v1_server_set_battery_level_status(battery_service_v1_t * service, const battery_level_status_t * battery_level_status); void battery_service_v1_server_deinit(void);