void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){ int i; for (i=0;i<record_handle_count;i++){ record_handle = big_endian_read_32(data, i*4); record_counter++; uint8_t event[10]; event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE; event[1] = 8; little_endian_store_16(event, 2, total_count); little_endian_store_16(event, 4, record_counter); little_endian_store_32(event, 6, record_handle); (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } }
static void little_endian_fstore_16(FILE * file, uint16_t value){ uint8_t buf[2]; little_endian_store_32(buf, 0, value); fwrite(&buf, 1, 2, file); }
static void little_endian_fstore_32(FILE * file, uint32_t value){ uint8_t buf[4]; little_endian_store_32(buf, 0, value); fwrite(&buf, 1, 4, file); }
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(); }
void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { if (dump_file < 0) return; // not activated yet #ifdef HAVE_POSIX_FILE_IO // don't grow bigger than max_nr_packets if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){ if (nr_packets >= max_nr_packets){ lseek(dump_file, 0, SEEK_SET); ftruncate(dump_file, 0); nr_packets = 0; } nr_packets++; } // get time struct timeval curr_time; struct tm* ptm; gettimeofday(&curr_time, NULL); time_t curr_time_secs = curr_time.tv_sec; switch (dump_format){ case HCI_DUMP_STDOUT: { /* Obtain the time of day, and convert it to a tm struct. */ ptm = localtime (&curr_time_secs); /* assert localtime was successful */ if (!ptm) break; /* Format the date and time, down to a single second. */ strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm); /* Compute milliseconds from microseconds. */ uint16_t milliseconds = curr_time.tv_usec / 1000; /* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */ printf ("%s.%03u] ", time_string, milliseconds); printf_packet(packet_type, in, packet, len); break; } case HCI_DUMP_BLUEZ: little_endian_store_16( header_bluez, 0, 1 + len); header_bluez[2] = in; header_bluez[3] = 0; little_endian_store_32( header_bluez, 4, (uint32_t) curr_time.tv_sec); little_endian_store_32( header_bluez, 8, curr_time.tv_usec); header_bluez[12] = packet_type; write (dump_file, header_bluez, HCIDUMP_HDR_SIZE); write (dump_file, packet, len ); break; case HCI_DUMP_PACKETLOGGER: big_endian_store_32( header_packetlogger, 0, PKTLOG_HDR_SIZE - 4 + len); big_endian_store_32( header_packetlogger, 4, (uint32_t) curr_time.tv_sec); big_endian_store_32( header_packetlogger, 8, curr_time.tv_usec); switch (packet_type){ case HCI_COMMAND_DATA_PACKET: header_packetlogger[12] = 0x00; break; case HCI_ACL_DATA_PACKET: if (in) { header_packetlogger[12] = 0x03; } else { header_packetlogger[12] = 0x02; } break; case HCI_SCO_DATA_PACKET: if (in) { header_packetlogger[12] = 0x09; } else { header_packetlogger[12] = 0x08; } break; case HCI_EVENT_PACKET: header_packetlogger[12] = 0x01; break; case LOG_MESSAGE_PACKET: header_packetlogger[12] = 0xfc; break; default: return; } write (dump_file, &header_packetlogger, PKTLOG_HDR_SIZE); write (dump_file, packet, len ); break; default: break; } #else // #ifdef HAVE_EMBEDDED_TICK // uint32_t time_ms = btstack_run_loop_embedded_get_time_ms(); // printf("[%06u] ", time_ms); // #endif printf_packet(packet_type, in, packet, len); #endif }