xref: /btstack/src/classic/hfp_hf.c (revision e4dd59a7e369e0ea063319d2554c64e499d60dc3)
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