int ad_data_contains_uuid16(uint8_t ad_len, uint8_t * ad_data, uint16_t uuid16){ ad_context_t context; for (ad_iterator_init(&context, ad_len, ad_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){ uint8_t data_type = ad_iterator_get_data_type(&context); uint8_t data_len = ad_iterator_get_data_len(&context); uint8_t * data = ad_iterator_get_data(&context); int i; uint8_t ad_uuid128[16], uuid128_bt[16]; switch (data_type){ case IncompleteList16: case CompleteList16: for (i=0; i<data_len; i+=2){ uint16_t uuid = little_endian_read_16(data, i); if ( uuid == uuid16 ) return 1; } break; case IncompleteList128: case CompleteList128: uuid_add_bluetooth_prefix(ad_uuid128, uuid16); reverse_128(ad_uuid128, uuid128_bt); for (i=0; i<data_len; i+=16){ if (memcmp(uuid128_bt, &data[i], 16) == 0) return 1; } break; default: break; } } return 0; }
static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){ if (init_script_offset >= init_script_size) { return BTSTACK_CHIPSET_DONE; } // init script is stored with the HCI Command Packet Type init_script_offset++; // copy command header memcpy(&hci_cmd_buffer[0], (uint8_t *) &init_script[init_script_offset], 3); init_script_offset += 3; int payload_len = hci_cmd_buffer[2]; // copy command payload memcpy(&hci_cmd_buffer[3], (uint8_t *) &init_script[init_script_offset], payload_len); // support for on-the-fly configuration updates update_init_script_command(hci_cmd_buffer); init_script_offset += payload_len; // support for warm boot command uint16_t varid = little_endian_read_16(hci_cmd_buffer, 10); if (varid == 0x4002){ return BTSTACK_CHIPSET_WARMSTART_REQUIRED; } return BTSTACK_CHIPSET_VALID_COMMAND; }
static void h4_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) { if (hci_transport_h4->ds->fd == 0) return; // read up to bytes_to_read data in ssize_t bytes_read = mtk_bt_read(hci_transport_h4->ds->fd, &hci_packet_in[0], sizeof(hci_packet_in)); if (bytes_read == 0) return; // iterate over packets uint16_t pos = 0; while (pos < bytes_read) { uint16_t packet_len; switch(hci_packet_in[pos]){ case HCI_EVENT_PACKET: packet_len = hci_packet_in[pos+2] + 3; break; case HCI_ACL_DATA_PACKET: packet_len = little_endian_read_16(hci_packet_in, pos + 3) + 5; break; default: log_error("h4_process: invalid packet type 0x%02x\n", hci_packet_in[pos]); return; } packet_handler(hci_packet_in[pos], &hci_packet_in[pos+1], packet_len-1); pos += packet_len; } }
static void ancs_chunk_parser_handle_byte(uint8_t data){ ancs_notification_buffer[ancs_bytes_received++] = data; if (ancs_bytes_received < ancs_bytes_needed) return; switch (chunk_parser_state){ case W4_ATTRIBUTE_ID: ancs_attribute_id = ancs_notification_buffer[ancs_bytes_received-1]; ancs_bytes_received = 0; ancs_bytes_needed = 2; chunk_parser_state = W4_ATTRIBUTE_LEN; break; case W4_ATTRIBUTE_LEN: ancs_attribute_len = little_endian_read_16(ancs_notification_buffer, ancs_bytes_received-2); ancs_bytes_received = 0; ancs_bytes_needed = ancs_attribute_len; if (ancs_attribute_len == 0) { ancs_bytes_needed = 1; chunk_parser_state = W4_ATTRIBUTE_ID; break; } chunk_parser_state = W4_ATTRIBUTE_COMPLETE; break; case W4_ATTRIBUTE_COMPLETE: ancs_notification_buffer[ancs_bytes_received] = 0; notify_client_text(ANCS_SUBEVENT_CLIENT_NOTIFICATION); ancs_bytes_received = 0; ancs_bytes_needed = 1; chunk_parser_state = W4_ATTRIBUTE_ID; break; } }
int ad_data_contains_uuid16(uint8_t ad_len, const uint8_t * ad_data, uint16_t uuid16){ ad_context_t context; for (ad_iterator_init(&context, ad_len, ad_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){ uint8_t data_type = ad_iterator_get_data_type(&context); uint8_t data_len = ad_iterator_get_data_len(&context); const uint8_t * data = ad_iterator_get_data(&context); int i; uint8_t ad_uuid128[16], uuid128_bt[16]; switch (data_type){ case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS: case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS: for (i=0; i<data_len; i+=2){ uint16_t uuid = little_endian_read_16(data, i); if ( uuid == uuid16 ) return 1; } break; case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS: case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS: uuid_add_bluetooth_prefix(ad_uuid128, uuid16); reverse_128(ad_uuid128, uuid128_bt); for (i=0; i<data_len; i+=16){ if (memcmp(uuid128_bt, &data[i], 16) == 0) return 1; } break; default: break; } } return 0; }
static void att_run_for_context(att_server_t * att_server){ switch (att_server->state){ case ATT_SERVER_REQUEST_RECEIVED: // wait until pairing is complete if (att_server->pairing_active) break; #ifdef ENABLE_LE_SIGNED_WRITE if (att_server->request_buffer[0] == ATT_SIGNED_WRITE_COMMAND){ log_info("ATT Signed Write!"); if (!sm_cmac_ready()) { log_info("ATT Signed Write, sm_cmac engine not ready. Abort"); att_server->state = ATT_SERVER_IDLE; return; } if (att_server->request_size < (3 + 12)) { log_info("ATT Signed Write, request to short. Abort."); att_server->state = ATT_SERVER_IDLE; return; } if (att_server->ir_lookup_active){ return; } if (att_server->ir_le_device_db_index < 0){ log_info("ATT Signed Write, CSRK not available"); att_server->state = ATT_SERVER_IDLE; return; } // check counter uint32_t counter_packet = little_endian_read_32(att_server->request_buffer, att_server->request_size-12); uint32_t counter_db = le_device_db_remote_counter_get(att_server->ir_le_device_db_index); log_info("ATT Signed Write, DB counter %"PRIu32", packet counter %"PRIu32, counter_db, counter_packet); if (counter_packet < counter_db){ log_info("ATT Signed Write, db reports higher counter, abort"); att_server->state = ATT_SERVER_IDLE; return; } // signature is { sequence counter, secure hash } sm_key_t csrk; le_device_db_remote_csrk_get(att_server->ir_le_device_db_index, csrk); att_server->state = ATT_SERVER_W4_SIGNED_WRITE_VALIDATION; log_info("Orig Signature: "); log_info_hexdump( &att_server->request_buffer[att_server->request_size-8], 8); uint16_t attribute_handle = little_endian_read_16(att_server->request_buffer, 1); sm_cmac_signed_write_start(csrk, att_server->request_buffer[0], attribute_handle, att_server->request_size - 15, &att_server->request_buffer[3], counter_packet, att_signed_write_handle_cmac_result); return; } #endif // move on att_server->state = ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED; att_dispatch_server_request_can_send_now_event(att_server->connection.con_handle); break; default: break; } }
// 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 void local_version_information_callback(uint8_t * packet){ printf("Local version information:\n"); uint16_t hci_version = little_endian_read_16(packet, 4); uint16_t hci_revision = little_endian_read_16(packet, 6); uint16_t lmp_version = little_endian_read_16(packet, 8); uint16_t manufacturer = little_endian_read_16(packet, 10); uint16_t lmp_subversion = little_endian_read_16(packet, 12); printf("- HCI Version 0x%04x\n", hci_version); printf("- HCI Revision 0x%04x\n", hci_revision); printf("- LMP Version 0x%04x\n", lmp_version); printf("- LMP Revision 0x%04x\n", lmp_subversion); printf("- Manufacturer 0x%04x\n", manufacturer); switch (manufacturer){ case COMPANY_ID_CAMBRIDGE_SILICON_RADIO: printf("Cambridge Silicon Radio CSR chipset.\n"); use_fast_uart(); hci_set_chipset(btstack_chipset_csr_instance()); break; case COMPANY_ID_TEXAS_INSTRUMENTS_INC: printf("Texas Instruments - CC256x compatible chipset.\n"); use_fast_uart(); hci_set_chipset(btstack_chipset_cc256x_instance()); #ifdef ENABLE_EHCILL printf("eHCILL enabled.\n"); #endif break; case COMPANY_ID_BROADCOM_CORPORATION: printf("Broadcom chipset. Not supported yet\n"); // hci_set_chipset(btstack_chipset_bcm_instance()); break; case COMPANY_ID_ST_MICROELECTRONICS: printf("ST Microelectronics - using STLC2500d driver.\n"); use_fast_uart(); hci_set_chipset(btstack_chipset_stlc2500d_instance()); break; case COMPANY_ID_EM_MICROELECTRONICS_MARIN: printf("EM Microelectronics - using EM9301 driver.\n"); hci_set_chipset(btstack_chipset_em9301_instance()); break; default: printf("Unknown manufacturer / manufacturer not supported yet.\n"); break; } }
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ if (packet_type != HCI_EVENT_PACKET) return; uint8_t event = hci_event_packet_get_type(packet); switch (event) { case BTSTACK_EVENT_STATE: // bt stack activated, get started if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ printf("SDP Query for RFCOMM services on %s started\n", bd_addr_to_str(remote)); sdp_client_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, SDP_PublicBrowseGroup); } break; case RFCOMM_EVENT_CHANNEL_OPENED: // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16) if (packet[2]) { state = DONE; printf("RFCOMM channel open failed, status %u\n", packet[2]); } else { // data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16) state = SENDING; rfcomm_cid = little_endian_read_16(packet, 12); mtu = little_endian_read_16(packet, 14); printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_cid, mtu); if ((test_data_len > mtu)) { test_data_len = mtu; } test_reset(); rfcomm_request_can_send_now_event(rfcomm_cid); break; } break; case RFCOMM_EVENT_CAN_SEND_NOW: send_packet(); break; case RFCOMM_EVENT_CHANNEL_CLOSED: if (state != DONE) { printf("RFCOMM_EVENT_CHANNEL_CLOSED received before all test data was sent\n"); state = DONE; } break; default: break; } }
static int battery_service_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ UNUSED(con_handle); UNUSED(transaction_mode); UNUSED(offset); UNUSED(buffer_size); if (attribute_handle == battery_value_handle_client_configuration){ battery_value_client_configuration = little_endian_read_16(buffer, 0); } return 0; }
static void local_version_information_handler(uint8_t * packet){ printf("Local version information:\n"); uint16_t hci_version = packet[6]; uint16_t hci_revision = little_endian_read_16(packet, 7); uint16_t lmp_version = packet[9]; uint16_t manufacturer = little_endian_read_16(packet, 10); uint16_t lmp_subversion = little_endian_read_16(packet, 12); printf("- HCI Version 0x%04x\n", hci_version); printf("- HCI Revision 0x%04x\n", hci_revision); printf("- LMP Version 0x%04x\n", lmp_version); printf("- LMP Revision 0x%04x\n", lmp_subversion); printf("- Manufacturer 0x%04x\n", manufacturer); switch (manufacturer){ case BLUETOOTH_COMPANY_ID_CAMBRIDGE_SILICON_RADIO: printf("Cambridge Silicon Radio CSR chipset.\n"); use_fast_uart(); hci_set_chipset(btstack_chipset_csr_instance()); break; case BLUETOOTH_COMPANY_ID_TEXAS_INSTRUMENTS_INC: printf("Texas Instruments - CC256x compatible chipset.\n"); use_fast_uart(); hci_set_chipset(btstack_chipset_cc256x_instance()); break; case BLUETOOTH_COMPANY_ID_BROADCOM_CORPORATION: printf("Broadcom chipset. Not supported by posix-h5 port, please use port/posix-h5-bcm\n"); exit(10); break; case BLUETOOTH_COMPANY_ID_ST_MICROELECTRONICS: printf("ST Microelectronics - using STLC2500d driver.\n"); use_fast_uart(); hci_set_chipset(btstack_chipset_stlc2500d_instance()); break; case BLUETOOTH_COMPANY_ID_EM_MICROELECTRONIC_MARIN_SA: printf("EM Microelectronics - using EM9301 driver.\n"); hci_set_chipset(btstack_chipset_em9301_instance()); break; default: printf("Unknown manufacturer / manufacturer not supported yet.\n"); break; } }
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ bd_addr_t event_addr; uint16_t psm; if (packet_type != HCI_EVENT_PACKET) return; switch (packet[0]) { case BTSTACK_EVENT_STATE: // bt stack activated, get started if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ printf("BTstack L2CAP Test Ready\n"); show_usage(); } break; case L2CAP_EVENT_CHANNEL_OPENED: // inform about new l2cap connection reverse_bd_addr(&packet[3], event_addr); psm = little_endian_read_16(packet, 11); local_cid = little_endian_read_16(packet, 13); handle = little_endian_read_16(packet, 9); if (packet[2] == 0) { printf("Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n", bd_addr_to_str(event_addr), handle, psm, local_cid, little_endian_read_16(packet, 15)); } else { printf("L2CAP connection to device %s failed. status code %u\n", bd_addr_to_str(event_addr), packet[2]); } break; case L2CAP_EVENT_INCOMING_CONNECTION: { uint16_t l2cap_cid = little_endian_read_16(packet, 12); printf("L2CAP Accepting incoming connection request\n"); l2cap_accept_connection(l2cap_cid); break; } default: break; } }
esp_err_t esp_eddystone_decode(const uint8_t* buf, uint8_t len, esp_eddystone_result_t* res) { static uint8_t pos=0; while(res->common.srv_data_type != EDDYSTONE_SERVICE_UUID) { pos++; uint8_t ad_type = buf[pos++]; switch(ad_type) { case ESP_BLE_AD_TYPE_FLAG: { res->common.flags = buf[pos++]; break; } case ESP_BLE_AD_TYPE_16SRV_CMPL: { uint16_t uuid = little_endian_read_16(buf, pos); if(uuid != EDDYSTONE_SERVICE_UUID) { return -1; } res->common.srv_uuid = uuid; pos += 2; break; } case ESP_BLE_AD_TYPE_SERVICE_DATA: { uint16_t type = little_endian_read_16(buf, pos); pos += 2; uint8_t frame_type = buf[pos++]; if(type != EDDYSTONE_SERVICE_UUID || !(frame_type == EDDYSTONE_FRAME_TYPE_UID || frame_type == EDDYSTONE_FRAME_TYPE_URL || frame_type == EDDYSTONE_FRAME_TYPE_TLM)) { return -1; } res->common.srv_data_type = type; res->common.frame_type = frame_type; break; } default: break; } } return esp_eddystone_get_inform(buf+pos, len-pos, res); }
int wav_reader_open(const char * filepath){ wav_reader_fd = open(filepath, O_RDONLY); if (!wav_reader_fd) { log_error("Can't open file %s", filepath); return 1; } uint8_t buf[40]; __read(wav_reader_fd, buf, sizeof(buf)); int num_channels = little_endian_read_16(buf, 22); int block_align = little_endian_read_16(buf, 32); if (num_channels != 1 && num_channels != 2) { log_error("Unexpected num channels %d", num_channels); return 1; } bytes_per_sample = block_align/num_channels; if (bytes_per_sample > 2){ bytes_per_sample = bytes_per_sample/8; } return 0; }
static void transport_deliver_packets(void){ xSemaphoreTake(ring_buffer_mutex, portMAX_DELAY); while (btstack_ring_buffer_bytes_available(&hci_ringbuffer)){ uint32_t number_read; uint8_t len_tag[2]; btstack_ring_buffer_read(&hci_ringbuffer, len_tag, 2, &number_read); uint32_t len = little_endian_read_16(len_tag, 0); btstack_ring_buffer_read(&hci_ringbuffer, hci_receive_buffer, len, &number_read); xSemaphoreGive(ring_buffer_mutex); transport_packet_handler(hci_receive_buffer[0], &hci_receive_buffer[1], len-1); xSemaphoreTake(ring_buffer_mutex, portMAX_DELAY); } xSemaphoreGive(ring_buffer_mutex); }
static void packet_handler(uint8_t * event, uint16_t event_size){ // printf("Packet handler event 0x%02x\n", event[0]); switch (event[0]) { case BTSTACK_EVENT_STATE: if (event[2] != HCI_STATE_WORKING) break; show_usage(); break; case HCI_EVENT_HSP_META: switch (event[2]) { case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: if (event[3] == 0){ sco_handle = little_endian_read_16(event, 4); printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle); } else { printf("Audio connection establishment failed with status %u\n", event[3]); sco_handle = 0; } break; case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE: if (event[3] == 0){ printf("Audio connection released.\n\n"); sco_handle = 0; } else { printf("Audio connection releasing failed with status %u\n", event[3]); } break; case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED: printf("Received microphone gain change %d\n", event[3]); break; case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED: printf("Received speaker gain change %d\n", event[3]); break; case HSP_SUBEVENT_RING: printf("HS: RING RING!\n"); break; case HSP_SUBEVENT_AG_INDICATION: memset(hs_cmd_buffer, 0, sizeof(hs_cmd_buffer)); int size = event[3] <= sizeof(hs_cmd_buffer)? event[3] : sizeof(hs_cmd_buffer); memcpy(hs_cmd_buffer, &event[4], size - 1); printf("Received custom indication: \"%s\". \nExit code or call hsp_hs_send_result.\n", hs_cmd_buffer); break; default: printf("event not handled %u\n", event[2]); break; } break; default: break; } }
int wav_reader_read_int16(int num_samples, int16_t * data){ if (!wav_reader_fd) return 1; int i; int bytes_read = 0; for (i=0; i<num_samples; i++){ uint8_t buf[2]; bytes_read +=__read(wav_reader_fd, &buf, 2); data[i] = little_endian_read_16(buf, 0); } if (bytes_read == num_samples*bytes_per_sample) { return 0; } else { return 1; } }
void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ uint16_t aHandle; bd_addr_t event_address; switch (packet_type) { case HCI_EVENT_PACKET: switch (packet[0]) { case SM_EVENT_PASSKEY_INPUT_NUMBER: // store peer address for input printf("\nGAP Bonding: Enter 6 digit passkey: '"); fflush(stdout); break; case SM_EVENT_PASSKEY_DISPLAY_NUMBER: printf("\nGAP Bonding: Display Passkey '%06u\n", little_endian_read_32(packet, 11)); break; case SM_EVENT_PASSKEY_DISPLAY_CANCEL: printf("\nGAP Bonding: Display cancel\n"); break; case SM_EVENT_JUST_WORKS_REQUEST: // auto-authorize connection if requested sm_just_works_confirm(little_endian_read_16(packet, 2)); printf("Just Works request confirmed\n"); break; case SM_EVENT_AUTHORIZATION_REQUEST: // auto-authorize connection if requested sm_authorization_grant(little_endian_read_16(packet, 2)); break; default: break; } } }
// write requests static int att_write_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ // ignore cancel sent for new connections if (transaction_mode == ATT_TRANSACTION_MODE_CANCEL) return 0; // find characteristic for handle switch (att_handle){ case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE: le_notification_enabled = little_endian_read_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION; att_con_handle = con_handle; return 0; case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE: printf("Write on test characteristic: "); printf_hexdump(buffer, buffer_size); return 0; default: printf("WRITE Callback, handle %04x, mode %u, offset %u, data: ", con_handle, transaction_mode, offset); printf_hexdump(buffer, buffer_size); return 0; } }
static int att_server_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ switch (transaction_mode){ case ATT_TRANSACTION_MODE_VALIDATE: return att_validate_prepared_write(con_handle); case ATT_TRANSACTION_MODE_EXECUTE: case ATT_TRANSACTION_MODE_CANCEL: att_notify_write_callbacks(con_handle, transaction_mode); return 0; default: break; } // track CCC writes if (att_is_persistent_ccc(attribute_handle) && offset == 0 && buffer_size == 2){ att_server_persistent_ccc_write(con_handle, attribute_handle, little_endian_read_16(buffer, 0)); } att_write_callback_t callback = att_server_write_callback_for_handle(attribute_handle); if (!callback) return 0; return (*callback)(con_handle, attribute_handle, transaction_mode, offset, buffer, buffer_size); }
static void sco_demo_receive_CVSD(uint8_t * packet, uint16_t size){ if (!num_samples_to_write) return; int16_t audio_frame_out[128]; // if (size > sizeof(audio_frame_out)){ printf("sco_demo_receive_CVSD: SCO packet larger than local output buffer - dropping data.\n"); return; } #if defined(SCO_WAV_FILENAME) || defined(USE_PORTAUDIO) const int audio_bytes_read = size - 3; const int num_samples = audio_bytes_read / CVSD_BYTES_PER_FRAME; // convert into host endian int16_t audio_frame_in[128]; int i; for (i=0;i<num_samples;i++){ audio_frame_in[i] = little_endian_read_16(packet, 3 + i * 2); } btstack_cvsd_plc_process_data(&cvsd_plc_state, audio_frame_in, num_samples, audio_frame_out); #endif #ifdef SCO_WAV_FILENAME // Samples in CVSD SCO packet are in little endian, ready for wav files (take shortcut) const int samples_to_write = btstack_min(num_samples, num_samples_to_write); wav_writer_write_le_int16(samples_to_write, audio_frame_out); num_samples_to_write -= samples_to_write; if (num_samples_to_write == 0){ wav_writer_close(); } #endif #ifdef USE_PORTAUDIO btstack_ring_buffer_write(&pa_output_ring_buffer, (uint8_t *)audio_frame_out, audio_bytes_read); #endif }
static wiced_result_t h4_rx_worker_receive_packet(void * arg){ #ifdef WICED_BT_UART_MANUAL_CTS_RTS platform_gpio_output_low(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]); #endif while (1){ rx_worker_read_pos = 0; h4_rx_worker_receive_bytes(1); switch (hci_packet[0]){ case HCI_EVENT_PACKET: h4_rx_worker_receive_bytes(HCI_EVENT_HEADER_SIZE); h4_rx_worker_receive_bytes(hci_packet[2]); break; case HCI_ACL_DATA_PACKET: h4_rx_worker_receive_bytes(HCI_ACL_HEADER_SIZE); h4_rx_worker_receive_bytes(little_endian_read_16( hci_packet, 3)); break; case HCI_SCO_DATA_PACKET: h4_rx_worker_receive_bytes(HCI_SCO_HEADER_SIZE); h4_rx_worker_receive_bytes(hci_packet[3]); break; default: // try again log_error("h4_rx_worker_receive_packet: invalid packet type 0x%02x", hci_packet[0]); continue; } #ifdef WICED_BT_UART_MANUAL_CTS_RTS platform_gpio_output_high(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]); #endif // deliver packet on main thread btstack_run_loop_wiced_execute_code_on_main_thread(&h4_main_deliver_packet, NULL); return WICED_SUCCESS; } }
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 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); }
/* LISTING_START(GAPLEAdvDataParsing): Parsing advertising data */ static void dump_advertisement_data(const uint8_t * adv_data, uint8_t adv_size){ ad_context_t context; bd_addr_t address; uint8_t uuid_128[16]; for (ad_iterator_init(&context, adv_size, (uint8_t *)adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){ uint8_t data_type = ad_iterator_get_data_type(&context); uint8_t size = ad_iterator_get_data_len(&context); const uint8_t * data = ad_iterator_get_data(&context); if (data_type > 0 && data_type < 0x1B){ printf(" %s: ", ad_types[data_type]); } int i; // Assigned Numbers GAP switch (data_type){ case 0x01: // Flags // show only first octet, ignore rest for (i=0; i<8;i++){ if (data[0] & (1<<i)){ printf("%s; ", flags[i]); } } break; case 0x02: // Incomplete List of 16-bit Service Class UUIDs case 0x03: // Complete List of 16-bit Service Class UUIDs case 0x14: // List of 16-bit Service Solicitation UUIDs for (i=0; i<size;i+=2){ printf("%02X ", little_endian_read_16(data, i)); } break; case 0x04: // Incomplete List of 32-bit Service Class UUIDs case 0x05: // Complete List of 32-bit Service Class UUIDs for (i=0; i<size;i+=4){ printf("%04"PRIX32, little_endian_read_32(data, i)); } break; case 0x06: // Incomplete List of 128-bit Service Class UUIDs case 0x07: // Complete List of 128-bit Service Class UUIDs case 0x15: // List of 128-bit Service Solicitation UUIDs reverse_128(data, uuid_128); printf("%s", uuid128_to_str(uuid_128)); break; case 0x08: // Shortened Local Name case 0x09: // Complete Local Name for (i=0; i<size;i++){ printf("%c", (char)(data[i])); } break; case 0x0A: // Tx Power Level printf("%d dBm", *(int8_t*)data); break; case 0x12: // Slave Connection Interval Range printf("Connection Interval Min = %u ms, Max = %u ms", little_endian_read_16(data, 0) * 5/4, little_endian_read_16(data, 2) * 5/4); break; case 0x16: // Service Data printf_hexdump(data, size); break; case 0x17: // Public Target Address case 0x18: // Random Target Address reverse_bd_addr(data, address); printf("%s", bd_addr_to_str(address)); break; case 0x19: // Appearance // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml printf("%02X", little_endian_read_16(data, 0) ); break; case 0x1A: // Advertising Interval printf("%u ms", little_endian_read_16(data, 0) * 5/8 ); break; case 0x3D: // 3D Information Data printf_hexdump(data, size); break; case 0xFF: // Manufacturer Specific Data break; case 0x0D: // Class of Device (3B) case 0x0E: // Simple Pairing Hash C (16B) case 0x0F: // Simple Pairing Randomizer R (16B) case 0x10: // Device ID case 0x11: // Security Manager TK Value (16B) default: printf("Unknown Advertising Data Type"); break; } printf("\n"); } printf("\n"); }
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ // printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); if (packet_type == RFCOMM_DATA_PACKET){ // skip over leading newline while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){ size--; packet++; } if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){ emit_ring_event(); } else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){ wait_ok = 0; } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0){ uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_MICROPHONE_GAIN)]); emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain); } else if (strncmp((char *)packet, HSP_SPEAKER_GAIN, strlen(HSP_SPEAKER_GAIN)) == 0){ uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_SPEAKER_GAIN)]); emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain); } else { if (!hsp_hs_callback) return; // strip trailing newline while (size > 0 && (packet[size-1] == '\n' || packet[size-1] == '\r')){ size--; } // add trailing \0 packet[size] = 0; // re-use incoming buffer to avoid reserving large buffers - ugly but efficient uint8_t * event = packet - 4; event[0] = HCI_EVENT_HSP_META; event[1] = size + 2; event[2] = HSP_SUBEVENT_AG_INDICATION; event[3] = size; (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, size+4); } hsp_run(); return; } if (packet_type != HCI_EVENT_PACKET) return; uint8_t event = hci_event_packet_get_type(packet); bd_addr_t event_addr; uint16_t handle; switch (event) { case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED) return; int index = 2; uint8_t status = packet[index++]; sco_handle = little_endian_read_16(packet, index); index+=2; bd_addr_t address; memcpy(address, &packet[index], 6); index+=6; uint8_t link_type = packet[index++]; uint8_t transmission_interval = packet[index++]; // measured in slots uint8_t retransmission_interval = packet[index++];// measured in slots uint16_t rx_packet_length = little_endian_read_16(packet, index); // measured in bytes index+=2; uint16_t tx_packet_length = little_endian_read_16(packet, index); // measured in bytes index+=2; uint8_t air_mode = packet[index]; if (status != 0){ log_error("(e)SCO Connection failed, status %u", status); emit_event_audio_connected(status, sco_handle); hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ; break; } switch (link_type){ case 0x00: log_info("SCO Connection established."); if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval); if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval); if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length); if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length); break; case 0x02: log_info("eSCO Connection established."); break; default: log_error("(e)SCO reserved link_type 0x%2x", link_type); break; } log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, " " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle, bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); hsp_state = HSP_AUDIO_CONNECTION_ESTABLISHED; emit_event_audio_connected(status, sco_handle); break; } case RFCOMM_EVENT_INCOMING_CONNECTION: // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) if (hsp_state != HSP_IDLE) return; reverse_bd_addr(&packet[2], event_addr); rfcomm_cid = little_endian_read_16(packet, 9); log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr)); hsp_state = HSP_W4_RFCOMM_CONNECTED; rfcomm_accept_connection(rfcomm_cid); break; case RFCOMM_EVENT_CHANNEL_OPENED: // printf("RFCOMM_EVENT_CHANNEL_OPENED packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16) if (hsp_state != HSP_W4_RFCOMM_CONNECTED) return; if (packet[2]) { log_info("RFCOMM channel open failed, status %u", packet[2]); hsp_state = HSP_IDLE; hsp_hs_reset_state(); } else { // data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16) rfcomm_handle = little_endian_read_16(packet, 9); rfcomm_cid = little_endian_read_16(packet, 12); mtu = little_endian_read_16(packet, 14); log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, handle %02x", rfcomm_cid, mtu, rfcomm_handle); hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED; } emit_event(HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE, packet[2]); break; case RFCOMM_EVENT_CAN_SEND_NOW: hsp_run(); break; case HCI_EVENT_DISCONNECTION_COMPLETE: handle = little_endian_read_16(packet,3); if (handle == sco_handle){ sco_handle = 0; hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED; emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0); break; } if (handle == rfcomm_handle) { rfcomm_handle = 0; hsp_state = HSP_IDLE; emit_event(HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE,0); hsp_hs_reset_state(); } break; case RFCOMM_EVENT_CHANNEL_CLOSED: hsp_hs_reset_state(); hsp_hs_callback(HCI_EVENT_PACKET, 0, packet, size); break; default: break; } hsp_run(); }
static void h4_block_received(void){ read_pos += bytes_to_read; // act switch (h4_state) { case H4_W4_PACKET_TYPE: switch (hci_packet[0]) { case HCI_EVENT_PACKET: h4_state = H4_W4_EVENT_HEADER; bytes_to_read = HCI_EVENT_HEADER_SIZE; break; case HCI_ACL_DATA_PACKET: h4_state = H4_W4_ACL_HEADER; bytes_to_read = HCI_ACL_HEADER_SIZE; break; case HCI_SCO_DATA_PACKET: h4_state = H4_W4_SCO_HEADER; bytes_to_read = HCI_SCO_HEADER_SIZE; break; default: log_error("h4_process: invalid packet type 0x%02x", hci_packet[0]); h4_init_sm(); return; } break; case H4_W4_EVENT_HEADER: bytes_to_read = hci_packet[2]; if (bytes_to_read == 0) { h4_state = H4_PACKET_RECEIVED; break; } h4_state = H4_W4_PAYLOAD; break; case H4_W4_ACL_HEADER: bytes_to_read = little_endian_read_16( hci_packet, 3); // check ACL length if (HCI_ACL_HEADER_SIZE + bytes_to_read > HCI_PACKET_BUFFER_SIZE){ log_error("h4_process: invalid ACL payload len %u - only space for %u", bytes_to_read, HCI_PACKET_BUFFER_SIZE - HCI_ACL_HEADER_SIZE); h4_init_sm(); return; } if (bytes_to_read == 0) { h4_state = H4_PACKET_RECEIVED; break; } h4_state = H4_W4_PAYLOAD; break; case H4_W4_SCO_HEADER: bytes_to_read = hci_packet[3]; if (bytes_to_read == 0) { h4_state = H4_PACKET_RECEIVED; break; } h4_state = H4_W4_PAYLOAD; break; case H4_W4_PAYLOAD: h4_state = H4_PACKET_RECEIVED; bytes_to_read = 0; // trigger run loop btstack_run_loop_embedded_trigger(); break; default: bytes_to_read = 0; break; } // read next block if (bytes_to_read) { hal_uart_dma_receive_block(&hci_packet[read_pos], bytes_to_read); } }
/* LISTING_START(packetHandler): Packet Handler */ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { /* LISTING_PAUSE */ uint8_t event; bd_addr_t event_addr; uint8_t status; uint16_t l2cap_cid; /* LISTING_RESUME */ switch (packet_type) { case HCI_EVENT_PACKET: event = hci_event_packet_get_type(packet); switch (event) { /* @text When BTSTACK_EVENT_STATE with state HCI_STATE_WORKING * is received and the example is started in client mode, the remote SDP HID query is started. */ case BTSTACK_EVENT_STATE: if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ printf("Start SDP HID query for remote HID Device.\n"); sdp_client_query_uuid16(&handle_sdp_client_query_result, remote_addr, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE); } break; /* LISTING_PAUSE */ case HCI_EVENT_PIN_CODE_REQUEST: // inform about pin code request printf("Pin code request - using '0000'\n"); hci_event_pin_code_request_get_bd_addr(packet, event_addr); gap_pin_code_response(event_addr, "0000"); break; case HCI_EVENT_USER_CONFIRMATION_REQUEST: // inform about user confirmation request printf("SSP User Confirmation Request with numeric value '%"PRIu32"'\n", little_endian_read_32(packet, 8)); printf("SSP User Confirmation Auto accept\n"); break; /* LISTING_RESUME */ case L2CAP_EVENT_CHANNEL_OPENED: status = packet[2]; if (status){ printf("L2CAP Connection failed: 0x%02x\n", status); break; } l2cap_cid = little_endian_read_16(packet, 13); if (!l2cap_cid) break; if (l2cap_cid == l2cap_hid_control_cid){ status = l2cap_create_channel(packet_handler, remote_addr, hid_interrupt_psm, 48, &l2cap_hid_interrupt_cid); if (status){ printf("Connecting to HID Control failed: 0x%02x\n", status); break; } } if (l2cap_cid == l2cap_hid_interrupt_cid){ printf("HID Connection established\n"); } break; default: break; } break; case L2CAP_DATA_PACKET: // for now, just dump incoming data if (channel == l2cap_hid_interrupt_cid){ hid_host_handle_interrupt_report(packet, size); } else if (channel == l2cap_hid_control_cid){ printf("HID Control: "); printf_hexdump(packet, size); } else { break; } default: break; } }
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; } }
/* LISTING_START(attWrite): ATT Write */ static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ if (att_handle != ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE) return 0; le_notification_enabled = little_endian_read_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION; con_handle = connection_handle; return 0; }