diff --git a/src/hfp.c b/src/hfp.c index 988f6177f..ec20d9151 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -469,7 +469,7 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE: // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16) - printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); + printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x, size %u\n", packet_type, packet[0], size); bt_flip_addr(event_addr, &packet[3]); context = get_hfp_connection_context_for_bd_addr(event_addr); @@ -501,13 +501,23 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t break; case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ + bt_flip_addr(event_addr, &packet[5]); + printf("SCO Complete packet_handler type %u (HCI = %u), packet[0] %x, size %u\n", packet_type, HCI_EVENT_PACKET, packet[0], size); + int index = 2; uint8_t status = packet[index++]; + + if (status != 0){ + log_error("(e)SCO Connection is not established, status %u", status); + break; + } + uint16_t sco_handle = READ_BT_16(packet, index); index+=2; - bd_addr_t address; - memcpy(address, &packet[index], 6); + + bt_flip_addr(event_addr, &packet[index]); 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 @@ -517,20 +527,16 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t index+=2; uint8_t air_mode = packet[index]; - if (status != 0){ - log_error("(e)SCO Connection is not established, status %u", status); - break; - } switch (link_type){ case 0x00: - printf("SCO Connection established. \n"); + log_info("SCO Connection established. \n"); 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: - printf("eSCO Connection established. \n"); + log_info("eSCO Connection established. \n"); break; default: log_error("(e)SCO reserved link_type 0x%2x", link_type); @@ -538,11 +544,17 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t } 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); + bd_addr_to_str(event_addr), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); - context = get_hfp_connection_context_for_bd_addr(address); + context = get_hfp_connection_context_for_bd_addr(event_addr); + + if (!context) { + log_error("SCO link created, context not found."); + break; + } if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){ + log_info("sco about to disconnect: HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN"); context->state = HFP_W2_DISCONNECT_SCO; break; } @@ -575,10 +587,12 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t if (context->state != HFP_W4_SCO_DISCONNECTED){ log_info("Received gap disconnect in wrong hfp state"); } - + log_info("Check SCO handle: incoming 0x%02x, context 0x%02x\n", handle,context->sco_handle); + if (handle == context->sco_handle){ - printf("SCO disconnected, w2 disconnect RFCOMM\n"); + log_info("SCO disconnected, w2 disconnect RFCOMM\n"); context->sco_handle = 0; + context->release_audio_connection = 0; context->state = HFP_W2_DISCONNECT_RFCOMM; hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED, 0); break; @@ -722,7 +736,8 @@ static void process_command(hfp_connection_t * context){ if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0) return; - printf(" process unknown command 3 %s \n", context->line_buffer); + context->command = HFP_CMD_ERROR; + printf(" process unknown command %s \n", context->line_buffer); } #if 0 @@ -1072,10 +1087,10 @@ void hfp_release_service_level_connection(hfp_connection_t * context){ return; } -void hfp_release_audio_connection(hfp_connection_t * connection){ - if (!connection) return; - if (connection->state >= HFP_W2_DISCONNECT_SCO) return; - connection->release_audio_connection = 1; +void hfp_release_audio_connection(hfp_connection_t * context){ + if (!context) return; + if (context->state >= HFP_W2_DISCONNECT_SCO) return; + context->release_audio_connection = 1; } diff --git a/src/hfp_ag.c b/src/hfp_ag.c index 3d0528ef6..ad492b1cb 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -329,11 +329,12 @@ static int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint return send_str_over_rfcomm(cid, buffer); } -static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t indicator){ - char buffer[20]; - sprintf(buffer, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator.index, indicator.status); - return send_str_over_rfcomm(cid, buffer); -} +// static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t indicator){ +// char buffer[20]; +// sprintf(buffer, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator.index, indicator.status); +// log_info("HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE send %s", buffer); +// return send_str_over_rfcomm(cid, buffer); +// } static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){ char buffer[40]; @@ -368,10 +369,11 @@ static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){ + log_info(" AG run for context_service_level_connection \n"); if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return 0; - //printf(" AG run for context_service_level_connection \n"); int done = 0; - + log_info(" AG run for context_service_level_connection 1\n"); + switch(context->command){ case HFP_CMD_SUPPORTED_FEATURES: switch(context->state){ @@ -498,7 +500,7 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * co static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){ if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; int done = 0; - //printf(" SLC queries: "); + log_info(" SLC queries: "); switch(context->command){ case HFP_CMD_AVAILABLE_CODECS: @@ -528,15 +530,19 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio } break; case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:{ - int i; - for (i = 0; i < context->ag_indicators_nr; i++){ - if (context->ag_indicators[i].enabled == 0) continue; - if (context->ag_indicators[i].status_changed == 0) continue; - hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]); - done = 1; - context->ag_indicators[i].status_changed = 0; - return done; - } + + hfp_ag_ok(context->rfcomm_cid); + done = 1; + break; + // int i; + // for (i = 0; i < context->ag_indicators_nr; i++){ + // if (context->ag_indicators[i].enabled == 0) continue; + // if (context->ag_indicators[i].status_changed == 0) continue; + // hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]); + // done = 1; + // context->ag_indicators[i].status_changed = 0; + // return done; + // } break; } case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: @@ -550,8 +556,9 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio return done; } + log_info("SLC queries: ag_trigger_codec_connection_setup"); if (context->ag_trigger_codec_connection_setup){ // received BCS - //printf(" send BCS \n"); + log_info(" send BCS \n"); context->ag_trigger_codec_connection_setup = 0; context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; context->suggested_codec = hfp_ag_suggest_codec(context); @@ -578,15 +585,16 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){ + log_info(" AG run for context_codecs_connection: "); if (context->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || context->state > HFP_W2_DISCONNECT_SCO) return 0; int done = 0; - //printf(" AG run for context_codecs_connection: "); + switch (context->state){ case HFP_SLE_W2_EXCHANGE_COMMON_CODEC: if (context->ag_trigger_codec_connection_setup){ // received BCS - //printf(" send BCS \n"); + log_info(" send BCS \n"); context->ag_trigger_codec_connection_setup = 0; context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; context->suggested_codec = hfp_ag_suggest_codec(context); @@ -596,10 +604,11 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){ } break; case HFP_SLE_W4_EXCHANGE_COMMON_CODEC: + log_info("entered HFP_SLE_W4_EXCHANGE_COMMON_CODEC state"); switch(context->command){ case HFP_CMD_AVAILABLE_CODECS: if (context->notify_ag_on_new_codecs){ // received BAC - //printf(" received BAC\n"); + log_info(" received BAC\n"); context->notify_ag_on_new_codecs = 0; if (context->suggested_codec != hfp_ag_suggest_codec(context)){ context->suggested_codec = hfp_ag_suggest_codec(context); @@ -612,7 +621,7 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){ } break; case HFP_CMD_HF_CONFIRMED_CODEC: - //printf(" received AT+BCS\n"); + log_info(" received AT+BCS\n"); if (context->codec_confirmed != context->suggested_codec){ context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_ag_error(context->rfcomm_cid); @@ -626,6 +635,7 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){ done = 1; break; default: + log_info("command not handled"); break; } break; @@ -664,14 +674,19 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){ if (context->establish_audio_connection){ context->state = HFP_W4_SCO_CONNECTED; - hci_send_cmd(&hci_setup_synchronous_connection, context->con_handle, 8000, 8000, 0xFFFF, 0x0043, 0xFF, 0x003F); + hci_send_cmd(&hci_setup_synchronous_connection, context->con_handle, 8000, 8000, 0xFFFF, hci_get_sco_voice_setting(), 0xFF, 0x003F); done = 1; return done; } break; - - case HFP_AUDIO_CONNECTION_ESTABLISHED: + case HFP_W2_DISCONNECT_SCO: + context->state = HFP_W4_SCO_DISCONNECTED; + gap_disconnect(context->sco_handle); + done = 1; + return done; + + case HFP_AUDIO_CONNECTION_ESTABLISHED: if (context->release_audio_connection){ context->state = HFP_W4_SCO_DISCONNECTED; gap_disconnect(context->sco_handle); @@ -679,20 +694,42 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){ return done; } break; - default: break; } + + if (done) return done; + + if (context->release_audio_connection){ + context->state = HFP_W4_SCO_DISCONNECTED; + gap_disconnect(context->sco_handle); + done = 1; + return done; + } return done; } static void hfp_run_for_context(hfp_connection_t *context){ + log_info("ag hfp_run_for_context entered"); + if (!context) return; + log_info("ag hfp_run_for_context context found"); if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; + log_info("ag hfp_run_for_context rfcomm_can_send_packet_now"); + + if (context->command == HFP_CMD_ERROR){ + log_info("ag hfp_run_for_context HFP_CMD_ERROR"); + hfp_ag_error(context->rfcomm_cid); + context->send_ok = 0; + context->send_error = 0; + context->command = HFP_CMD_NONE; + return; + } - // printf("AG hfp_run_for_context 1 state %d == %d (HFP_W2_DISCONNECT_SCO), command %d\n", context->state, HFP_W2_DISCONNECT_SCO, context->command); + if (context->send_ok){ + log_info("ag hfp_run_for_context hfp_ag_ok"); hfp_ag_ok(context->rfcomm_cid); context->send_ok = 0; context->command = HFP_CMD_NONE; @@ -700,6 +737,7 @@ static void hfp_run_for_context(hfp_connection_t *context){ } if (context->send_error){ + log_info("ag hfp_run_for_context hfp_ag_error"); hfp_ag_error(context->rfcomm_cid); context->send_error = 0; context->command = HFP_CMD_NONE; @@ -707,16 +745,20 @@ static void hfp_run_for_context(hfp_connection_t *context){ } int done = hfp_ag_run_for_context_service_level_connection(context); - + log_info("hfp_ag_run_for_context_service_level_connection = %d", done); + if (rfcomm_can_send_packet_now(context->rfcomm_cid) && !done){ done = hfp_ag_run_for_context_service_level_connection_queries(context); + log_info("hfp_ag_run_for_context_service_level_connection_queries = %d", done); + if (rfcomm_can_send_packet_now(context->rfcomm_cid) && !done){ done = hfp_ag_run_for_context_codecs_connection(context); + log_info("hfp_ag_run_for_context_codecs_connection = %d", done); } } - if (context->command == HFP_CMD_NONE && !done){ + log_info("context->command == HFP_CMD_NONE"); switch(context->state){ case HFP_W2_DISCONNECT_RFCOMM: context->state = HFP_W4_RFCOMM_DISCONNECTED; @@ -783,7 +825,11 @@ void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); return; } + l2cap_init(); + l2cap_register_packet_handler(packet_handler); + rfcomm_register_packet_handler(packet_handler); + hfp_init(rfcomm_channel_nr); hfp_supported_features = supported_features; @@ -906,13 +952,21 @@ static void hfp_ag_negotiate_codecs(bd_addr_t bd_addr){ void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){ hfp_ag_establish_service_level_connection(bd_addr); hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); - if (!has_codec_negotiation_feature(connection)) return; + if (!has_codec_negotiation_feature(connection)){ + log_info("hfp_ag_establish_audio_connection 1 - no codec negotiation"); + return; + } + connection->establish_audio_connection = 0; if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; if (connection->state >= HFP_W2_DISCONNECT_SCO) return; + log_info("hfp_ag_establish_audio_connection 2"); + connection->establish_audio_connection = 1; if (connection->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){ + log_info("hfp_ag_establish_audio_connection ag_trigger_codec_connection_setup"); + connection->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP; connection->ag_trigger_codec_connection_setup = 1; } hfp_run_for_context(connection); diff --git a/src/hfp_hf.c b/src/hfp_hf.c index 00746debd..701ec6573 100644 --- a/src/hfp_hf.c +++ b/src/hfp_hf.c @@ -724,6 +724,8 @@ void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){ } void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status){ + l2cap_init(); + l2cap_register_packet_handler(packet_handler); rfcomm_register_packet_handler(packet_handler); hfp_init(rfcomm_channel_nr); diff --git a/test/hfp/hfp_ag_client_test.c b/test/hfp/hfp_ag_client_test.c index 88686f540..f650ea2e2 100644 --- a/test/hfp/hfp_ag_client_test.c +++ b/test/hfp/hfp_ag_client_test.c @@ -217,31 +217,31 @@ TEST(HFPClient, HFAudioConnectionEstablished){ CHECK_EQUAL(audio_connection_established, 0); } -// TEST(HFPClient, HFCodecsConnectionEstablished){ -// for (int i = 0; i < cc_tests_size(); i++){ -// setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size()); -// CHECK_EQUAL(service_level_connection_established, 1); +TEST(HFPClient, HFCodecsConnectionEstablished){ + for (int i = 0; i < cc_tests_size(); i++){ + setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size()); + CHECK_EQUAL(service_level_connection_established, 1); -// setup_hfp_codecs_connection(hfp_cc_tests()[i].test, hfp_cc_tests()[i].len); -// CHECK_EQUAL(codecs_connection_established, 1); -// teardown(); -// } -// } + setup_hfp_codecs_connection(hfp_cc_tests()[i].test, hfp_cc_tests()[i].len); + CHECK_EQUAL(codecs_connection_established, 1); + teardown(); + } +} -// TEST(HFPClient, HFServiceLevelConnectionCommands){ -// setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size()); -// CHECK_EQUAL(service_level_connection_established, 1); -// for (int i = 0; i < slc_cmds_tests_size(); i++){ -// simulate_test_sequence(hfp_slc_cmds_tests()[i].test, hfp_slc_cmds_tests()[i].len); -// } -// } +TEST(HFPClient, HFServiceLevelConnectionCommands){ + setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size()); + CHECK_EQUAL(service_level_connection_established, 1); + for (int i = 0; i < slc_cmds_tests_size(); i++){ + simulate_test_sequence(hfp_slc_cmds_tests()[i].test, hfp_slc_cmds_tests()[i].len); + } +} -// TEST(HFPClient, HFServiceLevelConnectionEstablished){ -// for (int i = 0; i < slc_tests_size(); i++){ -// setup_hfp_service_level_connection(hfp_slc_tests()[i].test, hfp_slc_tests()[i].len); -// CHECK_EQUAL(service_level_connection_established, 1); -// } -// } +TEST(HFPClient, HFServiceLevelConnectionEstablished){ + for (int i = 0; i < slc_tests_size(); i++){ + setup_hfp_service_level_connection(hfp_slc_tests()[i].test, hfp_slc_tests()[i].len); + CHECK_EQUAL(service_level_connection_established, 1); + } +} int main (int argc, const char * argv[]){ diff --git a/test/hfp/mock.c b/test/hfp/mock.c index 1cef34440..ef5e1528e 100644 --- a/test/hfp/mock.c +++ b/test/hfp/mock.c @@ -261,6 +261,9 @@ le_command_status_t gap_disconnect(hci_con_handle_t handle){ return BLE_PERIPHERAL_OK; } +uint16_t hci_get_sco_voice_setting(){ + return 0x40; +} void inject_rfcomm_command_to_hf(uint8_t * data, int len){ if (memcmp((char*)data, "AT", 2) == 0) return; diff --git a/test/pts/hfp_ag_test.c b/test/pts/hfp_ag_test.c index de9f0f69f..1a0426397 100644 --- a/test/pts/hfp_ag_test.c +++ b/test/pts/hfp_ag_test.c @@ -102,9 +102,6 @@ char cmd; // prototypes static void show_usage(); -static void reset_pst_flags(){ -} - // Testig User Interface static void show_usage(void){ printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n"); @@ -113,12 +110,12 @@ static void show_usage(void){ printf("a - establish HFP connection to PTS module\n"); printf("A - release HFP connection to PTS module\n"); + printf("z - establish HFP connection to speaker\n"); + printf("Z - release HFP connection to speaker\n"); + printf("b - establish AUDIO connection\n"); printf("B - release AUDIO connection\n"); - printf("z - establish HFP connection to local mac\n"); - printf("Z - release HFP connection to local mac\n"); - printf("d - report AG failure\n"); printf("---\n"); @@ -181,7 +178,12 @@ static void packet_handler(uint8_t * event, uint16_t event_size){ break; case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: printf("Service level connection released.\n\n"); - reset_pst_flags(); + break; + case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED: + printf("\n** Audio connection established **\n\n"); + break; + case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED: + printf("\n** Audio connection released **\n\n"); break; default: printf("event not handled %u\n", event[2]);