static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); bd_addr_t local_addr; switch (packet_type) { case HCI_EVENT_PACKET: switch (packet[0]) { case BTSTACK_EVENT_STATE: // bt stack activated, get started if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ gap_local_bd_addr(local_addr); printf("BD_ADDR: %s\n", bd_addr_to_str(local_addr)); // generate OOB data sm_generate_sc_oob_data(sc_local_oob_generated_callback); } break; case HCI_EVENT_LE_META: switch (hci_event_le_meta_get_subevent_code(packet)) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: connection_handle = little_endian_read_16(packet, 4); printf("CONNECTED: Connection handle 0x%04x\n", connection_handle); break; default: break; } break; case HCI_EVENT_DISCONNECTION_COMPLETE: break; case SM_EVENT_JUST_WORKS_REQUEST: printf("JUST_WORKS_REQUEST\n"); break; case SM_EVENT_NUMERIC_COMPARISON_REQUEST: printf("NUMERIC_COMPARISON_REQUEST\n"); break; case SM_EVENT_PASSKEY_INPUT_NUMBER: // display number printf("PASSKEY_INPUT_NUMBER\n"); ui_passkey = 0; ui_digits_for_passkey = 6; sm_keypress_notification(connection_handle, SM_KEYPRESS_PASSKEY_ENTRY_STARTED); break; case SM_EVENT_PASSKEY_DISPLAY_NUMBER: // display number printf("PASSKEY_DISPLAY_NUMBER: %06u\n", little_endian_read_32(packet, 11)); break; case SM_EVENT_PASSKEY_DISPLAY_CANCEL: break; case SM_EVENT_AUTHORIZATION_REQUEST: break; case SM_EVENT_PAIRING_COMPLETE: printf("\nPAIRING_COMPLETE: %u,%u\n", sm_event_pairing_complete_get_status(packet), sm_event_pairing_complete_get_reason(packet)); if (sm_event_pairing_complete_get_status(packet)) break; if (we_are_central){ printf("Search for LE Counter service.\n"); state = TC_W4_SERVICE_RESULT; gatt_client_discover_primary_services_by_uuid128(handle_gatt_client_event, connection_handle, le_counter_service_uuid); } break; case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE: break; case ATT_EVENT_CAN_SEND_NOW: att_server_notify(connection_handle, ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE, (uint8_t *) "Pairing Success!", 16); break; default: break; } } fflush(stdout); }
static void handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){ le_command_status_t status; if (packet_type != HCI_EVENT_PACKET) return; switch (packet[0]) { case HCI_EVENT_DISCONNECTION_COMPLETE: printf("test client - DISCONNECTED\n"); break; case GAP_LE_ADVERTISING_REPORT: if (tc_state != TC_W4_SCAN_RESULT) return; printf("test client - SCAN ACTIVE\n"); ad_event_t ad_event; int pos = 2; ad_event.event_type = packet[pos++]; ad_event.address_type = packet[pos++]; memcpy(ad_event.address, &packet[pos], 6); pos += 6; ad_event.rssi = packet[pos++]; ad_event.length = packet[pos++]; ad_event.data = &packet[pos]; pos += ad_event.length; dump_ad_event(&ad_event); test_device_addr_type = ad_event.address_type; bd_addr_t found_device_addr; memcpy(found_device_addr, ad_event.address, 6); swapX(ad_event.address, found_device_addr, 6); if (memcmp(&found_device_addr, &sensor_tag1_addr, 6) == 0 || memcmp(&found_device_addr, &sensor_tag2_addr, 6) == 0) { tc_state = TC_W4_CONNECT; le_central_stop_scan(); le_central_connect(&found_device_addr, test_device_addr_type); } break; case BTSTACK_EVENT_STATE: // BTstack activated, get started if (packet[2] == HCI_STATE_WORKING) { printf("BTstack activated, get started!\n"); tc_state = TC_W4_SCAN_RESULT; le_central_start_scan(); } break; case HCI_EVENT_LE_META: switch (packet[2]) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: { if (tc_state != TC_W4_CONNECT) return; tc_state = TC_W4_SERVICE_RESULT; printf("\n test client - CONNECTED, query ACC service\n"); test_gatt_client_handle = READ_BT_16(packet, 4); gatt_client_start(&test_gatt_client_context, test_gatt_client_handle); // let's start gatt_client_discover_primary_services_by_uuid128(&test_gatt_client_context, acc_service_uuid); break; } default: break; } break; case DAEMON_EVENT_HCI_PACKET_SENT: switch(tc_state){ case TC_W2_WRITE_WITHOUT_RESPONSE: status = gatt_client_write_value_of_characteristic_without_response(&test_gatt_client_context, characteristic.value_handle, 1, chr_short_value); if (status != BLE_PERIPHERAL_OK) break; tc_state = TC_W4_READ_LONG_RESULT; gatt_client_read_long_value_of_characteristic(&test_gatt_client_context, &characteristic); default: break; } default: 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(le_event_t * event) { uint8_t * packet = (uint8_t*) event; int connection_encrypted; // handle connect / disconncet events first switch (packet[0]) { case HCI_EVENT_LE_META: switch (packet[2]) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: gc_handle = READ_BT_16(packet, 4); printf("Connection handle 0x%04x, request encryption\n", 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 != READ_BT_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 printf("\nANCS Client - CONNECTED, discover ANCS service\n"); tc_state = TC_W4_SERVICE_RESULT; gatt_client_discover_primary_services_by_uuid128(gc_id, gc_handle, ancs_service_uuid); return; case HCI_EVENT_DISCONNECTION_COMPLETE: notify_client(ANCS_CLIENT_DISCONNECTED); return; default: break; } le_characteristic_t characteristic; le_characteristic_value_event_t * value_event; switch(tc_state) { case TC_W4_SERVICE_RESULT: switch(event->type) { case GATT_SERVICE_QUERY_RESULT: ancs_service = ((le_service_event_t *) event)->service; ancs_service_found = 1; break; case GATT_QUERY_COMPLETE: if (!ancs_service_found) { printf("ANCS Service not found"); tc_state = TC_IDLE; break; } tc_state = TC_W4_CHARACTERISTIC_RESULT; printf("ANCS Client - Discover characteristics for ANCS SERVICE \n"); gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &ancs_service); break; default: break; } break; case TC_W4_CHARACTERISTIC_RESULT: switch(event->type) { case GATT_CHARACTERISTIC_QUERY_RESULT: characteristic = ((le_characteristic_event_t *) event)->characteristic; if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0) { printf("ANCS Notification Source Characterisic found\n"); ancs_notification_source_characteristic = characteristic; ancs_characteristcs++; break; } if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0) { printf("ANCS Control Point found\n"); ancs_control_point_characteristic = characteristic; ancs_characteristcs++; break; } if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0) { printf("ANCS Data Source Characterisic found\n"); ancs_data_source_characteristic = characteristic; ancs_characteristcs++; break; } break; 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_id, gc_handle, &ancs_notification_source_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; default: break; } break; case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED: switch(event->type) { case GATT_QUERY_COMPLETE: printf("ANCS Notification Source subscribed\n"); tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED; gatt_client_write_client_characteristic_configuration(gc_id, gc_handle, &ancs_data_source_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); break; default: break; } break; case TC_W4_DATA_SOURCE_SUBSCRIBED: switch(event->type) { case GATT_QUERY_COMPLETE: printf("ANCS Data Source subscribed\n"); tc_state = TC_SUBSCRIBED; notify_client(ANCS_CLIENT_CONNECTED); break; default: break; } break; case TC_SUBSCRIBED: if ( event->type != GATT_NOTIFICATION && event->type != GATT_INDICATION ) break; value_event = (le_characteristic_value_event_t *) event; if (value_event->value_handle == ancs_data_source_characteristic.value_handle) { int i; for (i=0; i<value_event->blob_length; i++) { ancs_chunk_parser_handle_byte(value_event->blob[i]); } } else if (value_event->value_handle == ancs_notification_source_characteristic.value_handle) { ancs_notification_uid = READ_BT_32(value_event->blob, 4); printf("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x\n", value_event->blob[0], value_event->blob[1], value_event->blob[2], value_event->blob[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}; 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_id, gc_handle, ancs_control_point_characteristic.value_handle, sizeof(get_notification_attributes), get_notification_attributes); } else { printf("Unknown Source: "); printf_hexdump(value_event->blob , value_event->blob_length); } break; default: break; } // app_run(); }
static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); if (packet_type != HCI_EVENT_PACKET) return; uint16_t conn_interval; uint8_t event = hci_event_packet_get_type(packet); switch (event) { case BTSTACK_EVENT_STATE: // BTstack activated, get started if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) { le_streamer_client_start(); } else { state = TC_OFF; } break; case GAP_EVENT_ADVERTISING_REPORT: if (state != TC_W4_SCAN_RESULT) return; // check name in advertisement if (!advertisement_report_contains_name("LE Streamer", packet)) return; // store address and type gap_event_advertising_report_get_address(packet, le_streamer_addr); le_streamer_addr_type = gap_event_advertising_report_get_address_type(packet); // stop scanning, and connect to the device state = TC_W4_CONNECT; gap_stop_scan(); printf("Stop scan. Connect to device with addr %s.\n", bd_addr_to_str(le_streamer_addr)); gap_connect(le_streamer_addr,le_streamer_addr_type); break; case HCI_EVENT_LE_META: // wait for connection complete if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; if (state != TC_W4_CONNECT) return; connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); // print connection parameters (without using float operations) conn_interval = hci_subevent_le_connection_complete_get_conn_interval(packet); printf("Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3)); printf("Connection Latency: %u\n", hci_subevent_le_connection_complete_get_conn_latency(packet)); // initialize gatt client context with handle, and add it to the list of active clients // query primary services printf("Search for LE Streamer service.\n"); state = TC_W4_SERVICE_RESULT; gatt_client_discover_primary_services_by_uuid128(handle_gatt_client_event, connection_handle, le_streamer_service_uuid); break; case HCI_EVENT_DISCONNECTION_COMPLETE: // unregister listener connection_handle = HCI_CON_HANDLE_INVALID; if (listener_registered){ listener_registered = 0; gatt_client_stop_listening_for_characteristic_value_updates(¬ification_listener); } if (cmdline_addr_found){ printf("Disconnected %s\n", bd_addr_to_str(cmdline_addr)); return; } printf("Disconnected %s\n", bd_addr_to_str(le_streamer_addr)); if (state == TC_OFF) break; le_streamer_client_start(); break; default: break; } }