diff --git a/README.md b/README.md index 3c1be1c67..676b67992 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -**_Note: Major API Changes. For older projects, you may use the [v0.9 branch](https://github.com/bluekitchen/btstack/tree/v0.9)_** +**_Note: Major API Changes. For older projects, you may use the [v0.9 branch](https://github.com/bluekitchen/btstack/tree/v0.9). +Please see [Migration notes](https://github.com/bluekitchen/btstack/blob/master/doc/manual/docs/appendix/migration.md)_** # Welcome to BTstack @@ -26,8 +27,8 @@ It has been qualified with the the Bluetooth SIG for GAP, IOP, HFP, HSP, SPP, PA GATT, SM of the Bluetooth 4.2 LE Central and Peripheral roles (QD ID 25340). ## Documentation -- [HTML](http://bluekitchen-gmbh.com/btstack/v1.0) -- [PDF](http://bluekitchen-gmbh.com/btstack_v1.0.pdf) +- [HTML](http://bluekitchen-gmbh.com/btstack) +- [PDF](http://bluekitchen-gmbh.com/btstack.pdf) ## Supported Protocols * L2CAP diff --git a/example/hfp_ag_demo.c b/example/hfp_ag_demo.c index 153ab611f..4a9234bb4 100644 --- a/example/hfp_ag_demo.c +++ b/example/hfp_ag_demo.c @@ -61,14 +61,29 @@ #endif +static int phase = 0; + +// input signal: pre-computed sine wave, 160 Hz +static const uint8_t sine[] = { + 0, 15, 31, 46, 61, 74, 86, 97, 107, 114, + 120, 124, 126, 126, 124, 120, 114, 107, 97, 86, + 74, 61, 46, 31, 15, 0, 241, 225, 210, 195, + 182, 170, 159, 149, 142, 136, 132, 130, 130, 132, + 136, 142, 149, 159, 170, 182, 195, 210, 225, 241, +}; + uint8_t hfp_service_buffer[150]; const uint8_t rfcomm_channel_nr = 1; const char hfp_ag_service_name[] = "BTstack HFP AG Test"; -static bd_addr_t device_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46}; +// PTS +// static bd_addr_t device_addr = {0x00,0x15,0x83,0x5F,0x9D,0x46}; +// BT-201 +static bd_addr_t device_addr = {0x00, 0x07, 0xB0, 0x83, 0x02, 0x5E}; static uint8_t codecs[1] = {HFP_CODEC_CVSD}; static uint16_t handle = -1; +static hci_con_handle_t sco_handle; static int memory_1_enabled = 1; static int ag_indicators_nr = 7; @@ -189,7 +204,7 @@ static void inquiry_packet_handler (uint8_t packet_type, uint8_t *packet, uint16 numResponses = hci_event_inquiry_result_get_num_responses(packet); int offset = 3; for (i=0; i= 0) continue; // already in our list @@ -234,7 +249,7 @@ static void inquiry_packet_handler (uint8_t packet_type, uint8_t *packet, uint16 break; case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: - reverse_bd_addr(addr, &packet[3]); + reverse_bd_addr(&packet[3], addr); index = getDeviceIndexForAddress(addr); if (index >= 0) { if (packet[2] == 0) { @@ -259,10 +274,13 @@ static void show_usage(void); // Testig User Interface static void show_usage(void){ - printf("\n--- Bluetooth HFP Audiogateway (AG) unit Test Console ---\n"); + bd_addr_t iut_address; + gap_local_bd_addr(iut_address); + + printf("\n--- Bluetooth HFP Audiogateway (AG) unit Test Console %s ---\n", bd_addr_to_str(iut_address)); printf("---\n"); - printf("a - establish HFP connection to PTS module\n"); + printf("a - establish HFP connection to PTS module %s\n", bd_addr_to_str(device_addr)); // printf("A - release HFP connection to PTS module\n"); printf("b - establish AUDIO connection\n"); @@ -514,7 +532,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac break; case 't': log_info("USER:\'%c\'", cmd); - printf("Terminate HCI connection.\n"); + printf("Terminate HCI connection. 0x%2x\n", handle); gap_disconnect(handle); break; case 'u': @@ -547,77 +565,122 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac } #endif -static void packet_handler(uint8_t * event, uint16_t event_size){ - switch (event[0]){ - case HCI_EVENT_INQUIRY_RESULT: - case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: - case HCI_EVENT_INQUIRY_COMPLETE: - case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: - inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size); - break; +#define SCO_REPORT_PERIOD 100 +static void send_sco_data(void){ + if (!sco_handle) return; + + const int sco_packet_length = hci_get_sco_packet_length(); + const int sco_payload_length = sco_packet_length - 3; + const int frames_per_packet = sco_payload_length; // for 8-bit data. for 16-bit data it's /2 - default: - break; + 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; + int i; + for (i=0;i= sizeof(sine)) phase = 0; } + hci_send_sco_packet_buffer(sco_packet_length); + // request another send event + hci_request_sco_can_send_now_event(); - if (event[0] != HCI_EVENT_HFP_META) return; + static int count = 0; + count++; + if ((count % SCO_REPORT_PERIOD) == 0) printf("Sent %u\n", count); +} - if (event[3] - && event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER - && event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG - && event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){ - printf("ERROR, status: %u\n", event[3]); - return; - } - - switch (event[2]) { - case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: - handle = hfp_subevent_service_level_connection_established_get_con_handle(event); - printf("Service level connection established.\n"); - break; - case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: - printf("Service level connection released.\n"); - break; - case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED: - printf("\n** Audio connection established **\n"); - break; - case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED: - printf("\n** Audio connection released **\n"); - break; - case HFP_SUBEVENT_START_RINGINIG: - printf("\n** Start Ringing **\n"); - break; - case HFP_SUBEVENT_STOP_RINGINIG: - printf("\n** Stop Ringing **\n"); - break; - case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER: - printf("\n** Outgoing call '%s' **\n", hfp_subevent_place_call_with_number_get_number(event)); - // validate number - if ( strcmp("1234567", hfp_subevent_place_call_with_number_get_number(event)) == 0 - || strcmp("7654321", hfp_subevent_place_call_with_number_get_number(event)) == 0 - || (memory_1_enabled && strcmp(">1", hfp_subevent_place_call_with_number_get_number(event)) == 0)){ - printf("Dialstring valid: accept call\n"); - hfp_ag_outgoing_call_accepted(); - } else { - printf("Dialstring invalid: reject call\n"); - hfp_ag_outgoing_call_rejected(); +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ + switch (packet_type){ + case HCI_EVENT_PACKET: + switch (event[0]){ + case HCI_EVENT_INQUIRY_RESULT: + case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: + case HCI_EVENT_INQUIRY_COMPLETE: + case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: + inquiry_packet_handler(HCI_EVENT_PACKET, event, event_size); + break; + case HCI_EVENT_SCO_CAN_SEND_NOW: + send_sco_data(); + break; + default: + break; + } + + if (event[0] != HCI_EVENT_HFP_META) return; + + if (event[3] + && event[2] != HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER + && event[2] != HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG + && event[2] != HFP_SUBEVENT_TRANSMIT_DTMF_CODES){ + printf("ERROR, status: %u\n", event[3]); + return; + } + + switch (event[2]) { + case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: + handle = hfp_subevent_service_level_connection_established_get_con_handle(event); + printf("Service level connection established.\n"); + break; + case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: + printf("Service level connection released.\n"); + sco_handle = 0; + break; + case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED: + if (hfp_subevent_audio_connection_established_get_status(event)){ + printf("Audio connection establishment failed with status %u\n", hfp_subevent_audio_connection_established_get_status(event)); + sco_handle = 0; + } else { + sco_handle = hfp_subevent_audio_connection_established_get_handle(event); + printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle); + hci_request_sco_can_send_now_event(); + } + break; + case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED: + printf("\n** Audio connection released **\n"); + sco_handle = 0; + break; + case HFP_SUBEVENT_START_RINGINIG: + printf("\n** Start Ringing **\n"); + break; + case HFP_SUBEVENT_STOP_RINGINIG: + printf("\n** Stop Ringing **\n"); + break; + case HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER: + printf("\n** Outgoing call '%s' **\n", hfp_subevent_place_call_with_number_get_number(event)); + // validate number + if ( strcmp("1234567", hfp_subevent_place_call_with_number_get_number(event)) == 0 + || strcmp("7654321", hfp_subevent_place_call_with_number_get_number(event)) == 0 + || (memory_1_enabled && strcmp(">1", hfp_subevent_place_call_with_number_get_number(event)) == 0)){ + printf("Dialstring valid: accept call\n"); + hfp_ag_outgoing_call_accepted(); + } else { + printf("Dialstring invalid: reject call\n"); + hfp_ag_outgoing_call_rejected(); + } + break; + + case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG: + printf("\n** Attach number to voice tag. Sending '1234567\n"); + hfp_ag_send_phone_number_for_voice_tag(device_addr, "1234567"); + break; + case HFP_SUBEVENT_TRANSMIT_DTMF_CODES: + printf("\n** Send DTMF Codes: '%s'\n", hfp_subevent_transmit_dtmf_codes_get_dtmf(event)); + hfp_ag_send_dtmf_code_done(device_addr); + break; + case HFP_SUBEVENT_CALL_ANSWERED: + printf("Call answered by HF\n"); + break; + default: + printf("Event not handled %u\n", event[2]); + break; } - break; - - case HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG: - printf("\n** Attach number to voice tag. Sending '1234567\n"); - hfp_ag_send_phone_number_for_voice_tag(device_addr, "1234567"); - break; - case HFP_SUBEVENT_TRANSMIT_DTMF_CODES: - printf("\n** Send DTMF Codes: '%s'\n", hfp_subevent_transmit_dtmf_codes_get_dtmf(event)); - hfp_ag_send_dtmf_code_done(device_addr); - break; - case HFP_SUBEVENT_CALL_ANSWERED: - printf("Call answered by HF\n"); - break; default: - printf("Event not handled %u\n", event[2]); break; } } @@ -639,22 +702,26 @@ static hfp_phone_number_t subscriber_number = { int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]){ - // HFP HS address is hardcoded, please change it - // init L2CAP - l2cap_init(); - rfcomm_init(); - sdp_init(); + gap_discoverable_control(1); + + // L2CAP + l2cap_init(); + + // HFP + rfcomm_init(); hfp_ag_init(rfcomm_channel_nr); hfp_ag_init_supported_features(0x3ef | (1<= sizeof(hs_cmd_buffer)-1){ - size = sizeof(hs_cmd_buffer)-1; - } - memcpy(hs_cmd_buffer, hsp_subevent_ag_indication_get_value(event), size); - printf("Received custom indication: \"%s\". \nExit code or call hsp_hs_send_result.\n", hs_cmd_buffer); + case HCI_EVENT_HSP_META: + switch (event[2]) { + case HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE: + if (hsp_subevent_rfcomm_connection_complete_get_status(event)){ + printf("RFCOMM connection establishement failed with status %u\n", hsp_subevent_rfcomm_connection_complete_get_status(event)); + } else { + printf("RFCOMM connection established.\n"); + } + break; + case HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE: + if (hsp_subevent_rfcomm_disconnection_complete_get_status(event)){ + printf("RFCOMM disconnection failed with status %u.\n", hsp_subevent_rfcomm_disconnection_complete_get_status(event)); + } else { + printf("RFCOMM disconnected.\n"); + } + break; + case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: + if (hsp_subevent_audio_connection_complete_get_status(event)){ + printf("Audio connection establishment failed with status %u\n", hsp_subevent_audio_connection_complete_get_status(event)); + sco_handle = 0; + } else { + sco_handle = hsp_subevent_audio_connection_complete_get_handle(event); + printf("Audio connection established with SCO handle 0x%04x.\n", sco_handle); + hci_request_sco_can_send_now_event(); + } + break; + case HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE: + if (hsp_subevent_audio_disconnection_complete_get_status(event)){ + printf("Audio connection releasing failed with status %u\n", hsp_subevent_audio_disconnection_complete_get_status(event)); + } else { + printf("Audio connection released.\n\n"); + sco_handle = 0; + } + break; + case HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED: + printf("Received microphone gain change %d\n", hsp_subevent_microphone_gain_changed_get_gain(event)); + break; + case HSP_SUBEVENT_SPEAKER_GAIN_CHANGED: + printf("Received speaker gain change %d\n", hsp_subevent_speaker_gain_changed_get_gain(event)); + 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 = hsp_subevent_ag_indication_get_value_length(event); + if (size >= sizeof(hs_cmd_buffer)-1){ + size = sizeof(hs_cmd_buffer)-1; + } + memcpy(hs_cmd_buffer, hsp_subevent_ag_indication_get_value(event), size); + 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: - printf("event not handled %u\n", event[2]); break; } - break; default: break; } } -static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){ - packet_handler(packet, size); -} - /* @section Main Application Setup * * @text Listing MainConfiguration shows main application code. @@ -323,9 +322,9 @@ int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]){ // register for HCI events - hci_event_callback_registration.callback = &handle_hci_event; + hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); - hci_register_sco_packet_handler(&sco_packet_handler); + hci_register_sco_packet_handler(&packet_handler); l2cap_init(); diff --git a/platform/embedded/hci_transport_h4_embedded.c b/platform/embedded/hci_transport_h4_embedded.c index 90a525478..734ca9b68 100644 --- a/platform/embedded/hci_transport_h4_embedded.c +++ b/platform/embedded/hci_transport_h4_embedded.c @@ -67,6 +67,7 @@ typedef enum { H4_W4_PACKET_TYPE = 1, H4_W4_EVENT_HEADER, H4_W4_ACL_HEADER, + H4_W4_SCO_HEADER, H4_W4_PAYLOAD, H4_PACKET_RECEIVED } H4_STATE; @@ -172,13 +173,17 @@ static void h4_block_received(void){ 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_EVENT_PACKET: - h4_state = H4_W4_EVENT_HEADER; - bytes_to_read = HCI_EVENT_HEADER_SIZE; + 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]); @@ -210,7 +215,16 @@ static void h4_block_received(void){ } h4_state = H4_W4_PAYLOAD; break; - + + case H4_W4_SCO_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_PAYLOAD: h4_state = H4_PACKET_RECEIVED; bytes_to_read = 0; diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 803bb4196..6057c61c0 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -904,9 +904,10 @@ typedef uint8_t sm_key_t[16]; #define HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED 0x02 /** - * @format 11 + * @format 11H * @param subevent_code * @param status 0 == OK + * @param handle */ #define HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED 0x03 diff --git a/src/btstack_event.h b/src/btstack_event.h index c498133ba..04001c73a 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -2660,6 +2660,15 @@ static inline hci_con_handle_t hfp_subevent_service_level_connection_established static inline uint8_t hfp_subevent_audio_connection_established_get_status(const uint8_t * event){ return event[3]; } +/** + * @brief Get field handle from event HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED + * @param event packet + * @return handle + * @note: btstack_type H + */ +static inline hci_con_handle_t hfp_subevent_audio_connection_established_get_handle(const uint8_t * event){ + return little_endian_read_16(event, 4); +} /** diff --git a/src/classic/hfp.c b/src/classic/hfp.c index 3e72da8b7..a47178ad6 100644 --- a/src/classic/hfp.c +++ b/src/classic/hfp.c @@ -96,10 +96,12 @@ static const char * hfp_ag_features[] = { static btstack_linked_list_t hfp_connections = NULL; static void parse_sequence(hfp_connection_t * context); -static hfp_callback_t hfp_callback; +static btstack_packet_handler_t hfp_callback; static btstack_packet_handler_t rfcomm_packet_handler; -void hfp_set_callback(hfp_callback_t callback){ +static hfp_connection_t * sco_establishment_active; + +void hfp_set_callback(btstack_packet_handler_t callback){ hfp_callback = callback; } @@ -184,26 +186,26 @@ int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){ return offset; } -void hfp_emit_simple_event(hfp_callback_t callback, uint8_t event_subtype){ +void hfp_emit_simple_event(btstack_packet_handler_t callback, uint8_t event_subtype){ if (!callback) return; uint8_t event[3]; event[0] = HCI_EVENT_HFP_META; event[1] = sizeof(event) - 2; event[2] = event_subtype; - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){ +void hfp_emit_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t value){ if (!callback) return; uint8_t event[4]; event[0] = HCI_EVENT_HFP_META; event[1] = sizeof(event) - 2; event[2] = event_subtype; event[3] = value; // status 0 == OK - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -void hfp_emit_connection_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle){ +void hfp_emit_connection_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle){ if (!callback) return; uint8_t event[6]; event[0] = HCI_EVENT_HFP_META; @@ -211,10 +213,10 @@ void hfp_emit_connection_event(hfp_callback_t callback, uint8_t event_subtype, u event[2] = event_subtype; event[3] = status; // status 0 == OK little_endian_store_16(event, 4, con_handle); - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value){ +void hfp_emit_string_event(btstack_packet_handler_t callback, uint8_t event_subtype, const char * value){ if (!callback) return; uint8_t event[40]; event[0] = HCI_EVENT_HFP_META; @@ -223,7 +225,7 @@ void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const int size = (strlen(value) < sizeof(event) - 4) ? strlen(value) : sizeof(event) - 4; strncpy((char*)&event[3], value, size); event[3 + size] = 0; - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } btstack_linked_list_t * hfp_get_connections(void){ @@ -438,13 +440,48 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin } } +static void hfp_handle_failed_sco_connection(uint8_t status){ + + if (!sco_establishment_active){ + log_error("(e)SCO Connection failed but not started by us"); + return; + } + log_error("(e)SCO Connection failed status 0x%02x", status); + + // invalid params / unspecified error + if (status != 0x11 && status != 0x1f) return; + + switch (sco_establishment_active->link_setting){ + case HFP_LINK_SETTINGS_D0: + return; // no other option left + case HFP_LINK_SETTINGS_D1: + sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D0; + break; + case HFP_LINK_SETTINGS_S1: + sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D1; + break; + case HFP_LINK_SETTINGS_S2: + case HFP_LINK_SETTINGS_S3: + case HFP_LINK_SETTINGS_S4: + sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S1; + break; + case HFP_LINK_SETTINGS_T1: + case HFP_LINK_SETTINGS_T2: + sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S3; + break; + } + sco_establishment_active->establish_audio_connection = 1; + sco_establishment_active = 0; +} + + void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ bd_addr_t event_addr; uint16_t rfcomm_cid, handle; hfp_connection_t * hfp_connection = NULL; uint8_t status; - // printf("AG packet_handler type %u, event type %x, size %u\n", packet_type, hci_event_packet_get_type(packet), size); + log_info("AG packet_handler type %u, event type %x, size %u", packet_type, hci_event_packet_get_type(packet), size); switch (hci_event_packet_get_type(packet)) { @@ -490,9 +527,19 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet default: break; } + rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); } break; + case HCI_EVENT_COMMAND_STATUS: + if (hci_event_command_status_get_command_opcode(packet) == hci_setup_synchronous_connection.opcode) { + status = hci_event_command_status_get_status(packet); + if (status) { + hfp_handle_failed_sco_connection(hci_event_command_status_get_status(packet)); + } + } + break; + case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ reverse_bd_addr(&packet[5], event_addr); @@ -500,32 +547,7 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet status = packet[index++]; if (status != 0){ - log_error("(e)SCO Connection failed status %u", status); - // if outgoing && link_setting != d0 && appropriate error - if (status != 0x11 && status != 0x1f) break; // invalid params / unspecified error - hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr); - if (!hfp_connection) break; - switch (hfp_connection->link_setting){ - case HFP_LINK_SETTINGS_D0: - return; // no other option left - case HFP_LINK_SETTINGS_D1: - // hfp_connection->link_setting = HFP_LINK_SETTINGS_D0; - // break; - case HFP_LINK_SETTINGS_S1: - // hfp_connection->link_setting = HFP_LINK_SETTINGS_D1; - // break; - case HFP_LINK_SETTINGS_S2: - case HFP_LINK_SETTINGS_S3: - case HFP_LINK_SETTINGS_S4: - // hfp_connection->link_setting = HFP_LINK_SETTINGS_S1; - // break; - case HFP_LINK_SETTINGS_T1: - case HFP_LINK_SETTINGS_T2: - // hfp_connection->link_setting = HFP_LINK_SETTINGS_S3; - hfp_connection->link_setting = HFP_LINK_SETTINGS_D0; - break; - } - hfp_connection->establish_audio_connection = 1; + hfp_handle_failed_sco_connection(status); break; } @@ -1331,10 +1353,12 @@ static const struct link_settings { { 0x000d, 0x02, 0x0380 } // HFP_LINK_SETTINGS_T2, 2-EV3 }; -void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t setting){ +void hfp_setup_synchronous_connection(hfp_connection_t * hfp_connection){ // all packet types, fixed bandwidth + int setting = hfp_connection->link_setting; log_info("hfp_setup_synchronous_connection using setting nr %u", setting); - hci_send_cmd(&hci_setup_synchronous_connection, handle, 8000, 8000, hfp_link_settings[setting].max_latency, + sco_establishment_active = hfp_connection; + hci_send_cmd(&hci_setup_synchronous_connection, hfp_connection->acl_handle, 8000, 8000, hfp_link_settings[setting].max_latency, hci_get_sco_voice_setting(), hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380 } diff --git a/src/classic/hfp.h b/src/classic/hfp.h index 22dc8a640..e1c067342 100644 --- a/src/classic/hfp.h +++ b/src/classic/hfp.h @@ -432,8 +432,6 @@ typedef enum{ HFP_CALL_SM } hfp_state_machine_t; -typedef void (*hfp_callback_t)(uint8_t * event, uint16_t event_size); - typedef struct{ uint16_t uuid; uint8_t state; // enabled @@ -621,16 +619,16 @@ int get_bit(uint16_t bitmap, int position); int store_bit(uint32_t bitmap, int position, uint8_t value); // UTILS_END -void hfp_set_callback(hfp_callback_t callback); +void hfp_set_callback(btstack_packet_handler_t callback); void hfp_set_packet_handler_for_rfcomm_connections(btstack_packet_handler_t handler); void hfp_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t service_uuid, int rfcomm_channel_nr, const char * name); void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); -void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value); -void hfp_emit_simple_event(hfp_callback_t callback, uint8_t event_subtype); -void hfp_emit_string_event(hfp_callback_t callback, uint8_t event_subtype, const char * value); -void hfp_emit_connection_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle); +void hfp_emit_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t value); +void hfp_emit_simple_event(btstack_packet_handler_t callback, uint8_t event_subtype); +void hfp_emit_string_event(btstack_packet_handler_t callback, uint8_t event_subtype, const char * value); +void hfp_emit_connection_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle); hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid); hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr); @@ -645,7 +643,7 @@ void hfp_reset_context_flags(hfp_connection_t * connection); void hfp_release_audio_connection(hfp_connection_t * connection); -void hfp_setup_synchronous_connection(hci_con_handle_t handle, hfp_link_setttings_t link_settings); +void hfp_setup_synchronous_connection(hfp_connection_t * connection); const char * hfp_hf_feature(int index); const char * hfp_ag_feature(int index); diff --git a/src/classic/hfp_ag.c b/src/classic/hfp_ag.c index 7b1dbaed3..f8fe311d2 100644 --- a/src/classic/hfp_ag.c +++ b/src/classic/hfp_ag.c @@ -95,7 +95,7 @@ static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_ static int hfp_ag_call_hold_services_nr = 0; static char *hfp_ag_call_hold_services[6]; -static hfp_callback_t hfp_callback; +static btstack_packet_handler_t hfp_callback; static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state; static int hfp_ag_response_and_hold_active = 0; @@ -149,7 +149,7 @@ static int get_ag_indicator_index_for_name(const char * name){ } -void hfp_ag_register_packet_handler(hfp_callback_t callback){ +void hfp_ag_register_packet_handler(btstack_packet_handler_t callback){ if (callback == NULL){ log_error("hfp_ag_register_packet_handler called with NULL callback"); return; @@ -557,7 +557,6 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){ switch (hfp_connection->command){ case HFP_CMD_AVAILABLE_CODECS: - //printf("HFP_CODECS_RECEIVED_LIST \n"); if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ hfp_connection->codecs_state = HFP_CODECS_RECEIVED_LIST; hfp_ag_ok(hfp_connection->rfcomm_cid); @@ -576,20 +575,17 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){ return 1; case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: - //printf(" HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP \n"); hfp_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; hfp_ag_ok(hfp_connection->rfcomm_cid); return 1; case HFP_CMD_AG_SEND_COMMON_CODEC: - //printf(" HFP_CMD_AG_SEND_COMMON_CODEC \n"); hfp_connection->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC; hfp_connection->suggested_codec = hfp_ag_suggest_codec(hfp_connection); hfp_ag_cmd_suggest_codec(hfp_connection->rfcomm_cid, hfp_connection->suggested_codec); return 1; case HFP_CMD_HF_CONFIRMED_CODEC: - //printf("HFP_CMD_HF_CONFIRMED_CODEC \n"); if (hfp_connection->codec_confirmed != hfp_connection->suggested_codec){ hfp_connection->codecs_state = HFP_CODECS_ERROR; hfp_ag_error(hfp_connection->rfcomm_cid); @@ -636,9 +632,9 @@ static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){ } static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){ + log_info("hfp_ag_run_for_context_service_level_connection state %u, command %u", hfp_connection->state, hfp_connection->command); if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; int done = 0; - // printf(" -> State machine: SLC\n"); switch(hfp_connection->command){ case HFP_CMD_SUPPORTED_FEATURES: switch(hfp_connection->state){ @@ -665,18 +661,9 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hf case HFP_CMD_RETRIEVE_AG_INDICATORS: if (hfp_connection->state == HFP_W4_RETRIEVE_INDICATORS) { - hfp_connection->command = HFP_CMD_NONE; // prevent reentrance - int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment); - if (next_segment < hfp_ag_indicators_cmd_generator_num_segments(hfp_connection)){ - // prepare sending of next segment - hfp_connection->send_ag_indicators_segment = next_segment; - hfp_connection->command = HFP_CMD_RETRIEVE_AG_INDICATORS; - } else { - // done, go to next state - hfp_connection->send_ag_indicators_segment = 0; - hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; - } - return 1; + // HF requested AG Indicators and we did expect it + hfp_connection->state = HFP_RETRIEVE_INDICATORS; + // continue below in state switch } break; @@ -729,16 +716,35 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hf default: break; } + + switch (hfp_connection->state){ + case HFP_RETRIEVE_INDICATORS: { + int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment); + int num_segments = hfp_ag_indicators_cmd_generator_num_segments(hfp_connection); + log_info("HFP_CMD_RETRIEVE_AG_INDICATORS next segment %u, num_segments %u", next_segment, num_segments); + if (next_segment < num_segments){ + // prepare sending of next segment + hfp_connection->send_ag_indicators_segment = next_segment; + log_info("HFP_CMD_RETRIEVE_AG_INDICATORS more. command %u, next seg %u", hfp_connection->command, next_segment); + } else { + // done, go to next state + hfp_connection->send_ag_indicators_segment = 0; + hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; + } + return 1; + } + default: + break; + } + return done; } static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){ - // if (hfp_connection->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; - + int done = codecs_exchange_state_machine(hfp_connection); if (done) return done; - // printf(" -> State machine: SLC Queries\n"); switch(hfp_connection->command){ case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, hfp_connection->ag_activate_voice_recognition); @@ -801,13 +807,12 @@ static int hfp_ag_run_for_audio_connection(hfp_connection_t * hfp_connection){ // run codecs exchange int done = codecs_exchange_state_machine(hfp_connection); if (done) return done; - // printf(" -> State machine: Audio hfp_connection\n"); if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return done; if (hfp_connection->establish_audio_connection){ hfp_connection->state = HFP_W4_SCO_CONNECTED; hfp_connection->establish_audio_connection = 0; - hfp_setup_synchronous_connection(hfp_connection->acl_handle, hfp_connection->link_setting); + hfp_setup_synchronous_connection(hfp_connection); return 1; } return 0; @@ -1610,9 +1615,15 @@ static void hfp_ag_send_call_status(hfp_connection_t * hfp_connection, int call_ } static void hfp_run_for_context(hfp_connection_t *hfp_connection){ + + log_info("hfp_run_for_context %p", hfp_connection); + if (!hfp_connection) return; + if (!hfp_connection->rfcomm_cid) return; + if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) { + log_info("hfp_run_for_context: request can send for 0x%02x", hfp_connection->rfcomm_cid); rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); return; } @@ -1763,6 +1774,10 @@ static void hfp_run_for_context(hfp_connection_t *hfp_connection){ if (done){ hfp_connection->command = HFP_CMD_NONE; } + // + if (done) { + rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); + } } static hfp_generic_status_indicator_t *get_hf_indicator_by_number(int number){ @@ -2037,8 +2052,6 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr){ hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); - l2cap_init(); - rfcomm_register_service(&packet_handler, rfcomm_channel_nr, 0xffff); hfp_ag_response_and_hold_active = 0; diff --git a/src/classic/hfp_ag.h b/src/classic/hfp_ag.h index 9881d08f2..272792ae9 100644 --- a/src/classic/hfp_ag.h +++ b/src/classic/hfp_ag.h @@ -115,7 +115,7 @@ void hfp_ag_init_call_hold_services(int call_hold_services_nr, const char * call * @brief Register callback for the HFP Audio Gateway (AG) client. * @param callback */ -void hfp_ag_register_packet_handler(hfp_callback_t callback); +void hfp_ag_register_packet_handler(btstack_packet_handler_t callback); /** * @brief Enable in-band ring tone. diff --git a/src/classic/hfp_hf.c b/src/classic/hfp_hf.c index 7586bffca..1506ea854 100644 --- a/src/classic/hfp_hf.c +++ b/src/classic/hfp_hf.c @@ -74,7 +74,7 @@ static uint32_t hfp_indicators_value[HFP_MAX_NUM_HF_INDICATORS]; static uint8_t hfp_hf_speaker_gain = 9; static uint8_t hfp_hf_microphone_gain = 9; -static hfp_callback_t hfp_callback; +static btstack_packet_handler_t hfp_callback; static hfp_call_status_t hfp_call_status; static hfp_callsetup_status_t hfp_callsetup_status; @@ -84,7 +84,7 @@ static char phone_number[25]; static btstack_packet_callback_registration_t hci_event_callback_registration; -void hfp_hf_register_packet_handler(hfp_callback_t callback){ +void hfp_hf_register_packet_handler(btstack_packet_handler_t callback){ hfp_callback = callback; if (callback == NULL){ log_error("hfp_hf_register_packet_handler called with NULL callback"); @@ -94,7 +94,7 @@ void hfp_hf_register_packet_handler(hfp_callback_t callback){ hfp_set_callback(callback); } -static void hfp_hf_emit_subscriber_information(hfp_callback_t callback, uint8_t event_subtype, uint8_t status, uint8_t bnip_type, const char * bnip_number){ +static void hfp_hf_emit_subscriber_information(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, uint8_t bnip_type, const char * bnip_number){ if (!callback) return; uint8_t event[31]; event[0] = HCI_EVENT_HFP_META; @@ -105,10 +105,10 @@ static void hfp_hf_emit_subscriber_information(hfp_callback_t callback, uint8_t int size = (strlen(bnip_number) < sizeof(event) - 6) ? strlen(bnip_number) : sizeof(event) - 6; strncpy((char*)&event[5], bnip_number, size); event[5 + size] = 0; - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -static void hfp_hf_emit_type_and_number(hfp_callback_t callback, uint8_t event_subtype, uint8_t bnip_type, const char * bnip_number){ +static void hfp_hf_emit_type_and_number(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t bnip_type, const char * bnip_number){ if (!callback) return; uint8_t event[30]; event[0] = HCI_EVENT_HFP_META; @@ -118,10 +118,10 @@ static void hfp_hf_emit_type_and_number(hfp_callback_t callback, uint8_t event_s int size = (strlen(bnip_number) < sizeof(event) - 5) ? strlen(bnip_number) : sizeof(event) - 5; strncpy((char*)&event[4], bnip_number, size); event[4 + size] = 0; - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -static void hfp_hf_emit_enhanced_call_status(hfp_callback_t callback, uint8_t clcc_idx, uint8_t clcc_dir, +static void hfp_hf_emit_enhanced_call_status(btstack_packet_handler_t callback, uint8_t clcc_idx, uint8_t clcc_dir, uint8_t clcc_status, uint8_t clcc_mpty, uint8_t bnip_type, const char * bnip_number){ if (!callback) return; uint8_t event[35]; @@ -136,7 +136,7 @@ static void hfp_hf_emit_enhanced_call_status(hfp_callback_t callback, uint8_t cl int size = (strlen(bnip_number) < sizeof(event) - 10) ? strlen(bnip_number) : sizeof(event) - 10; strncpy((char*)&event[9], bnip_number, size); event[9 + size] = 0; - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } static int hfp_hf_supports_codec(uint8_t codec){ @@ -373,7 +373,7 @@ static int hfp_hf_send_clcc(uint16_t cid){ return send_str_over_rfcomm(cid, buffer); } -static void hfp_emit_ag_indicator_event(hfp_callback_t callback, hfp_ag_indicator_t indicator){ +static void hfp_emit_ag_indicator_event(btstack_packet_handler_t callback, hfp_ag_indicator_t indicator){ if (!callback) return; uint8_t event[5+HFP_MAX_INDICATOR_DESC_SIZE+1]; event[0] = HCI_EVENT_HFP_META; @@ -383,10 +383,10 @@ static void hfp_emit_ag_indicator_event(hfp_callback_t callback, hfp_ag_indicato event[4] = indicator.status; strncpy((char*)&event[5], indicator.name, HFP_MAX_INDICATOR_DESC_SIZE); event[5+HFP_MAX_INDICATOR_DESC_SIZE] = 0; - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -static void hfp_emit_network_operator_event(hfp_callback_t callback, hfp_network_opearator_t network_operator){ +static void hfp_emit_network_operator_event(btstack_packet_handler_t callback, hfp_network_opearator_t network_operator){ if (!callback) return; uint8_t event[24]; event[0] = HCI_EVENT_HFP_META; @@ -395,7 +395,7 @@ static void hfp_emit_network_operator_event(hfp_callback_t callback, hfp_network event[3] = network_operator.mode; event[4] = network_operator.format; strcpy((char*)&event[5], network_operator.name); - (*callback)(event, sizeof(event)); + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){ @@ -566,7 +566,7 @@ static int hfp_hf_run_for_audio_connection(hfp_connection_t * hfp_connection){ if (hfp_connection->establish_audio_connection){ hfp_connection->state = HFP_W4_SCO_CONNECTED; hfp_connection->establish_audio_connection = 0; - hfp_setup_synchronous_connection(hfp_connection->acl_handle, hfp_connection->link_setting); + hfp_setup_synchronous_connection(hfp_connection); return 1; } @@ -1083,8 +1083,6 @@ void hfp_hf_init(uint16_t rfcomm_channel_nr){ hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); - l2cap_init(); - rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); hfp_set_packet_handler_for_rfcomm_connections(&packet_handler); diff --git a/src/classic/hfp_hf.h b/src/classic/hfp_hf.h index a3832bc1e..8e88bad9b 100644 --- a/src/classic/hfp_hf.h +++ b/src/classic/hfp_hf.h @@ -95,7 +95,7 @@ void hfp_hf_init_hf_indicators(int indicators_nr, uint16_t * indicators); * @brief Register callback for the HFP Hands-Free (HF) client. * @param callback */ -void hfp_hf_register_packet_handler(hfp_callback_t callback); +void hfp_hf_register_packet_handler(btstack_packet_handler_t callback); /** * @brief Establish RFCOMM connection with the AG with given Bluetooth address, diff --git a/src/classic/hsp_ag.c b/src/classic/hsp_ag.c index 3e953d452..c4bf0d1ab 100644 --- a/src/classic/hsp_ag.c +++ b/src/classic/hsp_ag.c @@ -124,15 +124,15 @@ typedef enum { static hsp_state_t hsp_state = HSP_IDLE; -static hsp_ag_callback_t hsp_ag_callback; +static btstack_packet_handler_t hsp_ag_callback; static void hsp_run(void); static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); -static void dummy_notify(uint8_t * event, uint16_t size){} +static void dummy_notify(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t size){} -void hsp_ag_register_packet_handler(hsp_ag_callback_t callback){ +void hsp_ag_register_packet_handler(btstack_packet_handler_t callback){ if (callback == NULL){ callback = &dummy_notify; } @@ -146,7 +146,7 @@ static void emit_event(uint8_t event_subtype, uint8_t value){ event[1] = sizeof(event) - 2; event[2] = event_subtype; event[3] = value; // status 0 == OK - (*hsp_ag_callback)(event, sizeof(event)); + (*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } static void emit_event_audio_connected(uint8_t status, uint16_t handle){ @@ -157,7 +157,7 @@ static void emit_event_audio_connected(uint8_t status, uint16_t handle){ event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE; event[3] = status; little_endian_store_16(event, 4, handle); - (*hsp_ag_callback)(event, sizeof(event)); + (*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } void hsp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name){ @@ -554,7 +554,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack event[1] = size + 2; event[2] = HSP_SUBEVENT_HS_COMMAND; event[3] = size; - (*hsp_ag_callback)(event, size+4); + (*hsp_ag_callback)(HCI_EVENT_PACKET, 0, event, size+4); } hsp_run(); diff --git a/src/classic/hsp_ag.h b/src/classic/hsp_ag.h index 085ee700b..9f6692a83 100644 --- a/src/classic/hsp_ag.h +++ b/src/classic/hsp_ag.h @@ -54,23 +54,6 @@ extern "C" { /* API_START */ -/** - * @brief Packet handler for HSP Audio Gateway (AG) events. - * - * The HSP AG event has type HCI_EVENT_HSP_META with following subtypes: - * - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE - * - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE - * - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE - * - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE - * - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED - * - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED - * - HSP_SUBEVENT_HS_COMMAND - * - * @param event See include/btstack/hci_cmds.h - * @param event_size - */ -typedef void (*hsp_ag_callback_t)(uint8_t * event, uint16_t event_size); - /** * @brief Set up HSP AG. * @param rfcomm_channel_nr @@ -88,9 +71,19 @@ void hsp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, /** * @brief Register packet handler to receive HSP AG events. + + * The HSP AG event has type HCI_EVENT_HSP_META with following subtypes: + * - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE + * - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE + * - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE + * - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE + * - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED + * - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED + * - HSP_SUBEVENT_HS_COMMAND + * * @param callback */ -void hsp_ag_register_packet_handler(hsp_ag_callback_t callback); +void hsp_ag_register_packet_handler(btstack_packet_handler_t callback); /** * @brief Connect to HSP Headset. diff --git a/src/classic/hsp_hs.c b/src/classic/hsp_hs.c index 4ee77e2b8..8b8995166 100644 --- a/src/classic/hsp_hs.c +++ b/src/classic/hsp_hs.c @@ -123,10 +123,10 @@ static void hsp_run(void); static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); -static hsp_hs_callback_t hsp_hs_callback; -static void dummy_notify(uint8_t * event, uint16_t size){} +static btstack_packet_handler_t hsp_hs_callback; +static void dummy_notify(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t size){} -void hsp_hs_register_packet_handler(hsp_hs_callback_t callback){ +void hsp_hs_register_packet_handler(btstack_packet_handler_t callback){ if (callback == NULL){ callback = &dummy_notify; } @@ -140,7 +140,7 @@ static void emit_event(uint8_t event_subtype, uint8_t value){ event[1] = sizeof(event) - 2; event[2] = event_subtype; event[3] = value; // status 0 == OK - (*hsp_hs_callback)(event, sizeof(event)); + (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } static void emit_ring_event(void){ @@ -149,7 +149,7 @@ static void emit_ring_event(void){ event[0] = HCI_EVENT_HSP_META; event[1] = sizeof(event) - 2; event[2] = HSP_SUBEVENT_RING; - (*hsp_hs_callback)(event, sizeof(event)); + (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } static void emit_event_audio_connected(uint8_t status, uint16_t handle){ @@ -160,7 +160,7 @@ static void emit_event_audio_connected(uint8_t status, uint16_t handle){ event[2] = HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE; event[3] = status; little_endian_store_16(event, 4, handle); - (*hsp_hs_callback)(event, sizeof(event)); + (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } // remote audio volume control @@ -276,9 +276,6 @@ void hsp_hs_init(uint8_t rfcomm_channel_nr){ hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); - // init L2CAP - l2cap_init(); - rfcomm_init(); rfcomm_register_service(packet_handler, rfcomm_channel_nr, 0xffff); // reserved channel, mtu limited by l2cap @@ -477,7 +474,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack event[1] = size + 2; event[2] = HSP_SUBEVENT_AG_INDICATION; event[3] = size; - (*hsp_hs_callback)(event, size+4); + (*hsp_hs_callback)(HCI_EVENT_PACKET, 0, event, size+4); } hsp_run(); return; @@ -590,7 +587,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack case RFCOMM_EVENT_CHANNEL_CLOSED: hsp_hs_reset_state(); - hsp_hs_callback(packet, size); + hsp_hs_callback(HCI_EVENT_PACKET, 0, packet, size); break; default: diff --git a/src/classic/hsp_hs.h b/src/classic/hsp_hs.h index d1838367b..ab29d3ad8 100644 --- a/src/classic/hsp_hs.h +++ b/src/classic/hsp_hs.h @@ -54,24 +54,6 @@ extern "C" { /* API_START */ -/** - * @brief Packet handler for HSP Headset (HS) events. - * - * The HSP HS event has type HCI_EVENT_HSP_META with following subtypes: - * - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE - * - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE - * - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE - * - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE - * - HSP_SUBEVENT_RING - * - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED - * - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED - * - HSP_SUBEVENT_AG_INDICATION - * - * @param event See include/btstack/hci_cmds.h - * @param event_size - */ -typedef void (*hsp_hs_callback_t)(uint8_t * event, uint16_t event_size); - /** * @brief Set up HSP HS. * @param rfcomm_channel_nr @@ -89,9 +71,20 @@ void hsp_hs_create_sdp_record(uint8_t * service, uint32_t service_record_handle, /** * @brief Register packet handler to receive HSP HS events. + * + * The HSP HS event has type HCI_EVENT_HSP_META with following subtypes: + * - HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE + * - HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE + * - HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE + * - HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE + * - HSP_SUBEVENT_RING + * - HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED + * - HSP_SUBEVENT_SPEAKER_GAIN_CHANGED + * - HSP_SUBEVENT_AG_INDICATION + * * @param callback */ -void hsp_hs_register_packet_handler(hsp_hs_callback_t callback); +void hsp_hs_register_packet_handler(btstack_packet_handler_t callback); /** * @brief Connect to HSP Audio Gateway. diff --git a/src/hci.c b/src/hci.c index 43791acac..b8231d4a3 100644 --- a/src/hci.c +++ b/src/hci.c @@ -1860,7 +1860,7 @@ static void event_handler(uint8_t *packet, int size){ static void sco_handler(uint8_t * packet, uint16_t size){ if (!hci_stack->sco_packet_handler) return; - hci_stack->sco_packet_handler(HCI_SCO_DATA_PACKET, packet, size); + hci_stack->sco_packet_handler(HCI_SCO_DATA_PACKET, 0, packet, size); } static void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){ @@ -1888,14 +1888,14 @@ void hci_add_event_handler(btstack_packet_callback_registration_t * callback_han /** Register HCI packet handlers */ -void hci_register_acl_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){ +void hci_register_acl_packet_handler(btstack_packet_handler_t handler){ hci_stack->acl_packet_handler = handler; } /** * @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles. */ -void hci_register_sco_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){ +void hci_register_sco_packet_handler(btstack_packet_handler_t handler){ hci_stack->sco_packet_handler = handler; } @@ -2974,7 +2974,7 @@ static void hci_emit_event(uint8_t * event, uint16_t size, int dump){ static void hci_emit_acl_packet(uint8_t * packet, uint16_t size){ if (!hci_stack->acl_packet_handler) return; - hci_stack->acl_packet_handler(HCI_ACL_DATA_PACKET, packet, size); + hci_stack->acl_packet_handler(HCI_ACL_DATA_PACKET, 0, packet, size); } static void hci_notify_if_sco_can_send_now(void){ @@ -2984,7 +2984,7 @@ static void hci_notify_if_sco_can_send_now(void){ hci_stack->sco_waiting_for_can_send_now = 0; uint8_t event[2] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0 }; hci_dump_packet(HCI_EVENT_PACKET, 1, event, sizeof(event)); - hci_stack->sco_packet_handler(HCI_EVENT_PACKET, event, sizeof(event)); + hci_stack->sco_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); } } diff --git a/src/hci.h b/src/hci.h index 71bfb07b7..ce9b15265 100644 --- a/src/hci.h +++ b/src/hci.h @@ -520,10 +520,10 @@ typedef struct { btstack_linked_list_t connections; /* callback to L2CAP layer */ - void (*acl_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size); + btstack_packet_handler_t acl_packet_handler; /* callback for SCO data */ - void (*sco_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size); + btstack_packet_handler_t sco_packet_handler; /* callbacks for events */ btstack_linked_list_t event_handlers; @@ -721,12 +721,12 @@ void hci_add_event_handler(btstack_packet_callback_registration_t * callback_han /** * @brief Registers a packet handler for ACL data. Used by L2CAP */ -void hci_register_acl_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)); +void hci_register_acl_packet_handler(btstack_packet_handler_t handler); /** * @brief Registers a packet handler for SCO data. Used for HSP and HFP profiles. */ -void hci_register_sco_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)); +void hci_register_sco_packet_handler(btstack_packet_handler_t handler); // Sending HCI Commands diff --git a/src/l2cap.c b/src/l2cap.c index ddc4f9121..51ce5320a 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -82,7 +82,7 @@ static void l2cap_emit_channel_closed(l2cap_channel_t *channel); static void l2cap_emit_connection_request(l2cap_channel_t *channel); static int l2cap_channel_ready_for_open(l2cap_channel_t *channel); static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); -static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t size ); +static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ); static void l2cap_notify_channel_can_send(void); typedef struct l2cap_fixed_channel { @@ -1381,7 +1381,7 @@ static void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * } } -static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t size ){ +static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){ // Get Channel ID uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); @@ -1487,9 +1487,9 @@ static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t siz default: { // Find channel for this channel_id and connection handle - l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id); - if (channel) { - l2cap_dispatch_to_channel(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); + l2cap_channel_t * l2cap_channel = l2cap_get_channel_for_local_cid(channel_id); + if (l2cap_channel) { + l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); } break; } @@ -1499,7 +1499,7 @@ static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t siz } // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE -void l2cap_finialize_channel_close(l2cap_channel_t *channel){ +void l2cap_finialize_channel_close(l2cap_channel_t * channel){ channel->state = L2CAP_STATE_CLOSED; l2cap_emit_channel_closed(channel); // discard channel diff --git a/test/hfp/hfp_ag_client_test.c b/test/hfp/hfp_ag_client_test.c index a976ae135..176718419 100644 --- a/test/hfp/hfp_ag_client_test.c +++ b/test/hfp/hfp_ag_client_test.c @@ -346,7 +346,8 @@ static void simulate_test_sequence(hfp_test_item_t * test_item){ } } -void packet_handler(uint8_t * event, uint16_t event_size){ +void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ + if (event[0] != HCI_EVENT_HFP_META) return; if (event[3] diff --git a/test/hfp/hfp_hf_client_test.c b/test/hfp/hfp_hf_client_test.c index b8d8e8cde..6d4068d36 100644 --- a/test/hfp/hfp_hf_client_test.c +++ b/test/hfp/hfp_hf_client_test.c @@ -391,7 +391,7 @@ void simulate_test_sequence(hfp_test_item_t * test_item){ } } -void packet_handler(uint8_t * event, uint16_t event_size){ +void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ if (event[0] != HCI_EVENT_HFP_META) return; switch (event[2]) { diff --git a/test/pts/hfp_ag_test.c b/test/pts/hfp_ag_test.c index 4d89527ba..e27e0a0b2 100644 --- a/test/pts/hfp_ag_test.c +++ b/test/pts/hfp_ag_test.c @@ -570,7 +570,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac } -static void packet_handler(uint8_t * event, uint16_t event_size){ +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ switch (event[0]){ case HCI_EVENT_INQUIRY_RESULT: case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: diff --git a/test/pts/hfp_hf_test.c b/test/pts/hfp_hf_test.c index b55c5a9fb..76d1df4bd 100644 --- a/test/pts/hfp_hf_test.c +++ b/test/pts/hfp_hf_test.c @@ -462,7 +462,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac } -static void packet_handler(uint8_t * event, uint16_t event_size){ +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ if (event[0] != HCI_EVENT_HFP_META) return; switch (event[2]) { diff --git a/test/pts/hsp_ag_test.c b/test/pts/hsp_ag_test.c index a79e0fe25..b1b63008a 100644 --- a/test/pts/hsp_ag_test.c +++ b/test/pts/hsp_ag_test.c @@ -154,7 +154,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac } // Audio Gateway routines -static void packet_handler(uint8_t * event, uint16_t event_size){ +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ switch (event[2]) { case HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE: if (event[3] == 0){ diff --git a/test/pts/hsp_hs_test.c b/test/pts/hsp_hs_test.c index 7d131d883..c0a9e3e07 100644 --- a/test/pts/hsp_hs_test.c +++ b/test/pts/hsp_hs_test.c @@ -159,7 +159,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac } } -static void packet_handler(uint8_t * event, uint16_t event_size){ +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size){ // printf("Packet handler event 0x%02x\n", event[0]); switch (event[0]) { case BTSTACK_EVENT_STATE: