gtt client extended to handle multiple subclients of a peripheral

This commit is contained in:
mila@ringwald.ch 2014-10-31 15:58:44 +00:00
parent f53da564a8
commit 3e05add930
6 changed files with 229 additions and 140 deletions

View File

@ -55,12 +55,68 @@
#include "sm.h"
static linked_list_t gatt_client_connections = NULL;
static linked_list_t gatt_subclients = NULL;
static uint16_t gatt_client_id = 0;
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_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code);
void (*gatt_client_callback)(le_event_t * event);
static void dummy_notify(le_event_t* event){}
static uint16_t gatt_client_next_id(){
if (gatt_client_id < 0xFFFF) {
gatt_client_id++;
} else {
gatt_client_id = 1;
}
return gatt_client_id;
}
static gatt_client_callback_t gatt_client_callback_for_id(uint16_t id){
linked_list_iterator_t it;
linked_list_iterator_init(&it, &gatt_subclients);
while (linked_list_iterator_has_next(&it)){
gatt_subclient_t * item = (gatt_subclient_t*) linked_list_iterator_next(&it);
if ( item->id != id) continue;
return item->callback;
}
return NULL;
}
uint16_t gatt_client_register_packet_handler(gatt_client_callback_t gatt_callback){
if (gatt_callback == NULL){
gatt_callback = &dummy_notify;
}
gatt_subclient_t * subclient = btstack_memory_gatt_subclient_get();
if (!subclient) return 0;
subclient->id = gatt_client_next_id();
subclient->callback = gatt_callback;
linked_list_add(&gatt_subclients, (linked_item_t *) subclient);
printf("regstered callback %p, id %d\n", gatt_callback, subclient->id);
return subclient->id;
}
void gatt_client_unregister_packet_handler(uint16_t gatt_client_id){
linked_list_iterator_t it;
linked_list_iterator_init(&it, &gatt_subclients);
while (linked_list_iterator_has_next(&it)){
gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it);
if ( subclient->id != gatt_client_id) continue;
linked_list_remove(&gatt_subclients, (linked_item_t *) subclient);
btstack_memory_gatt_subclient_free(subclient);
}
}
void gatt_client_init(){
att_client_start_handle = 0x0000;
gatt_client_connections = NULL;
att_dispatch_register_client(gatt_client_att_packet_handler);
}
static gatt_client_t * gatt_client_for_timer(timer_source_t * ts){
linked_list_iterator_t it;
@ -94,21 +150,6 @@ static void gatt_client_timeout_stop(gatt_client_t * peripheral){
run_loop_remove_timer(&peripheral->gc_timeout);
}
void gatt_client_init(){
att_client_start_handle = 0x0000;
gatt_client_connections = NULL;
att_dispatch_register_client(gatt_client_att_packet_handler);
}
static void dummy_notify(le_event_t* event){}
void gatt_client_register_packet_handler(void (*gatt_callback)(le_event_t* event)){
if (gatt_callback == NULL){
gatt_callback = &dummy_notify;
}
gatt_client_callback = gatt_callback;
}
static 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){
@ -362,13 +403,20 @@ static void gatt_client_handle_transaction_complete(gatt_client_t * peripheral){
gatt_client_timeout_stop(peripheral);
}
static inline void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){
static void emit_event(uint16_t gatt_client_id, le_event_t* event){
gatt_client_callback_t gatt_client_callback = gatt_client_callback_for_id(gatt_client_id);
if (!gatt_client_callback) return;
(*gatt_client_callback)(event);
}
static void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){
gatt_complete_event_t event;
event.type = GATT_QUERY_COMPLETE;
event.handle = peripheral->handle;
event.attribute_handle = peripheral->attribute_handle;
event.status = status;
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
static void report_gatt_services(gatt_client_t * peripheral, uint8_t * packet, uint16_t size){
@ -395,7 +443,7 @@ static void report_gatt_services(gatt_client_t * peripheral, uint8_t * packet,
event.service = service;
// log_info(" report_gatt_services 0x%02x : 0x%02x-0x%02x", service.uuid16, service.start_group_handle, service.end_group_handle);
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
// log_info("report_gatt_services for %02X done", peripheral->handle);
}
@ -437,7 +485,8 @@ static void characteristic_end_found(gatt_client_t * peripheral, uint16_t end_ha
event.characteristic.properties = peripheral->characteristic_properties;
event.characteristic.uuid16 = peripheral->uuid16;
memcpy(event.characteristic.uuid128, peripheral->uuid128, 16);
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
peripheral->characteristic_start_handle = 0;
}
@ -473,7 +522,7 @@ static void report_gatt_included_service(gatt_client_t * peripheral, uint8_t *uu
event.type = GATT_INCLUDED_SERVICE_QUERY_RESULT;
event.service = service;
event.handle = peripheral->handle;
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
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){
@ -484,7 +533,7 @@ static void send_characteristic_value_event(gatt_client_t * peripheral, uint16_t
event.value_offset = offset;
event.blob_length = length;
event.blob = value;
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
static void report_gatt_long_characteristic_value_blob(gatt_client_t * peripheral, uint8_t * value, uint16_t blob_length, int value_offset){
@ -519,7 +568,7 @@ static void report_gatt_characteristic_descriptor(gatt_client_t * peripheral, ui
event.value = value;
event.value_length = value_length;
event.characteristic_descriptor = descriptor;
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
static void report_gatt_all_characteristic_descriptors(gatt_client_t * peripheral, uint8_t * packet, uint16_t size, uint16_t pair_size){
@ -541,7 +590,7 @@ static void report_gatt_all_characteristic_descriptors(gatt_client_t * periphera
event.value_length = 0;
event.characteristic_descriptor = descriptor;
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
}
@ -773,6 +822,15 @@ static void gatt_client_run(){
}
static void emit_event_to_all_subclients(le_event_t * event){
linked_list_iterator_t it;
linked_list_iterator_init(&it, &gatt_subclients);
while (linked_list_iterator_has_next(&it)){
gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it);
(*subclient->callback)(event);
}
}
static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) {
if (is_ready(peripheral)) return;
gatt_client_handle_transaction_complete(peripheral);
@ -792,8 +850,8 @@ static void gatt_client_hci_event_packet_handler(uint8_t packet_type, uint8_t *p
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);
// Forward event to all subclients
emit_event_to_all_subclients((le_event_t *) packet);
break;
}
default:
@ -924,7 +982,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle,
service.uuid16 = peripheral->uuid16;
event.service = service;
event.handle = peripheral->handle;
(*gatt_client_callback)((le_event_t*)&event);
emit_event(peripheral->subclient_id, (le_event_t*)&event);
}
trigger_next_service_by_uuid_query(peripheral, service.end_group_handle);
@ -1080,14 +1138,14 @@ static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
}
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){
le_command_status_t gatt_client_signed_write_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t handle, uint16_t message_len, uint8_t * message, sm_key_t csrk, uint32_t sign_counter){
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()) {
log_info("ATT Signed Write, sm_cmac engine not ready. Abort");
return BLE_PERIPHERAL_IN_WRONG_STATE;
}
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = handle;
peripheral->attribute_length = message_len;
peripheral->attribute_value = message;
@ -1100,11 +1158,12 @@ le_command_status_t gatt_client_signed_write_without_response(uint16_t con_handl
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_discover_primary_services(uint16_t handle){
gatt_client_t * peripheral = provide_context_for_conn_handle(handle);
le_command_status_t gatt_client_discover_primary_services(uint16_t gatt_client_id, uint16_t con_handle){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = 0x0001;
peripheral->end_group_handle = 0xffff;
peripheral->gatt_client_state = P_W2_SEND_SERVICE_QUERY;
@ -1114,12 +1173,13 @@ le_command_status_t gatt_client_discover_primary_services(uint16_t handle){
}
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_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t uuid16){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = 0x0001;
peripheral->end_group_handle = 0xffff;
peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
@ -1129,12 +1189,13 @@ le_command_status_t gatt_client_discover_primary_services_by_uuid16(uint16_t con
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t con_handle, const uint8_t * uuid128){
le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, const uint8_t * uuid128){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = 0x0001;
peripheral->end_group_handle = 0xffff;
peripheral->uuid16 = 0;
@ -1144,12 +1205,13 @@ le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t co
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t con_handle, le_service_t *service){
le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = service->start_group_handle;
peripheral->end_group_handle = service->end_group_handle;
peripheral->filter_with_uuid = 0;
@ -1159,12 +1221,13 @@ le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t co
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_find_included_services_for_service(uint16_t con_handle, le_service_t *service){
le_command_status_t gatt_client_find_included_services_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = service->start_group_handle;
peripheral->end_group_handle = service->end_group_handle;
peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_QUERY;
@ -1173,12 +1236,13 @@ le_command_status_t gatt_client_find_included_services_for_service(uint16_t con_
return BLE_PERIPHERAL_OK;
}
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_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = start_handle;
peripheral->end_group_handle = end_handle;
peripheral->filter_with_uuid = 1;
@ -1191,12 +1255,13 @@ le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uui
return BLE_PERIPHERAL_OK;
}
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){
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid128){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = start_handle;
peripheral->end_group_handle = end_handle;
peripheral->filter_with_uuid = 1;
@ -1210,15 +1275,15 @@ 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(uint16_t handle, le_service_t *service, uint16_t 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_uuid16(uint16_t gatt_client_id, uint16_t handle, le_service_t *service, uint16_t uuid16){
return gatt_client_discover_characteristics_for_handle_range_by_uuid16(gatt_client_id, handle, service->start_group_handle, service->end_group_handle, uuid16);
}
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(handle, service->start_group_handle, service->end_group_handle, uuid128);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t gatt_client_id, uint16_t handle, le_service_t *service, uint8_t * uuid128){
return gatt_client_discover_characteristics_for_handle_range_by_uuid128(gatt_client_id, handle, service->start_group_handle, service->end_group_handle, uuid128);
}
le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con_handle, le_characteristic_t *characteristic){
le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t *characteristic){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
@ -1228,6 +1293,7 @@ le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con
emit_gatt_complete_event(peripheral, 0);
return BLE_PERIPHERAL_OK;
}
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = characteristic->value_handle + 1;
peripheral->end_group_handle = characteristic->end_handle;
peripheral->gatt_client_state = P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY;
@ -1236,12 +1302,13 @@ le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t con_handle, uint16_t value_handle){
le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = value_handle;
peripheral->attribute_offset = 0;
peripheral->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY;
@ -1249,17 +1316,18 @@ le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(
return BLE_PERIPHERAL_OK;
}
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(handle, characteristic->value_handle);
le_command_status_t gatt_client_read_value_of_characteristic(uint16_t gatt_client_id, uint16_t handle, le_characteristic_t *characteristic){
return gatt_client_read_value_of_characteristic_using_value_handle(gatt_client_id, handle, characteristic->value_handle);
}
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t con_handle, uint16_t value_handle){
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = value_handle;
peripheral->attribute_offset = 0;
peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY;
@ -1267,11 +1335,11 @@ le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_ha
return BLE_PERIPHERAL_OK;
}
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(handle, characteristic->value_handle);
le_command_status_t gatt_client_read_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t handle, le_characteristic_t *characteristic){
return gatt_client_read_long_value_of_characteristic_using_value_handle(gatt_client_id, handle, characteristic->value_handle);
}
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){
le_command_status_t gatt_client_write_value_of_characteristic_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
@ -1279,16 +1347,18 @@ le_command_status_t gatt_client_write_value_of_characteristic_without_response(u
if (value_length >= peripheral->mtu - 3) return BLE_VALUE_TOO_LONG;
peripheral->subclient_id = gatt_client_id;
att_write_request(ATT_WRITE_COMMAND, peripheral->handle, value_handle, value_length, value);
return BLE_PERIPHERAL_OK;
}
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){
le_command_status_t gatt_client_write_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = value_handle;
peripheral->attribute_length = value_length;
peripheral->attribute_value = value;
@ -1297,12 +1367,13 @@ le_command_status_t gatt_client_write_value_of_characteristic(uint16_t con_handl
return BLE_PERIPHERAL_OK;
}
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){
le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = value_handle;
peripheral->attribute_length = value_length;
peripheral->attribute_offset = 0;
@ -1312,12 +1383,13 @@ le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t con_
return BLE_PERIPHERAL_OK;
}
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){
le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = value_handle;
peripheral->attribute_length = value_length;
peripheral->attribute_offset = 0;
@ -1327,7 +1399,7 @@ le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration){
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
@ -1343,6 +1415,7 @@ le_command_status_t gatt_client_write_client_characteristic_configuration(uint16
return BLE_CHARACTERISTIC_INDICATION_NOT_SUPPORTED;
}
peripheral->subclient_id = gatt_client_id;
peripheral->start_group_handle = characteristic->value_handle;
peripheral->end_group_handle = characteristic->end_handle;
bt_store_16(peripheral->client_characteristic_configuration_value, 0, configuration);
@ -1352,12 +1425,13 @@ le_command_status_t gatt_client_write_client_characteristic_configuration(uint16
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = descriptor->handle;
peripheral->uuid16 = descriptor->uuid16;
if (!descriptor->uuid16){
@ -1369,12 +1443,13 @@ le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t con_hand
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = descriptor->handle;
peripheral->attribute_offset = 0;
peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY;
@ -1382,12 +1457,13 @@ le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t con
return BLE_PERIPHERAL_OK;
}
le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = descriptor->handle;
peripheral->attribute_length = length;
peripheral->attribute_offset = 0;
@ -1397,12 +1473,13 @@ le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t con_han
return BLE_PERIPHERAL_OK;
}
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){
le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
peripheral->subclient_id = gatt_client_id;
peripheral->attribute_handle = descriptor->handle;
peripheral->attribute_length = length;
peripheral->attribute_offset = 0;

View File

@ -40,8 +40,14 @@
#if defined __cplusplus
extern "C" {
#endif
// *************** gatt client
typedef struct le_event {
uint8_t type;
uint16_t handle;
} le_event_t;
typedef void (*gatt_client_callback_t)(le_event_t * event);
typedef enum {
P_READY,
P_W2_SEND_SERVICE_QUERY,
@ -102,14 +108,7 @@ typedef enum {
P_W4_CMAC
} gatt_client_state_t;
typedef struct gatt_subclient {
linked_item_t item;
uint16_t id;
// gatt_client_callback_t callback;
} gatt_subclient_t;
typedef enum{
SEND_MTU_EXCHANGE,
@ -119,10 +118,11 @@ typedef enum{
typedef struct gatt_client{
linked_item_t item;
//TODO: rename gatt_client_state -> state
gatt_client_state_t gatt_client_state;
// context used by higher layer
void * context;
// subclient
uint16_t subclient_id;
uint16_t handle;
@ -160,10 +160,12 @@ typedef struct gatt_client{
timer_source_t gc_timeout;
} gatt_client_t;
typedef struct le_event {
uint8_t type;
uint16_t handle;
} le_event_t;
typedef struct gatt_subclient {
linked_item_t item;
uint16_t id;
gatt_client_callback_t callback;
} gatt_subclient_t;
typedef struct gatt_complete_event{
uint8_t type;
@ -229,8 +231,11 @@ typedef struct le_characteristic_descriptor_event{
// Set up GATT client.
void gatt_client_init();
// Register packet handler.
void gatt_client_register_packet_handler(void (*le_callback)(le_event_t * event));
// Register callback (packet handler) for gatt client. Returns gatt client ID.
uint16_t gatt_client_register_packet_handler (gatt_client_callback_t callback);
// Unregister callback (packet handler) for gatt client.
void gatt_client_unregister_packet_handler(uint16_t gatt_client_id);
// Returns the GATT client context for the specified handle.
// gatt_client_t * get_gatt_client_context_for_handle(uint16_t con_handle);
@ -243,7 +248,7 @@ int gatt_client_is_ready(uint16_t handle);
// will be generated and passed to the registered callback.
// The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE,
// marks the end of discovery.
le_command_status_t gatt_client_discover_primary_services(uint16_t con_handle);
le_command_status_t gatt_client_discover_primary_services(uint16_t gatt_client_id, uint16_t con_handle);
// Discovers a specific primary service given its UUID. This service
// may exist multiple times. For each found service, an
@ -251,8 +256,8 @@ le_command_status_t gatt_client_discover_primary_services(uint16_t con_handle);
// will be generated and passed to the registered callback.
// The gatt_complete_event_t, with type set to GATT_QUERY_COMPLETE,
// marks the end of discovery.
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(uint16_t con_handle, const uint8_t * uuid);
le_command_status_t gatt_client_discover_primary_services_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t uuid16);
le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, const uint8_t * uuid);
// Finds included services within the specified service. For each
// found included service, an le_service_event_t with type set to
@ -265,14 +270,14 @@ le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t co
// for the returned start group handle (returning the handle and
// the UUID for primary or secondary service) or by comparing the
// service to the list of all primary services.
le_command_status_t gatt_client_find_included_services_for_service(uint16_t con_handle, le_service_t *service);
le_command_status_t gatt_client_find_included_services_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service);
// Discovers all characteristics within the specified service. For
// each found characteristic, an le_characteristics_event_t with
// type set to GATT_CHARACTERISTIC_QUERY_RESULT will be generated
// and passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of discovery.
le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t con_handle, le_service_t *service);
le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service);
// The following four functions are used to discover all
// characteristics within the specified service or handle range, and
@ -281,10 +286,10 @@ le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t co
// GATT_CHARACTERISTIC_QUERY_RESULT will be generated and passed to
// the registered callback. The gatt_complete_event_t with type set
// to GATT_QUERY_COMPLETE, marks the end of discovery.
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(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 (uint16_t con_handle, le_service_t *service, uint16_t uuid16);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t con_handle, le_service_t *service, uint8_t * uuid128);
le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(uint16_t gatt_client_id, 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(uint16_t gatt_client_id, 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 (uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service, uint16_t uuid16);
le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service, uint8_t * uuid128);
// Discovers attribute handle and UUID of a characteristic
// descriptor within the specified characteristic. For each found
@ -293,7 +298,7 @@ le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(
// generated and passed to the registered callback. The
// gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks
// the end of discovery.
le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con_handle, le_characteristic_t *characteristic);
le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t *characteristic);
// Reads the characteristic value using the characteristic's value
// handle. If the characteristic value is found, an
@ -301,8 +306,8 @@ le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t con
// GATT_CHARACTERISTIC_VALUE_QUERY_RESULT will be generated and
// passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of read.
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(uint16_t con_handle, uint16_t characteristic_value_handle);
le_command_status_t gatt_client_read_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t *characteristic);
le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle);
// Reads the long characteristic value using the characteristic's
// value handle. The value will be returned in several blobs. For
@ -311,25 +316,25 @@ le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(
// will be generated and passed to the registered callback. The
// gatt_complete_event_t with type set to GATT_QUERY_COMPLETE, marks
// the end of read.
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(uint16_t con_handle, uint16_t characteristic_value_handle);
le_command_status_t gatt_client_read_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t *characteristic);
le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle);
// Writes the characteristic value using the characteristic's value
// handle without an acknowledgement that the write was successfully
// performed.
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);
le_command_status_t gatt_client_write_value_of_characteristic_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
// Writes the authenticated characteristic value using the
// characteristic's value handle without an acknowledgement
// that the write was successfully performed.
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);
le_command_status_t gatt_client_signed_write_without_response(uint16_t gatt_client_id, 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
// handle. The gatt_complete_event_t with type set to
// GATT_QUERY_COMPLETE, marks the end of write. The write is
// successfully performed, if the event's status field is set to 0.
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(uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
le_command_status_t gatt_client_write_value_of_characteristic(uint16_t gatt_client_id, 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(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
// Writes of the long characteristic value using the
// characteristic's value handle. It uses server response to
@ -337,7 +342,7 @@ le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t con_
// The gatt_complete_event_t with type set to GATT_QUERY_COMPLETE
// marks the end of write. The write is successfully performed, if
// the event's status field is set to 0.
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);
le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t length, uint8_t * data);
// Reads the characteristic descriptor using its handle. If the
// characteristic descriptor is found, an
@ -345,7 +350,7 @@ le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint
// GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated
// and passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of read.
le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor);
le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor);
// Reads the long characteristic descriptor using its handle. It
// will be returned in several blobs. For each blob, an
@ -353,14 +358,14 @@ le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t con_hand
// GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT will be generated
// and passed to the registered callback. The gatt_complete_event_t
// with type set to GATT_QUERY_COMPLETE, marks the end of read.
le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t con_handle, le_characteristic_descriptor_t * descriptor);
le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor);
// Writes the characteristic descriptor using its handle.
// The gatt_complete_event_t with type set to
// GATT_QUERY_COMPLETE, marks the end of write. The write is
// successfully performed, if the event's status field is set to 0.
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(uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * data);
le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t gatt_client_id, 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(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * data);
// Writes the client characteristic configuration of the specified
// characteristic. It is used to subscribe for notifications or
@ -369,7 +374,7 @@ le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t co
// GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION resp.
// GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION
// as configuration value.
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration);
le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration);
#if defined __cplusplus
}

