static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(packet_type); UNUSED(channel); UNUSED(size); gatt_client_service_t service; gatt_client_characteristic_t characteristic; switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT:\ gatt_event_service_query_result_get_service(packet, &service); dump_service(&service); services[service_count++] = service; break; case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); dump_characteristic(&characteristic); break; case GATT_EVENT_QUERY_COMPLETE: if (search_services){ // GATT_EVENT_QUERY_COMPLETE of search services service_index = 0; printf("\nGATT browser - CHARACTERISTIC for SERVICE %s\n", uuid128_to_str(service.uuid128)); search_services = 0; gatt_client_discover_characteristics_for_service(handle_gatt_client_event, connection_handler, &services[service_index]); } else { // GATT_EVENT_QUERY_COMPLETE of search characteristics if (service_index < service_count) { service = services[service_index++]; printf("\nGATT browser - CHARACTERISTIC for SERVICE %s, [0x%04x-0x%04x]\n", uuid128_to_str(service.uuid128), service.start_group_handle, service.end_group_handle); gatt_client_discover_characteristics_for_service(handle_gatt_client_event, connection_handler, &service); break; } service_index = 0; gap_disconnect(connection_handler); } break; default: break; } }
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(packet_type); UNUSED(channel); UNUSED(size); int status; char message[30]; switch(state){ case TC_W4_SERVICE_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT: gatt_event_service_query_result_get_service(packet, &le_counter_service); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } state = TC_W4_CHARACTERISTIC_RESULT; printf("Search for counter characteristic.\n"); gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_counter_service, le_counter_characteristic_uuid); break; default: break; } break; case TC_W4_CHARACTERISTIC_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &le_counter_characteristic); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } state = TC_W4_SUBSCRIBED; printf("Configure counter for notify.\n"); status = gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle, &le_counter_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; default: break; } break; case TC_W4_SUBSCRIBED: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_QUERY_COMPLETE: // register handler for notifications state = TC_SUBSCRIBED; printf("Subscribed, start listening\n"); gatt_client_listen_for_characteristic_value_updates(¬ification_listener, handle_gatt_client_event, connection_handle, &le_counter_characteristic); break; default: break; } break; case TC_SUBSCRIBED: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_NOTIFICATION: memset(message, 0, sizeof(message)); memcpy(message, gatt_event_notification_get_value(packet), gatt_event_notification_get_value_length(packet)); printf("COUNTER: %s\n", message); log_info("COUNTER: %s", message); break; default: break; } default: break; } fflush(stdout); }
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ int status; uint8_t battery_level; switch(state){ case TC_W4_SERVICE_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT: gatt_event_service_query_result_get_service(packet, &battery_service); dump_service(&battery_service); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); add_to_blacklist(report.address); gap_disconnect(connection_handle); break; } state = TC_W4_CHARACTERISTIC_RESULT; printf("\nSearch for battery level characteristic.\n"); gatt_client_discover_characteristics_for_service_by_uuid16(handle_gatt_client_event, connection_handle, &battery_service, battery_level_characteristic_uuid); break; default: break; } break; case TC_W4_CHARACTERISTIC_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &config_characteristic); dump_characteristic(&config_characteristic); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); add_to_blacklist(report.address); gap_disconnect(connection_handle); break; } state = TC_W4_BATTERY_DATA; printf("\nConfigure battery level characteristic for notify.\n"); status = gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle, &config_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); if (status != 0){ printf("\nNotification not supported. Query value of characteristic.\n"); gatt_client_read_value_of_characteristic(handle_gatt_client_event, connection_handle, &config_characteristic); } break; default: break; } break; case TC_W4_BATTERY_DATA: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_NOTIFICATION: printf("\nBattery Data:\n"); dump_characteristic_value(&packet[8], little_endian_read_16(packet, 6)); break; case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: if (gatt_event_characteristic_value_query_result_get_value_length(packet) < 1) break; battery_level = gatt_event_characteristic_value_query_result_get_value(packet)[0]; printf("Battry level %d \n", battery_level); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_VALUE_QUERY_RESULT - Error status %x.\n", packet[4]); break; } // Use timer if repeated request is needed and notification is not supperted gap_disconnect(connection_handle); break; default: printf("Unknown packet type %x\n", hci_event_packet_get_type(packet)); break; } break; default: printf("error\n"); break; } }
static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(packet_type); UNUSED(channel); UNUSED(size); int connection_encrypted; // handle connect / disconncet events first switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_LE_META: switch (packet[2]) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: gc_handle = little_endian_read_16(packet, 4); log_info("Connection handle 0x%04x, request encryption", gc_handle); // we need to be paired to enable notifications tc_state = TC_W4_ENCRYPTED_CONNECTION; sm_send_security_request(gc_handle); break; default: break; } return; case HCI_EVENT_ENCRYPTION_CHANGE: if (gc_handle != little_endian_read_16(packet, 3)) return; connection_encrypted = packet[5]; log_info("Encryption state change: %u", connection_encrypted); if (!connection_encrypted) return; if (tc_state != TC_W4_ENCRYPTED_CONNECTION) return; // let's start log_info("\nANCS Client - CONNECTED, discover ANCS service"); tc_state = TC_W4_SERVICE_RESULT; gatt_client_discover_primary_services_by_uuid128(handle_hci_event, gc_handle, ancs_service_uuid); return; case HCI_EVENT_DISCONNECTION_COMPLETE: if (hci_event_disconnection_complete_get_connection_handle(packet) != gc_handle) break; if (tc_state == TC_SUBSCRIBED){ notify_client_simple(ANCS_SUBEVENT_CLIENT_DISCONNECTED); } tc_state = TC_IDLE; gc_handle = 0; return; default: break; } gatt_client_characteristic_t characteristic; uint8_t * value; uint16_t value_handle; uint16_t value_length; switch(tc_state){ case TC_W4_SERVICE_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT: gatt_event_service_query_result_get_service(packet, &ancs_service); ancs_service_found = 1; break; case GATT_EVENT_QUERY_COMPLETE: if (!ancs_service_found){ log_info("ANCS Service not found"); tc_state = TC_IDLE; break; } tc_state = TC_W4_CHARACTERISTIC_RESULT; log_info("ANCS Client - Discover characteristics for ANCS SERVICE "); gatt_client_discover_characteristics_for_service(handle_hci_event, gc_handle, &ancs_service); break; default: break; } break; case TC_W4_CHARACTERISTIC_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0){ log_info("ANCS Notification Source found, attribute handle %u", characteristic.value_handle); ancs_notification_source_characteristic = characteristic; ancs_characteristcs++; break; } if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0){ log_info("ANCS Control Point found, attribute handle %u", characteristic.value_handle); ancs_control_point_characteristic = characteristic; ancs_characteristcs++; break; } if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0){ log_info("ANCS Data Source found, attribute handle %u", characteristic.value_handle); ancs_data_source_characteristic = characteristic; ancs_characteristcs++; break; } break; case GATT_EVENT_QUERY_COMPLETE: log_info("ANCS Characteristcs count %u", ancs_characteristcs); tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED; gatt_client_listen_for_characteristic_value_updates(&ancs_notification_source_notification, &handle_hci_event, gc_handle, &ancs_notification_source_characteristic); gatt_client_write_client_characteristic_configuration(handle_hci_event, gc_handle, &ancs_notification_source_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; default: break; } break; case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_QUERY_COMPLETE: log_info("ANCS Notification Source subscribed"); tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED; gatt_client_listen_for_characteristic_value_updates(&ancs_data_source_notification, &handle_hci_event, gc_handle, &ancs_data_source_characteristic); gatt_client_write_client_characteristic_configuration(handle_hci_event, gc_handle, &ancs_data_source_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; default: break; } break; case TC_W4_DATA_SOURCE_SUBSCRIBED: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_QUERY_COMPLETE: log_info("ANCS Data Source subscribed"); tc_state = TC_SUBSCRIBED; notify_client_simple(ANCS_SUBEVENT_CLIENT_CONNECTED); break; default: break; } break; case TC_SUBSCRIBED: if (hci_event_packet_get_type(packet) != GATT_EVENT_NOTIFICATION && hci_event_packet_get_type(packet) != GATT_EVENT_INDICATION ) break; value_handle = little_endian_read_16(packet, 4); value_length = little_endian_read_16(packet, 6); value = &packet[8]; log_info("ANCS Notification, value handle %u", value_handle); if (value_handle == ancs_data_source_characteristic.value_handle){ int i; for (i=0;i<value_length;i++) { ancs_chunk_parser_handle_byte(value[i]); } } else if (value_handle == ancs_notification_source_characteristic.value_handle){ ancs_notification_uid = little_endian_read_32(value, 4); log_info("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x", value[0], value[1], value[2], value[3], (int) ancs_notification_uid); static uint8_t get_notification_attributes[] = {0, 0,0,0,0, 0, 1,32,0, 2,32,0, 3,32,0, 4, 5}; little_endian_store_32(get_notification_attributes, 1, ancs_notification_uid); ancs_notification_uid = 0; ancs_chunk_parser_init(); gatt_client_write_value_of_characteristic(handle_hci_event, gc_handle, ancs_control_point_characteristic.value_handle, sizeof(get_notification_attributes), get_notification_attributes); } else { log_info("Unknown Source: "); log_info_hexdump(value , value_length); } break; default: break; } // app_run(); }
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(packet_type); UNUSED(channel); UNUSED(size); uint16_t mtu; switch(state){ case TC_W4_SERVICE_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_SERVICE_QUERY_RESULT: // store service (we expect only one) gatt_event_service_query_result_get_service(packet, &le_streamer_service); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } // service query complete, look for characteristic state = TC_W4_CHARACTERISTIC_RX_RESULT; printf("Search for LE Streamer RX characteristic.\n"); gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_streamer_service, le_streamer_characteristic_rx_uuid); break; default: break; } break; case TC_W4_CHARACTERISTIC_RX_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &le_streamer_characteristic_rx); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } // rx characteristiic found, look for tx characteristic state = TC_W4_CHARACTERISTIC_TX_RESULT; printf("Search for LE Streamer TX characteristic.\n"); gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_streamer_service, le_streamer_characteristic_tx_uuid); break; default: break; } break; case TC_W4_CHARACTERISTIC_TX_RESULT: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: gatt_event_characteristic_query_result_get_characteristic(packet, &le_streamer_characteristic_tx); break; case GATT_EVENT_QUERY_COMPLETE: if (packet[4] != 0){ printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); gap_disconnect(connection_handle); break; } // register handler for notifications listener_registered = 1; gatt_client_listen_for_characteristic_value_updates(¬ification_listener, handle_gatt_client_event, connection_handle, &le_streamer_characteristic_tx); // setup tracking le_streamer_connection.name = 'A'; le_streamer_connection.test_data_len = ATT_DEFAULT_MTU - 3; test_reset(&le_streamer_connection); gatt_client_get_mtu(connection_handle, &mtu); le_streamer_connection.test_data_len = btstack_min(mtu - 3, sizeof(le_streamer_connection.test_data)); printf("%c: ATT MTU = %u => use test data of len %u\n", le_streamer_connection.name, mtu, le_streamer_connection.test_data_len); // enable notifications #if (TEST_MODE & TEST_MODE_ENABLE_NOTIFICATIONS) printf("Start streaming - enable notify on test characteristic.\n"); state = TC_W4_ENABLE_NOTIFICATIONS_COMPLETE; gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle, &le_streamer_characteristic_tx, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; #endif state = TC_W4_TEST_DATA; #if (TEST_MODE & TEST_MODE_WRITE_WITHOUT_RESPONSE) printf("Start streaming - request can send now.\n"); gatt_client_request_can_write_without_response_event(handle_gatt_client_event, connection_handle); #endif break; default: break; } break; case TC_W4_ENABLE_NOTIFICATIONS_COMPLETE: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_QUERY_COMPLETE: printf("Notifications enabled, status %02x\n", gatt_event_query_complete_get_status(packet)); state = TC_W4_TEST_DATA; #if (TEST_MODE & TEST_MODE_WRITE_WITHOUT_RESPONSE) printf("Start streaming - request can send now.\n"); gatt_client_request_can_write_without_response_event(handle_gatt_client_event, connection_handle); #endif break; default: break; } break; case TC_W4_TEST_DATA: switch(hci_event_packet_get_type(packet)){ case GATT_EVENT_NOTIFICATION: test_track_data(&le_streamer_connection, gatt_event_notification_get_value_length(packet)); break; case GATT_EVENT_QUERY_COMPLETE: break; case GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE: streamer(&le_streamer_connection); break; default: printf("Unknown packet type %x\n", hci_event_packet_get_type(packet)); break; } break; default: printf("error\n"); break; } }