gatt-service/bas-client: use request to send

This commit is contained in:
Matthias Ringwald 2024-09-25 15:42:09 +02:00
parent b60c168034
commit 814908c5a4
2 changed files with 106 additions and 34 deletions

View File

@ -61,6 +61,8 @@
#define BATTERY_SERVICE_INVALID_INDEX 0xFF
static btstack_context_callback_registration_t battery_service_handle_can_send_now;
static btstack_linked_list_t clients;
static uint16_t battery_service_cid_counter = 0;
static btstack_packet_callback_registration_t hci_event_callback_registration;
@ -73,6 +75,12 @@ static uint16_t battery_service_get_next_cid(void){
return battery_service_cid_counter;
}
static uint8_t battery_service_client_request_send_gatt_query(battery_service_client_t * client){
battery_service_handle_can_send_now.context = (void *)(uintptr_t)client->cid;
return gatt_client_request_to_send_gatt_query(&battery_service_handle_can_send_now, client->con_handle);
}
static battery_service_client_t * battery_service_create_client(hci_con_handle_t con_handle, uint16_t cid){
battery_service_client_t * client = btstack_memory_battery_service_client_get();
if (!client){
@ -191,14 +199,23 @@ static bool battery_service_registered_notification(battery_service_client_t * c
return status;
}
static void battery_service_start_polling_if_needed(battery_service_client_t * client){
if (client->poll_interval_ms > 0){
client->need_poll_bitmap = client->poll_bitmap;
battery_service_poll_timer_start(client);
}
static bool battery_service_is_polling_needed(battery_service_client_t * client){
return (client->poll_bitmap > 0u) && (client->poll_interval_ms > 0u);
}
static void battery_service_run_for_client(battery_service_client_t * client){
static void battery_service_start_polling(battery_service_client_t * client){
client->need_poll_bitmap = client->poll_bitmap;
battery_service_poll_timer_start(client);
}
static void battery_service_send_next_query(void * context){
uint16_t cid = (uint16_t)(uintptr_t)context;
battery_service_client_t * client = battery_service_get_client_for_cid(cid);
if (client == NULL){
return;
}
uint8_t status;
uint8_t i;
gatt_client_characteristic_t characteristic;
@ -207,10 +224,14 @@ static void battery_service_run_for_client(battery_service_client_t * client){
case BATTERY_SERVICE_CLIENT_STATE_CONNECTED:
for (i = 0; i < client->num_instances; i++){
if ( ((client->need_poll_bitmap >> i) & 0x01) == 0x01 ){
client->state = BATTERY_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE_READ;
// clear bit of polled service
client->need_poll_bitmap &= ~(1u << i);
client->polled_service_index = i;
#ifdef ENABLE_TESTING_SUPPORT
printf("Poll value [%d]\n", i);
#endif
// poll value of characteristic
characteristic.value_handle = client->services[i].value_handle;
characteristic.properties = client->services[i].properties;
@ -286,13 +307,16 @@ static void battery_service_run_for_client(battery_service_client_t * client){
#endif
client->state = BATTERY_SERVICE_CLIENT_STATE_CONNECTED;
battery_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
battery_service_start_polling_if_needed(client);
if (battery_service_is_polling_needed(client)){
battery_service_start_polling(client);
}
break;
default:
break;
}
}
static void battery_service_poll_timer_timeout_handler(btstack_timer_source_t * timer){
uint16_t battery_service_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
@ -300,15 +324,15 @@ static void battery_service_poll_timer_timeout_handler(btstack_timer_source_t *
btstack_assert(client != NULL);
client->need_poll_bitmap = client->poll_bitmap;
battery_service_poll_timer_start(client);
battery_service_run_for_client(client);
battery_service_client_request_send_gatt_query(client);
}
static void battery_service_poll_timer_start(battery_service_client_t * client){
btstack_run_loop_set_timer_handler(&client->poll_timer, battery_service_poll_timer_timeout_handler);
btstack_run_loop_set_timer_context(&client->poll_timer, (void *)(uintptr_t)client->cid);
btstack_run_loop_set_timer(&client->poll_timer, client->poll_interval_ms);
btstack_run_loop_set_timer(&client->poll_timer, client->poll_interval_ms);
btstack_run_loop_remove_timer(&client->poll_timer);
btstack_run_loop_add_timer(&client->poll_timer);
}
@ -328,7 +352,7 @@ static void battery_service_client_validate_service(battery_service_client_t * c
}
// @return true if client valid / run function should be called
static bool battery_service_client_handle_query_complete(battery_service_client_t * client, uint8_t status){
static bool battery_service_client_handle_query_complete_for_connection_setup(battery_service_client_t * client, uint8_t status){
switch (client->state){
case BATTERY_SERVICE_CLIENT_STATE_W4_SERVICE_RESULT:
if (status != ATT_ERROR_SUCCESS){
@ -395,7 +419,10 @@ static bool battery_service_client_handle_query_complete(battery_service_client_
case BATTERY_SERVICE_CLIENT_W4_CHARACTERISTIC_CONFIGURATION_RESULT:
client->state = BATTERY_SERVICE_CLIENT_STATE_CONNECTED;
battery_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
battery_service_start_polling_if_needed(client);
if (battery_service_is_polling_needed(client)){
battery_service_start_polling(client);
return false;
}
break;
#endif
case BATTERY_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED:
@ -406,33 +433,47 @@ static bool battery_service_client_handle_query_complete(battery_service_client_
}
#ifdef ENABLE_TESTING_SUPPORT
for (client->service_index = 0; client->service_index < client->num_instances; client->service_index++){
bool need_polling = (client->poll_bitmap & (1 << client->service_index)) != 0;
printf("read CCC 1 0x%02x, polling %d \n", client->services[client->service_index].ccc_handle, (int) need_polling);
if ( (client->services[client->service_index].ccc_handle != 0) && !need_polling ) {
client->state = BATTERY_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION;
break;
}
}
bool need_polling = (client->poll_bitmap & (1 << client->service_index)) != 0;
printf("read CCC 1 0x%02x, polling %d \n", client->services[client->service_index].ccc_handle, (int) need_polling);
if ( (client->services[client->service_index].ccc_handle != 0) && !need_polling ) {
client->state = BATTERY_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION;
break;
}
}
#endif
client->state = BATTERY_SERVICE_CLIENT_STATE_CONNECTED;
battery_service_emit_connection_established(client, ERROR_CODE_SUCCESS);
battery_service_start_polling_if_needed(client);
if (battery_service_is_polling_needed(client)){
battery_service_start_polling(client);
return false;
}
break;
case BATTERY_SERVICE_CLIENT_STATE_CONNECTED:
default:
return false;
}
return true;
}
static bool battery_service_client_handle_query_complete(battery_service_client_t * client, uint8_t status){
switch (client->state){
case BATTERY_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE_READ:
if (client->polled_service_index != BATTERY_SERVICE_INVALID_INDEX){
if (status != ATT_ERROR_SUCCESS){
battery_service_emit_battery_level(client, client->services[client->polled_service_index].value_handle, status, 0);
}
client->polled_service_index = BATTERY_SERVICE_INVALID_INDEX;
}
break;
client->state = BATTERY_SERVICE_CLIENT_STATE_CONNECTED;
return (client->need_poll_bitmap != 0u);
default:
break;
}
return true;
return false;
}
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
@ -443,7 +484,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
battery_service_client_t * client = NULL;
gatt_client_service_t service;
gatt_client_characteristic_t characteristic;
bool call_run = true;
bool send_next_gatt_query = false;
switch(hci_event_packet_get_type(packet)){
case GATT_EVENT_SERVICE_QUERY_RESULT:
@ -462,6 +503,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
} else {
log_info("Found more then %d, Battery Service instances. Increase MAX_NUM_BATTERY_SERVICES to store all.", MAX_NUM_BATTERY_SERVICES);
}
// for sending next query w4 GATT_EVENT_QUERY_COMPLETE
break;
case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
@ -483,6 +525,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
characteristic.value_handle, characteristic.uuid16,
client->service_index);
#endif
// for sending next query w4 GATT_EVENT_QUERY_COMPLETE
break;
case GATT_EVENT_NOTIFICATION:
@ -495,6 +538,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
gatt_event_notification_get_value_handle(packet),
ATT_ERROR_SUCCESS,
gatt_event_notification_get_value(packet)[0]);
break;
case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
@ -514,6 +558,7 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
gatt_event_characteristic_value_query_result_get_value_handle(packet),
ATT_ERROR_SUCCESS,
gatt_event_characteristic_value_query_result_get_value(packet)[0]);
// reset need_poll_bitmap in GATT_EVENT_QUERY_COMPLETE
break;
#ifdef ENABLE_TESTING_SUPPORT
@ -533,21 +578,37 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint
characteristic_descriptor.uuid16);
}
break;
// for sending next query w4 GATT_EVENT_QUERY_COMPLETE
}
#endif
case GATT_EVENT_QUERY_COMPLETE:
client = battery_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
btstack_assert(client != NULL);
call_run = battery_service_client_handle_query_complete(client, gatt_event_query_complete_get_att_status(packet));
// 1. handle service establishment/notification subscription query results (client->state < BATTERY_SERVICE_CLIENT_STATE_CONNECTED)
if (client->state < BATTERY_SERVICE_CLIENT_STATE_CONNECTED){
send_next_gatt_query = battery_service_client_handle_query_complete_for_connection_setup(client, gatt_event_query_complete_get_att_status(packet));
break;
}
// 2. handle battery value query result when devices is connected
send_next_gatt_query = battery_service_client_handle_query_complete(client, gatt_event_query_complete_get_att_status(packet));
if (!send_next_gatt_query){
// if there are no further queries, and we're connected, trigger next polling read
if (battery_service_is_polling_needed(client)){
battery_service_poll_timer_start(client);
}
}
break;
default:
break;
}
if (call_run && (client != NULL)){
battery_service_run_for_client(client);
if (send_next_gatt_query){
battery_service_client_request_send_gatt_query(client);
return;
}
}
@ -598,8 +659,12 @@ uint8_t battery_service_client_connect(hci_con_handle_t con_handle, btstack_pack
client->client_handler = packet_handler;
client->poll_interval_ms = poll_interval_ms;
client->state = BATTERY_SERVICE_CLIENT_STATE_W2_QUERY_SERVICE;
battery_service_run_for_client(client);
return ERROR_CODE_SUCCESS;
uint8_t status = battery_service_client_request_send_gatt_query(client);
if (status != ERROR_CODE_SUCCESS){
client->state = BATTERY_SERVICE_CLIENT_STATE_IDLE;
}
return status;
}
uint8_t battery_service_client_disconnect(uint16_t battery_service_cid){
@ -612,12 +677,13 @@ uint8_t battery_service_client_disconnect(uint16_t battery_service_cid){
return ERROR_CODE_SUCCESS;
}
uint8_t battery_service_client_read_battery_level(uint16_t battery_service_cid, uint8_t service_index){
battery_service_client_t * client = battery_service_get_client_for_cid(battery_service_cid);
if (client == NULL) {
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
if (client->state != BATTERY_SERVICE_CLIENT_STATE_CONNECTED) {
if (client->state < BATTERY_SERVICE_CLIENT_STATE_CONNECTED) {
return GATT_CLIENT_IN_WRONG_STATE;
}
if (service_index >= client->num_instances) {
@ -625,13 +691,18 @@ uint8_t battery_service_client_read_battery_level(uint16_t battery_service_cid,
}
client->need_poll_bitmap |= (1u << service_index);
battery_service_run_for_client(client);
return ERROR_CODE_SUCCESS;
uint8_t status = battery_service_client_request_send_gatt_query(client);
if (status != ERROR_CODE_SUCCESS){
client->need_poll_bitmap &= ~(1u << client->polled_service_index);
}
return status;
}
void battery_service_client_init(void){
hci_event_callback_registration.callback = &handle_hci_event;
hci_add_event_handler(&hci_event_callback_registration);
battery_service_handle_can_send_now.callback = &battery_service_send_next_query;
}
void battery_service_client_deinit(void){

View File

@ -83,6 +83,7 @@ typedef enum {
BATTERY_SERVICE_CLIENT_STATE_W2_REGISTER_NOTIFICATION,
BATTERY_SERVICE_CLIENT_STATE_W4_NOTIFICATION_REGISTERED,
BATTERY_SERVICE_CLIENT_STATE_CONNECTED,
BATTERY_SERVICE_CLIENT_STATE_W4_CHARACTERISTIC_VALUE_READ,
#ifdef ENABLE_TESTING_SUPPORT
BATTERY_SERVICE_CLIENT_W2_READ_CHARACTERISTIC_CONFIGURATION,
@ -142,7 +143,7 @@ void battery_service_client_init(void);
* If notifications are not supported by remote Battery Service, the client will poll battery level
* If poll_interval_ms is 0, polling is disabled, and only notifications will be received.
* In either case, the battery level is received via GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL event.
* The battery level is reported as percentage, i.e. 100 = full and it is valid if the ATTT status is equal to ATT_ERROR_SUCCESS,
* The battery level is reported as percentage, i.e. 100 = full and it is valid if the ATT status is equal to ATT_ERROR_SUCCESS,
* see ATT errors (see bluetooth.h) for other values.
*
* For manual polling, see battery_service_client_read_battery_level below.