static void emit_mtu_exchange_complete(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle, uint16_t new_mtu){ if (!packet_handler) return; uint8_t packet[6]; packet[0] = ATT_EVENT_MTU_EXCHANGE_COMPLETE; packet[1] = sizeof(packet) - 2; little_endian_store_16(packet, 2, con_handle); little_endian_store_16(packet, 4, new_mtu); packet_handler(HCI_EVENT_PACKET, con_handle, packet, 1); }
// SDP Parser static void sdp_parser_emit_value_byte(uint8_t event_byte){ uint8_t event[11]; event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE; event[1] = 9; little_endian_store_16(event, 2, record_counter); little_endian_store_16(event, 4, attribute_id); little_endian_store_16(event, 6, attribute_value_size); little_endian_store_16(event, 8, attribute_bytes_delivered); event[10] = event_byte; (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); }
static void notify_client_text(int event_type){ if (!client_handler) return; uint8_t event[7 + sizeof(ancs_notification_buffer) + 1]; event[0] = HCI_EVENT_ANCS_META; event[1] = 5 + ancs_attribute_len; event[2] = event_type; little_endian_store_16(event, 3, gc_handle); little_endian_store_16(event, 5, ancs_attribute_id); memcpy(&event[7], ancs_notification_buffer, ancs_attribute_len); // we're nice event[7+ancs_attribute_len] = 0; (*client_handler)(HCI_EVENT_PACKET, 0, event, event[1] + 2); }
static void att_emit_mtu_event(hci_con_handle_t con_handle, uint16_t mtu){ if (!att_client_packet_handler) return; uint8_t event[6]; int pos = 0; event[pos++] = ATT_EVENT_MTU_EXCHANGE_COMPLETE; event[pos++] = sizeof(event) - 2; little_endian_store_16(event, pos, con_handle); pos += 2; little_endian_store_16(event, pos, mtu); att_dispatch_server_mtu_exchanged(con_handle, mtu); (*att_client_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); }
static void att_handle_value_indication_notify_client(uint8_t status, uint16_t client_handle, uint16_t attribute_handle){ if (!att_client_packet_handler) return; uint8_t event[7]; int pos = 0; event[pos++] = ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE; event[pos++] = sizeof(event) - 2; event[pos++] = status; little_endian_store_16(event, pos, client_handle); pos += 2; little_endian_store_16(event, pos, attribute_handle); (*att_client_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); }
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 att_server_persistent_ccc_restore(att_server_t * att_server){ if (!att_server) return; int le_device_index = att_server->ir_le_device_db_index; log_info("Restore CCC values of remote %s, le device id %d", bd_addr_to_str(att_server->peer_address), le_device_index); // check if bonded if (le_device_index < 0) return; // get btstack_tlv const btstack_tlv_t * tlv_impl = NULL; void * tlv_context; btstack_tlv_get_instance(&tlv_impl, &tlv_context); if (!tlv_impl) return; // get all ccc tag int index; persistent_ccc_entry_t entry; for (index=0;index<NVN_NUM_GATT_SERVER_CCC;index++){ uint32_t tag = att_server_persistent_ccc_tag_for_index(index); int len = tlv_impl->get_tag(tlv_context, tag, (uint8_t *) &entry, sizeof(persistent_ccc_entry_t)); if (len != sizeof(persistent_ccc_entry_t)) continue; if (entry.device_index != le_device_index) continue; // simulate write callback uint16_t attribute_handle = entry.att_handle; uint8_t value[2]; little_endian_store_16(value, 0, entry.value); att_write_callback_t callback = att_server_write_callback_for_handle(attribute_handle); if (!callback) continue; log_info("CCC Index %u: Set Attribute handle 0x%04x to value 0x%04x", index, attribute_handle, entry.value ); (*callback)(att_server->connection.con_handle, attribute_handle, ATT_TRANSACTION_MODE_NONE, 0, value, sizeof(value)); } }
static int host_recv_pkt_cb(uint8_t *data, uint16_t len){ if (xPortInIsrContext()){ report_recv_called_from_isr(); return 0; } xSemaphoreTake(ring_buffer_mutex, portMAX_DELAY); // check space uint16_t space = btstack_ring_buffer_bytes_free(&hci_ringbuffer); if (space < len){ xSemaphoreGive(ring_buffer_mutex); log_error("transport_recv_pkt_cb packet %u, space %u -> dropping packet", len, space); return 0; } // store size in ringbuffer uint8_t len_tag[2]; little_endian_store_16(len_tag, 0, len); btstack_ring_buffer_write(&hci_ringbuffer, len_tag, sizeof(len_tag)); // store in ringbuffer btstack_ring_buffer_write(&hci_ringbuffer, data, len); xSemaphoreGive(ring_buffer_mutex); // set flag and trigger delivery of packets on main thread transport_packets_to_deliver = 1; btstack_run_loop_freertos_trigger(); return 0; }
static void notify_client_simple(int event_type){ if (!client_handler) return; uint8_t event[5]; event[0] = HCI_EVENT_ANCS_META; event[1] = 3; event[2] = event_type; little_endian_store_16(event, 3, gc_handle); (*client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); }
static void emit_event_audio_connected(uint8_t status, uint16_t handle){ if (!hsp_hs_callback) return; uint8_t event[6]; event[0] = HCI_EVENT_HSP_META; event[1] = sizeof(event) - 2; event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE; event[3] = status; little_endian_store_16(event, 4, handle); (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); }
// 8 kHz samples for CVSD/SCO packets in little endian static void sco_demo_sine_wave_int16_at_8000_hz_little_endian(unsigned int num_samples, uint8_t * data){ unsigned int i; for (i=0; i < num_samples; i++){ int16_t sample = sine_int16_at_16000hz[phase]; little_endian_store_16(data, i * 2, sample); // ony use every second sample from 16khz table to get 8khz phase += 2; if (phase >= (sizeof(sine_int16_at_16000hz) / sizeof(int16_t))){ phase = 0; } } }
static void a2dp_streaming_emit_can_send_media_packet_now(btstack_packet_handler_t callback, uint16_t cid, uint8_t seid){ if (!callback) return; uint8_t event[8]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW; little_endian_store_16(event, pos, cid); pos += 2; event[pos++] = seid; (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); }
// set requested baud rate static void update_init_script_command(uint8_t *hci_cmd_buffer){ uint16_t varid = little_endian_read_16(hci_cmd_buffer, 10); if (varid != 0x7003) return; uint16_t key = little_endian_read_16(hci_cmd_buffer, 14); log_info("csr: pskey 0x%04x", key); if (key != 0x01ea) return; // check for baud rate if (!hci_transport_config_uart) return; uint32_t baudrate = hci_transport_config_uart->baudrate_main; if (baudrate == 0){ baudrate = hci_transport_config_uart->baudrate_init; } // uint32_t is stored as 2 x uint16_t with most important 16 bits first little_endian_store_16(hci_cmd_buffer, 20, baudrate >> 16); little_endian_store_16(hci_cmd_buffer, 22, baudrate & 0xffff); }
static uint16_t battery_service_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ UNUSED(offset); UNUSED(buffer_size); if (attribute_handle == battery_value_handle_value){ if (buffer) { buffer[0] = battery_value; } return 1; } if (attribute_handle == battery_value_handle_client_configuration){ if (buffer){ little_endian_store_16(buffer, 0, battery_value_client_configuration); battery_value_client_configuration_connection = con_handle; } return 2; } return 0; }
void sco_demo_send(hci_con_handle_t sco_handle){ if (!sco_handle) return; const int sco_packet_length = 24 + 3; // hci_get_sco_packet_length(); const int sco_payload_length = sco_packet_length - 3; hci_reserve_packet_buffer(); uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); // set handle + flags little_endian_store_16(sco_packet, 0, sco_handle); // set len sco_packet[2] = sco_payload_length; const int frames_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE int i; for (i=0;i<frames_per_packet;i++){ sco_packet[3+i] = sine[phase]; phase++; if (phase >= sizeof(sine)) phase = 0; } #else #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII memset(&sco_packet[3], phase++, frames_per_packet); if (phase > 'z') phase = 'a'; #else int j; for (j=0;j<frames_per_packet;j++){ sco_packet[3+j] = phase++; } #endif #endif hci_send_sco_packet_buffer(sco_packet_length); // request another send event hci_request_sco_can_send_now_event(); count_sent++; if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); }
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); uint8_t signal_identifier; uint8_t status; uint8_t local_seid; uint8_t remote_seid; uint16_t cid; bd_addr_t address; if (packet_type != HCI_EVENT_PACKET) return; if (hci_event_packet_get_type(packet) != HCI_EVENT_AVDTP_META) return; switch (packet[2]){ case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED: avdtp_subevent_signaling_connection_established_get_bd_addr(packet, sc.remote_addr); cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet); status = avdtp_subevent_signaling_connection_established_get_status(packet); if (status != 0){ log_info("AVDTP_SUBEVENT_SIGNALING_CONNECTION failed status %d ---", status); a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, status); break; } sc.active_remote_sep = NULL; next_remote_sep_index_to_query = 0; if (!sc.local_stream_endpoint) { app_state = A2DP_CONNECTED; uint8_t event[11]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED; little_endian_store_16(event, pos, cid); pos += 2; reverse_bd_addr(event+pos, sc.remote_addr); pos += 6; (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); return; } app_state = A2DP_W2_DISCOVER_SEPS; avdtp_source_discover_stream_endpoints(cid); break; case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND: break; case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:{ if (!sc.local_stream_endpoint) { // printf("local seid %d \n", avdtp_subevent_signaling_media_codec_sbc_capability_get_local_seid(packet)); return; } uint8_t sampling_frequency = avdtp_choose_sbc_sampling_frequency(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet)); uint8_t channel_mode = avdtp_choose_sbc_channel_mode(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet)); uint8_t block_length = avdtp_choose_sbc_block_length(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet)); uint8_t subbands = avdtp_choose_sbc_subbands(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet)); uint8_t allocation_method = avdtp_choose_sbc_allocation_method(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet)); uint8_t max_bitpool_value = avdtp_choose_sbc_max_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet)); uint8_t min_bitpool_value = avdtp_choose_sbc_min_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet)); sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[0] = (sampling_frequency << 4) | channel_mode; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[1] = (block_length << 4) | (subbands << 2) | allocation_method; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[2] = min_bitpool_value; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[3] = max_bitpool_value; sc.local_stream_endpoint->remote_configuration_bitmap = store_bit16(sc.local_stream_endpoint->remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1); sc.local_stream_endpoint->remote_configuration.media_codec.media_type = AVDTP_AUDIO; sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC; app_state = A2DP_W2_SET_CONFIGURATION; break; } case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY: log_info("received non SBC codec. not implemented"); break; case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{ // TODO check cid sc.sampling_frequency = avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet); sc.block_length = avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet); sc.subbands = avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet); sc.allocation_method = avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet) - 1; sc.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet); sc.channel_mode = avdtp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet); // TODO: deal with reconfigure: avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet); break; } case AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW: cid = avdtp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(packet); a2dp_streaming_emit_can_send_media_packet_now(a2dp_source_context.a2dp_callback, cid, 0); break; case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED: avdtp_subevent_streaming_connection_established_get_bd_addr(packet, address); status = avdtp_subevent_streaming_connection_established_get_status(packet); cid = avdtp_subevent_streaming_connection_established_get_avdtp_cid(packet); remote_seid = avdtp_subevent_streaming_connection_established_get_remote_seid(packet); local_seid = avdtp_subevent_streaming_connection_established_get_local_seid(packet); if (status != 0){ log_info("AVDTP_SUBEVENT_STREAMING_CONNECTION could not be established, status %d ---", status); a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, address, local_seid, remote_seid, status); break; } app_state = A2DP_STREAMING_OPENED; a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, address, local_seid, remote_seid, 0); log_info("AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED --- avdtp_cid 0x%02x, local seid %d, remote seid %d", cid, local_seid, remote_seid); break; case AVDTP_SUBEVENT_SIGNALING_ACCEPT: // TODO check cid signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet); cid = avdtp_subevent_signaling_accept_get_avdtp_cid(packet); log_info("Accepted %d", signal_identifier); switch (app_state){ case A2DP_W2_DISCOVER_SEPS: app_state = A2DP_W2_GET_ALL_CAPABILITIES; sc.active_remote_sep = avdtp_source_remote_sep(cid, next_remote_sep_index_to_query++); if (!sc.active_remote_sep) { app_state = A2DP_IDLE; a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); break; } // printf("Query get caps for seid %d\n", sc.active_remote_sep->seid); avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); break; case A2DP_W2_GET_CAPABILITIES: case A2DP_W2_GET_ALL_CAPABILITIES: if (next_remote_sep_index_to_query < avdtp_source_remote_seps_num(cid)){ sc.active_remote_sep = avdtp_source_remote_sep(cid, next_remote_sep_index_to_query++); // printf("Query get caps for seid %d\n", sc.active_remote_sep->seid); avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); } else { // printf("No more remote seps found\n"); app_state = A2DP_IDLE; a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); } break; case A2DP_W2_SET_CONFIGURATION:{ if (!sc.local_stream_endpoint) return; app_state = A2DP_W2_GET_CONFIGURATION; avdtp_source_set_configuration(cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), sc.active_remote_sep->seid, sc.local_stream_endpoint->remote_configuration_bitmap, sc.local_stream_endpoint->remote_configuration); break; } case A2DP_W2_GET_CONFIGURATION: app_state = A2DP_W2_OPEN_STREAM_WITH_SEID; avdtp_source_get_configuration(cid, sc.active_remote_sep->seid); break; case A2DP_W2_OPEN_STREAM_WITH_SEID:{ app_state = A2DP_W4_OPEN_STREAM_WITH_SEID; btstack_sbc_encoder_init(&sc.sbc_encoder_state, SBC_MODE_STANDARD, sc.block_length, sc.subbands, sc.allocation_method, sc.sampling_frequency, sc.max_bitpool_value, sc.channel_mode); avdtp_source_open_stream(cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), sc.active_remote_sep->seid); break; } case A2DP_STREAMING_OPENED: if (!a2dp_source_context.a2dp_callback) return; switch (signal_identifier){ case AVDTP_SI_START:{ uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_STARTED; little_endian_store_16(event, pos, cid); pos += 2; event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } case AVDTP_SI_SUSPEND:{ uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_SUSPENDED; little_endian_store_16(event, pos, cid); pos += 2; event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } case AVDTP_SI_ABORT: case AVDTP_SI_CLOSE:{ uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_STOPPED; little_endian_store_16(event, pos, cid); pos += 2; log_info("send A2DP_SUBEVENT_STREAM_RELEASED to app"); event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } default: break; } break; default: app_state = A2DP_IDLE; break; } break; case AVDTP_SUBEVENT_SIGNALING_REJECT: app_state = A2DP_IDLE; signal_identifier = avdtp_subevent_signaling_reject_get_signal_identifier(packet); log_info("Rejected %d", signal_identifier); break; case AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT: app_state = A2DP_IDLE; signal_identifier = avdtp_subevent_signaling_general_reject_get_signal_identifier(packet); log_info("Rejected %d", signal_identifier); break; case AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:{ app_state = A2DP_IDLE; uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED; little_endian_store_16(event, pos, avdtp_subevent_streaming_connection_released_get_avdtp_cid(packet)); pos += 2; event[pos++] = avdtp_subevent_streaming_connection_released_get_local_seid(packet); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } case AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED:{ app_state = A2DP_IDLE; uint8_t event[6]; int pos = 0; event[pos++] = HCI_EVENT_A2DP_META; event[pos++] = sizeof(event) - 2; event[pos++] = A2DP_SUBEVENT_STREAM_RELEASED; little_endian_store_16(event, pos, avdtp_subevent_streaming_connection_released_get_avdtp_cid(packet)); pos += 2; event[pos++] = avdtp_subevent_streaming_connection_released_get_local_seid(packet); (*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); break; } default: app_state = A2DP_IDLE; log_info("not implemented"); break; } }
static void little_endian_fstore_16(FILE *wav_file, uint16_t value){ uint8_t buf[2]; little_endian_store_16(buf, 0, value); fwrite(&buf, 1, 2, wav_file); }
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 }
void sco_demo_send(hci_con_handle_t sco_handle){ if (!sco_handle) return; int sco_packet_length = hci_get_sco_packet_length(); int sco_payload_length = sco_packet_length - 3; hci_reserve_packet_buffer(); uint8_t * sco_packet = hci_get_outgoing_packet_buffer(); #if SCO_DEMO_MODE == SCO_DEMO_MODE_SINE #ifdef ENABLE_HFP_WIDE_BAND_SPEECH if (negotiated_codec == HFP_CODEC_MSBC){ // overwrite sco_payload_length = 24; sco_packet_length = sco_payload_length + 3; if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ log_error("mSBC stream is empty."); } hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); if (msbc_file_out){ // log outgoing mSBC data for testing fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); } sco_demo_msbc_fill_sine_audio_frame(); } else #endif { const int audio_samples_per_packet = sco_payload_length / CVSD_BYTES_PER_FRAME; sco_demo_sine_wave_int16_at_8000_hz_little_endian(audio_samples_per_packet, &sco_packet[3]); } #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_MICROPHONE #ifdef HAVE_PORTAUDIO if (negotiated_codec == HFP_CODEC_MSBC){ // MSBC // overwrite sco_payload_length = 24; sco_packet_length = sco_payload_length + 3; if (pa_input_paused){ if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= MSBC_PA_PREBUFFER_BYTES){ // resume sending pa_input_paused = 0; } } if (!pa_input_paused){ int num_samples = hfp_msbc_num_audio_samples_per_frame(); if (hfp_msbc_can_encode_audio_frame_now() && btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= (num_samples * MSBC_BYTES_PER_FRAME)){ int16_t sample_buffer[num_samples]; uint32_t bytes_read; btstack_ring_buffer_read(&pa_input_ring_buffer, (uint8_t*) sample_buffer, num_samples * MSBC_BYTES_PER_FRAME, &bytes_read); hfp_msbc_encode_audio_frame(sample_buffer); num_audio_frames++; } } if (hfp_msbc_num_bytes_in_stream() < sco_payload_length){ log_error("mSBC stream should not be empty."); memset(sco_packet + 3, 0, sco_payload_length); pa_input_paused = 1; } else { hfp_msbc_read_from_stream(sco_packet + 3, sco_payload_length); if (msbc_file_out){ // log outgoing mSBC data for testing fwrite(sco_packet + 3, sco_payload_length, 1, msbc_file_out); } } } else { // CVSD log_info("send: bytes avail %u, free %u, counter %u", btstack_ring_buffer_bytes_available(&pa_input_ring_buffer), btstack_ring_buffer_bytes_free(&pa_input_ring_buffer), pa_input_counter); // fill with silence while paused int bytes_to_copy = sco_payload_length; if (pa_input_paused){ if (btstack_ring_buffer_bytes_available(&pa_input_ring_buffer) >= CVSD_PA_PREBUFFER_BYTES){ // resume sending pa_input_paused = 0; } } // get data from ringbuffer uint16_t pos = 0; uint8_t * sample_data = &sco_packet[3]; if (!pa_input_paused){ uint32_t bytes_read = 0; btstack_ring_buffer_read(&pa_input_ring_buffer, sample_data, bytes_to_copy, &bytes_read); // flip 16 on big endian systems // @note We don't use (uint16_t *) casts since all sample addresses are odd which causes crahses on some systems if (btstack_is_big_endian()){ int i; for (i=0;i<bytes_read;i+=2){ uint8_t tmp = sample_data[i*2]; sample_data[i*2] = sample_data[i*2+1]; sample_data[i*2+1] = tmp; } } bytes_to_copy -= bytes_read; pos += bytes_read; } // fill with 0 if not enough if (bytes_to_copy){ memset(sample_data + pos, 0, bytes_to_copy); pa_input_paused = 1; } } #else // just send '0's if (negotiated_codec == HFP_CODEC_MSBC){ sco_payload_length = 24; sco_packet_length = sco_payload_length + 3; } memset(sco_packet + 3, 0, sco_payload_length); #endif #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_ASCII memset(&sco_packet[3], phase++, sco_payload_length); if (phase > 'z') phase = 'a'; #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_COUNTER int j; for (j=0;j<sco_payload_length;j++){ sco_packet[3+j] = phase++; } #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_55 int j; for (j=0;j<sco_payload_length;j++){ // sco_packet[3+j] = j & 1 ? 0x35 : 0x53; sco_packet[3+j] = 0x55; } #endif #if SCO_DEMO_MODE == SCO_DEMO_MODE_00 int j; for (j=0;j<sco_payload_length;j++){ sco_packet[3+j] = 0x00; } // additional hack // big_endian_store_16(sco_packet, 5, phase++); (void) phase; #endif // test silence // memset(sco_packet+3, 0, sco_payload_length); // set handle + flags little_endian_store_16(sco_packet, 0, sco_handle); // set len sco_packet[2] = sco_payload_length; // finally send packet hci_send_sco_packet_buffer(sco_packet_length); // request another send event hci_request_sco_can_send_now_event(); count_sent++; #if SCO_DEMO_MODE != SCO_DEMO_MODE_55 if ((count_sent % SCO_REPORT_PERIOD) == 0) sco_report(); #endif }