View File

@ -90,7 +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 uint32_t ancs_notification_uid;
static uint16_t gc_handle;
static uint16_t gc_handle, gc_id;
static int ancs_service_found;
static le_service_t ancs_service;
static le_characteristic_t ancs_notification_source_characteristic;
@ -181,7 +181,7 @@ static void handle_gatt_client_event(le_event_t * event){
}
tc_state = TC_W4_CHARACTERISTIC_RESULT;
printf("ANCS Client - Discover characteristics for ANCS SERVICE \n");
gatt_client_discover_characteristics_for_service(gc_handle, &ancs_service);
gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &ancs_service);
break;
default:
break;
@ -214,7 +214,7 @@ static void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE:
printf("ANCS Characteristcs count %u\n", ancs_characteristcs);
tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED;
gatt_client_write_client_characteristic_configuration(gc_handle, &ancs_notification_source_characteristic,
gatt_client_write_client_characteristic_configuration(gc_id, gc_handle, &ancs_notification_source_characteristic,
GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break;
default:
@ -226,7 +226,7 @@ static void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE:
printf("ANCS Notification Source subscribed\n");
tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED;
gatt_client_write_client_characteristic_configuration(gc_handle, &ancs_data_source_characteristic,
gatt_client_write_client_characteristic_configuration(gc_id, gc_handle, &ancs_data_source_characteristic,
GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break;
default:
@ -260,7 +260,7 @@ static void handle_gatt_client_event(le_event_t * event){
bt_store_32(get_notification_attributes, 1, ancs_notification_uid);
ancs_notification_uid = 0;
ancs_chunk_parser_init();
gatt_client_write_value_of_characteristic(gc_handle, ancs_control_point_characteristic.value_handle,
gatt_client_write_value_of_characteristic(gc_id, gc_handle, ancs_control_point_characteristic.value_handle,
sizeof(get_notification_attributes), get_notification_attributes);
} else {
printf("Unknown Source: ");
@ -306,7 +306,7 @@ void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8
// let's start
printf("\nANCS Client - CONNECTED, discover ANCS service\n");
tc_state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services_by_uuid128(gc_handle, ancs_service_uuid);
gatt_client_discover_primary_services_by_uuid128(gc_id, gc_handle, ancs_service_uuid);
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
@ -320,5 +320,5 @@ void ancs_client_hci_event_handler (uint8_t packet_type, uint16_t channel, uint8
}
void ancs_client_init(){
gatt_client_register_packet_handler(&handle_gatt_client_event);
gc_id = gatt_client_register_packet_handler(&handle_gatt_client_event);
}

View File

@ -86,7 +86,7 @@ typedef enum {
static bd_addr_t cmdline_addr = { };
static int cmdline_addr_found = 0;
uint16_t gc_handle;
uint16_t gc_id, gc_handle;
static uint16_t battery_service_uuid = 0x180F;
static uint16_t battery_level_characteristic_uuid = 0x2a19;
static le_service_t battery_service;
@ -148,9 +148,15 @@ void handle_gatt_client_event(le_event_t * event){
dump_service(&battery_service);
break;
case GATT_QUERY_COMPLETE:
if (!((gatt_complete_event_t *) event)->status){
printf("Battery service not found. Restart scan.\n");
state = TC_W4_SCAN_RESULT;
le_central_start_scan();
break;
}
state = TC_W4_CHARACTERISTIC_RESULT;
printf("\nSearch for battery level characteristic in battery service. ");
gatt_client_discover_characteristics_for_service_by_uuid16(gc_handle, &battery_service, battery_level_characteristic_uuid);
gatt_client_discover_characteristics_for_service_by_uuid16(gc_id, gc_handle, &battery_service, battery_level_characteristic_uuid);
break;
default:
break;
@ -167,7 +173,7 @@ void handle_gatt_client_event(le_event_t * event){
case GATT_QUERY_COMPLETE:
state = TC_W4_BATTERY_DATA;
printf("\nConfigure battery level characteristic for notify.");
gatt_client_write_client_characteristic_configuration(gc_handle, &config_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
gatt_client_write_client_characteristic_configuration(gc_id, gc_handle, &config_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break;
default:
break;
@ -219,7 +225,7 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
// BTstack activated, get started
if (packet[2] != HCI_STATE_WORKING) break;
if (cmdline_addr_found){
printf("Trying to connect to %s\n", bd_addr_to_str(cmdline_addr));
printf("Start connect to %s\n", bd_addr_to_str(cmdline_addr));
state = TC_W4_CONNECT;
le_central_connect(&cmdline_addr, 0);
break;
@ -247,7 +253,7 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
// query primary services
printf("\nSearch for battery service. ");
state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services_by_uuid16(gc_handle, battery_service_uuid);
gatt_client_discover_primary_services_by_uuid16(gc_id, gc_handle, battery_service_uuid);
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("\nDISCONNECTED\n");
@ -286,7 +292,7 @@ void setup(void){
l2cap_register_packet_handler(&handle_hci_event);
gatt_client_init();
gatt_client_register_packet_handler(&handle_gatt_client_event);
gc_id = gatt_client_register_packet_handler(&handle_gatt_client_event);
sm_init();
sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);

View File

@ -87,7 +87,7 @@ typedef enum {
static bd_addr_t cmdline_addr = { };
static int cmdline_addr_found = 0;
uint16_t gc_handle;
uint16_t gc_id, gc_handle;
static le_service_t services[40];
static int service_count = 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 ");
printUUID128(service.uuid128); printf("\n");
gatt_client_discover_characteristics_for_service(gc_handle, &services[service_index]);
gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &services[service_index]);
break;
default:
break;
@ -159,7 +159,7 @@ void handle_gatt_client_event(le_event_t * event){
printUUID128(service.uuid128);
printf(", [0x%04x-0x%04x]\n", service.start_group_handle, service.end_group_handle);
gatt_client_discover_characteristics_for_service(gc_handle, &service);
gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &service);
break;
}
state = TC_W4_DISCONNECT;
@ -217,9 +217,9 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
if (state != TC_W4_SCAN_RESULT) return;
fill_advertising_report_from_packet(&report, packet);
// stop scanning, and connect to the device
// state = TC_W4_CONNECT;
//le_central_stop_scan();
//le_central_connect(&report.address,report.address_type);
state = TC_W4_CONNECT;
le_central_stop_scan();
le_central_connect(&report.address,report.address_type);
break;
case HCI_EVENT_LE_META:
// wait for connection complete
@ -228,7 +228,7 @@ static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t ch
gc_handle = READ_BT_16(packet, 4);
// query primary services
state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services(gc_handle);
gatt_client_discover_primary_services(gc_id, gc_handle);
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
printf("\ntest client - DISCONNECTED\n");
@ -246,7 +246,7 @@ void setup(void){
run_loop_init(RUN_LOOP_POSIX);
// 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
remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
@ -267,7 +267,7 @@ void setup(void){
l2cap_register_packet_handler(&handle_hci_event);
gatt_client_init();
gatt_client_register_packet_handler(&handle_gatt_client_event);
gc_id = gatt_client_register_packet_handler(&handle_gatt_client_event);
sm_init();
sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);

View File

@ -174,6 +174,7 @@ static int power_management_sleep = 0;
static linked_list_t clients = NULL; // list of connected clients `
#ifdef HAVE_BLE
static linked_list_t gatt_client_helpers = NULL; // list of used gatt client (helpers)
static uint16_t gatt_client_id = 0;
#endif
static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth_status_handler;
@ -933,57 +934,57 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
case GATT_DISCOVER_ALL_PRIMARY_SERVICES:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
gatt_client_discover_primary_services(gatt_helper->con_handle);
gatt_client_discover_primary_services(gatt_client_id, gatt_helper->con_handle);
break;
case GATT_DISCOVER_PRIMARY_SERVICES_BY_UUID16:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
gatt_client_discover_primary_services_by_uuid16(gatt_helper->con_handle, READ_BT_16(packet, 5));
gatt_client_discover_primary_services_by_uuid16(gatt_client_id, gatt_helper->con_handle, READ_BT_16(packet, 5));
break;
case GATT_DISCOVER_PRIMARY_SERVICES_BY_UUID128:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
swap128(&packet[5], uuid128);
gatt_client_discover_primary_services_by_uuid128(gatt_helper->con_handle, uuid128);
gatt_client_discover_primary_services_by_uuid128(gatt_client_id, gatt_helper->con_handle, uuid128);
break;
case GATT_FIND_INCLUDED_SERVICES_FOR_SERVICE:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_service(packet, 5, &service);
gatt_client_find_included_services_for_service(gatt_helper->con_handle, &service);
gatt_client_find_included_services_for_service(gatt_client_id, gatt_helper->con_handle, &service);
break;
case GATT_DISCOVER_CHARACTERISTICS_FOR_SERVICE:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_service(packet, 5, &service);
gatt_client_discover_characteristics_for_service(gatt_helper->con_handle, &service);
gatt_client_discover_characteristics_for_service(gatt_client_id, gatt_helper->con_handle, &service);
break;
case GATT_DISCOVER_CHARACTERISTICS_FOR_SERVICE_BY_UUID128:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_service(packet, 5, &service);
swap128(&packet[5 + SERVICE_LENGTH], uuid128);
gatt_client_discover_characteristics_for_service_by_uuid128(gatt_helper->con_handle, &service, uuid128);
gatt_client_discover_characteristics_for_service_by_uuid128(gatt_client_id, gatt_helper->con_handle, &service, uuid128);
break;
case GATT_DISCOVER_CHARACTERISTIC_DESCRIPTORS:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_discover_characteristic_descriptors(gatt_helper->con_handle, &characteristic);
gatt_client_discover_characteristic_descriptors(gatt_client_id, gatt_helper->con_handle, &characteristic);
break;
case GATT_READ_VALUE_OF_CHARACTERISTIC:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_read_value_of_characteristic(gatt_helper->con_handle, &characteristic);
gatt_client_read_value_of_characteristic(gatt_client_id, gatt_helper->con_handle, &characteristic);
break;
case GATT_READ_LONG_VALUE_OF_CHARACTERISTIC:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_read_long_value_of_characteristic(gatt_helper->con_handle, &characteristic);
gatt_client_read_long_value_of_characteristic(gatt_client_id, gatt_helper->con_handle, &characteristic);
break;
case GATT_WRITE_VALUE_OF_CHARACTERISTIC_WITHOUT_RESPONSE:
@ -993,7 +994,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_value_of_characteristic_without_response(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
gatt_client_write_value_of_characteristic_without_response(gatt_client_id, gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break;
case GATT_WRITE_VALUE_OF_CHARACTERISTIC:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
@ -1002,7 +1003,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_value_of_characteristic(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
gatt_client_write_value_of_characteristic(gatt_client_id, gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break;
case GATT_WRITE_LONG_VALUE_OF_CHARACTERISTIC:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
@ -1011,7 +1012,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_long_value_of_characteristic(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
gatt_client_write_long_value_of_characteristic(gatt_client_id, gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break;
case GATT_RELIABLE_WRITE_LONG_VALUE_OF_CHARACTERISTIC:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
@ -1020,20 +1021,20 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
data = gatt_helper->characteristic_buffer;
memcpy(data, &packet[7 + CHARACTERISTIC_LENGTH], data_length);
gatt_client_write_long_value_of_characteristic(gatt_helper->con_handle, characteristic.value_handle, data_length, data);
gatt_client_write_long_value_of_characteristic(gatt_client_id, gatt_helper->con_handle, characteristic.value_handle, data_length, data);
break;
case GATT_READ_CHARACTERISTIC_DESCRIPTOR:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
handle = READ_BT_16(packet, 3);
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
gatt_client_read_characteristic_descriptor(gatt_helper->con_handle, &descriptor);
gatt_client_read_characteristic_descriptor(gatt_client_id, gatt_helper->con_handle, &descriptor);
break;
case GATT_READ_LONG_CHARACTERISTIC_DESCRIPTOR:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
if (!gatt_helper) break;
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
gatt_client_read_long_characteristic_descriptor(gatt_helper->con_handle, &descriptor);
gatt_client_read_long_characteristic_descriptor(gatt_client_id, gatt_helper->con_handle, &descriptor);
break;
case GATT_WRITE_CHARACTERISTIC_DESCRIPTOR:
@ -1042,7 +1043,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
data = gatt_helper->characteristic_buffer;
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_DESCRIPTOR_LENGTH);
gatt_client_write_characteristic_descriptor(gatt_helper->con_handle, &descriptor, data_length, data);
gatt_client_write_characteristic_descriptor(gatt_client_id, gatt_helper->con_handle, &descriptor, data_length, data);
break;
case GATT_WRITE_LONG_CHARACTERISTIC_DESCRIPTOR:
gatt_helper = daemon_setup_gatt_client_request(connection, packet);
@ -1050,7 +1051,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
daemon_gatt_deserialize_characteristic_descriptor(packet, 5, &descriptor);
data = gatt_helper->characteristic_buffer;
data_length = READ_BT_16(packet, 5 + CHARACTERISTIC_DESCRIPTOR_LENGTH);
gatt_client_write_long_characteristic_descriptor(gatt_helper->con_handle, &descriptor, data_length, data);
gatt_client_write_long_characteristic_descriptor(gatt_client_id, gatt_helper->con_handle, &descriptor, data_length, data);
break;
case GATT_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:{
uint16_t configuration = READ_BT_16(packet, 5 + CHARACTERISTIC_LENGTH);
@ -1058,7 +1059,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
if (!gatt_helper) break;
data = gatt_helper->characteristic_buffer;
daemon_gatt_deserialize_characteristic(packet, 5, &characteristic);
gatt_client_write_client_characteristic_configuration(gatt_helper->con_handle, &characteristic, configuration);
gatt_client_write_client_characteristic_configuration(gatt_client_id, gatt_helper->con_handle, &characteristic, configuration);
break;
}
#endif
@ -1799,7 +1800,7 @@ int main (int argc, char * const * argv){
#ifdef HAVE_BLE
// GATT Client
gatt_client_init();
gatt_client_register_packet_handler(&handle_gatt_client_event);
gatt_client_id = gatt_client_register_packet_handler(&handle_gatt_client_event);
// sm_init();
// sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY);