mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-15 23:42:52 +00:00
gatt-service/bas-server: generate advertisement data for application
This commit is contained in:
parent
feeb84592b
commit
6a9e015f96
@ -51,6 +51,7 @@
|
||||
|
||||
#include "ble/gatt-service/battery_service_v1_server.h"
|
||||
#include "hci_event_builder.h"
|
||||
#include "bluetooth_data_types.h"
|
||||
|
||||
#define BAS_TASK_BATTERY_LEVEL_CHANGED 0x0001
|
||||
#define BAS_TASK_BATTERY_LEVEL_STATUS_CHANGED 0x0002
|
||||
@ -210,68 +211,68 @@ static battery_service_v1_t * battery_service_service_for_con_handle(hci_con_han
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_characteristic_index_t index, uint8_t * event, uint8_t event_size){
|
||||
static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_characteristic_index_t index, uint8_t * buffer, uint8_t buffer_size){
|
||||
uint8_t pos = 0;
|
||||
switch ((bas_characteristic_index_t) index){
|
||||
case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL:
|
||||
event[pos++] = service->battery_level;
|
||||
buffer[pos++] = service->battery_level;
|
||||
break;
|
||||
|
||||
case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS:
|
||||
if (service->level_status == NULL){
|
||||
return 0;
|
||||
}
|
||||
event[pos++] = service->level_status->flags;
|
||||
little_endian_store_16(event, pos, service->level_status->power_state_flags);
|
||||
buffer[pos++] = service->level_status->flags;
|
||||
little_endian_store_16(buffer, pos, service->level_status->power_state_flags);
|
||||
pos += 2;
|
||||
if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_IDENTIFIER_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->level_status->identifier);
|
||||
little_endian_store_16(buffer, pos, service->level_status->identifier);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_BATTERY_LEVEL_PRESENT) > 0u){
|
||||
event[pos++] = service->level_status->battery_level;
|
||||
buffer[pos++] = service->level_status->battery_level;
|
||||
}
|
||||
if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){
|
||||
event[pos++] = service->level_status->additional_status_flags;
|
||||
buffer[pos++] = service->level_status->additional_status_flags;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE:
|
||||
little_endian_store_24(event, pos, service->estimated_service_date_days);
|
||||
little_endian_store_24(buffer, pos, service->estimated_service_date_days);
|
||||
pos += 3;
|
||||
break;
|
||||
|
||||
case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS:
|
||||
event[pos++] = service->critcal_status_flags;
|
||||
buffer[pos++] = service->critical_status_flags;
|
||||
break;
|
||||
|
||||
case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS:
|
||||
if (service->energy_status == NULL){
|
||||
return 0;
|
||||
}
|
||||
event[pos++] = service->energy_status->flags;
|
||||
buffer[pos++] = service->energy_status->flags;
|
||||
if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_EXTERNAL_SOURCE_POWER_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->energy_status->external_source_power_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->energy_status->external_source_power_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_PRESENT_VOLTAGE_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->energy_status->present_voltage_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->energy_status->present_voltage_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_ENERGY_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->energy_status->available_energy_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->energy_status->available_energy_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_BATTERY_CAPACITY_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->energy_status->available_battery_capacity_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->energy_status->available_battery_capacity_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_CHARGE_RATE_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->energy_status->charge_rate_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->energy_status->charge_rate_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->energy_status->flags & BATTERY_ENERGY_STATUS_BITMASK_AVAILABLE_ENERGY_AT_LAST_CHARGE_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->energy_status->available_energy_at_last_charge_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->energy_status->available_energy_at_last_charge_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
break;
|
||||
@ -280,15 +281,15 @@ static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_
|
||||
if (service->time_status == NULL){
|
||||
return 0;
|
||||
}
|
||||
event[pos++] = service->time_status->flags;
|
||||
little_endian_store_24(event, pos, service->time_status->time_until_discharged_minutes);
|
||||
buffer[pos++] = service->time_status->flags;
|
||||
little_endian_store_24(buffer, pos, service->time_status->time_until_discharged_minutes);
|
||||
pos += 3;
|
||||
if ((service->time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_DISCHARGED_ON_STANDBY_PRESENT) > 0u){
|
||||
little_endian_store_24(event, pos, service->time_status->time_until_discharged_on_standby_minutes);
|
||||
little_endian_store_24(buffer, pos, service->time_status->time_until_discharged_on_standby_minutes);
|
||||
pos += 3;
|
||||
}
|
||||
if ((service->time_status->flags & BATTERY_TIME_STATUS_BITMASK_TIME_UNTIL_RECHARGED_PRESENT) > 0u){
|
||||
little_endian_store_24(event, pos, service->time_status->time_until_recharged_minutes);
|
||||
little_endian_store_24(buffer, pos, service->time_status->time_until_recharged_minutes);
|
||||
pos += 3;
|
||||
}
|
||||
break;
|
||||
@ -297,19 +298,19 @@ static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_
|
||||
if (service->health_status == NULL){
|
||||
return 0;
|
||||
}
|
||||
event[pos++] = service->health_status->flags;
|
||||
buffer[pos++] = service->health_status->flags;
|
||||
if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){
|
||||
event[pos++] = service->health_status->summary;
|
||||
buffer[pos++] = service->health_status->summary;
|
||||
}
|
||||
if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CYCLE_COUNT_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->health_status->cycle_count);
|
||||
little_endian_store_16(buffer, pos, service->health_status->cycle_count);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CURRENT_TEMPERATURE_PRESENT) > 0u){
|
||||
event[pos++] = service->health_status->current_temperature_degree_celsius;
|
||||
buffer[pos++] = service->health_status->current_temperature_degree_celsius;
|
||||
}
|
||||
if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_DEEP_DISCHARGE_COUNT_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->health_status->deep_discharge_count);
|
||||
little_endian_store_16(buffer, pos, service->health_status->deep_discharge_count);
|
||||
pos += 2;
|
||||
}
|
||||
break;
|
||||
@ -318,16 +319,16 @@ static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_
|
||||
if (service->health_information == NULL){
|
||||
return 0;
|
||||
}
|
||||
event[pos++] = service->health_information->flags;
|
||||
buffer[pos++] = service->health_information->flags;
|
||||
if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_CYCLE_COUNT_DESIGNED_LIFETIME_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->health_information->cycle_count_designed_lifetime);
|
||||
little_endian_store_16(buffer, pos, service->health_information->cycle_count_designed_lifetime);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_DESIGNED_OPERATING_TEMPERATURE_PRESENT) > 0u){
|
||||
event[pos++] = service->health_information->min_designed_operating_temperature_degree_celsius;
|
||||
buffer[pos++] = service->health_information->min_designed_operating_temperature_degree_celsius;
|
||||
}
|
||||
if ((service->health_information->flags & BATTERY_HEALTH_INFORMATION_BITMASK_DESIGNED_OPERATING_TEMPERATURE_PRESENT) > 0u){
|
||||
event[pos++] = service->health_information->max_designed_operating_temperature_degree_celsius;
|
||||
buffer[pos++] = service->health_information->max_designed_operating_temperature_degree_celsius;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -335,38 +336,38 @@ static uint8_t bas_serialize_characteristic(battery_service_v1_t * service, bas_
|
||||
if (service->information == NULL){
|
||||
return 0;
|
||||
}
|
||||
little_endian_store_16(event, pos, service->information->flags);
|
||||
little_endian_store_16(buffer, pos, service->information->flags);
|
||||
pos += 2;
|
||||
event[pos++] = service->information->features;
|
||||
buffer[pos++] = service->information->features;
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_MANUFACTURE_DATE_PRESENT) > 0u){
|
||||
little_endian_store_24(event, pos, service->information->manufacture_date_days);
|
||||
little_endian_store_24(buffer, pos, service->information->manufacture_date_days);
|
||||
pos += 3;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){
|
||||
little_endian_store_24(event, pos, service->information->expiration_date_days);
|
||||
little_endian_store_24(buffer, pos, service->information->expiration_date_days);
|
||||
pos += 3;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_DESIGNED_CAPACITY_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->information->designed_capacity_kWh_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->information->designed_capacity_kWh_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_LOW_ENERGY_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->information->low_energy_kWh_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->information->low_energy_kWh_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CRITICAL_ENERGY_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->information->critical_energy_kWh_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->information->critical_energy_kWh_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){
|
||||
event[pos++] = service->information->chemistry;
|
||||
buffer[pos++] = service->information->chemistry;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_NOMINAL_VOLTAGE_PRESENT) > 0u){
|
||||
little_endian_store_16(event, pos, service->information->nominal_voltage_medfloat16);
|
||||
little_endian_store_16(buffer, pos, service->information->nominal_voltage_medfloat16);
|
||||
pos += 2;
|
||||
}
|
||||
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){
|
||||
event[pos++] = service->information->aggregation_group;
|
||||
buffer[pos++] = service->information->aggregation_group;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -469,6 +470,7 @@ static int battery_service_write_callback(hci_con_handle_t con_handle, uint16_t
|
||||
uint8_t new_value = little_endian_read_16(buffer, 0);
|
||||
bool broadcast_old = (service->battery_level_status_broadcast_configuration & 1) != 0;
|
||||
bool broadcast_new = (new_value & 1) != 0;
|
||||
service->battery_level_status_broadcast_configuration = new_value;
|
||||
if (broadcast_old != broadcast_new){
|
||||
// emit broadcast start/stop based on value of broadcast_new
|
||||
uint8_t event[5];
|
||||
@ -480,7 +482,6 @@ static int battery_service_write_callback(hci_con_handle_t con_handle, uint16_t
|
||||
(*battery_service_app_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
}
|
||||
service->battery_level_status_broadcast_configuration = new_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -644,7 +645,7 @@ void battery_service_v1_server_register(battery_service_v1_t *service, battery_s
|
||||
|
||||
log_info("Found Battery Service 0x%02x-0x%02x", start_handle, end_handle);
|
||||
|
||||
btstack_linked_list_add(&battery_services, (btstack_linked_item_t *) service);
|
||||
btstack_linked_list_add_tail(&battery_services, (btstack_linked_item_t *) service);
|
||||
}
|
||||
|
||||
|
||||
@ -730,7 +731,7 @@ uint8_t battery_service_v1_server_set_critcal_status_flags(battery_service_v1_t
|
||||
return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
|
||||
}
|
||||
|
||||
service->critcal_status_flags = critcal_status_flags;
|
||||
service->critical_status_flags = critcal_status_flags;
|
||||
bas_server_set_callback(service, BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
@ -904,3 +905,100 @@ void battery_service_v1_server_deinit(void){
|
||||
battery_service_v1_server_deregister(service);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t battery_service_v1_server_get_broadcast_advertisement(uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size){
|
||||
|
||||
if (adv_size < 7) return 0u;
|
||||
|
||||
uint16_t pos = 0;
|
||||
// adv flags
|
||||
adv_buffer[pos++] = 2;
|
||||
adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_FLAGS;
|
||||
adv_buffer[pos++] = 0x04;
|
||||
|
||||
// adv interval
|
||||
adv_buffer[pos++] = 3;
|
||||
adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL;
|
||||
little_endian_store_16(adv_buffer, pos, adv_interval);
|
||||
pos += 2;
|
||||
|
||||
uint16_t pos_without_data = pos;
|
||||
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &battery_services);
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
|
||||
if ((service->battery_level_status_broadcast_configuration & 1) != 0) {
|
||||
uint8_t value_buffer[10];
|
||||
uint16_t value_len = bas_serialize_characteristic(service, BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS, value_buffer, sizeof(value_buffer));
|
||||
if ((pos + 4 + value_len) <= adv_size) {
|
||||
adv_buffer[pos++] = 3 + value_len;
|
||||
adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID;
|
||||
little_endian_store_16(adv_buffer, pos, ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE);
|
||||
pos += 2;
|
||||
memcpy(&adv_buffer[pos], value_buffer, value_len);
|
||||
pos += value_len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// indicate nothing to broadcast
|
||||
if (pos == pos_without_data) {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
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){
|
||||
|
||||
if (adv_size < 7) return 0u;
|
||||
|
||||
uint16_t pos = 0;
|
||||
// adv flags
|
||||
adv_buffer[pos++] = 2;
|
||||
adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_FLAGS;
|
||||
adv_buffer[pos++] = 0x04;
|
||||
|
||||
// adv interval
|
||||
adv_buffer[pos++] = 3;
|
||||
adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL;
|
||||
little_endian_store_16(adv_buffer, pos, adv_interval);
|
||||
pos += 2;
|
||||
|
||||
uint16_t pos_without_data = pos;
|
||||
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &battery_services);
|
||||
while (btstack_linked_list_iterator_has_next(&it)){
|
||||
battery_service_v1_t * service = (battery_service_v1_t*) btstack_linked_list_iterator_next(&it);
|
||||
if (service == service_single) {
|
||||
if ((service->battery_level_status_broadcast_configuration & 1) != 0) {
|
||||
uint8_t value_buffer[10];
|
||||
uint16_t value_len = bas_serialize_characteristic(service,
|
||||
BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS,
|
||||
value_buffer, sizeof(value_buffer));
|
||||
if ((pos + 4 + value_len) <= adv_size) {
|
||||
adv_buffer[pos++] = 3 + value_len;
|
||||
adv_buffer[pos++] = BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID;
|
||||
little_endian_store_16(adv_buffer, pos, ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE);
|
||||
pos += 2;
|
||||
memcpy(&adv_buffer[pos], value_buffer, value_len);
|
||||
pos += value_len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// indicate nothing to broadcast
|
||||
if (pos == pos_without_data) {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
@ -260,7 +260,7 @@ typedef struct battery_service_v1 {
|
||||
uint32_t estimated_service_date_days;
|
||||
|
||||
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_CRITCAL_STATUS
|
||||
uint8_t critcal_status_flags;
|
||||
uint8_t critical_status_flags;
|
||||
|
||||
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_ENERGY_STATUS
|
||||
const battery_energy_status_t * energy_status;
|
||||
@ -426,6 +426,24 @@ uint8_t battery_service_v1_server_set_model_number(battery_service_v1_t * servic
|
||||
*/
|
||||
uint8_t battery_service_v1_server_set_serial_number(battery_service_v1_t * service, const char * serial_number);
|
||||
|
||||
/**
|
||||
* @brief Get Advertisement Data for all active Characteristic Broadcasts
|
||||
* @param adv_interval
|
||||
* @param adv_buffer
|
||||
* @param adv_size
|
||||
* @return
|
||||
*/
|
||||
uint16_t battery_service_v1_server_get_broadcast_advertisement(uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size);
|
||||
|
||||
/**
|
||||
* @brief Get Advertisement Data for single active Characteristic Broadcast
|
||||
* @param adv_interval
|
||||
* @param adv_buffer
|
||||
* @param adv_size
|
||||
* @return
|
||||
*/
|
||||
uint16_t battery_service_v1_server_get_broadcast_advertisement_single(battery_service_v1_t * service, uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size);
|
||||
|
||||
void battery_service_v1_server_deinit(void);
|
||||
|
||||
/* API_END */
|
||||
|
Loading…
x
Reference in New Issue
Block a user