rewrote gatt_client state handling: API uses handles instaed of context structs (adapted examples and daemon)

This commit is contained in:
mila@ringwald.ch 2014-10-02 20:06:29 +00:00
parent 01159b07a8
commit 7c40ac80c0
6 changed files with 619 additions and 365 deletions

View File

@ -58,9 +58,41 @@ static linked_list_t gatt_client_connections = NULL;
static uint16_t att_client_start_handle = 0x0001; static uint16_t att_client_start_handle = 0x0001;
static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size); static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size);
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code);
void (*gatt_client_callback)(le_event_t * event); void (*gatt_client_callback)(le_event_t * event);
static gatt_client_t * gatt_client_for_timer(timer_source_t * ts){
linked_list_iterator_t it;
linked_list_iterator_init(&it, &gatt_client_connections);
while (linked_list_iterator_has_next(&it)){
gatt_client_t * peripheral = (gatt_client_t *) linked_list_iterator_next(&it);
if ( &peripheral->gc_timeout == ts) {
return peripheral;
}
}
return NULL;
}
static void gatt_client_timeout_handler(timer_source_t * timer){
gatt_client_t * peripheral = gatt_client_for_timer(timer);
if (!peripheral) return;
log_info("GATT client timeout handle, handle 0x%02x", peripheral->handle);
gatt_client_report_error_if_pending(peripheral, ATT_ERROR_TIMEOUT);
}
static void gatt_client_timeout_start(gatt_client_t * peripheral){
log_info("GATT client timeout start, handle 0x%02x", peripheral->handle);
run_loop_remove_timer(&peripheral->gc_timeout);
run_loop_set_timer_handler(&peripheral->gc_timeout, gatt_client_timeout_handler);
run_loop_set_timer(&peripheral->gc_timeout, 30000); // 30 seconds sm timeout
run_loop_add_timer(&peripheral->gc_timeout);
}
static void gatt_client_timeout_stop(gatt_client_t * peripheral){
log_info("GATT client timeout stop, handle 0x%02x", peripheral->handle);
run_loop_remove_timer(&peripheral->gc_timeout);
}
void gatt_client_init(){ void gatt_client_init(){
att_client_start_handle = 0x0000; att_client_start_handle = 0x0000;
@ -77,24 +109,46 @@ void gatt_client_register_packet_handler(void (*gatt_callback)(le_event_t* event
gatt_client_callback = gatt_callback; gatt_client_callback = gatt_callback;
} }
// gatt client API static gatt_client_t * get_gatt_client_context_for_handle(uint16_t handle){
// start/stop gatt client linked_item_t *it;
void gatt_client_start(gatt_client_t *context, uint16_t handle){ for (it = (linked_item_t *) gatt_client_connections; it ; it = it->next){
memset(context, 0, sizeof(gatt_client_t)); gatt_client_t * peripheral = (gatt_client_t *) it;
context->handle = handle; if (peripheral->handle == handle){
return peripheral;
}
}
return NULL;
}
// @returns context
// returns existing one, or tries to setup new one
static gatt_client_t * provide_context_for_conn_handle(uint16_t con_handle){
gatt_client_t * context = get_gatt_client_context_for_handle(con_handle);
if (context) return context;
context = btstack_memory_gatt_client_get();
if (!context) return NULL;
// init state
context->handle = con_handle;
context->mtu_state = SEND_MTU_EXCHANGE; context->mtu_state = SEND_MTU_EXCHANGE;
context->gatt_client_state = P_READY; context->gatt_client_state = P_READY;
gatt_client_timeout_start(context);
linked_list_add(&gatt_client_connections, (linked_item_t*)context); linked_list_add(&gatt_client_connections, (linked_item_t*)context);
return context;
} }
void gatt_client_stop(gatt_client_t *context){ static int is_ready(gatt_client_t * context){
linked_list_remove(&gatt_client_connections, (linked_item_t*) context);
}
int gatt_client_is_ready(gatt_client_t *context){
return context->gatt_client_state == P_READY; return context->gatt_client_state == P_READY;
} }
int gatt_client_is_ready(uint16_t handle){
gatt_client_t * context = provide_context_for_conn_handle(handle);
if (!context) return 0;
return is_ready(context);
}
// precondition: can_send_packet_now == TRUE // precondition: can_send_packet_now == TRUE
static void att_confirmation(uint16_t peripheral_handle){ static void att_confirmation(uint16_t peripheral_handle){
l2cap_reserve_packet_buffer(); l2cap_reserve_packet_buffer();
@ -303,10 +357,16 @@ static uint16_t get_last_result_handle(uint8_t * packet, uint16_t size){
return READ_BT_16(packet, size - attr_length + handle_offset); return READ_BT_16(packet, size - attr_length + handle_offset);
} }
static inline void send_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){ static void gatt_client_handle_transaction_complete(gatt_client_t * peripheral){
peripheral->gatt_client_state = P_READY;
gatt_client_timeout_stop(peripheral);
}
static inline void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){
gatt_complete_event_t event; gatt_complete_event_t event;
event.type = GATT_QUERY_COMPLETE; event.type = GATT_QUERY_COMPLETE;
event.client = peripheral; event.handle = peripheral->handle;
event.attribute_handle = peripheral->attribute_handle;
event.status = status; event.status = status;
(*gatt_client_callback)((le_event_t*)&event); (*gatt_client_callback)((le_event_t*)&event);
} }
@ -318,7 +378,7 @@ static void report_gatt_services(gatt_client_t * peripheral, uint8_t * packet,
le_service_t service; le_service_t service;
le_service_event_t event; le_service_event_t event;
event.type = GATT_SERVICE_QUERY_RESULT; event.type = GATT_SERVICE_QUERY_RESULT;
event.client = peripheral; event.handle = peripheral->handle;
int i; int i;
for (i = 2; i < size; i += attr_length){ for (i = 2; i < size; i += attr_length){
@ -370,7 +430,7 @@ static void characteristic_end_found(gatt_client_t * peripheral, uint16_t end_ha
le_characteristic_event_t event; le_characteristic_event_t event;
event.type = GATT_CHARACTERISTIC_QUERY_RESULT; event.type = GATT_CHARACTERISTIC_QUERY_RESULT;
event.client = peripheral; event.handle = peripheral->handle;
event.characteristic.start_handle = peripheral->characteristic_start_handle; event.characteristic.start_handle = peripheral->characteristic_start_handle;
event.characteristic.value_handle = peripheral->attribute_handle; event.characteristic.value_handle = peripheral->attribute_handle;
event.characteristic.end_handle = end_handle; event.characteristic.end_handle = end_handle;
@ -412,15 +472,15 @@ static void report_gatt_included_service(gatt_client_t * peripheral, uint8_t *uu
le_service_event_t event; le_service_event_t event;
event.type = GATT_INCLUDED_SERVICE_QUERY_RESULT; event.type = GATT_INCLUDED_SERVICE_QUERY_RESULT;
event.service = service; event.service = service;
event.client = peripheral; event.handle = peripheral->handle;
(*gatt_client_callback)((le_event_t*)&event); (*gatt_client_callback)((le_event_t*)&event);
} }
static void send_characteristic_value_event(gatt_client_t * peripheral, uint16_t handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){ static void send_characteristic_value_event(gatt_client_t * peripheral, uint16_t value_handle, uint8_t * value, uint16_t length, uint16_t offset, uint8_t event_type){
le_characteristic_value_event_t event; le_characteristic_value_event_t event;
event.type = event_type; event.type = event_type;
event.client = peripheral; event.handle = peripheral->handle;
event.value_handle = handle; event.value_handle = value_handle;
event.value_offset = offset; event.value_offset = offset;
event.blob_length = length; event.blob_length = length;
event.blob = value; event.blob = value;
@ -446,7 +506,7 @@ static void report_gatt_characteristic_value(gatt_client_t * peripheral, uint16_
static void report_gatt_characteristic_descriptor(gatt_client_t * peripheral, uint16_t handle, uint8_t *value, uint16_t value_length, uint16_t value_offset, uint8_t event_type){ static void report_gatt_characteristic_descriptor(gatt_client_t * peripheral, uint16_t handle, uint8_t *value, uint16_t value_length, uint16_t value_offset, uint8_t event_type){
le_characteristic_descriptor_event_t event; le_characteristic_descriptor_event_t event;
event.type = event_type; event.type = event_type;
event.client = peripheral; event.handle = peripheral->handle;
le_characteristic_descriptor_t descriptor; le_characteristic_descriptor_t descriptor;
descriptor.handle = handle; descriptor.handle = handle;
@ -466,7 +526,7 @@ static void report_gatt_all_characteristic_descriptors(gatt_client_t * periphera
le_characteristic_descriptor_t descriptor; le_characteristic_descriptor_t descriptor;
le_characteristic_descriptor_event_t event; le_characteristic_descriptor_event_t event;
event.type = GATT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT; event.type = GATT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
event.client = peripheral; event.handle = peripheral->handle;
int i; int i;
for (i = 0; i<size; i+=pair_size){ for (i = 0; i<size; i+=pair_size){
@ -493,8 +553,8 @@ static void trigger_next_query(gatt_client_t * peripheral, uint16_t last_result_
return; return;
} }
// DONE // DONE
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
} }
@ -533,8 +593,8 @@ static inline void trigger_next_blob_query(gatt_client_t * peripheral, gatt_clie
uint16_t max_blob_length = peripheral->mtu - 1; uint16_t max_blob_length = peripheral->mtu - 1;
if (received_blob_length < max_blob_length){ if (received_blob_length < max_blob_length){
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
return; return;
} }
@ -552,18 +612,6 @@ static int is_value_valid(gatt_client_t *peripheral, uint8_t *packet, uint16_t s
} }
gatt_client_t * get_gatt_client_context_for_handle(uint16_t handle){
linked_item_t *it;
for (it = (linked_item_t *) gatt_client_connections; it ; it = it->next){
gatt_client_t * peripheral = (gatt_client_t *) it;
if (peripheral->handle == handle){
return peripheral;
}
}
return NULL;
}
static void gatt_client_run(){ static void gatt_client_run(){
linked_item_t *it; linked_item_t *it;
@ -604,8 +652,8 @@ static void gatt_client_run(){
case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE: case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE:
case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR: case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR:
if (peripheral->attribute_length < peripheral->mtu - 3) break; if (peripheral->attribute_length < peripheral->mtu - 3) break;
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH); emit_gatt_complete_event(peripheral, ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH);
return; return;
default: default:
break; break;
@ -726,20 +774,26 @@ static void gatt_client_run(){
} }
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) { static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) {
if (gatt_client_is_ready(peripheral)) return; if (is_ready(peripheral)) return;
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, error_code); emit_gatt_complete_event(peripheral, error_code);
} }
static void gatt_client_hci_event_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){ static void gatt_client_hci_event_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
switch (packet[0]) { switch (packet[0]) {
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
{ {
uint16_t handle = READ_BT_16(packet,3); log_info("gatt client: HCI_EVENT_DISCONNECTION_COMPLETE gatt_client_hci_event_packet_handler ");
gatt_client_t * peripheral = get_gatt_client_context_for_handle(handle); uint16_t con_handle = READ_BT_16(packet,3);
gatt_client_t * peripheral = get_gatt_client_context_for_handle(con_handle);
if (!peripheral) break; if (!peripheral) break;
gatt_client_report_error_if_pending(peripheral, ATT_ERROR_HCI_DISCONNECT_RECEIVED); gatt_client_report_error_if_pending(peripheral, ATT_ERROR_HCI_DISCONNECT_RECEIVED);
linked_list_remove(&gatt_client_connections, (linked_item_t *) peripheral); linked_list_remove(&gatt_client_connections, (linked_item_t *) peripheral);
btstack_memory_gatt_client_free(peripheral);
// HACK: forward disconnect event to client, needed by the daemon currently
(*gatt_client_callback)((le_event_t *) packet);
break; break;
} }
default: default:
@ -841,12 +895,12 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
} }
case P_W4_READ_CHARACTERISTIC_VALUE_RESULT: case P_W4_READ_CHARACTERISTIC_VALUE_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
report_gatt_characteristic_value(peripheral, peripheral->attribute_handle, &packet[1], size-1); report_gatt_characteristic_value(peripheral, peripheral->attribute_handle, &packet[1], size-1);
break; break;
case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:{ case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:{
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
report_gatt_characteristic_descriptor(peripheral, peripheral->attribute_handle, &packet[1], size-1, 0, GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT); report_gatt_characteristic_descriptor(peripheral, peripheral->attribute_handle, &packet[1], size-1, 0, GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT);
break; break;
} }
@ -869,7 +923,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
memcpy(service.uuid128, peripheral->uuid128, 16); memcpy(service.uuid128, peripheral->uuid128, 16);
service.uuid16 = peripheral->uuid16; service.uuid16 = peripheral->uuid16;
event.service = service; event.service = service;
event.client = peripheral; event.handle = peripheral->handle;
(*gatt_client_callback)((le_event_t*)&event); (*gatt_client_callback)((le_event_t*)&event);
} }
@ -893,16 +947,16 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
case ATT_WRITE_RESPONSE: case ATT_WRITE_RESPONSE:
switch (peripheral->gatt_client_state){ switch (peripheral->gatt_client_state){
case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT: case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT: case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
default: default:
break; break;
@ -957,16 +1011,16 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
case ATT_EXECUTE_WRITE_RESPONSE: case ATT_EXECUTE_WRITE_RESPONSE:
switch (peripheral->gatt_client_state){ switch (peripheral->gatt_client_state){
case P_W4_EXECUTE_PREPARED_WRITE_RESULT: case P_W4_EXECUTE_PREPARED_WRITE_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
case P_W4_CANCEL_PREPARED_WRITE_RESULT: case P_W4_CANCEL_PREPARED_WRITE_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 1); emit_gatt_complete_event(peripheral, 0);
break; break;
case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
default: default:
break; break;
@ -975,6 +1029,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
break; break;
case ATT_ERROR_RESPONSE: case ATT_ERROR_RESPONSE:
switch (packet[4]){ switch (packet[4]){
case ATT_ERROR_ATTRIBUTE_NOT_FOUND: { case ATT_ERROR_ATTRIBUTE_NOT_FOUND: {
switch(peripheral->gatt_client_state){ switch(peripheral->gatt_client_state){
@ -982,14 +1037,14 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
case P_W4_SERVICE_WITH_UUID_RESULT: case P_W4_SERVICE_WITH_UUID_RESULT:
case P_W4_INCLUDED_SERVICE_QUERY_RESULT: case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT: case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT: case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
characteristic_end_found(peripheral, peripheral->end_group_handle); characteristic_end_found(peripheral, peripheral->end_group_handle);
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
break; break;
default: default:
gatt_client_report_error_if_pending(peripheral, packet[4]); gatt_client_report_error_if_pending(peripheral, packet[4]);
@ -1016,9 +1071,8 @@ static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
gatt_client_t * peripheral = (gatt_client_t *) linked_list_iterator_next(&it); gatt_client_t * peripheral = (gatt_client_t *) linked_list_iterator_next(&it);
if (peripheral->gatt_client_state == P_W4_CMAC){ if (peripheral->gatt_client_state == P_W4_CMAC){
peripheral->gatt_client_state = P_READY; gatt_client_handle_transaction_complete(peripheral);
memcpy(peripheral->cmac, hash, 8); memcpy(peripheral->cmac, hash, 8);
att_signed_write_request(ATT_SIGNED_WRITE_COMMAND, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, peripheral->sign_counter, peripheral->cmac); att_signed_write_request(ATT_SIGNED_WRITE_COMMAND, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, peripheral->sign_counter, peripheral->cmac);
return; return;
} }
@ -1026,8 +1080,9 @@ static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
} }
le_command_status_t gatt_client_signed_write_without_response(gatt_client_t * peripheral, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sign_counter){ le_command_status_t gatt_client_signed_write_without_response(uint16_t con_handle, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sign_counter){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
if (!sm_cmac_ready()) { if (!sm_cmac_ready()) {
log_info("ATT Signed Write, sm_cmac engine not ready. Abort"); log_info("ATT Signed Write, sm_cmac engine not ready. Abort");
return BLE_PERIPHERAL_IN_WRONG_STATE; return BLE_PERIPHERAL_IN_WRONG_STATE;
@ -1045,8 +1100,11 @@ le_command_status_t gatt_client_signed_write_without_response(gatt_client_t * pe
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_discover_primary_services(gatt_client_t *peripheral){ le_command_status_t gatt_client_discover_primary_services(uint16_t handle){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = 0x0001; peripheral->start_group_handle = 0x0001;
peripheral->end_group_handle = 0xffff; peripheral->end_group_handle = 0xffff;
peripheral->gatt_client_state = P_W2_SEND_SERVICE_QUERY; peripheral->gatt_client_state = P_W2_SEND_SERVICE_QUERY;
@ -1056,8 +1114,12 @@ le_command_status_t gatt_client_discover_primary_services(gatt_client_t *periphe
} }
le_command_status_t gatt_client_discover_primary_services_by_uuid16(gatt_client_t *peripheral, uint16_t uuid16){ le_command_status_t gatt_client_discover_primary_services_by_uuid16(uint16_t con_handle, uint16_t uuid16){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = 0x0001; peripheral->start_group_handle = 0x0001;
peripheral->end_group_handle = 0xffff; peripheral->end_group_handle = 0xffff;
peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY; peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
@ -1067,21 +1129,27 @@ le_command_status_t gatt_client_discover_primary_services_by_uuid16(gatt_client_
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_discover_primary_services_by_uuid128(gatt_client_t *peripheral, const uint8_t * uuid128){ le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t con_handle, const uint8_t * uuid128){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = 0x0001; peripheral->start_group_handle = 0x0001;
peripheral->end_group_handle = 0xffff; peripheral->end_group_handle = 0xffff;
peripheral->uuid16 = 0; peripheral->uuid16 = 0;
memcpy(peripheral->uuid128, uuid128, 16); memcpy(peripheral->uuid128, uuid128, 16);
peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY; peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
gatt_client_run(); gatt_client_run();
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_discover_characteristics_for_service(gatt_client_t *peripheral, le_service_t *service){ le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t con_handle, le_service_t *service){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = service->start_group_handle; peripheral->start_group_handle = service->start_group_handle;
peripheral->end_group_handle = service->end_group_handle; peripheral->end_group_handle = service->end_group_handle;
peripheral->filter_with_uuid = 0; peripheral->filter_with_uuid = 0;
@ -1091,8 +1159,12 @@ le_command_status_t gatt_client_discover_characteristics_for_service(gatt_client
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_find_included_services_for_service(gatt_client_t *peripheral, le_service_t *service){ le_command_status_t gatt_client_find_included_services_for_service(uint16_t con_handle, le_service_t *service){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = service->start_group_handle; peripheral->start_group_handle = service->start_group_handle;
peripheral->end_group_handle = service->end_group_handle; peripheral->end_group_handle = service->end_group_handle;
peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_QUERY; peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_QUERY;
@ -1101,8 +1173,12 @@ le_command_status_t gatt_client_find_included_services_for_service(gatt_client_t
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(gatt_client_t *peripheral, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = start_handle; peripheral->start_group_handle = start_handle;
peripheral->end_group_handle = end_handle; peripheral->end_group_handle = end_handle;
peripheral->filter_with_uuid = 1; peripheral->filter_with_uuid = 1;
@ -1115,8 +1191,12 @@ le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uui
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(gatt_client_t *peripheral, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid128){ le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid128){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->start_group_handle = start_handle; peripheral->start_group_handle = start_handle;
peripheral->end_group_handle = end_handle; peripheral->end_group_handle = end_handle;
peripheral->filter_with_uuid = 1; peripheral->filter_with_uuid = 1;
@ -1130,18 +1210,22 @@ le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uui
} }
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid16 (gatt_client_t *peripheral, le_service_t *service, uint16_t uuid16){ le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid16(uint16_t handle, le_service_t *service, uint16_t uuid16){
return gatt_client_discover_characteristics_for_handle_range_by_uuid16(peripheral, service->start_group_handle, service->end_group_handle, uuid16); return gatt_client_discover_characteristics_for_handle_range_by_uuid16(handle, service->start_group_handle, service->end_group_handle, uuid16);
} }
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(gatt_client_t *peripheral, le_service_t *service, uint8_t * uuid128){ le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t handle, le_service_t *service, uint8_t * uuid128){
return gatt_client_discover_characteristics_for_handle_range_by_uuid128(peripheral, service->start_group_handle, service->end_group_handle, uuid128); return gatt_client_discover_characteristics_for_handle_range_by_uuid128(handle, service->start_group_handle, service->end_group_handle, uuid128);
} }
le_command_status_t gatt_client_discover_characteristic_descriptors(gatt_client_t *peripheral, le_characteristic_t *characteristic){ le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con_handle, le_characteristic_t *characteristic){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
if (characteristic->value_handle == characteristic->end_handle){ if (characteristic->value_handle == characteristic->end_handle){
send_gatt_complete_event(peripheral, 0); emit_gatt_complete_event(peripheral, 0);
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
peripheral->start_group_handle = characteristic->value_handle + 1; peripheral->start_group_handle = characteristic->value_handle + 1;
@ -1152,8 +1236,12 @@ le_command_status_t gatt_client_discover_characteristic_descriptors(gatt_client_
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(gatt_client_t *peripheral, uint16_t value_handle){ le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t con_handle, uint16_t value_handle){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = value_handle; peripheral->attribute_handle = value_handle;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
peripheral->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY; peripheral->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY;
@ -1161,13 +1249,17 @@ le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_read_value_of_characteristic(gatt_client_t *peripheral, le_characteristic_t *characteristic){ le_command_status_t gatt_client_read_value_of_characteristic(uint16_t handle, le_characteristic_t *characteristic){
return gatt_client_read_value_of_characteristic_using_value_handle(peripheral, characteristic->value_handle); return gatt_client_read_value_of_characteristic_using_value_handle(handle, characteristic->value_handle);
} }
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(gatt_client_t *peripheral, uint16_t value_handle){ le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t con_handle, uint16_t value_handle){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = value_handle; peripheral->attribute_handle = value_handle;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY; peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY;
@ -1175,23 +1267,28 @@ le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_ha
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_read_long_value_of_characteristic(gatt_client_t *peripheral, le_characteristic_t *characteristic){ le_command_status_t gatt_client_read_long_value_of_characteristic(uint16_t handle, le_characteristic_t *characteristic){
return gatt_client_read_long_value_of_characteristic_using_value_handle(peripheral, characteristic->value_handle); return gatt_client_read_long_value_of_characteristic_using_value_handle(handle, characteristic->value_handle);
} }
le_command_status_t gatt_client_write_value_of_characteristic_without_response(gatt_client_t *peripheral, uint16_t value_handle, uint16_t value_length, uint8_t * value){ le_command_status_t gatt_client_write_value_of_characteristic_without_response(uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
if (value_length >= peripheral->mtu - 3) return BLE_VALUE_TOO_LONG; if (value_length >= peripheral->mtu - 3) return BLE_VALUE_TOO_LONG;
att_write_request(ATT_WRITE_COMMAND, peripheral->handle, value_handle, value_length, value); att_write_request(ATT_WRITE_COMMAND, peripheral->handle, value_handle, value_length, value);
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_write_value_of_characteristic(gatt_client_t *peripheral, uint16_t value_handle, uint16_t value_length, uint8_t * value){ le_command_status_t gatt_client_write_value_of_characteristic(uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
if (!gatt_client_is_ready(peripheral)) { gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
hci_dump_log("gatt client not ready");
return BLE_PERIPHERAL_IN_WRONG_STATE; if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
} if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = value_handle; peripheral->attribute_handle = value_handle;
peripheral->attribute_length = value_length; peripheral->attribute_length = value_length;
peripheral->attribute_value = value; peripheral->attribute_value = value;
@ -1200,8 +1297,12 @@ le_command_status_t gatt_client_write_value_of_characteristic(gatt_client_t *per
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_write_long_value_of_characteristic(gatt_client_t *peripheral, uint16_t value_handle, uint16_t value_length, uint8_t * value){ le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = value_handle; peripheral->attribute_handle = value_handle;
peripheral->attribute_length = value_length; peripheral->attribute_length = value_length;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
@ -1211,8 +1312,12 @@ le_command_status_t gatt_client_write_long_value_of_characteristic(gatt_client_t
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(gatt_client_t *peripheral, uint16_t value_handle, uint16_t value_length, uint8_t * value){ le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = value_handle; peripheral->attribute_handle = value_handle;
peripheral->attribute_length = value_length; peripheral->attribute_length = value_length;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
@ -1222,8 +1327,12 @@ le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(gatt
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_write_client_characteristic_configuration(gatt_client_t *peripheral, le_characteristic_t * characteristic, uint16_t configuration){ le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) && if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) &&
(characteristic->properties & ATT_PROPERTY_NOTIFY) == 0) { (characteristic->properties & ATT_PROPERTY_NOTIFY) == 0) {
log_info("le_central_write_client_characteristic_configuration: BLE_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED"); log_info("le_central_write_client_characteristic_configuration: BLE_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED");
@ -1243,10 +1352,13 @@ le_command_status_t gatt_client_write_client_characteristic_configuration(gatt_c
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_read_characteristic_descriptor(gatt_client_t *peripheral, le_characteristic_descriptor_t * descriptor){ le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
peripheral->attribute_handle = descriptor->handle;
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = descriptor->handle;
peripheral->uuid16 = descriptor->uuid16; peripheral->uuid16 = descriptor->uuid16;
if (!descriptor->uuid16){ if (!descriptor->uuid16){
memcpy(peripheral->uuid128, descriptor->uuid128, 16); memcpy(peripheral->uuid128, descriptor->uuid128, 16);
@ -1257,8 +1369,12 @@ le_command_status_t gatt_client_read_characteristic_descriptor(gatt_client_t *pe
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_read_long_characteristic_descriptor(gatt_client_t *peripheral, le_characteristic_descriptor_t * descriptor){ le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = descriptor->handle; peripheral->attribute_handle = descriptor->handle;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY; peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY;
@ -1266,39 +1382,34 @@ le_command_status_t gatt_client_read_long_characteristic_descriptor(gatt_client_
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_write_characteristic_descriptor(gatt_client_t *peripheral, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){ le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = descriptor->handle; peripheral->attribute_handle = descriptor->handle;
peripheral->attribute_length = length; peripheral->attribute_length = length;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
peripheral->attribute_value = value; peripheral->attribute_value = value;
peripheral->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR; peripheral->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR;
gatt_client_run(); gatt_client_run();
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
le_command_status_t gatt_client_write_long_characteristic_descriptor(gatt_client_t *peripheral, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){ le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
if (!gatt_client_is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE; gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->attribute_handle = descriptor->handle; peripheral->attribute_handle = descriptor->handle;
peripheral->attribute_length = length; peripheral->attribute_length = length;
peripheral->attribute_offset = 0; peripheral->attribute_offset = 0;
peripheral->attribute_value = value; peripheral->attribute_value = value;
peripheral->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR; peripheral->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR;
gatt_client_run(); gatt_client_run();
return BLE_PERIPHERAL_OK; return BLE_PERIPHERAL_OK;
} }
// used by daemon
void gatt_client_disconnect_connection(void * connection){
if (!connection) return;
linked_item_t *it;
for (it = (linked_item_t *) gatt_client_connections; it ; it = it->next){
gatt_client_t * client = (gatt_client_t *) it;
if (client->context == connection){
gap_disconnect(client->handle);
}
}
}

View File

@ -150,16 +150,18 @@ typedef struct gatt_client{
sm_key_t csrk; sm_key_t csrk;
uint32_t sign_counter; uint32_t sign_counter;
uint8_t cmac[8]; uint8_t cmac[8];
timer_source_t gc_timeout;
} gatt_client_t; } gatt_client_t;
typedef struct le_event { typedef struct le_event {
uint8_t type; uint8_t type;
gatt_client_t * client; uint16_t handle;
} le_event_t; } le_event_t;
typedef struct gatt_complete_event{ typedef struct gatt_complete_event{
uint8_t type; uint8_t type;
gatt_client_t * client; uint16_t handle;
uint16_t attribute_handle;
uint8_t status; uint8_t status;
} gatt_complete_event_t; } gatt_complete_event_t;
@ -172,7 +174,7 @@ typedef struct le_service{
typedef struct le_service_event{ typedef struct le_service_event{
uint8_t type; uint8_t type;
gatt_client_t * client; uint16_t handle;
le_service_t service; le_service_t service;
} le_service_event_t; } le_service_event_t;
@ -187,13 +189,13 @@ typedef struct le_characteristic{
typedef struct le_characteristic_event{ typedef struct le_characteristic_event{
uint8_t type; uint8_t type;
gatt_client_t * client; uint16_t handle;
le_characteristic_t characteristic; le_characteristic_t characteristic;
} le_characteristic_event_t; } le_characteristic_event_t;
typedef struct le_characteristic_value_event{ typedef struct le_characteristic_value_event{
uint8_t type; uint8_t type;
gatt_client_t * client; uint16_t handle;
uint16_t value_handle; uint16_t value_handle;
uint16_t value_offset; uint16_t value_offset;
uint16_t blob_length; uint16_t blob_length;
@ -209,7 +211,7 @@ typedef struct le_characteristic_descriptor{
typedef struct le_characteristic_descriptor_event{ typedef struct le_characteristic_descriptor_event{
uint8_t type; uint8_t type;
gatt_client_t * client; uint16_t handle;
le_characteristic_descriptor_t characteristic_descriptor; le_characteristic_descriptor_t characteristic_descriptor;
uint16_t value_length; uint16_t value_length;
uint16_t value_offset; uint16_t value_offset;
@ -217,37 +219,24 @@ typedef struct le_characteristic_descriptor_event{
} le_characteristic_descriptor_event_t; } le_characteristic_descriptor_event_t;
//TODO: define uuid type //TODO: define uuid type
// used by daemon
void gatt_client_disconnect_connection(void * connection);
// Set up GATT client. // Set up GATT client.
void gatt_client_init(); void gatt_client_init();
// Register packet handler. // Register packet handler.
void gatt_client_register_packet_handler(void (*le_callback)(le_event_t * event)); void gatt_client_register_packet_handler(void (*le_callback)(le_event_t * event));
// To query a remote GATT Server, the application needs to provide a
// gatt client context structure and an active connection handle.
// This function initializes the provided gatt client context and
// adds it to the list of active clients.
void gatt_client_start(gatt_client_t *context, uint16_t handle);
// Removes the gatt client context from the list of the list of
// active clients.
void gatt_client_stop(gatt_client_t *context);
// Returns the GATT client context for the specified handle. // Returns the GATT client context for the specified handle.
gatt_client_t * get_gatt_client_context_for_handle(uint16_t handle); // gatt_client_t * get_gatt_client_context_for_handle(uint16_t con_handle);
// Returns if the gatt client is ready to receive a query. It is used with daemon. // Returns if the gatt client is ready to receive a query. It is used with daemon.
int gatt_client_is_ready(gatt_client_t *context); int gatt_client_is_ready(uint16_t handle);
// Discovers all primary services. For each found service, an // Discovers all primary services. For each found service, an
// le_service_event_t with type set to GATT_SERVICE_QUERY_RESULT // le_service_event_t with type set to GATT_SERVICE_QUERY_RESULT
// will be generated and passed to the registered callback. // will be generated and passed to the registered callback.
// The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE, // The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE,
// marks the end of discovery. // marks the end of discovery.
le_command_status_t gatt_client_discover_primary_services(gatt_client_t *context); le_command_status_t gatt_client_discover_primary_services(uint16_t con_handle);
// Discovers a specific primary service given its UUID. This service // Discovers a specific primary service given its UUID. This service
// may exist multiple times. For each found service, an // may exist multiple times. For each found service, an
@ -255,8 +244,8 @@ le_command_status_t gatt_client_discover_primary_services(gatt_client_t *context
// will be generated and passed to the registered callback. // will be generated and passed to the registered callback.
// The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE, // The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE,
// marks the end of discovery. // marks the end of discovery.
le_command_status_t gatt_client_discover_primary_services_by_uuid16(gatt_client_t *context, uint16_t uuid16); le_command_status_t gatt_client_discover_primary_services_by_uuid16(uint16_t con_handle, uint16_t uuid16);
le_command_status_t gatt_client_discover_primary_services_by_uuid128(gatt_client_t *context, const uint8_t * uuid); le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t con_handle, const uint8_t * uuid);
// Finds included services within the specified service. For each // Finds included services within the specified service. For each
// found included service, an le_service_event_t with type set to // found included service, an le_service_event_t with type set to
@ -269,14 +258,14 @@ le_command_status_t gatt_client_discover_primary_services_by_uuid128(gatt_client
// for the returned start group handle (returning the handle and // for the returned start group handle (returning the handle and
// the UUID for primary or secondary service) or by comparing the // the UUID for primary or secondary service) or by comparing the
// service to the list of all primary services. // service to the list of all primary services.
le_command_status_t gatt_client_find_included_services_for_service(gatt_client_t *context, le_service_t *service); le_command_status_t gatt_client_find_included_services_for_service(uint16_t con_handle, le_service_t *service);
// Discovers all characteristics within the specified service. For // Discovers all characteristics within the specified service. For
// each found characteristic, an le_characteristics_event_t with // each found characteristic, an le_characteristics_event_t with
// type set to GATT_CHARACTERISTIC_QUERY_RESULT will be generated // type set to GATT_CHARACTERISTIC_QUERY_RESULT will be generated
// and passed to the registered callback. The gatt_complete_event_t // and passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of discovery. // with type set to GATT_QUERY_COMPLETE, marks the end of discovery.
le_command_status_t gatt_client_discover_characteristics_for_service(gatt_client_t *context, le_service_t *service); le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t con_handle, le_service_t *service);
// The following four functions are used to discover all // The following four functions are used to discover all
// characteristics within the specified service or handle range, and // characteristics within the specified service or handle range, and
@ -285,10 +274,10 @@ le_command_status_t gatt_client_discover_characteristics_for_service(gatt_client
// GATT_CHARACTERISTIC_QUERY_RESULT will be generated and passed to // GATT_CHARACTERISTIC_QUERY_RESULT will be generated and passed to
// the registered callback. The gatt_complete_event_t with type set // the registered callback. The gatt_complete_event_t with type set
// to GATT_QUERY_COMPLETE, marks the end of discovery. // to GATT_QUERY_COMPLETE, marks the end of discovery.
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(gatt_client_t *context, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16); le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(gatt_client_t *context, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid); le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid16 (gatt_client_t *context, le_service_t *service, uint16_t uuid16); le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid16 (uint16_t con_handle, le_service_t *service, uint16_t uuid16);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(gatt_client_t *context, le_service_t *service, uint8_t * uuid128); le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t con_handle, le_service_t *service, uint8_t * uuid128);
// Discovers attribute handle and UUID of a characteristic // Discovers attribute handle and UUID of a characteristic
// descriptor within the specified characteristic. For each found // descriptor within the specified characteristic. For each found
@ -297,7 +286,7 @@ le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(
// generated and passed to the registered callback. The // generated and passed to the registered callback. The
// gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks // gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks
// the end of discovery. // the end of discovery.
le_command_status_t gatt_client_discover_characteristic_descriptors(gatt_client_t *context, le_characteristic_t *characteristic); le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con_handle, le_characteristic_t *characteristic);
// Reads the characteristic value using the characteristic's value // Reads the characteristic value using the characteristic's value
// handle. If the characteristic value is found, an // handle. If the characteristic value is found, an
@ -305,8 +294,8 @@ le_command_status_t gatt_client_discover_characteristic_descriptors(gatt_client_
// GATT_CHARACTERISTIC_VALUE_QUERY_RESULT will be generated and // GATT_CHARACTERISTIC_VALUE_QUERY_RESULT will be generated and
// passed to the registered callback. The gatt_complete_event_t // passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of read. // with type set to GATT_QUERY_COMPLETE, marks the end of read.
le_command_status_t gatt_client_read_value_of_characteristic(gatt_client_t *context, le_characteristic_t *characteristic); le_command_status_t gatt_client_read_value_of_characteristic(uint16_t con_handle, le_characteristic_t *characteristic);
le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(gatt_client_t *context, uint16_t characteristic_value_handle); le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t con_handle, uint16_t characteristic_value_handle);
// Reads the long characteristic value using the characteristic's // Reads the long characteristic value using the characteristic's
// value handle. The value will be returned in several blobs. For // value handle. The value will be returned in several blobs. For
@ -315,25 +304,25 @@ le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(
// will be generated and passed to the registered callback. The // will be generated and passed to the registered callback. The
// gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks // gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks
// the end of read. // the end of read.
le_command_status_t gatt_client_read_long_value_of_characteristic(gatt_client_t *context, le_characteristic_t *characteristic); le_command_status_t gatt_client_read_long_value_of_characteristic(uint16_t con_handle, le_characteristic_t *characteristic);
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(gatt_client_t *context, uint16_t characteristic_value_handle); le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t con_handle, uint16_t characteristic_value_handle);
// Writes the characteristic value using the characteristic's value // Writes the characteristic value using the characteristic's value
// handle without an acknowledgement that the write was successfully // handle without an acknowledgement that the write was successfully
// performed. // performed.
le_command_status_t gatt_client_write_value_of_characteristic_without_response(gatt_client_t *context, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data); le_command_status_t gatt_client_write_value_of_characteristic_without_response(uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
// Writes the authenticated characteristic value using the // Writes the authenticated characteristic value using the
// characteristic's value handle without an acknowledgement // characteristic's value handle without an acknowledgement
// that the write was successfully performed. // that the write was successfully performed.
le_command_status_t gatt_client_signed_write_without_response(gatt_client_t * context, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sgn_counter); le_command_status_t gatt_client_signed_write_without_response(uint16_t con_handle, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sgn_counter);
// Writes the characteristic value using the characteristic's value // Writes the characteristic value using the characteristic's value
// handle. The gatt_complete_event_t with type set to // handle. The gatt_complete_event_t with type set to
// GATT_QUERY_COMPLETE, marks the end of write. The write is // GATT_QUERY_COMPLETE, marks the end of write. The write is
// successfully performed, if the event's status field is set to 0. // successfully performed, if the event's status field is set to 0.
le_command_status_t gatt_client_write_value_of_characteristic(gatt_client_t *context, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data); le_command_status_t gatt_client_write_value_of_characteristic(uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
le_command_status_t gatt_client_write_long_value_of_characteristic(gatt_client_t *context, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data); le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
// Writes of the long characteristic value using the // Writes of the long characteristic value using the
// characteristic's value handle. It uses server response to // characteristic's value handle. It uses server response to
@ -341,7 +330,7 @@ le_command_status_t gatt_client_write_long_value_of_characteristic(gatt_client_t
// The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE // The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE
// marks the end of write. The write is successfully performed, if // marks the end of write. The write is successfully performed, if
// the event's status field is set to 0. // the event's status field is set to 0.
le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(gatt_client_t *context, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data); le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
// Reads the characteristic descriptor using its handle. If the // Reads the characteristic descriptor using its handle. If the
// characteristic descriptor is found, an // characteristic descriptor is found, an
@ -349,7 +338,7 @@ le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(gatt
// GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated // GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated
// and passed to the registered callback. The gatt_complete_event_t // and passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of read. // with type set to GATT_QUERY_COMPLETE, marks the end of read.
le_command_status_t gatt_client_read_characteristic_descriptor(gatt_client_t *context, le_characteristic_descriptor_t * descriptor); le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor);
// Reads the long characteristic descriptor using its handle. It // Reads the long characteristic descriptor using its handle. It
// will be returned in several blobs. For each blob, an // will be returned in several blobs. For each blob, an
@ -357,14 +346,14 @@ le_command_status_t gatt_client_read_characteristic_descriptor(gatt_client_t *co
// GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated // GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated
// and passed to the registered callback. The gatt_complete_event_t // and passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of read. // with type set to GATT_QUERY_COMPLETE, marks the end of read.
le_command_status_t gatt_client_read_long_characteristic_descriptor(gatt_client_t *context, le_characteristic_descriptor_t * descriptor); le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor);
// Writes the characteristic descriptor using its handle. // Writes the characteristic descriptor using its handle.
// The gatt_complete_event_t with type set to // The gatt_complete_event_t with type set to
// GATT_QUERY_COMPLETE, marks the end of write. The write is // GATT_QUERY_COMPLETE, marks the end of write. The write is
// successfully performed, if the event's status field is set to 0. // successfully performed, if the event's status field is set to 0.
le_command_status_t gatt_client_write_characteristic_descriptor(gatt_client_t *context, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * data); le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * data);
le_command_status_t gatt_client_write_long_characteristic_descriptor(gatt_client_t *context, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * data); le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * data);
// Writes the client characteristic configuration of the specified // Writes the client characteristic configuration of the specified
// characteristic. It is used to subscribe for notifications or // characteristic. It is used to subscribe for notifications or
@ -373,7 +362,7 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor(gatt_client
// GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION resp. // GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION resp.
// GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION // GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION
// as configuration value. // as configuration value.
le_command_status_t gatt_client_write_client_characteristic_configuration(gatt_client_t *context, le_characteristic_t * characteristic, uint16_t configuration); le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration);
#if defined __cplusplus #if defined __cplusplus
} }

View File

@ -90,8 +90,7 @@ static const uint8_t ancs_control_point_uuid[] = {0x69,0xD1,0xD8,0xF3,0x45
static const uint8_t ancs_data_source_uuid[] = {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB}; static const uint8_t ancs_data_source_uuid[] = {0x22,0xEA,0xC6,0xE9,0x24,0xD6,0x4B,0xB5,0xBE,0x44,0xB3,0x6A,0xCE,0x7C,0x7B,0xFB};
static uint32_t ancs_notification_uid; static uint32_t ancs_notification_uid;
static uint16_t handle; static uint16_t gc_handle;
static gatt_client_t ancs_client_context;
static int ancs_service_found; static int ancs_service_found;
static le_service_t ancs_service; static le_service_t ancs_service;
static le_characteristic_t ancs_notification_source_characteristic; static le_characteristic_t ancs_notification_source_characteristic;
@ -182,7 +181,7 @@ static void handle_gatt_client_event(le_event_t * event){
} }
tc_state = TC_W4_CHARACTERISTIC_RESULT; tc_state = TC_W4_CHARACTERISTIC_RESULT;
printf("ANCS Client - Discover characteristics for ANCS SERVICE \n"); printf("ANCS Client - Discover characteristics for ANCS SERVICE \n");
gatt_client_discover_characteristics_for_service(&ancs_client_context, &ancs_service); gatt_client_discover_characteristics_for_service(gc_handle, &ancs_service);
break; break;
default: default:
break; break;
@ -215,7 +214,7 @@ static void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE: case GATT_QUERY_COMPLETE:
printf("ANCS Characteristcs count %u\n", ancs_characteristcs); printf("ANCS Characteristcs count %u\n", ancs_characteristcs);
tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED; tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED;
gatt_client_write_client_characteristic_configuration(&ancs_client_context, &ancs_notification_source_characteristic, gatt_client_write_client_characteristic_configuration(gc_handle, &ancs_notification_source_characteristic,
GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break; break;
default: default:
@ -227,7 +226,7 @@ static void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE: case GATT_QUERY_COMPLETE:
printf("ANCS Notification Source subscribed\n"); printf("ANCS Notification Source subscribed\n");
tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED; tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED;
gatt_client_write_client_characteristic_configuration(&ancs_client_context, &ancs_data_source_characteristic, gatt_client_write_client_characteristic_configuration(gc_handle, &ancs_data_source_characteristic,
GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break; break;
default: default:
@ -261,7 +260,7 @@ static void handle_gatt_client_event(le_event_t * event){
bt_store_32(get_notification_attributes, 1, ancs_notification_uid); bt_store_32(get_notification_attributes, 1, ancs_notification_uid);
ancs_notification_uid = 0; ancs_notification_uid = 0;
ancs_chunk_parser_init(); ancs_chunk_parser_init();
gatt_client_write_value_of_characteristic(&ancs_client_context, ancs_control_point_characteristic.value_handle, gatt_client_write_value_of_characteristic(gc_handle, ancs_control_point_characteristic.value_handle,
sizeof(get_notification_attributes), get_notification_attributes); sizeof(get_notification_attributes), get_notification_attributes);
} else { } else {
printf("Unknown Source: "); printf("Unknown Source: ");
@ -284,8 +283,8 @@ void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8
case HCI_EVENT_LE_META: case HCI_EVENT_LE_META:
switch (packet[2]) { switch (packet[2]) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
handle = READ_BT_16(packet, 4); gc_handle = READ_BT_16(packet, 4);
printf("Connection handle 0x%04x\n", handle); printf("Connection ghandle 0x%04x\n", gc_handle);
// we need to be paired to enable notifications // we need to be paired to enable notifications
tc_state = TC_W4_ENCRYPTED_CONNECTION; tc_state = TC_W4_ENCRYPTED_CONNECTION;
@ -298,7 +297,7 @@ void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8
break; break;
case HCI_EVENT_ENCRYPTION_CHANGE: case HCI_EVENT_ENCRYPTION_CHANGE:
if (handle != READ_BT_16(packet, 3)) break; if (gc_handle != READ_BT_16(packet, 3)) break;
connection_encrypted = packet[5]; connection_encrypted = packet[5];
log_info("Encryption state change: %u", connection_encrypted); log_info("Encryption state change: %u", connection_encrypted);
if (!connection_encrypted) break; if (!connection_encrypted) break;
@ -307,8 +306,7 @@ void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8
// let's start // let's start
printf("\nANCS Client - CONNECTED, discover ANCS service\n"); printf("\nANCS Client - CONNECTED, discover ANCS service\n");
tc_state = TC_W4_SERVICE_RESULT; tc_state = TC_W4_SERVICE_RESULT;
gatt_client_start(&ancs_client_context, handle); gatt_client_discover_primary_services_by_uuid128(gc_handle, ancs_service_uuid);
gatt_client_discover_primary_services_by_uuid128(&ancs_client_context, ancs_service_uuid);
break; break;
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
@ -322,5 +320,5 @@ void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8
} }
void ancs_client_init(){ void ancs_client_init(){
gatt_client_register_packet_handler(&handle_gatt_client_event); gatt_client_register_packet_handler(&gc_handle_gatt_client_event);
} }

View File

@ -85,8 +85,8 @@ typedef enum {
static bd_addr_t cmdline_addr = { }; static bd_addr_t cmdline_addr = { };
static int cmdline_addr_found = 0; static int cmdline_addr_found = 0;
static gatt_client_t gc_context;
uint16_t gc_handle;
static uint16_t battery_service_uuid = 0x180F; static uint16_t battery_service_uuid = 0x180F;
static uint16_t battery_level_characteristic_uuid = 0x2a19; static uint16_t battery_level_characteristic_uuid = 0x2a19;
static le_service_t battery_service; static le_service_t battery_service;
@ -150,7 +150,7 @@ void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE: case GATT_QUERY_COMPLETE:
state = TC_W4_CHARACTERISTIC_RESULT; state = TC_W4_CHARACTERISTIC_RESULT;
printf("\nSearch for battery level characteristic in battery service. "); printf("\nSearch for battery level characteristic in battery service. ");
gatt_client_discover_characteristics_for_service_by_uuid16(&gc_context, &battery_service, battery_level_characteristic_uuid); gatt_client_discover_characteristics_for_service_by_uuid16(gc_handle, &battery_service, battery_level_characteristic_uuid);
break; break;
default: default:
break; break;
@ -167,7 +167,7 @@ void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE: case GATT_QUERY_COMPLETE:
state = TC_W4_BATTERY_DATA; state = TC_W4_BATTERY_DATA;
printf("\nConfigure battery level characteristic for notify."); printf("\nConfigure battery level characteristic for notify.");
gatt_client_write_client_characteristic_configuration(&gc_context, &config_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); gatt_client_write_client_characteristic_configuration(gc_handle, &config_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break; break;
default: default:
break; break;
@ -213,8 +213,6 @@ static void fill_advertising_report_from_packet(advertising_report_t * report, u
static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
if (packet_type != HCI_EVENT_PACKET) return; if (packet_type != HCI_EVENT_PACKET) return;
advertising_report_t report; advertising_report_t report;
uint16_t gc_handle;
uint8_t event = packet[0]; uint8_t event = packet[0];
switch (event) { switch (event) {
case BTSTACK_EVENT_STATE: case BTSTACK_EVENT_STATE:
@ -237,6 +235,7 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
// stop scanning, and connect to the device // stop scanning, and connect to the device
state = TC_W4_CONNECT; state = TC_W4_CONNECT;
le_central_stop_scan(); le_central_stop_scan();
printf("Stop scan. Start connect to device with addr %s.\n", bd_addr_to_str(report.address));
le_central_connect(&report.address,report.address_type); le_central_connect(&report.address,report.address_type);
break; break;
case HCI_EVENT_LE_META: case HCI_EVENT_LE_META:
@ -245,15 +244,13 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
if (state != TC_W4_CONNECT) return; if (state != TC_W4_CONNECT) return;
gc_handle = READ_BT_16(packet, 4); gc_handle = READ_BT_16(packet, 4);
// initialize gatt client context with handle, and add it to the list of active clients // initialize gatt client context with handle, and add it to the list of active clients
gatt_client_start(&gc_context, gc_handle);
// query primary services // query primary services
printf("\nSearch for battery service. "); printf("\nSearch for battery service. ");
state = TC_W4_SERVICE_RESULT; state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services_by_uuid16(&gc_context, battery_service_uuid); gatt_client_discover_primary_services_by_uuid16(gc_handle, battery_service_uuid);
break; break;
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("\nDISCONNECTED\n"); printf("\nDISCONNECTED\n");
gatt_client_stop(&gc_context);
exit(0); exit(0);
break; break;
default: default:
@ -268,7 +265,7 @@ void setup(void){
run_loop_init(RUN_LOOP_POSIX); run_loop_init(RUN_LOOP_POSIX);
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
hci_dump_open("/tmp/gatt_browser.pklg", HCI_DUMP_PACKETLOGGER); hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
// init HCI // init HCI
remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory; remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;

View File

@ -86,8 +86,8 @@ typedef enum {
static bd_addr_t cmdline_addr = { }; static bd_addr_t cmdline_addr = { };
static int cmdline_addr_found = 0; static int cmdline_addr_found = 0;
static gatt_client_t gc_context;
uint16_t gc_handle;
static le_service_t services[40]; static le_service_t services[40];
static int service_count = 0; static int service_count = 0;
static int service_index = 0; static int service_index = 0;
@ -138,7 +138,7 @@ void handle_gatt_client_event(le_event_t * event){
printf("\ntest client - CHARACTERISTIC for SERVICE "); printf("\ntest client - CHARACTERISTIC for SERVICE ");
printUUID128(service.uuid128); printf("\n"); printUUID128(service.uuid128); printf("\n");
gatt_client_discover_characteristics_for_service(&gc_context, &services[service_index]); gatt_client_discover_characteristics_for_service(gc_handle, &services[service_index]);
break; break;
default: default:
break; break;
@ -159,12 +159,12 @@ void handle_gatt_client_event(le_event_t * event){
printUUID128(service.uuid128); printUUID128(service.uuid128);
printf(", [0x%04x-0x%04x]\n", service.start_group_handle, service.end_group_handle); printf(", [0x%04x-0x%04x]\n", service.start_group_handle, service.end_group_handle);
gatt_client_discover_characteristics_for_service(&gc_context, &service); gatt_client_discover_characteristics_for_service(gc_handle, &service);
break; break;
} }
state = TC_W4_DISCONNECT; state = TC_W4_DISCONNECT;
service_index = 0; service_index = 0;
gap_disconnect(gc_context.handle); gap_disconnect(gc_handle);
break; break;
default: default:
break; break;
@ -196,8 +196,7 @@ static void fill_advertising_report_from_packet(advertising_report_t * report, u
static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
if (packet_type != HCI_EVENT_PACKET) return; if (packet_type != HCI_EVENT_PACKET) return;
advertising_report_t report; advertising_report_t report;
uint16_t gc_handle;
uint8_t event = packet[0]; uint8_t event = packet[0];
switch (event) { switch (event) {
case BTSTACK_EVENT_STATE: case BTSTACK_EVENT_STATE:
@ -227,15 +226,12 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
if (packet[2] != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; if (packet[2] != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break;
if (state != TC_W4_CONNECT) return; if (state != TC_W4_CONNECT) return;
gc_handle = READ_BT_16(packet, 4); gc_handle = READ_BT_16(packet, 4);
// initialize gatt client context with handle, and add it to the list of active clients
gatt_client_start(&gc_context, gc_handle);
// query primary services // query primary services
state = TC_W4_SERVICE_RESULT; state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services(&gc_context); gatt_client_discover_primary_services(gc_handle);
break; break;
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("\ntest client - DISCONNECTED\n"); printf("\ntest client - DISCONNECTED\n");
gatt_client_stop(&gc_context);
exit(0); exit(0);
break; break;
default: default:

View File

@ -124,8 +124,7 @@ typedef struct {
linked_list_t l2cap_cids; linked_list_t l2cap_cids;
linked_list_t l2cap_psms; linked_list_t l2cap_psms;
linked_list_t sdp_record_handles; linked_list_t sdp_record_handles;
linked_list_t gatt_client_handles; linked_list_t gatt_con_handles;
// power mode // power mode
HCI_POWER_MODE power_mode; HCI_POWER_MODE power_mode;
@ -139,9 +138,19 @@ typedef struct linked_list_uint32 {
uint32_t value; uint32_t value;
} linked_list_uint32_t; } linked_list_uint32_t;
typedef struct gatt_client_helper { typedef struct linked_list_connection {
linked_item_t item;
connection_t * connection;
} linked_list_connection_t;
typedef struct linked_list_gatt_client_helper{
linked_item_t item;
uint16_t con_handle;
connection_t * active_connection; // the one that started the current query
linked_list_t all_connections; // list of all connections that ever used this helper
uint16_t characteristic_length; uint16_t characteristic_length;
} gatt_client_helper_t; uint8_t characteristic_buffer[ATT_MAX_LONG_ATTRIBUTE_SIZE];
} linked_list_gatt_client_helper_t;
// MARK: prototypes // MARK: prototypes
static void handle_sdp_rfcomm_service_result(sdp_query_event_t * event, void * context); static void handle_sdp_rfcomm_service_result(sdp_query_event_t * event, void * context);
@ -162,7 +171,9 @@ static hci_uart_config_t config;
static timer_source_t timeout; static timer_source_t timeout;
static uint8_t timeout_active = 0; static uint8_t timeout_active = 0;
static int power_management_sleep = 0; static int power_management_sleep = 0;
static linked_list_t clients = NULL; // list of connected clients static linked_list_t clients = NULL; // list of connected clients `
static linked_list_t gatt_client_helpers = NULL; // list of used gatt client (helpers)
static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth_status_handler; static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth_status_handler;
static int global_enable = 0; static int global_enable = 0;
@ -188,6 +199,7 @@ static void daemon_no_connections_timeout(struct timer *ts){
hci_power_control(HCI_POWER_OFF); hci_power_control(HCI_POWER_OFF);
} }
static void add_uint32_to_list(linked_list_t *list, uint32_t value){ static void add_uint32_to_list(linked_list_t *list, uint32_t value){
linked_list_uint32_t * item = malloc(sizeof(linked_list_uint32_t)); linked_list_uint32_t * item = malloc(sizeof(linked_list_uint32_t));
if (!item) return; if (!item) return;
@ -266,22 +278,169 @@ static void daemon_remove_client_sdp_service_record_handle(connection_t * connec
remove_and_free_uint32_from_list(&client_state->sdp_record_handles, handle); remove_and_free_uint32_from_list(&client_state->sdp_record_handles, handle);
} }
static void daemon_add_gatt_client_handle(connection_t * connection, uint32_t handle){ static void daemon_add_gatt_client_handle(connection_t * connection, uint32_t handle){
client_state_t * client_state = client_for_connection(connection); client_state_t * client_state = client_for_connection(connection);
if (!client_state) return; if (!client_state) return;
add_uint32_to_list(&client_state->gatt_client_handles, handle);
// check if handle already exists in the gatt_con_handles list
linked_list_iterator_t it;
int handle_found = 0;
linked_list_iterator_init(&it, &client_state->gatt_con_handles);
while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
if (item->value == handle){
handle_found = 1;
break;
}
}
// if handle doesn't exist add it to gatt_con_handles
if (!handle_found){
add_uint32_to_list(&client_state->gatt_con_handles, handle);
}
// check if there is a helper with given handle
linked_list_gatt_client_helper_t * gatt_helper = NULL;
linked_list_iterator_init(&it, &gatt_client_helpers);
while (linked_list_iterator_has_next(&it)){
linked_list_gatt_client_helper_t * item = (linked_list_gatt_client_helper_t*) linked_list_iterator_next(&it);
if (item->con_handle == handle){
gatt_helper = item;
break;
}
}
// if gatt_helper doesn't exist, create it and add it to gatt_client_helpers list
if (!gatt_helper){
gatt_helper = malloc(sizeof(linked_list_gatt_client_helper_t));
if (!gatt_helper) return;
memset(gatt_helper, 0, sizeof(linked_list_gatt_client_helper_t));
gatt_helper->con_handle = handle;
linked_list_add(&gatt_client_helpers, (linked_item_t *) gatt_helper);
}
// check if connection exists
int connection_found = 0;
linked_list_iterator_init(&it, &gatt_helper->all_connections);
while (linked_list_iterator_has_next(&it)){
linked_list_connection_t * item = (linked_list_connection_t*) linked_list_iterator_next(&it);
if (item->connection == connection){
connection_found = 1;
break;
}
}
// if connection is not found, add it to the all_connections, and set it as active connection
if (!connection_found){
linked_list_connection_t * con = malloc(sizeof(linked_list_connection_t));
if (!con) return;
memset(con, 0, sizeof(linked_list_connection_t));
con->connection = connection;
linked_list_add(&gatt_helper->all_connections, (linked_item_t *)con);
}
// remember connection responsible for this request
gatt_helper->active_connection = connection;
} }
static void daemon_remove_gatt_client_handle(connection_t * connection, uint32_t handle){ static void daemon_remove_gatt_client_handle(connection_t * connection, uint32_t handle){
// PART 1 - uses connection & handle
// might be extracted or vanish totally
client_state_t * client_state = client_for_connection(connection); client_state_t * client_state = client_for_connection(connection);
if (!client_state) return; if (!client_state) return;
remove_and_free_uint32_from_list(&client_state->gatt_client_handles, handle);
linked_list_iterator_t it;
// remove handle from gatt_con_handles list
linked_list_iterator_init(&it, &client_state->gatt_con_handles);
while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
if (item->value == handle){
linked_list_remove(&client_state->gatt_con_handles, (linked_item_t *) item);
free(item);
}
}
// PART 2 - only uses handle
// find helper with given handle
linked_list_gatt_client_helper_t * helper = NULL;
linked_list_iterator_init(&it, &gatt_client_helpers);
while (linked_list_iterator_has_next(&it)){
linked_list_gatt_client_helper_t * item = (linked_list_gatt_client_helper_t*) linked_list_iterator_next(&it);
if (item->con_handle == handle){
helper = item;
break;
}
}
if (!helper) return;
// remove connection from helper
linked_list_iterator_init(&it, &helper->all_connections);
while (linked_list_iterator_has_next(&it)){
linked_list_connection_t * item = (linked_list_connection_t*) linked_list_iterator_next(&it);
if (item->connection == connection){
linked_list_remove(&helper->all_connections, (linked_item_t *) item);
free(item);
break;
}
}
if (helper->active_connection == connection){
helper->active_connection = NULL;
}
// if helper has no more connections, call disconnect
if (helper->all_connections == NULL){
gap_disconnect((hci_con_handle_t) helper->con_handle);
}
} }
static void daemon_rfcomm_close_connection(linked_list_t *rfcomm_services, linked_list_t *rfcomm_cids){ static void daemon_remove_gatt_client_helper(uint32_t con_handle){
linked_list_iterator_t it; linked_list_iterator_t it, cl;
// find helper with given handle
linked_list_gatt_client_helper_t * helper = NULL;
linked_list_iterator_init(&it, &gatt_client_helpers);
while (linked_list_iterator_has_next(&it)){
linked_list_gatt_client_helper_t * item = (linked_list_gatt_client_helper_t*) linked_list_iterator_next(&it);
if (item->con_handle == con_handle){
helper = item;
break;
}
}
if (!helper) return;
// remove all connection from helper
linked_list_iterator_init(&it, &helper->all_connections);
while (linked_list_iterator_has_next(&it)){
linked_list_connection_t * item = (linked_list_connection_t*) linked_list_iterator_next(&it);
linked_list_remove(&helper->all_connections, (linked_item_t *) item);
free(item);
}
free(helper);
linked_list_iterator_init(&cl, &clients);
while (linked_list_iterator_has_next(&cl)){
client_state_t * client_state = (client_state_t *) linked_list_iterator_next(&cl);
linked_list_iterator_init(&it, &client_state->gatt_con_handles);
while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
if (item->value == con_handle){
linked_list_remove(&client_state->gatt_con_handles, (linked_item_t *) item);
free(item);
}
}
}
}
static void daemon_rfcomm_close_connection(client_state_t * gatt_client){
linked_list_iterator_t it;
linked_list_t *rfcomm_services = &gatt_client->rfcomm_services;
linked_list_t *rfcomm_cids = &gatt_client->rfcomm_cids;
linked_list_iterator_init(&it, rfcomm_services); linked_list_iterator_init(&it, rfcomm_services);
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it); linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
@ -299,9 +458,12 @@ static void daemon_rfcomm_close_connection(linked_list_t *rfcomm_services, linke
} }
} }
static void daemon_l2cap_close_connection(linked_list_t *l2cap_psms, linked_list_t *l2cap_cids){
linked_list_iterator_t it;
static void daemon_l2cap_close_connection(client_state_t * gatt_client){
linked_list_iterator_t it;
linked_list_t *l2cap_psms = &gatt_client->l2cap_psms;
linked_list_t *l2cap_cids = &gatt_client->l2cap_cids;
linked_list_iterator_init(&it, l2cap_psms); linked_list_iterator_init(&it, l2cap_psms);
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it); linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
@ -319,25 +481,27 @@ static void daemon_l2cap_close_connection(linked_list_t *l2cap_psms, linked_list
} }
} }
static void daemon_sdp_close_connection(void *connection, linked_list_t *sdp_handles){ static void daemon_sdp_close_connection(client_state_t * gatt_client){
linked_list_t * list = &gatt_client->sdp_record_handles;
linked_list_iterator_t it; linked_list_iterator_t it;
linked_list_iterator_init(&it, sdp_handles); linked_list_iterator_init(&it, list);
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it); linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
sdp_unregister_service_internal(connection, item->value); sdp_unregister_service_internal(&gatt_client->connection, item->value);
linked_list_remove(sdp_handles, (linked_item_t *) item); linked_list_remove(list, (linked_item_t *) item);
free(item); free(item);
} }
} }
static void daemon_gatt_client_close_connection(linked_list_t *gatt_client_handles){ static void daemon_gatt_client_close_connection(connection_t * connection){
linked_list_iterator_t it; client_state_t * client = client_for_connection(connection);
linked_list_iterator_init(&it, gatt_client_handles); if (!client) return;
linked_list_iterator_t it;
linked_list_iterator_init(&it, &client->gatt_con_handles);
while (linked_list_iterator_has_next(&it)){ while (linked_list_iterator_has_next(&it)){
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it); linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
gap_disconnect((hci_con_handle_t) item->value); daemon_remove_gatt_client_handle(connection, item->value);
linked_list_remove(gatt_client_handles, (linked_item_t *) item);
free(item);
} }
} }
@ -347,13 +511,13 @@ static void daemon_disconnect_client(connection_t * connection){
client_state_t * client = client_for_connection(connection); client_state_t * client = client_for_connection(connection);
if (!client) return; if (!client) return;
daemon_sdp_close_connection(connection, &client->sdp_record_handles); daemon_sdp_close_connection(client);
daemon_rfcomm_close_connection(&client->rfcomm_services, &client->rfcomm_cids); daemon_rfcomm_close_connection(client);
daemon_l2cap_close_connection(&client->l2cap_psms, &client->l2cap_cids); daemon_l2cap_close_connection(client);
#ifdef HAVE_BLE #ifdef HAVE_BLE
// NOTE: experimental - disconnect all LE connections where GATT Client was used // NOTE: experimental - disconnect all LE connections where GATT Client was used
// gatt_client_disconnect_connection(connection); // gatt_client_disconnect_connection(connection);
daemon_gatt_client_close_connection(&client->gatt_client_handles); daemon_gatt_client_close_connection(connection);
#endif #endif
linked_list_remove(&clients, (linked_item_t *) client); linked_list_remove(&clients, (linked_item_t *) client);
@ -362,29 +526,17 @@ static void daemon_disconnect_client(connection_t * connection){
#ifdef HAVE_BLE #ifdef HAVE_BLE
static gatt_client_t * daemon_provide_gatt_client_context_for_handle(void * connection, uint16_t handle){ linked_list_gatt_client_helper_t * daemon_get_gatt_client_helper(uint16_t handle) {
gatt_client_t *context; linked_list_iterator_t it;
context = get_gatt_client_context_for_handle(handle); linked_list_iterator_init(&it, &gatt_client_helpers);
if (context) return context; while (linked_list_iterator_has_next(&it)){
linked_list_gatt_client_helper_t * item = (linked_list_gatt_client_helper_t*) linked_list_iterator_next(&it);
context = (gatt_client_t*)malloc(sizeof(gatt_client_t) + sizeof(gatt_client_helper_t) + ATT_MAX_LONG_ATTRIBUTE_SIZE); if (item->con_handle == handle){
if (!context) return NULL; return item;
}
gatt_client_start(context, handle); }
daemon_add_gatt_client_handle(connection, handle); log_info("daemon_get_gatt_client_helper for handle 0x%02x is NULL.", handle);
return context; return NULL;
}
gatt_client_helper_t * daemon_get_gatt_helper(gatt_client_t * context){
return (gatt_client_helper_t*) (((uint8_t *) context) + sizeof(gatt_client_t));
}
uint8_t * daemon_get_data_buffer(gatt_client_t *context) {
return ((uint8_t *) context) + sizeof(gatt_client_t) + sizeof(gatt_client_helper_t);
}
gatt_client_helper_t * daemon_get_gatt_client_helper(gatt_client_t *context) {
return (gatt_client_helper_t *) (((uint8_t *) context) + sizeof(gatt_client_t));
} }
static void send_gatt_query_complete(connection_t * connection, uint16_t handle, uint8_t status){ static void send_gatt_query_complete(connection_t * connection, uint16_t handle, uint8_t status){
@ -397,28 +549,32 @@ static void send_gatt_query_complete(connection_t * connection, uint16_t handle,
socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
} }
gatt_client_t * daemon_prepare_gatt_client_context(connection_t *connection, uint8_t *packet) { linked_list_gatt_client_helper_t * daemon_setup_gatt_client_request(connection_t *connection, uint8_t *packet) {
hci_con_handle_t handle = READ_BT_16(packet, 3); hci_con_handle_t handle = READ_BT_16(packet, 3);
log_info("daemon_setup_gatt_client_request for handle 0x%02x", handle);
hci_connection_t * hci_con = hci_connection_for_handle(handle); hci_connection_t * hci_con = hci_connection_for_handle(handle);
if ((hci_con == NULL) || (hci_con->state != OPEN)){ if ((hci_con == NULL) || (hci_con->state != OPEN)){
send_gatt_query_complete(connection, handle, GATT_CLIENT_NOT_CONNECTED); send_gatt_query_complete(connection, handle, GATT_CLIENT_NOT_CONNECTED);
return NULL; return NULL;
} }
gatt_client_t *context = daemon_provide_gatt_client_context_for_handle(connection, handle); linked_list_gatt_client_helper_t * helper = daemon_get_gatt_client_helper(handle);
if (!context) {
send_gatt_query_complete(connection, handle, BTSTACK_MEMORY_ALLOC_FAILED); if (!helper){
return NULL; helper = malloc(sizeof(linked_list_gatt_client_helper_t));
} if (!helper) return NULL;
// check state memset(helper, 0, sizeof(linked_list_gatt_client_helper_t));
if (!gatt_client_is_ready(context)){ helper->con_handle = handle;
linked_list_add(&gatt_client_helpers, (linked_item_t *) helper);
}
if (helper->active_connection){
send_gatt_query_complete(connection, handle, GATT_CLIENT_BUSY); send_gatt_query_complete(connection, handle, GATT_CLIENT_BUSY);
return NULL; return NULL;
} }
context->context = connection; daemon_add_gatt_client_handle(connection, handle);
return context; return helper;
} }
// (de)serialize structs from/to HCI commands/events // (de)serialize structs from/to HCI commands/events
@ -467,7 +623,7 @@ void daemon_setup_service_event(le_event_t *le_event, uint8_t* event) {
le_service_event_t * service_event = (le_service_event_t *) le_event; le_service_event_t * service_event = (le_service_event_t *) le_event;
event[0] = le_event->type; event[0] = le_event->type;
event[1] = SERVICE_LENGTH; event[1] = SERVICE_LENGTH;
bt_store_16(event, 2, service_event->client->handle); bt_store_16(event, 2, service_event->handle);
daemon_gatt_serialize_service(&service_event->service, event, 4); daemon_gatt_serialize_service(&service_event->service, event, 4);
} }
@ -475,7 +631,7 @@ void daemon_gatt_setup_characteristic_event(le_event_t *le_event, uint8_t* event
le_characteristic_event_t * characteristic_event = (le_characteristic_event_t *) le_event; le_characteristic_event_t * characteristic_event = (le_characteristic_event_t *) le_event;
event[0] = le_event->type; event[0] = le_event->type;
event[1] = CHARACTERISTIC_LENGTH; event[1] = CHARACTERISTIC_LENGTH;
bt_store_16(event, 2, characteristic_event->client->handle); bt_store_16(event, 2, characteristic_event->handle);
daemon_gatt_serialize_characteristic(&characteristic_event->characteristic, event, 4); daemon_gatt_serialize_characteristic(&characteristic_event->characteristic, event, 4);
} }
@ -483,7 +639,7 @@ void daemon_setup_characteristic_descriptor_event(le_event_t *le_event, uint8_t*
le_characteristic_descriptor_event_t * descriptor_event = (le_characteristic_descriptor_event_t *) le_event; le_characteristic_descriptor_event_t * descriptor_event = (le_characteristic_descriptor_event_t *) le_event;
event[0] = le_event->type; event[0] = le_event->type;
event[1] = CHARACTERISTIC_DESCRIPTOR_LENGTH; event[1] = CHARACTERISTIC_DESCRIPTOR_LENGTH;
bt_store_16(event, 2, descriptor_event->client->handle); bt_store_16(event, 2, descriptor_event->handle);
daemon_gatt_serialize_characteristic_descriptor(&descriptor_event->characteristic_descriptor, event, 4); daemon_gatt_serialize_characteristic_descriptor(&descriptor_event->characteristic_descriptor, event, 4);
} }
@ -500,7 +656,7 @@ void daemon_setup_characteristic_value_event(le_event_t *le_event, uint8_t* even
le_characteristic_value_event_t * cvalue_event = (le_characteristic_value_event_t *) le_event; le_characteristic_value_event_t * cvalue_event = (le_characteristic_value_event_t *) le_event;
event[0] = le_event->type; event[0] = le_event->type;
event[1] = 2 + (2 + 2 + cvalue_event->blob_length); event[1] = 2 + (2 + 2 + cvalue_event->blob_length);
bt_store_16(event, 2, cvalue_event->client->handle); bt_store_16(event, 2, cvalue_event->handle);
bt_store_16(event, 4, cvalue_event->value_handle); bt_store_16(event, 4, cvalue_event->value_handle);
bt_store_16(event, 6, cvalue_event->blob_length); bt_store_16(event, 6, cvalue_event->blob_length);
memcpy(&event[8], cvalue_event->blob, cvalue_event->blob_length); memcpy(&event[8], cvalue_event->blob, cvalue_event->blob_length);
@ -524,13 +680,13 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
client_state_t *client; client_state_t *client;
#if defined(HAVE_MALLOC) && defined(HAVE_BLE) #if defined(HAVE_MALLOC) && defined(HAVE_BLE)
gatt_client_t * context;
uint8_t uuid128[16]; uint8_t uuid128[16];
le_service_t service; le_service_t service;
le_characteristic_t characteristic; le_characteristic_t characteristic;
le_characteristic_descriptor_t descriptor; le_characteristic_descriptor_t descriptor;
uint16_t data_length; uint16_t data_length;
uint8_t * data; uint8_t * data;
linked_list_gatt_client_helper_t * gatt_helper;
#endif #endif
uint16_t serviceSearchPatternLen; uint16_t serviceSearchPatternLen;
@ -762,134 +918,134 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
break; break;
#if defined(HAVE_MALLOC) && defined(HAVE_BLE) #if defined(HAVE_MALLOC) && defined(HAVE_BLE)
case GATT_DISCOVER_ALL_PRIMARY_SERVICES: case GATT_DISCOVER_ALL_PRIMARY_SERVICES:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
gatt_client_discover_primary_services(context); gatt_client_discover_primary_services(gatt_helper->con_handle);
break; break;
case GATT_DISCOVER_PRIMARY_SERVICES_BY_UUID16: case GATT_DISCOVER_PRIMARY_SERVICES_BY_UUID16:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
gatt_client_discover_primary_services_by_uuid16(context, READ_BT_16(packet, 5)); gatt_client_discover_primary_services_by_uuid16(gatt_helper->con_handle, READ_BT_16(packet, 5));
break; break;
case GATT_DISCOVER_PRIMARY_SERVICES_BY_UUID128: case GATT_DISCOVER_PRIMARY_SERVICES_BY_UUID128:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
swap128(&packet[5], uuid128); swap128(&packet[5], uuid128);
gatt_client_discover_primary_services_by_uuid128(context, uuid128); gatt_client_discover_primary_services_by_uuid128(gatt_helper->con_handle, uuid128);
break; break;
case GATT_FIND_INCLUDED_SERVICES_FOR_SERVICE: case GATT_FIND_INCLUDED_SERVICES_FOR_SERVICE:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_service(packet, 5, &service); daemon_gatt_deserialize_service(packet, 5, &service);
gatt_client_find_included_services_for_service(context, &service); gatt_client_find_included_services_for_service(gatt_helper->con_handle, &service);
break; break;
case GATT_DISCOVER_CHARACTERISTICS_FOR_SERVICE: case GATT_DISCOVER_CHARACTERISTICS_FOR_SERVICE:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_service(packet, 5, &service); daemon_gatt_deserialize_service(packet, 5, &service);
gatt_client_discover_characteristics_for_service(context, &service); gatt_client_discover_characteristics_for_service(gatt_helper->con_handle, &service);
break; break;
case GATT_DISCOVER_CHARACTERISTICS_FOR_SERVICE_BY_UUID128: case GATT_DISCOVER_CHARACTERISTICS_FOR_SERVICE_BY_UUID128:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_service(packet, 5, &service); daemon_gatt_deserialize_service(packet, 5, &service);
swap128(&packet[5 + SERVICE_LENGTH], uuid128); swap128(&packet[5 + SERVICE_LENGTH], uuid128);
gatt_client_discover_characteristics_for_service_by_uuid128(context, &service, uuid128); gatt_client_discover_characteristics_for_service_by_uuid128(gatt_helper->con_handle, &service, uuid128);
break; break;
case GATT_DISCOVER_CHARACTERISTIC_DESCRIPTORS: case GATT_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_discover_characteristic_descriptors(context, &characteristic); gatt_client_discover_characteristic_descriptors(gatt_helper->con_handle, &characteristic);
break; break;
case GATT_READ_VALUE_OF_CHARACTERISTIC: case GATT_READ_VALUE_OF_CHARACTERISTIC:
// context = daemon_prepare_gatt_client_context(connection, packet, GATT_CHARACTERISTIC_VALUE_QUERY_RESULT); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
context = daemon_prepare_gatt_client_context(connection, packet); if (!gatt_helper) break;
if (!context) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_read_value_of_characteristic(context, &characteristic); gatt_client_read_value_of_characteristic(gatt_helper->con_handle, &characteristic);
break; break;
case GATT_READ_LONG_VALUE_OF_CHARACTERISTIC: case GATT_READ_LONG_VALUE_OF_CHARACTERISTIC:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_read_long_value_of_characteristic(context, &characteristic); gatt_client_read_long_value_of_characteristic(gatt_helper->con_handle, &characteristic);
break; break;
case GATT_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE: case GATT_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH); data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = daemon_get_data_buffer(context); data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length); memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_value_of_characteristic_without_response(context, characteristic.value_handle, data_length, data); gatt_client_write_value_of_characteristic_without_response(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break; break;
case GATT_WRITE_VALUE_OF_CHARACTERISTIC: case GATT_WRITE_VALUE_OF_CHARACTERISTIC:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH); data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = daemon_get_data_buffer(context); data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length); memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_value_of_characteristic(context, characteristic.value_handle, data_length, data); gatt_client_write_value_of_characteristic(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break; break;
case GATT_WRITE_LONG_VALUE_OF_CHARACTERISTIC: case GATT_WRITE_LONG_VALUE_OF_CHARACTERISTIC:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH); data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = daemon_get_data_buffer(context); data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length); memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_long_value_of_characteristic(context, characteristic.value_handle, data_length, data); gatt_client_write_long_value_of_characteristic(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break; break;
case GATT_RELIABLE_WRITE_LONG_VALUE_OF_CHARACTERISTIC: case GATT_RELIABLE_WRITE_LONG_VALUE_OF_CHARACTERISTIC:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH); data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = daemon_get_data_buffer(context); data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length); memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_long_value_of_characteristic(context, characteristic.value_handle, data_length, data); gatt_client_write_long_value_of_characteristic(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break; break;
case GATT_READ_CHARACTERISTIC_DESCRIPTOR: case GATT_READ_CHARACTERISTIC_DESCRIPTOR:
// context = daemon_prepare_gatt_client_context(connection, packet, GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
context = daemon_prepare_gatt_client_context(connection, packet); if (!gatt_helper) break;
if (!context) break; handle = READ_BT_16(packet, 3);
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor); daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
gatt_client_read_characteristic_descriptor(context, &descriptor); gatt_client_read_characteristic_descriptor(gatt_helper->con_handle, &descriptor);
break; break;
case GATT_READ_LONG_CHARACTERISTIC_DESCRIPTOR: case GATT_READ_LONG_CHARACTERISTIC_DESCRIPTOR:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor); daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
gatt_client_read_long_characteristic_descriptor(context, &descriptor); gatt_client_read_long_characteristic_descriptor(gatt_helper->con_handle, &descriptor);
break; break;
case GATT_WRITE_CHARACTERISTIC_DESCRIPTOR: case GATT_WRITE_CHARACTERISTIC_DESCRIPTOR:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor); daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
data = daemon_get_data_buffer(context); data = gatt_helper->characteristic_buffer;
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_DESCRIPTOR_LENGTH); data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_DESCRIPTOR_LENGTH);
gatt_client_write_characteristic_descriptor(context, &descriptor, data_length, data); gatt_client_write_characteristic_descriptor(gatt_helper->con_handle, &descriptor, data_length, data);
break; break;
case GATT_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR: case GATT_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR:
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor); daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
data = daemon_get_data_buffer(context); data = gatt_helper->characteristic_buffer;
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_DESCRIPTOR_LENGTH); data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_DESCRIPTOR_LENGTH);
gatt_client_write_long_characteristic_descriptor(context, &descriptor, data_length, data); gatt_client_write_long_characteristic_descriptor(gatt_helper->con_handle, &descriptor, data_length, data);
break; break;
case GATT_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:{ case GATT_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:{
uint16_t configuration = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH); uint16_t configuration = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
context = daemon_prepare_gatt_client_context(connection, packet); gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!context) break; if (!gatt_helper) break;
data = gatt_helper->characteristic_buffer;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic); daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_write_client_characteristic_configuration(context, &characteristic, configuration); gatt_client_write_client_characteristic_configuration(gatt_helper->con_handle, &characteristic, configuration);
break; break;
} }
#endif #endif
@ -1147,19 +1303,11 @@ static void daemon_packet_handler(void * connection, uint8_t packet_type, uint16
daemon_add_client_l2cap_service(connection, READ_BT_16(packet, 3)); daemon_add_client_l2cap_service(connection, READ_BT_16(packet, 3));
break; break;
#if defined(HAVE_BLE) && defined(HAVE_MALLOC) #if defined(HAVE_BLE) && defined(HAVE_MALLOC)
case HCI_EVENT_DISCONNECTION_COMPLETE:{ case HCI_EVENT_DISCONNECTION_COMPLETE:
// re-enable advertisements log_info("daemon : ignore HCI_EVENT_DISCONNECTION_COMPLETE ingnoring.");
// todos = ENABLE_ADVERTISEMENTS; // note: moved to gatt_client_handler because it's received here prematurely
// daemon_remove_gatt_client_helper(READ_BT_16(packet, 3));
uint16_t handle = READ_BT_16(packet, 3);
daemon_remove_gatt_client_handle(connection, handle);
gatt_client_t *context = get_gatt_client_context_for_handle(handle);
if (!context) break;
gatt_client_stop(context);
free(context);
break; break;
}
#endif #endif
default: default:
break; break;
@ -1286,8 +1434,6 @@ static void daemon_sigint_handler(int param){
exit(0); exit(0);
} }
// MARK: manage power off timer // MARK: manage power off timer
#define USE_POWER_OFF_TIMER #define USE_POWER_OFF_TIMER
@ -1377,12 +1523,30 @@ static void * run_loop_thread(void *context){
#ifdef HAVE_BLE #ifdef HAVE_BLE
static void handle_gatt_client_event(le_event_t * le_event){ static void handle_gatt_client_event(le_event_t * le_event){
connection_t * context = (connection_t *)le_event->client->context;
// hack: handle disconnection_complete_here instead of main hci event packet handler
// we receive a HCI event packet in disguise
if (le_event->type == HCI_EVENT_DISCONNECTION_COMPLETE){
log_info("daemon hack: handle disconnection_complete in handle_gatt_client_event instead of main hci event packet handler");
uint8_t * packet = (uint8_t*) le_event;
uint16_t handle = READ_BT_16(packet, 3);
daemon_remove_gatt_client_helper(handle);
return;
}
gatt_complete_event_t * complete_event = (gatt_complete_event_t *) le_event; gatt_complete_event_t * complete_event = (gatt_complete_event_t *) le_event;
linked_list_gatt_client_helper_t * gatt_client_helper = daemon_get_gatt_client_helper(le_event->handle);
if (!gatt_client_helper){
log_info("daemon handle_gatt_client_event: gc helper for handle 0x%2x is NULL.", le_event->handle);
return;
}
connection_t *connection = gatt_client_helper->active_connection;
if (!connection) return;
#if defined(HAVE_MALLOC) #if defined(HAVE_MALLOC)
uint8_t * data; uint8_t * data;
gatt_client_helper_t * gatt_client_helper;
uint8_t gatt_chunk = 0; uint8_t gatt_chunk = 0;
#endif #endif
@ -1393,14 +1557,14 @@ static void handle_gatt_client_event(le_event_t * le_event){
uint8_t event[4 + SERVICE_LENGTH]; uint8_t event[4 + SERVICE_LENGTH];
daemon_setup_service_event(le_event, event); daemon_setup_service_event(le_event, event);
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
socket_connection_send_packet(context, HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
break; break;
} }
case GATT_CHARACTERISTIC_QUERY_RESULT:{ case GATT_CHARACTERISTIC_QUERY_RESULT:{
uint8_t event[4 + CHARACTERISTIC_LENGTH]; uint8_t event[4 + CHARACTERISTIC_LENGTH];
daemon_gatt_setup_characteristic_event(le_event, event); daemon_gatt_setup_characteristic_event(le_event, event);
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
socket_connection_send_packet(context, HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
break; break;
} }
@ -1410,7 +1574,7 @@ static void handle_gatt_client_event(le_event_t * le_event){
uint8_t event[4 + CHARACTERISTIC_DESCRIPTOR_LENGTH]; uint8_t event[4 + CHARACTERISTIC_DESCRIPTOR_LENGTH];
daemon_setup_characteristic_descriptor_event(le_event, event); daemon_setup_characteristic_descriptor_event(le_event, event);
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
socket_connection_send_packet(context, HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
break; break;
} }
@ -1418,7 +1582,7 @@ static void handle_gatt_client_event(le_event_t * le_event){
uint8_t event[4 + 2 + 1 + ATT_MAX_ATTRIBUTE_SIZE]; // (type, len, handle), handle, len, data uint8_t event[4 + 2 + 1 + ATT_MAX_ATTRIBUTE_SIZE]; // (type, len, handle), handle, len, data
daemon_setup_characteristic_value_event(le_event, event); daemon_setup_characteristic_value_event(le_event, event);
hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
socket_connection_send_packet(context, HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
break; break;
} }
@ -1426,8 +1590,7 @@ static void handle_gatt_client_event(le_event_t * le_event){
#if defined(HAVE_MALLOC) #if defined(HAVE_MALLOC)
gatt_chunk = 1; gatt_chunk = 1;
le_characteristic_value_event_t * cvalue_event = (le_characteristic_value_event_t *) le_event; le_characteristic_value_event_t * cvalue_event = (le_characteristic_value_event_t *) le_event;
data = daemon_get_data_buffer(le_event->client); data = gatt_client_helper->characteristic_buffer;
gatt_client_helper = daemon_get_gatt_client_helper(le_event->client);
gatt_client_helper->characteristic_length = cvalue_event->value_offset + cvalue_event->blob_length; gatt_client_helper->characteristic_length = cvalue_event->value_offset + cvalue_event->blob_length;
memcpy(&data[cvalue_event->value_offset], cvalue_event->blob, cvalue_event->blob_length); memcpy(&data[cvalue_event->value_offset], cvalue_event->blob, cvalue_event->blob_length);
#endif #endif
@ -1447,17 +1610,17 @@ static void handle_gatt_client_event(le_event_t * le_event){
break; break;
} }
case GATT_QUERY_COMPLETE:{ case GATT_QUERY_COMPLETE:{
gatt_client_helper->active_connection = NULL;
if (gatt_chunk){ if (gatt_chunk){
gatt_client_helper = daemon_get_gatt_client_helper(le_event->client); data = gatt_client_helper->characteristic_buffer;
data = daemon_get_data_buffer(le_event->client);
uint8_t event[4 + 2 + 1 + gatt_client_helper->characteristic_length]; uint8_t event[4 + 2 + 1 + gatt_client_helper->characteristic_length];
daemon_setup_long_characteristic_value_event(event, complete_event->client->handle, daemon_setup_long_characteristic_value_event(event, complete_event->handle,
complete_event->client->attribute_handle, complete_event->attribute_handle,
gatt_client_helper->characteristic_length, data); gatt_client_helper->characteristic_length, data);
socket_connection_send_packet(context, HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
gatt_chunk = 0; gatt_chunk = 0;
} }
send_gatt_query_complete(context, complete_event->client->handle, complete_event->status); send_gatt_query_complete(connection, complete_event->handle, complete_event->status);
break; break;
} }
default: default: