gatt-service/bas_server: extract structs for battery characteristics

This commit is contained in:
Milanka Ringwald 2024-09-25 09:04:57 +02:00 committed by Matthias Ringwald
parent e5ae30da29
commit db9fdd6802
2 changed files with 255 additions and 205 deletions

View File

@ -131,6 +131,170 @@ 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){
uint8_t pos = 0;
switch ((bas_characteristic_index_t) index){
case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL:
event[pos++] = service->battery_value;
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);
pos += 2;
if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_IDENTIFIER_PRESENT) > 0u){
little_endian_store_16(event, 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;
}
if ((service->level_status->flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){
event[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);
pos += 3;
break;
case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS:
event[pos++] = service->battery_critcal_status_flags;
break;
case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS:
if (service->energy_status == NULL){
return 0;
}
event[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);
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);
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);
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);
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);
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);
pos += 2;
}
break;
case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS:
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);
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);
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);
pos += 3;
}
break;
case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS:
if (service->health_status == NULL){
return 0;
}
event[pos++] = service->health_status->flags;
if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){
event[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);
pos += 2;
}
if ((service->health_status->flags & BATTERY_HEALTH_STATUS_BITMASK_CURRENT_TEMPERATURE_PRESENT) > 0u){
event[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);
pos += 2;
}
break;
case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION:
if (service->health_information == NULL){
return 0;
}
event[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);
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;
}
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;
}
break;
case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION:
if (service->information == NULL){
return 0;
}
little_endian_store_16(event, pos, service->information->flags);
pos += 2;
event[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);
pos += 3;
}
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){
little_endian_store_24(event, 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);
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);
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);
pos += 2;
}
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){
event[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);
pos += 2;
}
if ((service->information->flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){
event[pos++] = service->information->aggregation_group;
}
break;
default:
break;
}
return pos;
}
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){
UNUSED(con_handle);
@ -157,155 +321,33 @@ static uint16_t battery_service_read_callback(hci_con_handle_t con_handle, uint1
continue;
}
switch ((bas_characteristic_index_t) index){
case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL:
return att_read_callback_handle_byte(service->battery_value, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING:
if (service->manufacturer_name == NULL){
return 0;
}
return att_read_callback_handle_blob((uint8_t *)service->manufacturer_name, strlen(service->manufacturer_name), offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL_STATUS:
event[pos++] = service->battery_level.flags;
little_endian_store_16(event, pos, service->battery_level.power_state_flags);
pos += 2;
if ((service->battery_level.flags & BATTERY_LEVEL_STATUS_BITMASK_IDENTIFIER_PRESENT) > 0u){
little_endian_store_16(event, pos, service->battery_level.identifier);
pos += 2;
case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING:
if (service->model_number == NULL){
return 0;
}
if ((service->battery_level.flags & BATTERY_LEVEL_STATUS_BITMASK_BATTERY_LEVEL_PRESENT) > 0u){
event[pos++] = service->battery_level.battery_level;
}
if ((service->battery_level.flags & BATTERY_LEVEL_STATUS_BITMASK_ADDITIONAL_STATUS_PRESENT) > 0u){
event[pos++] = service->battery_level.additional_status_flags;
}
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
return att_read_callback_handle_blob((uint8_t *)service->model_number, strlen(service->model_number), offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_ESTIMATED_SERVICE_DATE:
little_endian_store_24(event, pos, service->estimated_service_date_days);
pos += 3;
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_CRITCAL_STATUS:
return att_read_callback_handle_byte(service->battery_critcal_status_flags, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_ENERGY_STATUS:
event[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);
pos += 2;
case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING:
if (service->serial_number == NULL){
return 0;
}
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);
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);
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);
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);
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);
pos += 2;
}
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_TIME_STATUS:
event[pos++] = service->time_status.flags;
little_endian_store_24(event, 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);
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);
pos += 3;
}
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_STATUS:
event[pos++] = service->health_status.flags;
if ((service->health_status.flags & BATTERY_HEALTH_STATUS_BITMASK_HEALTH_SUMMARY_PRESENT) > 0u){
event[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);
pos += 2;
}
if ((service->health_status.flags & BATTERY_HEALTH_STATUS_BITMASK_CURRENT_TEMPERATURE_PRESENT) > 0u){
event[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);
pos += 2;
}
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_HEALTH_INFORMATION:
event[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);
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;
}
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;
}
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_BATTERY_INFORMATION:
little_endian_store_16(event, pos, service->information.flags);
pos += 2;
event[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);
pos += 3;
}
if ((service->information.flags & BATTERY_INFORMATION_BITMASK_EXPIRATION_DATE_PRESENT) > 0u){
little_endian_store_24(event, 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);
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);
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);
pos += 2;
}
if ((service->information.flags & BATTERY_INFORMATION_BITMASK_CHEMISTRY_PRESENT) > 0u){
event[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);
pos += 2;
}
if ((service->information.flags & BATTERY_INFORMATION_BITMASK_AGGREGATION_GROUP_PRESENT) > 0u){
event[pos++] = service->information.aggregation_group;
}
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_MANUFACTURER_NAME_STRING:
return att_read_callback_handle_blob(service->manufacturer_name, service->manufacturer_name_len, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_MODEL_NUMBER_STRING:
return att_read_callback_handle_blob(service->model_number, service->model_number_len, offset, buffer, buffer_size);
case BAS_CHARACTERISTIC_INDEX_SERIAL_NUMBER_STRING:
return att_read_callback_handle_blob(service->serial_number, service->serial_number_len, offset, buffer, buffer_size);
return att_read_callback_handle_blob((uint8_t *)service->serial_number, strlen(service->serial_number), offset, buffer, buffer_size);
default:
pos = bas_serialize_characteristic(service, index, event, sizeof(event));
if (pos == 1u){
return att_read_callback_handle_byte(event[0], offset, buffer, buffer_size);
}
if (pos > 1u){
return att_read_callback_handle_blob(event, pos, offset, buffer, buffer_size);
}
return 0;
}
}

