diff --git a/src/hfp.c b/src/hfp.c index 02e9c075f..bd395f480 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -702,8 +702,7 @@ void process_command(hfp_connection_t * context){ } if (strncmp((char *)context->line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){ - context->command = HFP_CMD_CONFIRM_COMMON_CODEC; - + context->command = HFP_CMD_RECEIVED_COMMON_CODEC; return; } @@ -831,12 +830,12 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes switch (context->command){ - case HFP_CMD_CONFIRM_COMMON_CODEC: + case HFP_CMD_RECEIVED_COMMON_CODEC: context->remote_codec_received = atoi((char*)context->line_buffer); break; case HFP_CMD_SUPPORTED_FEATURES: context->remote_supported_features = atoi((char*)context->line_buffer); - printf("Parsed supported feature %d\n", context->remote_supported_features); + log_info("Parsed supported feature %d\n", context->remote_supported_features); break; case HFP_CMD_AVAILABLE_CODECS: printf("Parsed codec %s\n", context->line_buffer); @@ -848,11 +847,11 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ if (context->retrieve_ag_indicators == 1){ strcpy((char *)context->ag_indicators[context->parser_item_index].name, (char *)context->line_buffer); context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1; - printf("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer); + log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer); } if (context->retrieve_ag_indicators_status == 1){ - printf("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer); + log_info("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer); context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer); context->parser_item_index++; break; @@ -861,32 +860,32 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: context->parser_item_index++; if (context->parser_item_index != 4) break; - printf("Parsed Enable indicators: %s\n", context->line_buffer); + log_info("Parsed Enable indicators: %s\n", context->line_buffer); value = atoi((char *)&context->line_buffer[0]); context->enable_status_update_for_ag_indicators = (uint8_t) value; break; case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: - printf("Parsed Support call hold: %s\n", context->line_buffer); + log_info("Parsed Support call hold: %s\n", context->line_buffer); if (context->line_size > 2 ) break; strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer); context->remote_call_services_nr++; break; case HFP_CMD_GENERIC_STATUS_INDICATOR: - printf("parser HFP_CMD_GENERIC_STATUS_INDICATOR 1 (%d, %d, %d)\n", + log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 1 (%d, %d, %d)\n", context->list_generic_status_indicators, context->retrieve_generic_status_indicators, context->retrieve_generic_status_indicators_state); if (context->retrieve_generic_status_indicators == 1 || context->list_generic_status_indicators == 1){ - printf("Parsed Generic status indicator: %s\n", context->line_buffer); + log_info("Parsed Generic status indicator: %s\n", context->line_buffer); context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer); context->parser_item_index++; context->generic_status_indicators_nr = context->parser_item_index; break; } - printf("parser HFP_CMD_GENERIC_STATUS_INDICATOR 2\n"); + log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 2\n"); if (context->retrieve_generic_status_indicators_state == 1){ // HF parses inital AG gen. ind. state - printf("Parsed List generic status indicator %s state: ", context->line_buffer); + log_info("Parsed List generic status indicator %s state: ", context->line_buffer); context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer); break; } @@ -894,7 +893,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE: // AG parses new gen. ind. state - printf("Parsed Enable ag indicator state: %s\n", context->line_buffer); + log_info("Parsed Enable ag indicator state: %s\n", context->line_buffer); value = atoi((char *)&context->line_buffer[0]); if (!context->ag_indicators[context->parser_item_index].mandatory){ context->ag_indicators[context->parser_item_index].enabled = value; @@ -904,22 +903,22 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: // indicators are indexed starting with 1 context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1; - printf("Parsed status of the AG indicator %d, status ", context->parser_item_index); + log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index); break; case HFP_CMD_QUERY_OPERATOR_SELECTION: if (context->operator_name_format == 1){ if (context->line_buffer[0] == '3'){ - printf("Parsed Set network operator format : %s, ", context->line_buffer); + log_info("Parsed Set network operator format : %s, ", context->line_buffer); break; } // TODO emit ERROR, wrong format - printf("ERROR Set network operator format: index %s not supported\n", context->line_buffer); + log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer); break; } if (context->operator_name == 1) { context->network_operator.mode = atoi((char *)&context->line_buffer[0]); - printf("Parsed network operator mode: %d, ", context->network_operator.mode); + log_info("Parsed network operator mode: %d, ", context->network_operator.mode); break; } break; @@ -942,12 +941,12 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ switch (context->command){ case HFP_CMD_QUERY_OPERATOR_SELECTION: if (context->operator_name_format == 1) { - printf("format %s \n", context->line_buffer); + log_info("format %s \n", context->line_buffer); context->network_operator.format = atoi((char *)&context->line_buffer[0]); break; } if (context->operator_name == 1){ - printf("format %s, ", context->line_buffer); + log_info("format %s, ", context->line_buffer); context->network_operator.format = atoi((char *)&context->line_buffer[0]); } break; @@ -961,7 +960,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ case HFP_CMD_INDICATOR: if (context->retrieve_ag_indicators == 1){ context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer); - printf("%s, ", context->line_buffer); + log_info("%s, ", context->line_buffer); } break; default: @@ -974,7 +973,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ case HFP_CMD_QUERY_OPERATOR_SELECTION: if (context->operator_name == 1){ strcpy(context->network_operator.name, (char *)context->line_buffer); - printf("name %s\n", context->line_buffer); + log_info("name %s\n", context->line_buffer); } break; case HFP_CMD_INDICATOR: @@ -982,7 +981,7 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){ context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer); context->parser_item_index++; context->ag_indicators_nr = context->parser_item_index; - printf("%s)\n", context->line_buffer); + log_info("%s)\n", context->line_buffer); } break; default: @@ -1006,7 +1005,6 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_ log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr)); return; } - printf("hfp_establish_service_level_connection context state %d\n", context->state); switch (context->state){ case HFP_W2_DISCONNECT_RFCOMM: context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; diff --git a/src/hfp.h b/src/hfp.h index d9830a3a0..831a48f0a 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -141,7 +141,7 @@ typedef enum { HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR, HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP, - HFP_CMD_CONFIRM_COMMON_CODEC + HFP_CMD_RECEIVED_COMMON_CODEC } hfp_command_t; @@ -363,6 +363,7 @@ typedef struct hfp_connection { uint8_t trigger_codec_connection_setup; uint8_t ag_ready_for_codecs_connection_setup; uint8_t remote_codec_received; + uint8_t codec_confirmed; uint8_t establish_audio_connection; uint8_t release_audio_connection; diff --git a/src/hfp_ag.c b/src/hfp_ag.c index 9203ee2fb..9181732c7 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -373,7 +373,7 @@ void hfp_run_for_context(hfp_connection_t *context){ // printf(" hfp_run_for_context \n"); if (!context) return; if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; - //printf(" hfp_run_for_context 1 state %d, command %d\n", context->state, context->command); + printf("AG hfp_run_for_context 1 state %d, command %d\n", context->state, context->command); if (context->state == HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ if (context->send_ok){ diff --git a/src/hfp_hf.c b/src/hfp_hf.c index 2ee3565ec..e521cc22f 100644 --- a/src/hfp_hf.c +++ b/src/hfp_hf.c @@ -452,51 +452,57 @@ static void hfp_run_for_context(hfp_connection_t * context){ // handle audio connection setup // printf("hfp_run_for_context state %d \n", context->state); + if (context->wait_ok) return; + switch (context->state){ case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: - if (context->wait_ok) return; - if (context->notify_ag_on_new_codecs){ - hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); context->wait_ok = 1; + hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); break; } if (context->trigger_codec_connection_setup){ - hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); + context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC; context->wait_ok = 1; + hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); break; } break; - case HFP_SLE_W2_EXCHANGE_COMMON_CODEC: - if (!context->remote_codec_received) return; - context->wait_ok = 1; - - if (hfp_hf_supports_codec(context->remote_codec_received)){ - context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; + case HFP_SLE_W4_EXCHANGE_COMMON_CODEC: + if (context->notify_ag_on_new_codecs){ + context->wait_ok = 1; + context->codec_confirmed = 0; + context->remote_codec_received = 0; + context->negotiated_codec = 0; + hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); + break; + } + if (context->remote_codec_received){ + context->codec_confirmed = 1; + context->wait_ok = 1; hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->remote_codec_received); break; } - context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; - context->notify_ag_on_new_codecs = 1; - context->remote_codec_received = 0; - hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); break; case HFP_CODECS_CONNECTION_ESTABLISHED: if (context->notify_ag_on_new_codecs){ - printf("restart codecs negotiation \n"); - // context->negotiated_codec = 0; + context->negotiated_codec = 0; context->wait_ok = 1; - context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; - hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); + context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); break; } - hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0); + if (context->trigger_codec_connection_setup){ + context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC; + context->wait_ok = 1; + hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); + break; + } if (context->establish_audio_connection){ // TODO AUDIO CONNECTION @@ -533,17 +539,28 @@ void hfp_hf_switch_on_ok(hfp_connection_t *context){ context->notify_ag_on_new_codecs = 0; break; } + case HFP_SLE_W2_EXCHANGE_COMMON_CODEC: if (context->trigger_codec_connection_setup){ context->trigger_codec_connection_setup = 0; - context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC; + context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; break; } break; case HFP_SLE_W4_EXCHANGE_COMMON_CODEC: - context->negotiated_codec = context->remote_codec_received; - printf("remote codec received\n"); - context->remote_codec_received = 0; - context->state = HFP_CODECS_CONNECTION_ESTABLISHED; + if (context->notify_ag_on_new_codecs){ + context->codec_confirmed = 0; + context->remote_codec_received = 0; + context->notify_ag_on_new_codecs = 0; + break; + } + if (context->codec_confirmed && context->remote_codec_received){ + context->negotiated_codec = context->remote_codec_received; + context->codec_confirmed = 0; + context->remote_codec_received = 0; + context->state = HFP_CODECS_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0); + break; + } break; case HFP_AUDIO_CONNECTION_ESTABLISHED: @@ -630,16 +647,17 @@ void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){ hfp_codecs[i] = codecs[i]; } + char buffer[30]; + int offset = join(buffer, sizeof(buffer), hfp_codecs, hfp_codecs_nr); + buffer[offset] = 0; + printf("set codecs %s\n", buffer); + linked_list_iterator_t it; linked_list_iterator_init(&it, hfp_get_connections()); while (linked_list_iterator_has_next(&it)){ hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); if (!connection) continue; connection->notify_ag_on_new_codecs = 1; - if (connection->negotiated_codec){ - connection->trigger_codec_connection_setup = 1; - } - printf("hfp_hf_set_codecs trigger %d\n", connection->trigger_codec_connection_setup); hfp_run_for_context(connection); } } @@ -721,16 +739,12 @@ void hfp_hf_negotiate_codecs(bd_addr_t bd_addr){ log_error("HFP HF: connection doesn't exist."); return; } - connection->trigger_codec_connection_setup = 0; + if (connection->state >= HFP_W2_DISCONNECT_SCO) return; + if (!has_codec_negotiation_feature(connection)) return; - if (connection->state == HFP_CODECS_CONNECTION_ESTABLISHED) return; - - if (!has_codec_negotiation_feature(connection)){ - connection->trigger_codec_connection_setup = 0; - return; + if (connection->state != HFP_SLE_W4_EXCHANGE_COMMON_CODEC){ + connection->trigger_codec_connection_setup = 1; } - connection->trigger_codec_connection_setup = 1; - hfp_run_for_context(connection); } diff --git a/test/hfp/hfp_hf_client_test.c b/test/hfp/hfp_hf_client_test.c index 4ac6a162a..5272d994d 100644 --- a/test/hfp/hfp_hf_client_test.c +++ b/test/hfp/hfp_hf_client_test.c @@ -75,7 +75,7 @@ const uint8_t rfcomm_channel_nr = 1; static bd_addr_t device_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08}; -static uint8_t codecs[1] = {HFP_CODEC_CVSD}; +static uint8_t codecs[2] = {1,2}; static uint16_t indicators[1] = {0x01}; static uint8_t service_level_connection_established = 0; @@ -143,6 +143,9 @@ static int expected_rfcomm_command(const char * cmd){ } static void verify_expected_rfcomm_command(const char * cmd){ + if (expected_rfcomm_command(cmd)){ + printf("\nError: Expected:'%s', but got:'%s'", cmd, (char *)get_rfcomm_payload()); + } CHECK_EQUAL(expected_rfcomm_command(cmd),0); } @@ -152,7 +155,7 @@ const char * hf_slc_test1[] = { "AT+BRSF=438", "+BRSF:1007", HFP_OK, - "AT+BAC=1", + "AT+BAC=1,2", HFP_OK, "AT+CIND=?", "+CIND:\"service\",(0,1),\"call\",(0,1),\"callsetup\",(0,3),\"battchg\",(0,5),\"signal\",(0,5),\"roam\",(0,1),\"callheld\",(0,2)", @@ -171,6 +174,12 @@ hfp_test_item_t hfp_slc_tests[] = { TEST_SEQUENCE(hf_slc_test1) }; +/* Service Level Connection (slc) common commands */ +const char * hf_slc_cmds_test1[] = { + "AT+BAC=1,3", + HFP_OK +}; + /* Codecs Connection (cc) test sequences */ const char * hf_cc_test1[] = { @@ -181,8 +190,20 @@ const char * hf_cc_test1[] = { HFP_OK }; +const char * hf_cc_test2[] = { + "AT+BCC", + HFP_OK, + "+BCS:1", + "AT+BAC=2,3", + HFP_OK, + "+BCS:2", + "AT+BCS=2", + HFP_OK +}; + hfp_test_item_t hfp_cc_tests[] = { - TEST_SEQUENCE(hf_cc_test1) + TEST_SEQUENCE(hf_cc_test1), + TEST_SEQUENCE(hf_cc_test2) }; @@ -202,8 +223,7 @@ TEST_GROUP(HandsfreeClient){ codecs_connection_established = 0; audio_connection_established = 0; service_level_connection_released = 0; - hfp_hf_set_codecs(codecs, 1); - + test_item_size = sizeof(hfp_test_item_t); slc_tests_size = sizeof(hfp_slc_tests)/test_item_size; cc_tests_size = sizeof(hfp_cc_tests) /test_item_size; @@ -226,8 +246,18 @@ TEST_GROUP(HandsfreeClient){ int i = 0; for (i=0; i < nr_test_steps; i++){ char * cmd = test_steps[i]; + // printf("---> next step %s\n", cmd); if (memcmp(cmd, "AT", 2) == 0){ - verify_expected_rfcomm_command(cmd); + int parsed_codecs[2]; + uint8_t new_codecs[2]; + if (memcmp(cmd, "AT+BAC=", 7) == 0){ + sscanf(&cmd[7],"%d,%d", &parsed_codecs[0], &parsed_codecs[1]); + new_codecs[0] = parsed_codecs[0]; + new_codecs[1] = parsed_codecs[1]; + hfp_hf_set_codecs((uint8_t*)new_codecs, 2); + } else { + verify_expected_rfcomm_command(cmd); + } } else { inject_rfcomm_command((uint8_t*)cmd, strlen(cmd)); } @@ -237,14 +267,16 @@ TEST_GROUP(HandsfreeClient){ void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){ service_level_connection_established = 0; hfp_hf_establish_service_level_connection(device_addr); - test((char **) hf_slc_test1, sizeof(hf_slc_test1)/sizeof(char*)); + test((char **) test_steps, nr_test_steps); CHECK_EQUAL(service_level_connection_established, 1); + hfp_hf_set_codecs(codecs, 1); + inject_rfcomm_command((uint8_t*)HFP_OK, strlen(HFP_OK)); } void setup_hfp_codecs_connection_state_machine(char ** test_steps, int nr_test_steps){ codecs_connection_established = 0; hfp_hf_negotiate_codecs(device_addr); - test((char **) hf_cc_test1, sizeof(hf_cc_test1)/sizeof(char*)); + test((char **) test_steps, nr_test_steps); CHECK_EQUAL(codecs_connection_established, 1); } @@ -255,10 +287,8 @@ TEST_GROUP(HandsfreeClient){ }; - -TEST(HandsfreeClient, HFCodecsConnectionEstablished1){ +TEST(HandsfreeClient, HFCodecsConnectionEstablished){ setup_hfp_service_level_connection(default_slc_setup, default_slc_setup_size); - for (int i = 0; i < cc_tests_size; i++){ setup_hfp_codecs_connection_state_machine(hfp_cc_tests[i].test, hfp_cc_tests[i].len); } @@ -266,10 +296,7 @@ TEST(HandsfreeClient, HFCodecsConnectionEstablished1){ TEST(HandsfreeClient, HFCodecChange){ setup_hfp_service_level_connection(default_slc_setup, default_slc_setup_size); - - uint8_t new_codecs[] = {1,2}; - hfp_hf_set_codecs(new_codecs, 2); - inject_rfcomm_command((uint8_t*)HFP_OK, strlen(HFP_OK)); + test((char**)hf_slc_cmds_test1, sizeof(hf_slc_cmds_test1)/sizeof(char*)); verify_expected_rfcomm_command(HFP_OK); CHECK_EQUAL(service_level_connection_established, 1); }