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 113*2ef54b27SMatthias Ringwald void hfp_hf_create_sdp_record(uint8_t * service, uint32_t service_record_handle, 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 } 117*2ef54b27SMatthias Ringwald hfp_create_sdp_record(service, service_record_handle, SDP_Handsfree, rfcomm_channel_nr, name); 1183deb3ec6SMatthias Ringwald 119aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); // Hands-Free Profile - SupportedFeatures 120aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 121aa4dd815SMatthias Ringwald } 1223deb3ec6SMatthias Ringwald 1233deb3ec6SMatthias Ringwald static int hfp_hf_cmd_exchange_supported_features(uint16_t cid){ 1243deb3ec6SMatthias Ringwald char buffer[20]; 1253deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=%d\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features); 1263deb3ec6SMatthias Ringwald // printf("exchange_supported_features %s\n", buffer); 1273deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1283deb3ec6SMatthias Ringwald } 1293deb3ec6SMatthias Ringwald 1303deb3ec6SMatthias Ringwald static int hfp_hf_cmd_notify_on_codecs(uint16_t cid){ 1313deb3ec6SMatthias Ringwald char buffer[30]; 1323deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_AVAILABLE_CODECS); 1333deb3ec6SMatthias Ringwald offset += join(buffer+offset, sizeof(buffer)-offset, hfp_codecs, hfp_codecs_nr); 1343deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 1353deb3ec6SMatthias Ringwald buffer[offset] = 0; 1363deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1373deb3ec6SMatthias Ringwald } 1383deb3ec6SMatthias Ringwald 1393deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_indicators(uint16_t cid){ 1403deb3ec6SMatthias Ringwald char buffer[20]; 1413deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=?\r\n", HFP_INDICATOR); 1423deb3ec6SMatthias Ringwald // printf("retrieve_indicators %s\n", buffer); 1433deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1443deb3ec6SMatthias Ringwald } 1453deb3ec6SMatthias Ringwald 1463deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_indicators_status(uint16_t cid){ 1473deb3ec6SMatthias Ringwald char buffer[20]; 1483deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s?\r\n", HFP_INDICATOR); 1493deb3ec6SMatthias Ringwald // printf("retrieve_indicators_status %s\n", buffer); 1503deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1513deb3ec6SMatthias Ringwald } 1523deb3ec6SMatthias Ringwald 1533deb3ec6SMatthias Ringwald static int hfp_hf_cmd_activate_status_update_for_all_ag_indicators(uint16_t cid, uint8_t activate){ 1543deb3ec6SMatthias Ringwald char buffer[20]; 1553deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=3,0,0,%d\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, activate); 1563deb3ec6SMatthias Ringwald // printf("toggle_indicator_status_update %s\n", buffer); 1573deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1583deb3ec6SMatthias Ringwald } 1593deb3ec6SMatthias Ringwald 1603deb3ec6SMatthias Ringwald static int hfp_hf_cmd_activate_status_update_for_ag_indicator(uint16_t cid, uint32_t indicators_status, int indicators_nr){ 1613deb3ec6SMatthias Ringwald char buffer[50]; 1623deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS); 1633deb3ec6SMatthias Ringwald offset += join_bitmap(buffer+offset, sizeof(buffer)-offset, indicators_status, indicators_nr); 1643deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 1653deb3ec6SMatthias Ringwald buffer[offset] = 0; 1663deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1673deb3ec6SMatthias Ringwald } 1683deb3ec6SMatthias Ringwald 1693deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_can_hold_call(uint16_t cid){ 1703deb3ec6SMatthias Ringwald char buffer[20]; 1713deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=?\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES); 1723deb3ec6SMatthias Ringwald // printf("retrieve_can_hold_call %s\n", buffer); 1733deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1743deb3ec6SMatthias Ringwald } 1753deb3ec6SMatthias Ringwald 1763deb3ec6SMatthias Ringwald static int hfp_hf_cmd_list_supported_generic_status_indicators(uint16_t cid){ 1773deb3ec6SMatthias Ringwald char buffer[30]; 1783deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_GENERIC_STATUS_INDICATOR); 1793deb3ec6SMatthias Ringwald offset += join(buffer+offset, sizeof(buffer)-offset, hfp_indicators, hfp_indicators_nr); 1803deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 1813deb3ec6SMatthias Ringwald buffer[offset] = 0; 1823deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1833deb3ec6SMatthias Ringwald } 1843deb3ec6SMatthias Ringwald 1853deb3ec6SMatthias Ringwald static int hfp_hf_cmd_retrieve_supported_generic_status_indicators(uint16_t cid){ 1863deb3ec6SMatthias Ringwald char buffer[20]; 1873deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=?\r\n", HFP_GENERIC_STATUS_INDICATOR); 1883deb3ec6SMatthias Ringwald // printf("retrieve_supported_generic_status_indicators %s\n", buffer); 1893deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1903deb3ec6SMatthias Ringwald } 1913deb3ec6SMatthias Ringwald 1923deb3ec6SMatthias Ringwald static int hfp_hf_cmd_list_initital_supported_generic_status_indicators(uint16_t cid){ 1933deb3ec6SMatthias Ringwald char buffer[20]; 1943deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s?\r\n", HFP_GENERIC_STATUS_INDICATOR); 1953deb3ec6SMatthias Ringwald // printf("list_initital_supported_generic_status_indicators %s\n", buffer); 1963deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1973deb3ec6SMatthias Ringwald } 1983deb3ec6SMatthias Ringwald 1993deb3ec6SMatthias Ringwald static int hfp_hf_cmd_query_operator_name_format(uint16_t cid){ 2003deb3ec6SMatthias Ringwald char buffer[20]; 2013deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=3,0\r\n", HFP_QUERY_OPERATOR_SELECTION); 2023deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2033deb3ec6SMatthias Ringwald } 2043deb3ec6SMatthias Ringwald 2053deb3ec6SMatthias Ringwald static int hfp_hf_cmd_query_operator_name(uint16_t cid){ 2063deb3ec6SMatthias Ringwald char buffer[20]; 2073deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s?\r\n", HFP_QUERY_OPERATOR_SELECTION); 2083deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2093deb3ec6SMatthias Ringwald } 2103deb3ec6SMatthias Ringwald 2113deb3ec6SMatthias Ringwald static int hfp_hf_cmd_enable_extended_audio_gateway_error_report(uint16_t cid, uint8_t enable){ 2123deb3ec6SMatthias Ringwald char buffer[20]; 2133deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=%d\r\n", HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, enable); 2143deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2153deb3ec6SMatthias Ringwald } 2163deb3ec6SMatthias Ringwald 2173deb3ec6SMatthias Ringwald static int hfp_hf_cmd_trigger_codec_connection_setup(uint16_t cid){ 2183deb3ec6SMatthias Ringwald char buffer[20]; 2193deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s\r\n", HFP_TRIGGER_CODEC_CONNECTION_SETUP); 2203deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2213deb3ec6SMatthias Ringwald } 2223deb3ec6SMatthias Ringwald 2233deb3ec6SMatthias Ringwald static int hfp_hf_cmd_confirm_codec(uint16_t cid, uint8_t codec){ 2243deb3ec6SMatthias Ringwald char buffer[20]; 2253deb3ec6SMatthias Ringwald sprintf(buffer, "AT%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec); 2263deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2273deb3ec6SMatthias Ringwald } 2283deb3ec6SMatthias Ringwald 2293deb3ec6SMatthias Ringwald static void hfp_emit_ag_indicator_event(hfp_callback_t callback, int status, hfp_ag_indicator_t indicator){ 2303deb3ec6SMatthias Ringwald if (!callback) return; 2313deb3ec6SMatthias Ringwald uint8_t event[6]; 2323deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 2333deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 2343deb3ec6SMatthias Ringwald event[2] = HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED; 2353deb3ec6SMatthias Ringwald event[3] = status; 2363deb3ec6SMatthias Ringwald event[4] = indicator.index; 2373deb3ec6SMatthias Ringwald event[5] = indicator.status; 2383deb3ec6SMatthias Ringwald (*callback)(event, sizeof(event)); 2393deb3ec6SMatthias Ringwald } 2403deb3ec6SMatthias Ringwald 2413deb3ec6SMatthias Ringwald static void hfp_emit_network_operator_event(hfp_callback_t callback, int status, hfp_network_opearator_t network_operator){ 2423deb3ec6SMatthias Ringwald if (!callback) return; 2433deb3ec6SMatthias Ringwald uint8_t event[24]; 2443deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 2453deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 2463deb3ec6SMatthias Ringwald event[2] = HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED; 2473deb3ec6SMatthias Ringwald event[3] = status; 2483deb3ec6SMatthias Ringwald event[4] = network_operator.mode; 2493deb3ec6SMatthias Ringwald event[5] = network_operator.format; 2503deb3ec6SMatthias Ringwald strcpy((char*)&event[6], network_operator.name); 2513deb3ec6SMatthias Ringwald (*callback)(event, sizeof(event)); 2523deb3ec6SMatthias Ringwald } 2533deb3ec6SMatthias Ringwald 2543deb3ec6SMatthias Ringwald static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * context){ 2553deb3ec6SMatthias Ringwald if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 256aa4dd815SMatthias Ringwald if (context->ok_pending) return 0; 257aa4dd815SMatthias Ringwald int done = 1; 2583deb3ec6SMatthias Ringwald 2593deb3ec6SMatthias Ringwald switch (context->state){ 2603deb3ec6SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES: 2613deb3ec6SMatthias Ringwald context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES; 262aa4dd815SMatthias Ringwald hfp_hf_cmd_exchange_supported_features(context->rfcomm_cid); 2633deb3ec6SMatthias Ringwald break; 2643deb3ec6SMatthias Ringwald case HFP_NOTIFY_ON_CODECS: 2653deb3ec6SMatthias Ringwald context->state = HFP_W4_NOTIFY_ON_CODECS; 266aa4dd815SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 2673deb3ec6SMatthias Ringwald break; 2683deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS: 2693deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS; 270aa4dd815SMatthias Ringwald hfp_hf_cmd_retrieve_indicators(context->rfcomm_cid); 2713deb3ec6SMatthias Ringwald break; 2723deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS_STATUS: 2733deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; 274aa4dd815SMatthias Ringwald hfp_hf_cmd_retrieve_indicators_status(context->rfcomm_cid); 2753deb3ec6SMatthias Ringwald break; 2763deb3ec6SMatthias Ringwald case HFP_ENABLE_INDICATORS_STATUS_UPDATE: 2773deb3ec6SMatthias Ringwald context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; 278aa4dd815SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, 1); 2793deb3ec6SMatthias Ringwald break; 2803deb3ec6SMatthias Ringwald case HFP_RETRIEVE_CAN_HOLD_CALL: 2813deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; 282aa4dd815SMatthias Ringwald hfp_hf_cmd_retrieve_can_hold_call(context->rfcomm_cid); 2833deb3ec6SMatthias Ringwald break; 2843deb3ec6SMatthias Ringwald case HFP_LIST_GENERIC_STATUS_INDICATORS: 2853deb3ec6SMatthias Ringwald context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 286aa4dd815SMatthias Ringwald hfp_hf_cmd_list_supported_generic_status_indicators(context->rfcomm_cid); 2873deb3ec6SMatthias Ringwald break; 2883deb3ec6SMatthias Ringwald case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS: 2893deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; 290aa4dd815SMatthias Ringwald hfp_hf_cmd_retrieve_supported_generic_status_indicators(context->rfcomm_cid); 2913deb3ec6SMatthias Ringwald break; 2923deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: 2933deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 294aa4dd815SMatthias Ringwald hfp_hf_cmd_list_initital_supported_generic_status_indicators(context->rfcomm_cid); 2953deb3ec6SMatthias Ringwald break; 2963deb3ec6SMatthias Ringwald default: 297aa4dd815SMatthias Ringwald done = 0; 2983deb3ec6SMatthias Ringwald break; 2993deb3ec6SMatthias Ringwald } 3003deb3ec6SMatthias Ringwald return done; 3013deb3ec6SMatthias Ringwald } 3023deb3ec6SMatthias Ringwald 3033deb3ec6SMatthias Ringwald static void hfp_hf_handle_ok_service_level_connection_establishment(hfp_connection_t *context){ 3043deb3ec6SMatthias Ringwald if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return; 3053deb3ec6SMatthias Ringwald switch (context->state){ 3063deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: 3073deb3ec6SMatthias Ringwald if (has_codec_negotiation_feature(context)){ 3083deb3ec6SMatthias Ringwald context->state = HFP_NOTIFY_ON_CODECS; 3093deb3ec6SMatthias Ringwald break; 3103deb3ec6SMatthias Ringwald } 3113deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INDICATORS; 3123deb3ec6SMatthias Ringwald break; 3133deb3ec6SMatthias Ringwald 3143deb3ec6SMatthias Ringwald case HFP_W4_NOTIFY_ON_CODECS: 3153deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INDICATORS; 3163deb3ec6SMatthias Ringwald break; 3173deb3ec6SMatthias Ringwald 3183deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS: 3193deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INDICATORS_STATUS; 3203deb3ec6SMatthias Ringwald break; 3213deb3ec6SMatthias Ringwald 3223deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS_STATUS: 3233deb3ec6SMatthias Ringwald context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE; 3243deb3ec6SMatthias Ringwald break; 3253deb3ec6SMatthias Ringwald 3263deb3ec6SMatthias Ringwald case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: 3273deb3ec6SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(context)){ 3283deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_CAN_HOLD_CALL; 3293deb3ec6SMatthias Ringwald break; 3303deb3ec6SMatthias Ringwald } 3313deb3ec6SMatthias Ringwald if (has_hf_indicators_feature(context)){ 3323deb3ec6SMatthias Ringwald context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; 3333deb3ec6SMatthias Ringwald break; 3343deb3ec6SMatthias Ringwald } 3353deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 3363deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 3373deb3ec6SMatthias Ringwald break; 3383deb3ec6SMatthias Ringwald 3393deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_CAN_HOLD_CALL: 3403deb3ec6SMatthias Ringwald if (has_hf_indicators_feature(context)){ 3413deb3ec6SMatthias Ringwald context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; 3423deb3ec6SMatthias Ringwald break; 3433deb3ec6SMatthias Ringwald } 3443deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 3453deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 3463deb3ec6SMatthias Ringwald break; 3473deb3ec6SMatthias Ringwald 3483deb3ec6SMatthias Ringwald case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: 3493deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS; 3503deb3ec6SMatthias Ringwald break; 3513deb3ec6SMatthias Ringwald 3523deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: 3533deb3ec6SMatthias Ringwald context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 3543deb3ec6SMatthias Ringwald break; 3553deb3ec6SMatthias Ringwald 3563deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: 3573deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 3583deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 3593deb3ec6SMatthias Ringwald break; 3603deb3ec6SMatthias Ringwald default: 3613deb3ec6SMatthias Ringwald break; 3623deb3ec6SMatthias Ringwald } 3633deb3ec6SMatthias Ringwald } 3643deb3ec6SMatthias Ringwald 365aa4dd815SMatthias Ringwald static int hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * context){ 366aa4dd815SMatthias Ringwald if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 367aa4dd815SMatthias Ringwald if (context->ok_pending) return 0; 3683deb3ec6SMatthias Ringwald 369aa4dd815SMatthias Ringwald int done = 0; 3703deb3ec6SMatthias Ringwald if (context->enable_status_update_for_ag_indicators != 0xFF){ 371aa4dd815SMatthias Ringwald context->ok_pending = 1; 372aa4dd815SMatthias Ringwald done = 1; 3733deb3ec6SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, context->enable_status_update_for_ag_indicators); 374aa4dd815SMatthias Ringwald return done; 3753deb3ec6SMatthias Ringwald }; 3763deb3ec6SMatthias Ringwald if (context->change_status_update_for_individual_ag_indicators){ 377aa4dd815SMatthias Ringwald context->ok_pending = 1; 378aa4dd815SMatthias Ringwald done = 1; 3793deb3ec6SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_ag_indicator(context->rfcomm_cid, 3803deb3ec6SMatthias Ringwald context->ag_indicators_status_update_bitmap, 3813deb3ec6SMatthias Ringwald context->ag_indicators_nr); 382aa4dd815SMatthias Ringwald return done; 3833deb3ec6SMatthias Ringwald } 3843deb3ec6SMatthias Ringwald 385aa4dd815SMatthias Ringwald if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT){ 386aa4dd815SMatthias Ringwald context->ok_pending = 1; 387aa4dd815SMatthias Ringwald done = 1; 3883deb3ec6SMatthias Ringwald hfp_hf_cmd_query_operator_name_format(context->rfcomm_cid); 389aa4dd815SMatthias Ringwald return done; 3903deb3ec6SMatthias Ringwald } 391aa4dd815SMatthias Ringwald if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME){ 392aa4dd815SMatthias Ringwald context->ok_pending = 1; 393aa4dd815SMatthias Ringwald done = 1; 3943deb3ec6SMatthias Ringwald hfp_hf_cmd_query_operator_name(context->rfcomm_cid); 395aa4dd815SMatthias Ringwald return done; 3963deb3ec6SMatthias Ringwald } 3973deb3ec6SMatthias Ringwald 3983deb3ec6SMatthias Ringwald if (context->enable_extended_audio_gateway_error_report){ 399aa4dd815SMatthias Ringwald context->ok_pending = 1; 400aa4dd815SMatthias Ringwald done = 1; 4013deb3ec6SMatthias Ringwald hfp_hf_cmd_enable_extended_audio_gateway_error_report(context->rfcomm_cid, context->enable_extended_audio_gateway_error_report); 402aa4dd815SMatthias Ringwald return done; 4033deb3ec6SMatthias Ringwald } 404aa4dd815SMatthias Ringwald 405aa4dd815SMatthias Ringwald return done; 4063deb3ec6SMatthias Ringwald } 4073deb3ec6SMatthias Ringwald 4083deb3ec6SMatthias Ringwald static void hfp_hf_handle_ok_service_level_connection_queries(hfp_connection_t * context){ 4093deb3ec6SMatthias Ringwald if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return; 4103deb3ec6SMatthias Ringwald 4113deb3ec6SMatthias Ringwald if (context->enable_status_update_for_ag_indicators != 0xFF){ 4123deb3ec6SMatthias Ringwald context->enable_status_update_for_ag_indicators = 0xFF; 4133deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0); 4143deb3ec6SMatthias Ringwald return; 4153deb3ec6SMatthias Ringwald }; 4163deb3ec6SMatthias Ringwald 4173deb3ec6SMatthias Ringwald if (context->change_status_update_for_individual_ag_indicators == 1){ 4183deb3ec6SMatthias Ringwald context->change_status_update_for_individual_ag_indicators = 0; 4193deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0); 4203deb3ec6SMatthias Ringwald return; 4213deb3ec6SMatthias Ringwald } 4223deb3ec6SMatthias Ringwald 423aa4dd815SMatthias Ringwald if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT){ 424aa4dd815SMatthias Ringwald context->command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME; 4253deb3ec6SMatthias Ringwald return; 4263deb3ec6SMatthias Ringwald } 4273deb3ec6SMatthias Ringwald 428aa4dd815SMatthias Ringwald if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME){ 4293deb3ec6SMatthias Ringwald hfp_emit_network_operator_event(hfp_callback, 0, context->network_operator); 4303deb3ec6SMatthias Ringwald return; 4313deb3ec6SMatthias Ringwald } 4323deb3ec6SMatthias Ringwald if (context->enable_extended_audio_gateway_error_report){ 4333deb3ec6SMatthias Ringwald context->enable_extended_audio_gateway_error_report = 0; 4343deb3ec6SMatthias Ringwald return; 4353deb3ec6SMatthias Ringwald } 4363deb3ec6SMatthias Ringwald } 4373deb3ec6SMatthias Ringwald 438aa4dd815SMatthias Ringwald static int codecs_exchange_state_machine(hfp_connection_t * context){ 439aa4dd815SMatthias Ringwald if (context->ok_pending) return 0; 440aa4dd815SMatthias Ringwald int done = 1; 4413deb3ec6SMatthias Ringwald 442aa4dd815SMatthias Ringwald switch(context->command){ 443aa4dd815SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 444aa4dd815SMatthias Ringwald switch (context->codecs_state){ 445aa4dd815SMatthias Ringwald case HFP_CODECS_W4_AG_COMMON_CODEC: 4463deb3ec6SMatthias Ringwald context->codec_confirmed = 0; 4473deb3ec6SMatthias Ringwald context->suggested_codec = 0; 4483deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 4493deb3ec6SMatthias Ringwald break; 450aa4dd815SMatthias Ringwald case HFP_CODECS_EXCHANGED: 4513deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 452aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; 4533deb3ec6SMatthias Ringwald break; 4543deb3ec6SMatthias Ringwald default: 4553deb3ec6SMatthias Ringwald break; 4563deb3ec6SMatthias Ringwald } 457aa4dd815SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 458aa4dd815SMatthias Ringwald break; 459aa4dd815SMatthias Ringwald case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 460aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; 461aa4dd815SMatthias Ringwald hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); 462aa4dd815SMatthias Ringwald break; 463aa4dd815SMatthias Ringwald 464aa4dd815SMatthias Ringwald case HFP_CMD_AG_SUGGESTED_CODEC: 465aa4dd815SMatthias Ringwald if (hfp_hf_supports_codec(context->suggested_codec)){ 466aa4dd815SMatthias Ringwald context->codec_confirmed = context->suggested_codec; 467aa4dd815SMatthias Ringwald hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec); 468aa4dd815SMatthias Ringwald } else { 469aa4dd815SMatthias Ringwald context->codec_confirmed = 0; 470aa4dd815SMatthias Ringwald context->suggested_codec = 0; 471aa4dd815SMatthias Ringwald context->negotiated_codec = 0; 472aa4dd815SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); 473aa4dd815SMatthias Ringwald } 474aa4dd815SMatthias Ringwald break; 475aa4dd815SMatthias Ringwald default: 476aa4dd815SMatthias Ringwald return 0; 477aa4dd815SMatthias Ringwald } 478aa4dd815SMatthias Ringwald 479aa4dd815SMatthias Ringwald if (done){ 480aa4dd815SMatthias Ringwald context->ok_pending = 1; 481aa4dd815SMatthias Ringwald } 482aa4dd815SMatthias Ringwald return done; 4833deb3ec6SMatthias Ringwald } 4843deb3ec6SMatthias Ringwald 4853deb3ec6SMatthias Ringwald static void hfp_hf_handle_ok_codecs_connection(hfp_connection_t * context){ 4863deb3ec6SMatthias Ringwald // handle audio connection setup 487aa4dd815SMatthias Ringwald switch (context->codecs_state){ 488aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: 489aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; 4903deb3ec6SMatthias Ringwald break; 4913deb3ec6SMatthias Ringwald default: 4923deb3ec6SMatthias Ringwald break; 4933deb3ec6SMatthias Ringwald } 4943deb3ec6SMatthias Ringwald } 4953deb3ec6SMatthias Ringwald 4963deb3ec6SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t * context){ 4973deb3ec6SMatthias Ringwald if (!context) return; 4983deb3ec6SMatthias Ringwald if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; 4993deb3ec6SMatthias Ringwald 500aa4dd815SMatthias Ringwald int done = hfp_hf_run_for_context_service_level_connection(context); 501aa4dd815SMatthias Ringwald if (!done){ 502aa4dd815SMatthias Ringwald done = hfp_hf_run_for_context_service_level_connection_queries(context); 503aa4dd815SMatthias Ringwald } 504aa4dd815SMatthias Ringwald if (!done){ 505aa4dd815SMatthias Ringwald done = codecs_exchange_state_machine(context); 506aa4dd815SMatthias Ringwald } 5073deb3ec6SMatthias Ringwald 508aa4dd815SMatthias Ringwald if (done) return; 5093deb3ec6SMatthias Ringwald // deal with disconnect 5103deb3ec6SMatthias Ringwald switch (context->state){ 5113deb3ec6SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM: 5123deb3ec6SMatthias Ringwald context->state = HFP_W4_RFCOMM_DISCONNECTED; 5133deb3ec6SMatthias Ringwald rfcomm_disconnect_internal(context->rfcomm_cid); 5143deb3ec6SMatthias Ringwald break; 5153deb3ec6SMatthias Ringwald 5163deb3ec6SMatthias Ringwald default: 5173deb3ec6SMatthias Ringwald break; 5183deb3ec6SMatthias Ringwald } 5193deb3ec6SMatthias Ringwald } 5203deb3ec6SMatthias Ringwald 5213deb3ec6SMatthias Ringwald static void hfp_hf_switch_on_ok(hfp_connection_t *context){ 5223deb3ec6SMatthias Ringwald // printf("switch on ok\n"); 523aa4dd815SMatthias Ringwald context->ok_pending = 0; 5243deb3ec6SMatthias Ringwald 5253deb3ec6SMatthias Ringwald hfp_hf_handle_ok_service_level_connection_establishment(context); 5263deb3ec6SMatthias Ringwald hfp_hf_handle_ok_service_level_connection_queries(context); 5273deb3ec6SMatthias Ringwald hfp_hf_handle_ok_codecs_connection(context); 5283deb3ec6SMatthias Ringwald // done 5293deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 5303deb3ec6SMatthias Ringwald } 5313deb3ec6SMatthias Ringwald 5323deb3ec6SMatthias Ringwald 5333deb3ec6SMatthias Ringwald static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 5343deb3ec6SMatthias Ringwald hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel); 5353deb3ec6SMatthias Ringwald if (!context) return; 5363deb3ec6SMatthias Ringwald 5373deb3ec6SMatthias Ringwald packet[size] = 0; 5383deb3ec6SMatthias Ringwald int pos, i; 5393deb3ec6SMatthias Ringwald //printf("\nHF received: %s", packet+2); 5403deb3ec6SMatthias Ringwald for (pos = 0; pos < size ; pos++){ 541aa4dd815SMatthias Ringwald hfp_parse(context, packet[pos], 1); 5423deb3ec6SMatthias Ringwald 5433deb3ec6SMatthias Ringwald // emit indicators status changed 5443deb3ec6SMatthias Ringwald for (i = 0; i < context->ag_indicators_nr; i++){ 5453deb3ec6SMatthias Ringwald if (context->ag_indicators[i].status_changed) { 5463deb3ec6SMatthias Ringwald context->ag_indicators[i].status_changed = 0; 547aa4dd815SMatthias Ringwald hfp_emit_ag_indicator_event(hfp_callback, 0, context->ag_indicators[i]); 5483deb3ec6SMatthias Ringwald break; 5493deb3ec6SMatthias Ringwald } 5503deb3ec6SMatthias Ringwald } 5513deb3ec6SMatthias Ringwald 5523deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_ERROR){ 553aa4dd815SMatthias Ringwald context->ok_pending = 0; 5543deb3ec6SMatthias Ringwald hfp_reset_context_flags(context); 5553deb3ec6SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 1); 5563deb3ec6SMatthias Ringwald return; 5573deb3ec6SMatthias Ringwald } 5583deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR){ 559aa4dd815SMatthias Ringwald context->ok_pending = 0; 5603deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = 0; 561aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, context->extended_audio_gateway_error); 5623deb3ec6SMatthias Ringwald return; 5633deb3ec6SMatthias Ringwald } 5643deb3ec6SMatthias Ringwald 5653deb3ec6SMatthias Ringwald if (context->command != HFP_CMD_OK) continue; 5663deb3ec6SMatthias Ringwald hfp_hf_switch_on_ok(context); 5673deb3ec6SMatthias Ringwald } 5683deb3ec6SMatthias Ringwald } 5693deb3ec6SMatthias Ringwald 5703deb3ec6SMatthias Ringwald static void hfp_run(){ 5713deb3ec6SMatthias Ringwald linked_list_iterator_t it; 5723deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 5733deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 5743deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 5753deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 5763deb3ec6SMatthias Ringwald } 5773deb3ec6SMatthias Ringwald } 5783deb3ec6SMatthias Ringwald 579ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 5803deb3ec6SMatthias Ringwald switch (packet_type){ 5813deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET: 5823deb3ec6SMatthias Ringwald hfp_handle_rfcomm_event(packet_type, channel, packet, size); 5833deb3ec6SMatthias Ringwald break; 5843deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 5853deb3ec6SMatthias Ringwald hfp_handle_hci_event(hfp_callback, packet_type, packet, size); 5863deb3ec6SMatthias Ringwald default: 5873deb3ec6SMatthias Ringwald break; 5883deb3ec6SMatthias Ringwald } 5893deb3ec6SMatthias Ringwald hfp_run(); 5903deb3ec6SMatthias Ringwald } 5913deb3ec6SMatthias Ringwald 5923deb3ec6SMatthias Ringwald void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){ 5933deb3ec6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS){ 5943deb3ec6SMatthias Ringwald log_error("hfp_hf_set_codecs: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); 5953deb3ec6SMatthias Ringwald return; 5963deb3ec6SMatthias Ringwald } 5973deb3ec6SMatthias Ringwald 5983deb3ec6SMatthias Ringwald hfp_codecs_nr = codecs_nr; 5993deb3ec6SMatthias Ringwald int i; 6003deb3ec6SMatthias Ringwald for (i=0; i<codecs_nr; i++){ 6013deb3ec6SMatthias Ringwald hfp_codecs[i] = codecs[i]; 6023deb3ec6SMatthias Ringwald } 6033deb3ec6SMatthias Ringwald 6043deb3ec6SMatthias Ringwald char buffer[30]; 6053deb3ec6SMatthias Ringwald int offset = join(buffer, sizeof(buffer), hfp_codecs, hfp_codecs_nr); 6063deb3ec6SMatthias Ringwald buffer[offset] = 0; 6073deb3ec6SMatthias Ringwald printf("set codecs %s\n", buffer); 6083deb3ec6SMatthias Ringwald 6093deb3ec6SMatthias Ringwald linked_list_iterator_t it; 6103deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 6113deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 6123deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 6133deb3ec6SMatthias Ringwald if (!connection) continue; 614aa4dd815SMatthias Ringwald connection->command = HFP_CMD_AVAILABLE_CODECS; 6153deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6163deb3ec6SMatthias Ringwald } 6173deb3ec6SMatthias Ringwald } 6183deb3ec6SMatthias Ringwald 6193deb3ec6SMatthias Ringwald void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status){ 620aa4dd815SMatthias Ringwald l2cap_init(); 621aa4dd815SMatthias Ringwald l2cap_register_packet_handler(packet_handler); 622e4dd59a7SMatthias Ringwald rfcomm_register_packet_handler(packet_handler); 6233deb3ec6SMatthias Ringwald hfp_init(rfcomm_channel_nr); 6243deb3ec6SMatthias Ringwald 6253deb3ec6SMatthias Ringwald hfp_supported_features = supported_features; 6263deb3ec6SMatthias Ringwald 6273deb3ec6SMatthias Ringwald hfp_indicators_nr = indicators_nr; 6283deb3ec6SMatthias Ringwald hfp_indicators_status = indicators_status; 6293deb3ec6SMatthias Ringwald int i; 6303deb3ec6SMatthias Ringwald for (i=0; i<indicators_nr; i++){ 6313deb3ec6SMatthias Ringwald hfp_indicators[i] = indicators[i]; 6323deb3ec6SMatthias Ringwald } 6333deb3ec6SMatthias Ringwald } 6343deb3ec6SMatthias Ringwald 6353deb3ec6SMatthias Ringwald void hfp_hf_establish_service_level_connection(bd_addr_t bd_addr){ 6363deb3ec6SMatthias Ringwald hfp_establish_service_level_connection(bd_addr, SDP_HandsfreeAudioGateway); 6373deb3ec6SMatthias Ringwald } 6383deb3ec6SMatthias Ringwald 6393deb3ec6SMatthias Ringwald void hfp_hf_release_service_level_connection(bd_addr_t bd_addr){ 6403deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 6413deb3ec6SMatthias Ringwald hfp_release_service_level_connection(connection); 6423deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6433deb3ec6SMatthias Ringwald } 6443deb3ec6SMatthias Ringwald 6453deb3ec6SMatthias Ringwald void hfp_hf_enable_status_update_for_all_ag_indicators(bd_addr_t bd_addr, uint8_t enable){ 6463deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 6473deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 6483deb3ec6SMatthias Ringwald if (!connection){ 6493deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 6503deb3ec6SMatthias Ringwald return; 6513deb3ec6SMatthias Ringwald } 6523deb3ec6SMatthias Ringwald connection->enable_status_update_for_ag_indicators = enable; 6533deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6543deb3ec6SMatthias Ringwald } 6553deb3ec6SMatthias Ringwald 6563deb3ec6SMatthias Ringwald // TODO: returned ERROR - wrong format 6573deb3ec6SMatthias Ringwald void hfp_hf_enable_status_update_for_individual_ag_indicators(bd_addr_t bd_addr, uint32_t indicators_status_bitmap){ 6583deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 6593deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 6603deb3ec6SMatthias Ringwald if (!connection){ 6613deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 6623deb3ec6SMatthias Ringwald return; 6633deb3ec6SMatthias Ringwald } 6643deb3ec6SMatthias Ringwald connection->change_status_update_for_individual_ag_indicators = 1; 6653deb3ec6SMatthias Ringwald connection->ag_indicators_status_update_bitmap = indicators_status_bitmap; 6663deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6673deb3ec6SMatthias Ringwald } 6683deb3ec6SMatthias Ringwald 6693deb3ec6SMatthias Ringwald void hfp_hf_query_operator_selection(bd_addr_t bd_addr){ 6703deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 6713deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 6723deb3ec6SMatthias Ringwald if (!connection){ 6733deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 6743deb3ec6SMatthias Ringwald return; 6753deb3ec6SMatthias Ringwald } 676aa4dd815SMatthias Ringwald connection->command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT; 6773deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6783deb3ec6SMatthias Ringwald } 6793deb3ec6SMatthias Ringwald 6803deb3ec6SMatthias Ringwald void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, uint8_t enable){ 6813deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 6823deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 6833deb3ec6SMatthias Ringwald if (!connection){ 6843deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 6853deb3ec6SMatthias Ringwald return; 6863deb3ec6SMatthias Ringwald } 6873deb3ec6SMatthias Ringwald connection->enable_extended_audio_gateway_error_report = enable; 6883deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 6893deb3ec6SMatthias Ringwald } 6903deb3ec6SMatthias Ringwald 6913deb3ec6SMatthias Ringwald void hfp_hf_establish_audio_connection(bd_addr_t bd_addr){ 6923deb3ec6SMatthias Ringwald hfp_hf_establish_service_level_connection(bd_addr); 6933deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 6943deb3ec6SMatthias Ringwald if (!has_codec_negotiation_feature(connection)) return; 6953deb3ec6SMatthias Ringwald connection->establish_audio_connection = 0; 6963deb3ec6SMatthias Ringwald if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; 6973deb3ec6SMatthias Ringwald if (connection->state >= HFP_W2_DISCONNECT_SCO) return; 6983deb3ec6SMatthias Ringwald 6993deb3ec6SMatthias Ringwald connection->establish_audio_connection = 1; 700aa4dd815SMatthias Ringwald switch (connection->codecs_state){ 701aa4dd815SMatthias Ringwald case HFP_CODECS_W4_AG_COMMON_CODEC: 702aa4dd815SMatthias Ringwald break; 703aa4dd815SMatthias Ringwald default: 704aa4dd815SMatthias Ringwald connection->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP; 705aa4dd815SMatthias Ringwald break; 7063deb3ec6SMatthias Ringwald } 7073deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7083deb3ec6SMatthias Ringwald } 7093deb3ec6SMatthias Ringwald 7103deb3ec6SMatthias Ringwald void hfp_hf_release_audio_connection(bd_addr_t bd_addr){ 7113deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 7123deb3ec6SMatthias Ringwald hfp_release_audio_connection(connection); 7133deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 7143deb3ec6SMatthias Ringwald } 7153deb3ec6SMatthias Ringwald 7163deb3ec6SMatthias Ringwald 717