View File

@ -59,7 +59,6 @@ extern "C" {
* If the battery level changes, you can call *battery_service_server_set_battery_value(value)*.
* The service supports sending Notifications if the client enables them.
*/
#define BATTERY_SERVICE_MAX_STRING_LEN 32
typedef enum {
BAS_CHARACTERISTIC_INDEX_BATTERY_LEVEL = 0,
@ -165,6 +164,68 @@ typedef struct {
uint16_t client_configuration_handle;
} bas_characteristic_t;
typedef struct {
uint8_t flags;
uint16_t power_state_flags;
uint16_t identifier;
uint8_t battery_level;
uint8_t additional_status_flags;
} battery_level_status_t;
typedef struct {
uint8_t flags;
uint16_t external_source_power_medfloat16;
uint16_t present_voltage_medfloat16;
uint16_t available_energy_medfloat16;
uint16_t available_battery_capacity_medfloat16;
uint16_t charge_rate_medfloat16;
uint16_t available_energy_at_last_charge_medfloat16;
} battery_energy_status_t;
typedef struct {
uint8_t flags;
// A value of 0xFFFFFF represents: Unknown
// A value of 0xFFFFFE represents: Greater than 0xFFFFFD
uint32_t time_until_discharged_minutes;
uint32_t time_until_discharged_on_standby_minutes;
uint32_t time_until_recharged_minutes;
} battery_time_status_t;
typedef struct {
uint8_t flags;
uint8_t summary; // Allowed range is 0 to 100.
uint16_t cycle_count;
int8_t current_temperature_degree_celsius;
uint16_t deep_discharge_count;
} battery_health_status_t;
typedef struct {
uint8_t flags;
uint16_t cycle_count_designed_lifetime;
// A raw value of 0x7F represents: Greater than 126.
// A raw value of 0x80 represents: Less than -127.
int8_t min_designed_operating_temperature_degree_celsius;
int8_t max_designed_operating_temperature_degree_celsius;
} battery_health_information_t;
typedef struct {
uint16_t flags;
uint8_t features;
uint32_t manufacture_date_days;
uint32_t expiration_date_days;
uint16_t designed_capacity_kWh_medfloat16;
uint16_t low_energy_kWh_medfloat16;
uint16_t critical_energy_kWh_medfloat16;
uint8_t chemistry;
uint16_t nominal_voltage_medfloat16;
uint8_t aggregation_group; // 0: not in group, 255: RFU
} battery_information_t;
typedef struct battery_service_v1 {
btstack_linked_item_t item;
@ -182,14 +243,7 @@ typedef struct battery_service_v1 {
uint8_t battery_value;
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_STATUS
struct {
uint8_t flags;
uint16_t power_state_flags;
uint16_t identifier;
uint8_t battery_level;
uint8_t additional_status_flags;
} battery_level;
const battery_level_status_t * level_status;
// ORG_BLUETOOTH_CHARACTERISTIC_ESTIMATED_SERVICE_DATE
uint32_t estimated_service_date_days;
@ -198,74 +252,28 @@ typedef struct battery_service_v1 {
uint8_t battery_critcal_status_flags;
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_ENERGY_STATUS
struct {
uint8_t flags;
uint16_t external_source_power_medfloat16;
uint16_t present_voltage_medfloat16;
uint16_t available_energy_medfloat16;
uint16_t available_battery_capacity_medfloat16;
uint16_t charge_rate_medfloat16;
uint16_t available_energy_at_last_charge_medfloat16;
} energy_status;
const battery_energy_status_t * energy_status;
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_TIME_STATUS
struct {
uint8_t flags;
// A value of 0xFFFFFF represents: Unknown
// A value of 0xFFFFFE represents: Greater than 0xFFFFFD
uint32_t time_until_discharged_minutes;
uint32_t time_until_discharged_on_standby_minutes;
uint32_t time_until_recharged_minutes;
} time_status;
const battery_time_status_t * time_status;
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_STATUS
struct {
uint8_t flags;
uint8_t summary; // Allowed range is 0 to 100.
uint16_t cycle_count;
int8_t current_temperature_degree_celsius;
uint16_t deep_discharge_count;
} health_status;
const battery_health_status_t * health_status;
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_HEALTH_INFORMATION
struct {
uint8_t flags;
uint16_t cycle_count_designed_lifetime;
// A raw value of 0x7F represents: Greater than 126.
// A raw value of 0x80 represents: Less than -127.
int8_t min_designed_operating_temperature_degree_celsius;
int8_t max_designed_operating_temperature_degree_celsius;
} health_information;
const battery_health_information_t * health_information;
// ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_INFORMATION
struct {
uint16_t flags;
uint8_t features;
uint32_t manufacture_date_days;
uint32_t expiration_date_days;
uint16_t designed_capacity_kWh_medfloat16;
uint16_t low_energy_kWh_medfloat16;
uint16_t critical_energy_kWh_medfloat16;
uint8_t chemistry;
uint16_t nominal_voltage_medfloat16;
uint8_t aggregation_group; // 0: not in group, 255: RFU
} information;
const battery_information_t * information;
// ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING
uint8_t manufacturer_name[BATTERY_SERVICE_MAX_STRING_LEN];
uint8_t manufacturer_name_len;
const char * manufacturer_name;
// ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING
uint8_t model_number[BATTERY_SERVICE_MAX_STRING_LEN];
uint8_t model_number_len;
const char * model_number;
// ORG_BLUETOOTH_CHARACTERISTIC_SERIAL_NUMBER_STRING
uint8_t serial_number[BATTERY_SERVICE_MAX_STRING_LEN];
uint8_t serial_number_len;
const char * serial_number;
uint8_t connections_max_num;
battery_service_v1_server_connection_t * connections;