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