13deb3ec6SMatthias Ringwald /* 23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 33deb3ec6SMatthias Ringwald * 43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 63deb3ec6SMatthias Ringwald * are met: 73deb3ec6SMatthias Ringwald * 83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 153deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183deb3ec6SMatthias Ringwald * monetary gain. 193deb3ec6SMatthias Ringwald * 203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 233deb3ec6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 243deb3ec6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 373deb3ec6SMatthias Ringwald 383deb3ec6SMatthias Ringwald // ***************************************************************************** 393deb3ec6SMatthias Ringwald // 403deb3ec6SMatthias Ringwald // Minimal setup for HFP Hands-Free (HF) unit (!! UNDER DEVELOPMENT !!) 413deb3ec6SMatthias Ringwald // 423deb3ec6SMatthias Ringwald // ***************************************************************************** 433deb3ec6SMatthias Ringwald 443deb3ec6SMatthias Ringwald #include "btstack-config.h" 453deb3ec6SMatthias Ringwald 463deb3ec6SMatthias Ringwald #include <stdint.h> 473deb3ec6SMatthias Ringwald #include <stdio.h> 483deb3ec6SMatthias Ringwald #include <stdlib.h> 493deb3ec6SMatthias Ringwald #include <string.h> 503deb3ec6SMatthias Ringwald 513deb3ec6SMatthias Ringwald #include "hci_cmds.h" 523deb3ec6SMatthias Ringwald #include "run_loop.h" 533deb3ec6SMatthias Ringwald 543deb3ec6SMatthias Ringwald #include "hci.h" 553deb3ec6SMatthias Ringwald #include "btstack_memory.h" 563deb3ec6SMatthias Ringwald #include "hci_dump.h" 573deb3ec6SMatthias Ringwald #include "l2cap.h" 583edc84c5SMatthias Ringwald #include "classic/sdp_query_rfcomm.h" 593edc84c5SMatthias Ringwald #include "classic/sdp.h" 603deb3ec6SMatthias Ringwald #include "debug.h" 613edc84c5SMatthias Ringwald #include "classic/hfp.h" 623edc84c5SMatthias Ringwald #include "classic/hfp_hf.h" 633deb3ec6SMatthias Ringwald 643deb3ec6SMatthias Ringwald 653deb3ec6SMatthias Ringwald static const char default_hfp_hf_service_name[] = "Hands-Free unit"; 663deb3ec6SMatthias Ringwald static uint16_t hfp_supported_features = HFP_DEFAULT_HF_SUPPORTED_FEATURES; 673deb3ec6SMatthias Ringwald static uint8_t hfp_codecs_nr = 0; 683deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS]; 693deb3ec6SMatthias Ringwald 703deb3ec6SMatthias Ringwald static uint8_t hfp_indicators_nr = 0; 713deb3ec6SMatthias Ringwald static uint8_t hfp_indicators[HFP_MAX_NUM_HF_INDICATORS]; 723deb3ec6SMatthias Ringwald static uint8_t hfp_indicators_status; 733deb3ec6SMatthias Ringwald 743deb3ec6SMatthias Ringwald static hfp_callback_t hfp_callback; 753deb3ec6SMatthias Ringwald 763deb3ec6SMatthias Ringwald void hfp_hf_register_packet_handler(hfp_callback_t callback){ 773deb3ec6SMatthias Ringwald hfp_callback = callback; 783deb3ec6SMatthias Ringwald if (callback == NULL){ 793deb3ec6SMatthias Ringwald log_error("hfp_hf_register_packet_handler called with NULL callback"); 803deb3ec6SMatthias Ringwald return; 813deb3ec6SMatthias Ringwald } 823deb3ec6SMatthias Ringwald hfp_callback = callback; 833deb3ec6SMatthias Ringwald } 843deb3ec6SMatthias Ringwald 853deb3ec6SMatthias Ringwald static int hfp_hf_supports_codec(uint8_t codec){ 863deb3ec6SMatthias Ringwald int i; 873deb3ec6SMatthias Ringwald for (i = 0; i < hfp_codecs_nr; i++){ 883deb3ec6SMatthias Ringwald if (hfp_codecs[i] == codec) return 1; 893deb3ec6SMatthias Ringwald } 903deb3ec6SMatthias Ringwald return 0; 913deb3ec6SMatthias Ringwald } 923deb3ec6SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * connection){ 933deb3ec6SMatthias Ringwald int hf = get_bit(hfp_supported_features, HFP_HFSF_CODEC_NEGOTIATION); 943deb3ec6SMatthias Ringwald int ag = get_bit(connection->remote_supported_features, HFP_AGSF_CODEC_NEGOTIATION); 953deb3ec6SMatthias Ringwald return hf && ag; 963deb3ec6SMatthias Ringwald } 973deb3ec6SMatthias Ringwald 983deb3ec6SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){ 993deb3ec6SMatthias Ringwald int hf = get_bit(hfp_supported_features, HFP_HFSF_THREE_WAY_CALLING); 1003deb3ec6SMatthias Ringwald int ag = get_bit(connection->remote_supported_features, HFP_AGSF_THREE_WAY_CALLING); 1013deb3ec6SMatthias Ringwald return hf && ag; 1023deb3ec6SMatthias Ringwald } 1033deb3ec6SMatthias Ringwald 1043deb3ec6SMatthias Ringwald 1053deb3ec6SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * connection){ 1063deb3ec6SMatthias Ringwald int hf = get_bit(hfp_supported_features, HFP_HFSF_HF_INDICATORS); 1073deb3ec6SMatthias Ringwald int ag = get_bit(connection->remote_supported_features, HFP_AGSF_HF_INDICATORS); 1083deb3ec6SMatthias Ringwald return hf && ag; 1093deb3ec6SMatthias Ringwald } 1103deb3ec6SMatthias Ringwald 111ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 1123deb3ec6SMatthias Ringwald 1133deb3ec6SMatthias Ringwald void hfp_hf_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name, uint16_t supported_features){ 1143deb3ec6SMatthias Ringwald if (!name){ 1153deb3ec6SMatthias Ringwald name = default_hfp_hf_service_name; 1163deb3ec6SMatthias Ringwald } 1173deb3ec6SMatthias Ringwald hfp_create_sdp_record(service, SDP_Handsfree, rfcomm_channel_nr, name, supported_features); 1183deb3ec6SMatthias Ringwald } 1193deb3ec6SMatthias Ringwald 1203deb3ec6SMatthias Ringwald 1213deb3ec6SMatthias Ringwald static int hfp_hf_cmd_exchange_supported_features(uint16_t cid){ 1223deb3ec6SMatthias Ringwald char buffer[20]; 1233deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=%d\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features); 1243deb3ec6SMatthias Ringwald // printf("exchange_supported_features %s\n", buffer); 1253deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1263deb3ec6SMatthias Ringwald } 1273deb3ec6SMatthias Ringwald 1283deb3ec6SMatthias Ringwald static int hfp_hf_cmd_notify_on_codecs(uint16_t cid){ 1293deb3ec6SMatthias Ringwald char buffer[30]; 1303deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_AVAILABLE_CODECS); 1313deb3ec6SMatthias Ringwald offset += join(buffer+offset, sizeof(buffer)-offset, hfp_codecs, hfp_codecs_nr); 1323deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 1333deb3ec6SMatthias Ringwald buffer[offset] = 0; 1343deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1353deb3ec6SMatthias Ringwald } 1363deb3ec6SMatthias Ringwald 1373deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_indicators(uint16_t cid){ 1383deb3ec6SMatthias Ringwald char buffer[20]; 1393deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=?\r\n", HFP_INDICATOR); 1403deb3ec6SMatthias Ringwald // printf("retrieve_indicators %s\n", buffer); 1413deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1423deb3ec6SMatthias Ringwald } 1433deb3ec6SMatthias Ringwald 1443deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_indicators_status(uint16_t cid){ 1453deb3ec6SMatthias Ringwald char buffer[20]; 1463deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s?\r\n", HFP_INDICATOR); 1473deb3ec6SMatthias Ringwald // printf("retrieve_indicators_status %s\n", buffer); 1483deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1493deb3ec6SMatthias Ringwald } 1503deb3ec6SMatthias Ringwald 1513deb3ec6SMatthias Ringwald static int hfp_hf_cmd_activate_status_update_for_all_ag_indicators(uint16_t cid, uint8_t activate){ 1523deb3ec6SMatthias Ringwald char buffer[20]; 1533deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=3,0,0,%d\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, activate); 1543deb3ec6SMatthias Ringwald // printf("toggle_indicator_status_update %s\n", buffer); 1553deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1563deb3ec6SMatthias Ringwald } 1573deb3ec6SMatthias Ringwald 1583deb3ec6SMatthias Ringwald static int hfp_hf_cmd_activate_status_update_for_ag_indicator(uint16_t cid, uint32_t indicators_status, int indicators_nr){ 1593deb3ec6SMatthias Ringwald char buffer[50]; 1603deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS); 1613deb3ec6SMatthias Ringwald offset += join_bitmap(buffer+offset, sizeof(buffer)-offset, indicators_status, indicators_nr); 1623deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 1633deb3ec6SMatthias Ringwald buffer[offset] = 0; 1643deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1653deb3ec6SMatthias Ringwald } 1663deb3ec6SMatthias Ringwald 1673deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_can_hold_call(uint16_t cid){ 1683deb3ec6SMatthias Ringwald char buffer[20]; 1693deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=?\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES); 1703deb3ec6SMatthias Ringwald // printf("retrieve_can_hold_call %s\n", buffer); 1713deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1723deb3ec6SMatthias Ringwald } 1733deb3ec6SMatthias Ringwald 1743deb3ec6SMatthias Ringwald static int hfp_hf_cmd_list_supported_generic_status_indicators(uint16_t cid){ 1753deb3ec6SMatthias Ringwald char buffer[30]; 1763deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_GENERIC_STATUS_INDICATOR); 1773deb3ec6SMatthias Ringwald offset += join(buffer+offset, sizeof(buffer)-offset, hfp_indicators, hfp_indicators_nr); 1783deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 1793deb3ec6SMatthias Ringwald buffer[offset] = 0; 1803deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1813deb3ec6SMatthias Ringwald } 1823deb3ec6SMatthias Ringwald 1833deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_supported_generic_status_indicators(uint16_t cid){ 1843deb3ec6SMatthias Ringwald char buffer[20]; 1853deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=?\r\n", HFP_GENERIC_STATUS_INDICATOR); 1863deb3ec6SMatthias Ringwald // printf("retrieve_supported_generic_status_indicators %s\n", buffer); 1873deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1883deb3ec6SMatthias Ringwald } 1893deb3ec6SMatthias Ringwald 1903deb3ec6SMatthias Ringwald static int hfp_hf_cmd_list_initital_supported_generic_status_indicators(uint16_t cid){ 1913deb3ec6SMatthias Ringwald char buffer[20]; 1923deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s?\r\n", HFP_GENERIC_STATUS_INDICATOR); 1933deb3ec6SMatthias Ringwald // printf("list_initital_supported_generic_status_indicators %s\n", buffer); 1943deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1953deb3ec6SMatthias Ringwald } 1963deb3ec6SMatthias Ringwald 1973deb3ec6SMatthias Ringwald static int hfp_hf_cmd_query_operator_name_format(uint16_t cid){ 1983deb3ec6SMatthias Ringwald char buffer[20]; 1993deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=3,0\r\n", HFP_QUERY_OPERATOR_SELECTION); 2003deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2013deb3ec6SMatthias Ringwald } 2023deb3ec6SMatthias Ringwald 2033deb3ec6SMatthias Ringwald static int hfp_hf_cmd_query_operator_name(uint16_t cid){ 2043deb3ec6SMatthias Ringwald char buffer[20]; 2053deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s?\r\n", HFP_QUERY_OPERATOR_SELECTION); 2063deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2073deb3ec6SMatthias Ringwald } 2083deb3ec6SMatthias Ringwald 2093deb3ec6SMatthias Ringwald static int hfp_hf_cmd_enable_extended_audio_gateway_error_report(uint16_t cid, uint8_t enable){ 2103deb3ec6SMatthias Ringwald char buffer[20]; 2113deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=%d\r\n", HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, enable); 2123deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2133deb3ec6SMatthias Ringwald } 2143deb3ec6SMatthias Ringwald 2153deb3ec6SMatthias Ringwald static int hfp_hf_cmd_trigger_codec_connection_setup(uint16_t cid){ 2163deb3ec6SMatthias Ringwald char buffer[20]; 2173deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s\r\n", HFP_TRIGGER_CODEC_CONNECTION_SETUP); 2183deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2193deb3ec6SMatthias Ringwald } 2203deb3ec6SMatthias Ringwald 2213deb3ec6SMatthias Ringwald static int hfp_hf_cmd_confirm_codec(uint16_t cid, uint8_t codec){ 2223deb3ec6SMatthias Ringwald char buffer[20]; 2233deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec); 2243deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2253deb3ec6SMatthias Ringwald } 2263deb3ec6SMatthias Ringwald 2273deb3ec6SMatthias Ringwald static void hfp_emit_ag_indicator_event(hfp_callback_t callback, int status, hfp_ag_indicator_t indicator){ 2283deb3ec6SMatthias Ringwald if (!callback) return; 2293deb3ec6SMatthias Ringwald uint8_t event[6]; 2303deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 2313deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 2323deb3ec6SMatthias Ringwald event[2] = HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED; 2333deb3ec6SMatthias Ringwald event[3] = status; 2343deb3ec6SMatthias Ringwald event[4] = indicator.index; 2353deb3ec6SMatthias Ringwald event[5] = indicator.status; 2363deb3ec6SMatthias Ringwald (*callback)(event, sizeof(event)); 2373deb3ec6SMatthias Ringwald } 2383deb3ec6SMatthias Ringwald 2393deb3ec6SMatthias Ringwald static void hfp_emit_network_operator_event(hfp_callback_t callback, int status, hfp_network_opearator_t network_operator){ 2403deb3ec6SMatthias Ringwald if (!callback) return; 2413deb3ec6SMatthias Ringwald uint8_t event[24]; 2423deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 2433deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 2443deb3ec6SMatthias Ringwald event[2] = HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED; 2453deb3ec6SMatthias Ringwald event[3] = status; 2463deb3ec6SMatthias Ringwald event[4] = network_operator.mode; 2473deb3ec6SMatthias Ringwald event[5] = network_operator.format; 2483deb3ec6SMatthias Ringwald strcpy((char*)&event[6], network_operator.name); 2493deb3ec6SMatthias Ringwald (*callback)(event, sizeof(event)); 2503deb3ec6SMatthias Ringwald } 2513deb3ec6SMatthias Ringwald 2523deb3ec6SMatthias Ringwald static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * context){ 2533deb3ec6SMatthias Ringwald if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 2543deb3ec6SMatthias Ringwald int done = 0; 2553deb3ec6SMatthias Ringwald if (context->wait_ok) return done; 2563deb3ec6SMatthias Ringwald 2573deb3ec6SMatthias Ringwald switch (context->state){ 2583deb3ec6SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES: 2593deb3ec6SMatthias Ringwald hfp_hf_cmd_exchange_supported_features(context->rfcomm_cid); 2603deb3ec6SMatthias Ringwald context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES; 2613deb3ec6SMatthias Ringwald break; 2623deb3ec6SMatthias Ringwald case HFP_NOTIFY_ON_CODECS: 2633deb3ec6SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 2643deb3ec6SMatthias Ringwald context->state = HFP_W4_NOTIFY_ON_CODECS; 2653deb3ec6SMatthias Ringwald break; 2663deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS: 2673deb3ec6SMatthias Ringwald hfp_hf_cmd_retrieve_indicators(context->rfcomm_cid); 2683deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS; 2693deb3ec6SMatthias Ringwald context->retrieve_ag_indicators = 1; 2703deb3ec6SMatthias Ringwald context->retrieve_ag_indicators_status = 0; 2713deb3ec6SMatthias Ringwald break; 2723deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS_STATUS: 2733deb3ec6SMatthias Ringwald hfp_hf_cmd_retrieve_indicators_status(context->rfcomm_cid); 2743deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; 2753deb3ec6SMatthias Ringwald context->retrieve_ag_indicators_status = 1; 2763deb3ec6SMatthias Ringwald context->retrieve_ag_indicators = 0; 2773deb3ec6SMatthias Ringwald break; 2783deb3ec6SMatthias Ringwald case HFP_ENABLE_INDICATORS_STATUS_UPDATE: 2793deb3ec6SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, 1); 2803deb3ec6SMatthias Ringwald context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; 2813deb3ec6SMatthias Ringwald break; 2823deb3ec6SMatthias Ringwald case HFP_RETRIEVE_CAN_HOLD_CALL: 2833deb3ec6SMatthias Ringwald hfp_hf_cmd_retrieve_can_hold_call(context->rfcomm_cid); 2843deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; 2853deb3ec6SMatthias Ringwald break; 2863deb3ec6SMatthias Ringwald case HFP_LIST_GENERIC_STATUS_INDICATORS: 2873deb3ec6SMatthias Ringwald hfp_hf_cmd_list_supported_generic_status_indicators(context->rfcomm_cid); 2883deb3ec6SMatthias Ringwald context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 2893deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 1; 2903deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; 2913deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 0; 2923deb3ec6SMatthias Ringwald break; 2933deb3ec6SMatthias Ringwald case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS: 2943deb3ec6SMatthias Ringwald hfp_hf_cmd_retrieve_supported_generic_status_indicators(context->rfcomm_cid); 2953deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; 2963deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 0; 2973deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 1; 2983deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 0; 2993deb3ec6SMatthias Ringwald break; 3003deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: 3013deb3ec6SMatthias Ringwald hfp_hf_cmd_list_initital_supported_generic_status_indicators(context->rfcomm_cid); 3023deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 3033deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 0; 3043deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; 3053deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 1; 3063deb3ec6SMatthias Ringwald break; 3073deb3ec6SMatthias Ringwald default: 3083deb3ec6SMatthias Ringwald break; 3093deb3ec6SMatthias Ringwald } 3103deb3ec6SMatthias Ringwald return done; 3113deb3ec6SMatthias Ringwald } 3123deb3ec6SMatthias Ringwald 3133deb3ec6SMatthias Ringwald static void hfp_hf_handle_ok_service_level_connection_establishment(hfp_connection_t *context){ 3143deb3ec6SMatthias Ringwald if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return; 3153deb3ec6SMatthias Ringwald switch (context->state){ 3163deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: 3173deb3ec6SMatthias Ringwald if (has_codec_negotiation_feature(context)){ 3183deb3ec6SMatthias Ringwald context->state = HFP_NOTIFY_ON_CODECS; 3193deb3ec6SMatthias Ringwald break; 3203deb3ec6SMatthias Ringwald } 3213deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INDICATORS; 3223deb3ec6SMatthias Ringwald break; 3233deb3ec6SMatthias Ringwald 3243deb3ec6SMatthias Ringwald case HFP_W4_NOTIFY_ON_CODECS: 3253deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INDICATORS; 3263deb3ec6SMatthias Ringwald break; 3273deb3ec6SMatthias Ringwald 3283deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS: 3293deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INDICATORS_STATUS; 3303deb3ec6SMatthias Ringwald context->retrieve_ag_indicators = 0; 3313deb3ec6SMatthias Ringwald break; 3323deb3ec6SMatthias Ringwald 3333deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS_STATUS: 3343deb3ec6SMatthias Ringwald context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE; 3353deb3ec6SMatthias Ringwald context->retrieve_ag_indicators_status = 0; 3363deb3ec6SMatthias Ringwald break; 3373deb3ec6SMatthias Ringwald 3383deb3ec6SMatthias Ringwald case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: 3393deb3ec6SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(context)){ 3403deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_CAN_HOLD_CALL; 3413deb3ec6SMatthias Ringwald break; 3423deb3ec6SMatthias Ringwald } 3433deb3ec6SMatthias Ringwald if (has_hf_indicators_feature(context)){ 3443deb3ec6SMatthias Ringwald context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; 3453deb3ec6SMatthias Ringwald break; 3463deb3ec6SMatthias Ringwald } 3473deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 3483deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 3493deb3ec6SMatthias Ringwald break; 3503deb3ec6SMatthias Ringwald 3513deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_CAN_HOLD_CALL: 3523deb3ec6SMatthias Ringwald if (has_hf_indicators_feature(context)){ 3533deb3ec6SMatthias Ringwald context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; 3543deb3ec6SMatthias Ringwald break; 3553deb3ec6SMatthias Ringwald } 3563deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 3573deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 3583deb3ec6SMatthias Ringwald break; 3593deb3ec6SMatthias Ringwald 3603deb3ec6SMatthias Ringwald case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: 3613deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS; 3623deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; 3633deb3ec6SMatthias Ringwald break; 3643deb3ec6SMatthias Ringwald 3653deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: 3663deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 3673deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; 3683deb3ec6SMatthias Ringwald break; 3693deb3ec6SMatthias Ringwald 3703deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: 3713deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 3723deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 0; 3733deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 3743deb3ec6SMatthias Ringwald break; 3753deb3ec6SMatthias Ringwald default: 3763deb3ec6SMatthias Ringwald break; 3773deb3ec6SMatthias Ringwald } 3783deb3ec6SMatthias Ringwald } 3793deb3ec6SMatthias Ringwald 3803deb3ec6SMatthias Ringwald static void hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * context){ 3813deb3ec6SMatthias Ringwald if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return; 3823deb3ec6SMatthias Ringwald if (context->wait_ok) return; 3833deb3ec6SMatthias Ringwald 3843deb3ec6SMatthias Ringwald if (context->enable_status_update_for_ag_indicators != 0xFF){ 3853deb3ec6SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, context->enable_status_update_for_ag_indicators); 3863deb3ec6SMatthias Ringwald context->wait_ok = 1; 3873deb3ec6SMatthias Ringwald return; 3883deb3ec6SMatthias Ringwald }; 3893deb3ec6SMatthias Ringwald if (context->change_status_update_for_individual_ag_indicators){ 3903deb3ec6SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_ag_indicator(context->rfcomm_cid, 3913deb3ec6SMatthias Ringwald context->ag_indicators_status_update_bitmap, 3923deb3ec6SMatthias Ringwald context->ag_indicators_nr); 3933deb3ec6SMatthias Ringwald context->wait_ok = 1; 3943deb3ec6SMatthias Ringwald return; 3953deb3ec6SMatthias Ringwald } 3963deb3ec6SMatthias Ringwald 3973deb3ec6SMatthias Ringwald if (context->operator_name_format){ 3983deb3ec6SMatthias Ringwald hfp_hf_cmd_query_operator_name_format(context->rfcomm_cid); 3993deb3ec6SMatthias Ringwald context->wait_ok = 1; 4003deb3ec6SMatthias Ringwald return; 4013deb3ec6SMatthias Ringwald } 4023deb3ec6SMatthias Ringwald if (context->operator_name){ 4033deb3ec6SMatthias Ringwald hfp_hf_cmd_query_operator_name(context->rfcomm_cid); 4043deb3ec6SMatthias Ringwald context->wait_ok = 1; 4053deb3ec6SMatthias Ringwald return; 4063deb3ec6SMatthias Ringwald } 4073deb3ec6SMatthias Ringwald 4083deb3ec6SMatthias Ringwald if (context->enable_extended_audio_gateway_error_report){ 4093deb3ec6SMatthias Ringwald hfp_hf_cmd_enable_extended_audio_gateway_error_report(context->rfcomm_cid, context->enable_extended_audio_gateway_error_report); 4103deb3ec6SMatthias Ringwald context->wait_ok = 1; 4113deb3ec6SMatthias Ringwald return; 4123deb3ec6SMatthias Ringwald } 4133deb3ec6SMatthias Ringwald } 4143deb3ec6SMatthias Ringwald 4153deb3ec6SMatthias Ringwald static void hfp_hf_handle_ok_service_level_connection_queries(hfp_connection_t * context){ 4163deb3ec6SMatthias Ringwald if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return; 4173deb3ec6SMatthias Ringwald 4183deb3ec6SMatthias Ringwald if (context->enable_status_update_for_ag_indicators != 0xFF){ 4193deb3ec6SMatthias Ringwald context->enable_status_update_for_ag_indicators = 0xFF; 4203deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0); 4213deb3ec6SMatthias Ringwald return; 4223deb3ec6SMatthias Ringwald }; 4233deb3ec6SMatthias Ringwald 4243deb3ec6SMatthias Ringwald if (context->change_status_update_for_individual_ag_indicators == 1){ 4253deb3ec6SMatthias Ringwald context->change_status_update_for_individual_ag_indicators = 0; 4263deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0); 4273deb3ec6SMatthias Ringwald return; 4283deb3ec6SMatthias Ringwald } 4293deb3ec6SMatthias Ringwald 4303deb3ec6SMatthias Ringwald if (context->operator_name_format){ 4313deb3ec6SMatthias Ringwald context->operator_name_format = 0; 4323deb3ec6SMatthias Ringwald context->operator_name = 1; 4333deb3ec6SMatthias Ringwald return; 4343deb3ec6SMatthias Ringwald } 4353deb3ec6SMatthias Ringwald 4363deb3ec6SMatthias Ringwald if (context->operator_name){ 4373deb3ec6SMatthias Ringwald context->operator_name = 0; 4383deb3ec6SMatthias Ringwald hfp_emit_network_operator_event(hfp_callback, 0, context->network_operator); 4393deb3ec6SMatthias Ringwald return; 4403deb3ec6SMatthias Ringwald } 4413deb3ec6SMatthias Ringwald if (context->enable_extended_audio_gateway_error_report){ 4423deb3ec6SMatthias Ringwald context->enable_extended_audio_gateway_error_report = 0; 4433deb3ec6SMatthias Ringwald return; 4443deb3ec6SMatthias Ringwald } 4453deb3ec6SMatthias Ringwald } 4463deb3ec6SMatthias Ringwald 4473deb3ec6SMatthias Ringwald 4483deb3ec6SMatthias Ringwald static void hfp_hf_run_for_context_codecs_connection(hfp_connection_t * context){ 4493deb3ec6SMatthias Ringwald // if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED && context->state <= HFP_AUDIO_CONNECTION_ESTABLISHED){ 4503deb3ec6SMatthias Ringwald 4513deb3ec6SMatthias Ringwald // handle audio connection setup 4523deb3ec6SMatthias Ringwald // printf("hfp_run_for_context state %d \n", context->state); 4533deb3ec6SMatthias Ringwald if (context->wait_ok) return; 4543deb3ec6SMatthias Ringwald 4553deb3ec6SMatthias Ringwald switch (context->state){ 4563deb3ec6SMatthias Ringwald case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: 4573deb3ec6SMatthias Ringwald if (context->notify_ag_on_new_codecs){ 4583deb3ec6SMatthias Ringwald context->wait_ok = 1; 4593deb3ec6SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 4603deb3ec6SMatthias Ringwald break; 4613deb3ec6SMatthias Ringwald } 4623deb3ec6SMatthias Ringwald 4633deb3ec6SMatthias Ringwald if (context->hf_trigger_codec_connection_setup){ 4643deb3ec6SMatthias Ringwald context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC; 4653deb3ec6SMatthias Ringwald context->wait_ok = 1; 4663deb3ec6SMatthias Ringwald hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); 4673deb3ec6SMatthias Ringwald break; 4683deb3ec6SMatthias Ringwald } 4693deb3ec6SMatthias Ringwald 4703deb3ec6SMatthias Ringwald if (context->suggested_codec){ 4713deb3ec6SMatthias Ringwald context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; 4723deb3ec6SMatthias Ringwald context->codec_confirmed = 1; 4733deb3ec6SMatthias Ringwald context->wait_ok = 1; 4743deb3ec6SMatthias Ringwald hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec); 4753deb3ec6SMatthias Ringwald break; 4763deb3ec6SMatthias Ringwald } 4773deb3ec6SMatthias Ringwald break; 4783deb3ec6SMatthias Ringwald 4793deb3ec6SMatthias Ringwald case HFP_SLE_W4_EXCHANGE_COMMON_CODEC: 4803deb3ec6SMatthias Ringwald if (context->notify_ag_on_new_codecs){ 4813deb3ec6SMatthias Ringwald context->wait_ok = 1; 4823deb3ec6SMatthias Ringwald context->codec_confirmed = 0; 4833deb3ec6SMatthias Ringwald context->suggested_codec = 0; 4843deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 4853deb3ec6SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 4863deb3ec6SMatthias Ringwald break; 4873deb3ec6SMatthias Ringwald } 4883deb3ec6SMatthias Ringwald if (context->suggested_codec){ 4893deb3ec6SMatthias Ringwald if (hfp_hf_supports_codec(context->suggested_codec)){ 4903deb3ec6SMatthias Ringwald context->codec_confirmed = context->suggested_codec; 4913deb3ec6SMatthias Ringwald context->wait_ok = 1; 4923deb3ec6SMatthias Ringwald hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec); 4933deb3ec6SMatthias Ringwald } else { 4943deb3ec6SMatthias Ringwald context->notify_ag_on_new_codecs = 1; 4953deb3ec6SMatthias Ringwald context->wait_ok = 1; 4963deb3ec6SMatthias Ringwald context->codec_confirmed = 0; 4973deb3ec6SMatthias Ringwald context->suggested_codec = 0; 4983deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 4993deb3ec6SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 5003deb3ec6SMatthias Ringwald } 5013deb3ec6SMatthias Ringwald 5023deb3ec6SMatthias Ringwald break; 5033deb3ec6SMatthias Ringwald } 5043deb3ec6SMatthias Ringwald 5053deb3ec6SMatthias Ringwald break; 5063deb3ec6SMatthias Ringwald 5073deb3ec6SMatthias Ringwald case HFP_CODECS_CONNECTION_ESTABLISHED: 5083deb3ec6SMatthias Ringwald if (context->notify_ag_on_new_codecs){ 5093deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 5103deb3ec6SMatthias Ringwald context->wait_ok = 1; 5113deb3ec6SMatthias Ringwald context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; 5123deb3ec6SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 5133deb3ec6SMatthias Ringwald break; 5143deb3ec6SMatthias Ringwald } 5153deb3ec6SMatthias Ringwald 5163deb3ec6SMatthias Ringwald if (context->hf_trigger_codec_connection_setup){ 5173deb3ec6SMatthias Ringwald context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC; 5183deb3ec6SMatthias Ringwald context->wait_ok = 1; 5193deb3ec6SMatthias Ringwald hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); 5203deb3ec6SMatthias Ringwald break; 5213deb3ec6SMatthias Ringwald } 5223deb3ec6SMatthias Ringwald 5233deb3ec6SMatthias Ringwald if (context->establish_audio_connection){ 5243deb3ec6SMatthias Ringwald // TODO AUDIO CONNECTION 5253deb3ec6SMatthias Ringwald } 5263deb3ec6SMatthias Ringwald break; 5273deb3ec6SMatthias Ringwald default: 5283deb3ec6SMatthias Ringwald break; 5293deb3ec6SMatthias Ringwald } 5303deb3ec6SMatthias Ringwald } 5313deb3ec6SMatthias Ringwald 5323deb3ec6SMatthias Ringwald static void hfp_hf_handle_ok_codecs_connection(hfp_connection_t * context){ 5333deb3ec6SMatthias Ringwald // handle audio connection setup 5343deb3ec6SMatthias Ringwald switch (context->state){ 5353deb3ec6SMatthias Ringwald case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: 5363deb3ec6SMatthias Ringwald if (context->notify_ag_on_new_codecs){ 5373deb3ec6SMatthias Ringwald context->notify_ag_on_new_codecs = 0; 5383deb3ec6SMatthias Ringwald break; 5393deb3ec6SMatthias Ringwald } 5403deb3ec6SMatthias Ringwald case HFP_SLE_W2_EXCHANGE_COMMON_CODEC: 5413deb3ec6SMatthias Ringwald if (context->hf_trigger_codec_connection_setup){ 5423deb3ec6SMatthias Ringwald context->hf_trigger_codec_connection_setup = 0; 5433deb3ec6SMatthias Ringwald context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC; 5443deb3ec6SMatthias Ringwald break; 5453deb3ec6SMatthias Ringwald } 5463deb3ec6SMatthias Ringwald break; 5473deb3ec6SMatthias Ringwald case HFP_SLE_W4_EXCHANGE_COMMON_CODEC: 5483deb3ec6SMatthias Ringwald if (context->notify_ag_on_new_codecs){ 5493deb3ec6SMatthias Ringwald context->codec_confirmed = 0; 5503deb3ec6SMatthias Ringwald context->suggested_codec = 0; 5513deb3ec6SMatthias Ringwald context->notify_ag_on_new_codecs = 0; 5523deb3ec6SMatthias Ringwald break; 5533deb3ec6SMatthias Ringwald } 5543deb3ec6SMatthias Ringwald if (context->codec_confirmed && context->suggested_codec){ 5553deb3ec6SMatthias Ringwald context->negotiated_codec = context->suggested_codec; 5563deb3ec6SMatthias Ringwald context->codec_confirmed = 0; 5573deb3ec6SMatthias Ringwald context->suggested_codec = 0; 5583deb3ec6SMatthias Ringwald context->state = HFP_CODECS_CONNECTION_ESTABLISHED; 5593deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0); 5603deb3ec6SMatthias Ringwald break; 5613deb3ec6SMatthias Ringwald } 5623deb3ec6SMatthias Ringwald break; 5633deb3ec6SMatthias Ringwald 5643deb3ec6SMatthias Ringwald case HFP_AUDIO_CONNECTION_ESTABLISHED: 5653deb3ec6SMatthias Ringwald printf("HFP_AUDIO_CONNECTION_ESTABLISHED \n"); 5663deb3ec6SMatthias Ringwald break; 5673deb3ec6SMatthias Ringwald 5683deb3ec6SMatthias Ringwald default: 5693deb3ec6SMatthias Ringwald break; 5703deb3ec6SMatthias Ringwald } 5713deb3ec6SMatthias Ringwald } 5723deb3ec6SMatthias Ringwald 5733deb3ec6SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t * context){ 5743deb3ec6SMatthias Ringwald 5753deb3ec6SMatthias Ringwald if (!context) return; 5763deb3ec6SMatthias Ringwald if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; 5773deb3ec6SMatthias Ringwald 5783deb3ec6SMatthias Ringwald hfp_hf_run_for_context_service_level_connection(context); 5793deb3ec6SMatthias Ringwald hfp_hf_run_for_context_service_level_connection_queries(context); 5803deb3ec6SMatthias Ringwald hfp_hf_run_for_context_codecs_connection(context); 5813deb3ec6SMatthias Ringwald 5823deb3ec6SMatthias Ringwald // deal with disconnect 5833deb3ec6SMatthias Ringwald switch (context->state){ 5843deb3ec6SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM: 5853deb3ec6SMatthias Ringwald context->state = HFP_W4_RFCOMM_DISCONNECTED; 5863deb3ec6SMatthias Ringwald rfcomm_disconnect_internal(context->rfcomm_cid); 5873deb3ec6SMatthias Ringwald break; 5883deb3ec6SMatthias Ringwald 5893deb3ec6SMatthias Ringwald default: 5903deb3ec6SMatthias Ringwald break; 5913deb3ec6SMatthias Ringwald } 5923deb3ec6SMatthias Ringwald } 5933deb3ec6SMatthias Ringwald 5943deb3ec6SMatthias Ringwald static void hfp_hf_switch_on_ok(hfp_connection_t *context){ 5953deb3ec6SMatthias Ringwald // printf("switch on ok\n"); 5963deb3ec6SMatthias Ringwald context->wait_ok = 0; 5973deb3ec6SMatthias Ringwald 5983deb3ec6SMatthias Ringwald hfp_hf_handle_ok_service_level_connection_establishment(context); 5993deb3ec6SMatthias Ringwald hfp_hf_handle_ok_service_level_connection_queries(context); 6003deb3ec6SMatthias Ringwald hfp_hf_handle_ok_codecs_connection(context); 6013deb3ec6SMatthias Ringwald 6023deb3ec6SMatthias Ringwald // done 6033deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 6043deb3ec6SMatthias Ringwald } 6053deb3ec6SMatthias Ringwald 6063deb3ec6SMatthias Ringwald 6073deb3ec6SMatthias Ringwald static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 6083deb3ec6SMatthias Ringwald hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel); 6093deb3ec6SMatthias Ringwald if (!context) return; 6103deb3ec6SMatthias Ringwald 6113deb3ec6SMatthias Ringwald packet[size] = 0; 6123deb3ec6SMatthias Ringwald int pos, i; 6133deb3ec6SMatthias Ringwald //printf("\nHF received: %s", packet+2); 6143deb3ec6SMatthias Ringwald for (pos = 0; pos < size ; pos++){ 6153deb3ec6SMatthias Ringwald hfp_parse(context, packet[pos]); 6163deb3ec6SMatthias Ringwald 6173deb3ec6SMatthias Ringwald // emit indicators status changed 6183deb3ec6SMatthias Ringwald for (i = 0; i < context->ag_indicators_nr; i++){ 6193deb3ec6SMatthias Ringwald if (context->ag_indicators[i].status_changed) { 6203deb3ec6SMatthias Ringwald hfp_emit_ag_indicator_event(hfp_callback, 0, context->ag_indicators[i]); 6213deb3ec6SMatthias Ringwald context->ag_indicators[i].status_changed = 0; 6223deb3ec6SMatthias Ringwald break; 6233deb3ec6SMatthias Ringwald } 6243deb3ec6SMatthias Ringwald } 6253deb3ec6SMatthias Ringwald 6263deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_ERROR){ 6273deb3ec6SMatthias Ringwald context->wait_ok = 0; 6283deb3ec6SMatthias Ringwald hfp_reset_context_flags(context); 6293deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 1); 6303deb3ec6SMatthias Ringwald return; 6313deb3ec6SMatthias Ringwald } 6323deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR){ 6333deb3ec6SMatthias Ringwald context->wait_ok = 0; 6343deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, context->extended_audio_gateway_error); 6353deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = 0; 6363deb3ec6SMatthias Ringwald return; 6373deb3ec6SMatthias Ringwald } 6383deb3ec6SMatthias Ringwald 6393deb3ec6SMatthias Ringwald if (context->command != HFP_CMD_OK) continue; 6403deb3ec6SMatthias Ringwald hfp_hf_switch_on_ok(context); 6413deb3ec6SMatthias Ringwald } 6423deb3ec6SMatthias Ringwald } 6433deb3ec6SMatthias Ringwald 6443deb3ec6SMatthias Ringwald static void hfp_run(){ 6453deb3ec6SMatthias Ringwald linked_list_iterator_t it; 6463deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 6473deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 6483deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 6493deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6503deb3ec6SMatthias Ringwald } 6513deb3ec6SMatthias Ringwald } 6523deb3ec6SMatthias Ringwald 653ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 6543deb3ec6SMatthias Ringwald switch (packet_type){ 6553deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET: 6563deb3ec6SMatthias Ringwald hfp_handle_rfcomm_event(packet_type, channel, packet, size); 6573deb3ec6SMatthias Ringwald break; 6583deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 6593deb3ec6SMatthias Ringwald hfp_handle_hci_event(hfp_callback, packet_type, packet, size); 6603deb3ec6SMatthias Ringwald default: 6613deb3ec6SMatthias Ringwald break; 6623deb3ec6SMatthias Ringwald } 6633deb3ec6SMatthias Ringwald hfp_run(); 6643deb3ec6SMatthias Ringwald } 6653deb3ec6SMatthias Ringwald 6663deb3ec6SMatthias Ringwald void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){ 6673deb3ec6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS){ 6683deb3ec6SMatthias Ringwald log_error("hfp_hf_set_codecs: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); 6693deb3ec6SMatthias Ringwald return; 6703deb3ec6SMatthias Ringwald } 6713deb3ec6SMatthias Ringwald 6723deb3ec6SMatthias Ringwald hfp_codecs_nr = codecs_nr; 6733deb3ec6SMatthias Ringwald int i; 6743deb3ec6SMatthias Ringwald for (i=0; i<codecs_nr; i++){ 6753deb3ec6SMatthias Ringwald hfp_codecs[i] = codecs[i]; 6763deb3ec6SMatthias Ringwald } 6773deb3ec6SMatthias Ringwald 6783deb3ec6SMatthias Ringwald char buffer[30]; 6793deb3ec6SMatthias Ringwald int offset = join(buffer, sizeof(buffer), hfp_codecs, hfp_codecs_nr); 6803deb3ec6SMatthias Ringwald buffer[offset] = 0; 6813deb3ec6SMatthias Ringwald printf("set codecs %s\n", buffer); 6823deb3ec6SMatthias Ringwald 6833deb3ec6SMatthias Ringwald linked_list_iterator_t it; 6843deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 6853deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 6863deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 6873deb3ec6SMatthias Ringwald if (!connection) continue; 6883deb3ec6SMatthias Ringwald connection->notify_ag_on_new_codecs = 1; 6893deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6903deb3ec6SMatthias Ringwald } 6913deb3ec6SMatthias Ringwald } 6923deb3ec6SMatthias Ringwald 6933deb3ec6SMatthias Ringwald void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status){ 694*e4dd59a7SMatthias Ringwald rfcomm_register_packet_handler(packet_handler); 6953deb3ec6SMatthias Ringwald hfp_init(rfcomm_channel_nr); 6963deb3ec6SMatthias Ringwald 6973deb3ec6SMatthias Ringwald hfp_supported_features = supported_features; 6983deb3ec6SMatthias Ringwald 6993deb3ec6SMatthias Ringwald hfp_indicators_nr = indicators_nr; 7003deb3ec6SMatthias Ringwald hfp_indicators_status = indicators_status; 7013deb3ec6SMatthias Ringwald int i; 7023deb3ec6SMatthias Ringwald for (i=0; i<indicators_nr; i++){ 7033deb3ec6SMatthias Ringwald hfp_indicators[i] = indicators[i]; 7043deb3ec6SMatthias Ringwald } 7053deb3ec6SMatthias Ringwald } 7063deb3ec6SMatthias Ringwald 7073deb3ec6SMatthias Ringwald void hfp_hf_establish_service_level_connection(bd_addr_t bd_addr){ 7083deb3ec6SMatthias Ringwald hfp_establish_service_level_connection(bd_addr, SDP_HandsfreeAudioGateway); 7093deb3ec6SMatthias Ringwald } 7103deb3ec6SMatthias Ringwald 7113deb3ec6SMatthias Ringwald void hfp_hf_release_service_level_connection(bd_addr_t bd_addr){ 7123deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7133deb3ec6SMatthias Ringwald hfp_release_service_level_connection(connection); 7143deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7153deb3ec6SMatthias Ringwald } 7163deb3ec6SMatthias Ringwald 7173deb3ec6SMatthias Ringwald void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_t enable){ 7183deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 7193deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7203deb3ec6SMatthias Ringwald if (!connection){ 7213deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 7223deb3ec6SMatthias Ringwald return; 7233deb3ec6SMatthias Ringwald } 7243deb3ec6SMatthias Ringwald connection->enable_status_update_for_ag_indicators = enable; 7253deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7263deb3ec6SMatthias Ringwald } 7273deb3ec6SMatthias Ringwald 7283deb3ec6SMatthias Ringwald // TODO: returned ERROR - wrong format 7293deb3ec6SMatthias Ringwald void hfp_hf_enable_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap){ 7303deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 7313deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7323deb3ec6SMatthias Ringwald if (!connection){ 7333deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 7343deb3ec6SMatthias Ringwald return; 7353deb3ec6SMatthias Ringwald } 7363deb3ec6SMatthias Ringwald connection->change_status_update_for_individual_ag_indicators = 1; 7373deb3ec6SMatthias Ringwald connection->ag_indicators_status_update_bitmap = indicators_status_bitmap; 7383deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7393deb3ec6SMatthias Ringwald } 7403deb3ec6SMatthias Ringwald 7413deb3ec6SMatthias Ringwald void hfp_hf_query_operator_selection(bd_addr_t bd_addr){ 7423deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 7433deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7443deb3ec6SMatthias Ringwald if (!connection){ 7453deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 7463deb3ec6SMatthias Ringwald return; 7473deb3ec6SMatthias Ringwald } 7483deb3ec6SMatthias Ringwald connection->operator_name_format = 1; 7493deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7503deb3ec6SMatthias Ringwald } 7513deb3ec6SMatthias Ringwald 7523deb3ec6SMatthias Ringwald void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, uint8_t enable){ 7533deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 7543deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7553deb3ec6SMatthias Ringwald if (!connection){ 7563deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 7573deb3ec6SMatthias Ringwald return; 7583deb3ec6SMatthias Ringwald } 7593deb3ec6SMatthias Ringwald connection->enable_extended_audio_gateway_error_report = enable; 7603deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7613deb3ec6SMatthias Ringwald } 7623deb3ec6SMatthias Ringwald 7633deb3ec6SMatthias Ringwald void hfp_hf_negotiate_codecs(bd_addr_t bd_addr){ 7643deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 7653deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7663deb3ec6SMatthias Ringwald if (!has_codec_negotiation_feature(connection)) return; 7673deb3ec6SMatthias Ringwald if (connection->remote_codecs_nr == 0) return; 7683deb3ec6SMatthias Ringwald 7693deb3ec6SMatthias Ringwald if (connection->state >= HFP_W2_DISCONNECT_SCO) return; 7703deb3ec6SMatthias Ringwald 7713deb3ec6SMatthias Ringwald if (connection->state != HFP_SLE_W2_EXCHANGE_COMMON_CODEC && 7723deb3ec6SMatthias Ringwald connection->state != HFP_SLE_W4_EXCHANGE_COMMON_CODEC){ 7733deb3ec6SMatthias Ringwald connection->hf_trigger_codec_connection_setup = 1; 7743deb3ec6SMatthias Ringwald } 7753deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7763deb3ec6SMatthias Ringwald } 7773deb3ec6SMatthias Ringwald 7783deb3ec6SMatthias Ringwald 7793deb3ec6SMatthias Ringwald void hfp_hf_establish_audio_connection(bd_addr_t bd_addr){ 7803deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 7813deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7823deb3ec6SMatthias Ringwald if (!has_codec_negotiation_feature(connection)) return; 7833deb3ec6SMatthias Ringwald connection->establish_audio_connection = 0; 7843deb3ec6SMatthias Ringwald if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; 7853deb3ec6SMatthias Ringwald if (connection->state >= HFP_W2_DISCONNECT_SCO) return; 7863deb3ec6SMatthias Ringwald 7873deb3ec6SMatthias Ringwald connection->establish_audio_connection = 1; 7883deb3ec6SMatthias Ringwald if (connection->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){ 7893deb3ec6SMatthias Ringwald connection->hf_trigger_codec_connection_setup = 1; 7903deb3ec6SMatthias Ringwald } 7913deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7923deb3ec6SMatthias Ringwald } 7933deb3ec6SMatthias Ringwald 7943deb3ec6SMatthias Ringwald void hfp_hf_release_audio_connection(bd_addr_t bd_addr){ 7953deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7963deb3ec6SMatthias Ringwald hfp_release_audio_connection(connection); 7973deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7983deb3ec6SMatthias Ringwald } 7993deb3ec6SMatthias Ringwald 8003deb3ec6SMatthias Ringwald 801