diff --git a/ble/gatt_client.c b/ble/gatt_client.c index 438475af4..0667143bb 100644 --- a/ble/gatt_client.c +++ b/ble/gatt_client.c @@ -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; diff --git a/ble/gatt_client.h b/ble/gatt_client.h index 437093d71..f3987d4e2 100644 --- a/ble/gatt_client.h +++ b/ble/gatt_client.h @@ -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 } diff --git a/example/libusb/ancs_client_lib.c b/example/libusb/ancs_client_lib.c index aec04988f..f590990f2 100644 --- a/example/libusb/ancs_client_lib.c +++ b/example/libusb/ancs_client_lib.c @@ -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); } diff --git a/example/libusb/gatt_battery_query.c b/example/libusb/gatt_battery_query.c index 405ee879e..169b6bba1 100644 --- a/example/libusb/gatt_battery_query.c +++ b/example/libusb/gatt_battery_query.c @@ -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); diff --git a/example/libusb/gatt_browser.c b/example/libusb/gatt_browser.c index 21eda5c7b..6eb0c484e 100644 --- a/example/libusb/gatt_browser.c +++ b/example/libusb/gatt_browser.c @@ -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); diff --git a/platforms/posix/src/daemon.c b/platforms/posix/src/daemon.c index dd45ee698..3d517ecad 100644 --- a/platforms/posix/src/daemon.c +++ b/platforms/posix/src/daemon.c @@ -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);