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 */ 37ab2c6ae4SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hfp_ag.c" 393deb3ec6SMatthias Ringwald 403deb3ec6SMatthias Ringwald // ***************************************************************************** 413deb3ec6SMatthias Ringwald // 4266a048abSMatthias Ringwald // HFP Audio Gateway (AG) unit 433deb3ec6SMatthias Ringwald // 443deb3ec6SMatthias Ringwald // ***************************************************************************** 453deb3ec6SMatthias Ringwald 467907f069SMatthias Ringwald #include "btstack_config.h" 473deb3ec6SMatthias Ringwald 483deb3ec6SMatthias Ringwald #include <stdint.h> 493deb3ec6SMatthias Ringwald #include <string.h> 503deb3ec6SMatthias Ringwald 5156042629SMatthias Ringwald #include "hci_cmd.h" 5282636622SMatthias Ringwald #include "btstack_run_loop.h" 533deb3ec6SMatthias Ringwald 54235946f1SMatthias Ringwald #include "bluetooth_sdp.h" 553deb3ec6SMatthias Ringwald #include "hci.h" 563deb3ec6SMatthias Ringwald #include "btstack_memory.h" 573deb3ec6SMatthias Ringwald #include "hci_dump.h" 583deb3ec6SMatthias Ringwald #include "l2cap.h" 5916ece135SMatthias Ringwald #include "btstack_debug.h" 60e30a6a47SMatthias Ringwald #include "btstack_event.h" 6159c6af15SMatthias Ringwald #include "classic/core.h" 623edc84c5SMatthias Ringwald #include "classic/hfp.h" 633edc84c5SMatthias Ringwald #include "classic/hfp_ag.h" 64023f2764SMatthias Ringwald #include "classic/hfp_gsm_model.h" 65efda0b48SMatthias Ringwald #include "classic/sdp_client_rfcomm.h" 66023f2764SMatthias Ringwald #include "classic/sdp_server.h" 67023f2764SMatthias Ringwald #include "classic/sdp_util.h" 683deb3ec6SMatthias Ringwald 69c5b64319SMatthias Ringwald // private prototypes 70f0aeb307SMatthias Ringwald static void hfp_ag_run_for_context(hfp_connection_t *hfp_connection); 71adaba9f3SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * hfp_connection); 72adaba9f3SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * hfp_connection); 73c5b64319SMatthias Ringwald 74c5b64319SMatthias Ringwald // public prototypes 7535833313SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void); 7635833313SMatthias Ringwald int get_hfp_generic_status_indicators_nr(void); 77c5b64319SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr); 78c5b64319SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr); 79c5b64319SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context); 80c5b64319SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context); 81c5b64319SMatthias Ringwald 8227950165SMatthias Ringwald 8320b2edb6SMatthias Ringwald // const 843deb3ec6SMatthias Ringwald static const char default_hfp_ag_service_name[] = "Voice gateway"; 85aa4dd815SMatthias Ringwald 8620b2edb6SMatthias Ringwald // globals 8720b2edb6SMatthias Ringwald static btstack_packet_callback_registration_t hfp_ag_hci_event_callback_registration; 88aa4dd815SMatthias Ringwald 8920b2edb6SMatthias Ringwald static uint16_t hfp_supported_features; 9020b2edb6SMatthias Ringwald 9120b2edb6SMatthias Ringwald static uint8_t hfp_codecs_nr; 923deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS]; 933deb3ec6SMatthias Ringwald 9420b2edb6SMatthias Ringwald static int hfp_ag_indicators_nr; 9525789943SMilanka Ringwald static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_INDICATORS]; 963deb3ec6SMatthias Ringwald 9720b2edb6SMatthias Ringwald static int hfp_generic_status_indicators_nr; 9825789943SMilanka Ringwald static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_INDICATORS]; 99a0ffb263SMatthias Ringwald 10020b2edb6SMatthias Ringwald static int hfp_ag_call_hold_services_nr; 1013deb3ec6SMatthias Ringwald static char *hfp_ag_call_hold_services[6]; 102ca59be51SMatthias Ringwald static btstack_packet_handler_t hfp_ag_callback; 1033deb3ec6SMatthias Ringwald 104ce263fc8SMatthias Ringwald static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state; 10520b2edb6SMatthias Ringwald static int hfp_ag_response_and_hold_active; 106aa4dd815SMatthias Ringwald 10720b2edb6SMatthias Ringwald // Subscriber information entries 10820b2edb6SMatthias Ringwald static hfp_phone_number_t * subscriber_numbers; 10920b2edb6SMatthias Ringwald static int subscriber_numbers_count; 110ce263fc8SMatthias Ringwald 11120b2edb6SMatthias Ringwald // code 112a0ffb263SMatthias Ringwald static int hfp_ag_get_ag_indicators_nr(hfp_connection_t * hfp_connection){ 113a0ffb263SMatthias Ringwald if (hfp_connection->ag_indicators_nr != hfp_ag_indicators_nr){ 114a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_nr = hfp_ag_indicators_nr; 1156535961aSMatthias Ringwald (void)memcpy(hfp_connection->ag_indicators, hfp_ag_indicators, 1166535961aSMatthias Ringwald hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 1173deb3ec6SMatthias Ringwald } 118a0ffb263SMatthias Ringwald return hfp_connection->ag_indicators_nr; 119a0ffb263SMatthias Ringwald } 120a0ffb263SMatthias Ringwald 121a0ffb263SMatthias Ringwald hfp_ag_indicator_t * hfp_ag_get_ag_indicators(hfp_connection_t * hfp_connection){ 122a0ffb263SMatthias Ringwald // TODO: save only value, and value changed in the hfp_connection? 123a0ffb263SMatthias Ringwald if (hfp_connection->ag_indicators_nr != hfp_ag_indicators_nr){ 124a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_nr = hfp_ag_indicators_nr; 1256535961aSMatthias Ringwald (void)memcpy(hfp_connection->ag_indicators, hfp_ag_indicators, 1266535961aSMatthias Ringwald hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 127a0ffb263SMatthias Ringwald } 128a0ffb263SMatthias Ringwald return (hfp_ag_indicator_t *)&(hfp_connection->ag_indicators); 1293deb3ec6SMatthias Ringwald } 1303deb3ec6SMatthias Ringwald 131aa4dd815SMatthias Ringwald static hfp_ag_indicator_t * get_ag_indicator_for_name(const char * name){ 132aa4dd815SMatthias Ringwald int i; 133aa4dd815SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr; i++){ 134aa4dd815SMatthias Ringwald if (strcmp(hfp_ag_indicators[i].name, name) == 0){ 135aa4dd815SMatthias Ringwald return &hfp_ag_indicators[i]; 136aa4dd815SMatthias Ringwald } 137aa4dd815SMatthias Ringwald } 138aa4dd815SMatthias Ringwald return NULL; 139aa4dd815SMatthias Ringwald } 140aa4dd815SMatthias Ringwald 141aa4dd815SMatthias Ringwald static int get_ag_indicator_index_for_name(const char * name){ 142aa4dd815SMatthias Ringwald int i; 143aa4dd815SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr; i++){ 144aa4dd815SMatthias Ringwald if (strcmp(hfp_ag_indicators[i].name, name) == 0){ 145aa4dd815SMatthias Ringwald return i; 146aa4dd815SMatthias Ringwald } 147aa4dd815SMatthias Ringwald } 148aa4dd815SMatthias Ringwald return -1; 149aa4dd815SMatthias Ringwald } 150aa4dd815SMatthias Ringwald 1519c9c64c1SMatthias Ringwald static hfp_connection_t * get_hfp_ag_connection_context_for_acl_handle(uint16_t handle){ 1529c9c64c1SMatthias Ringwald btstack_linked_list_iterator_t it; 1539c9c64c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 1549c9c64c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1559c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 1569c9c64c1SMatthias Ringwald if (hfp_connection->acl_handle != handle) continue; 1579c9c64c1SMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 1589c9c64c1SMatthias Ringwald return hfp_connection; 1599c9c64c1SMatthias Ringwald } 1609c9c64c1SMatthias Ringwald return NULL; 1619c9c64c1SMatthias Ringwald } 1623deb3ec6SMatthias Ringwald 1630cb5b971SMatthias Ringwald static int use_in_band_tone(void){ 164aa4dd815SMatthias Ringwald return get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE); 1653deb3ec6SMatthias Ringwald } 1663deb3ec6SMatthias Ringwald 167a0ffb263SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * hfp_connection){ 168a0ffb263SMatthias Ringwald int hf = get_bit(hfp_connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION); 1693deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION); 1703deb3ec6SMatthias Ringwald return hf && ag; 1713deb3ec6SMatthias Ringwald } 1723deb3ec6SMatthias Ringwald 173a0ffb263SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * hfp_connection){ 174a0ffb263SMatthias Ringwald int hf = get_bit(hfp_connection->remote_supported_features, HFP_HFSF_THREE_WAY_CALLING); 1753deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_THREE_WAY_CALLING); 1763deb3ec6SMatthias Ringwald return hf && ag; 1773deb3ec6SMatthias Ringwald } 1783deb3ec6SMatthias Ringwald 179a0ffb263SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * hfp_connection){ 180a0ffb263SMatthias Ringwald int hf = get_bit(hfp_connection->remote_supported_features, HFP_HFSF_HF_INDICATORS); 1813deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_HF_INDICATORS); 1823deb3ec6SMatthias Ringwald return hf && ag; 1833deb3ec6SMatthias Ringwald } 1843deb3ec6SMatthias Ringwald 18576cc1527SMatthias Ringwald /* unsolicited responses */ 186aa4dd815SMatthias Ringwald 187485ac19eSMilanka Ringwald static int hfp_ag_send_change_in_band_ring_tone_setting_cmd(uint16_t cid){ 188aa4dd815SMatthias Ringwald char buffer[20]; 189ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s:%d\r\n", 190ff7d6aeaSMatthias Ringwald HFP_CHANGE_IN_BAND_RING_TONE_SETTING, use_in_band_tone()); 191ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 192aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1933deb3ec6SMatthias Ringwald } 1943deb3ec6SMatthias Ringwald 1953deb3ec6SMatthias Ringwald static int hfp_ag_exchange_supported_features_cmd(uint16_t cid){ 1963deb3ec6SMatthias Ringwald char buffer[40]; 197ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s:%d\r\n\r\nOK\r\n", 198ff7d6aeaSMatthias Ringwald HFP_SUPPORTED_FEATURES, hfp_supported_features); 199ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 2003deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2013deb3ec6SMatthias Ringwald } 2023deb3ec6SMatthias Ringwald 203485ac19eSMilanka Ringwald static int hfp_ag_send_ok(uint16_t cid){ 2043deb3ec6SMatthias Ringwald char buffer[10]; 205ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\nOK\r\n"); 206ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 2073deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2083deb3ec6SMatthias Ringwald } 2093deb3ec6SMatthias Ringwald 210485ac19eSMilanka Ringwald static int hfp_ag_send_ring(uint16_t cid){ 211aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, (char *) "\r\nRING\r\n"); 212aa4dd815SMatthias Ringwald } 213aa4dd815SMatthias Ringwald 214aa4dd815SMatthias Ringwald static int hfp_ag_send_clip(uint16_t cid){ 215aa4dd815SMatthias Ringwald char buffer[50]; 216ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s: \"%s\",%u\r\n", HFP_ENABLE_CLIP, 217ff7d6aeaSMatthias Ringwald hfp_gsm_clip_number(), hfp_gsm_clip_type()); 218ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 219aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 220aa4dd815SMatthias Ringwald } 221aa4dd815SMatthias Ringwald 222ce263fc8SMatthias Ringwald static int hfp_send_subscriber_number_cmd(uint16_t cid, uint8_t type, const char * number){ 223ce263fc8SMatthias Ringwald char buffer[50]; 224ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s: ,\"%s\",%u, , \r\n", 225ff7d6aeaSMatthias Ringwald HFP_SUBSCRIBER_NUMBER_INFORMATION, number, type); 226ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 227ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 228ce263fc8SMatthias Ringwald } 229ce263fc8SMatthias Ringwald 230c1797c7dSMatthias Ringwald static int hfp_ag_send_phone_number_for_voice_tag_cmd(uint16_t cid){ 231aa4dd815SMatthias Ringwald char buffer[50]; 232ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s: %s\r\n", 233ff7d6aeaSMatthias Ringwald HFP_PHONE_NUMBER_FOR_VOICE_TAG, hfp_gsm_clip_number()); 234ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 235aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 236aa4dd815SMatthias Ringwald } 237aa4dd815SMatthias Ringwald 238aa4dd815SMatthias Ringwald static int hfp_ag_send_call_waiting_notification(uint16_t cid){ 239aa4dd815SMatthias Ringwald char buffer[50]; 240ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s: \"%s\",%u\r\n", 241ff7d6aeaSMatthias Ringwald HFP_ENABLE_CALL_WAITING_NOTIFICATION, hfp_gsm_clip_number(), 242ff7d6aeaSMatthias Ringwald hfp_gsm_clip_type()); 243ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 244aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 245aa4dd815SMatthias Ringwald } 246aa4dd815SMatthias Ringwald 247485ac19eSMilanka Ringwald static int hfp_ag_send_error(uint16_t cid){ 2483deb3ec6SMatthias Ringwald char buffer[10]; 249ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\nERROR\r\n"); 250ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 2513deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2523deb3ec6SMatthias Ringwald } 2533deb3ec6SMatthias Ringwald 254485ac19eSMilanka Ringwald static int hfp_ag_send_report_extended_audio_gateway_error(uint16_t cid, uint8_t error){ 2553deb3ec6SMatthias Ringwald char buffer[20]; 256ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s=%d\r\n", 257ff7d6aeaSMatthias Ringwald HFP_EXTENDED_AUDIO_GATEWAY_ERROR, error); 258ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 2593deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2603deb3ec6SMatthias Ringwald } 2613deb3ec6SMatthias Ringwald 262ad902e3dSMatthias Ringwald // get size for indicator string 263a0ffb263SMatthias Ringwald static int hfp_ag_indicators_string_size(hfp_connection_t * hfp_connection, int i){ 264ad902e3dSMatthias Ringwald // template: ("$NAME",($MIN,$MAX)) 26545718b6fSMatthias Ringwald return 8 + (int) strlen(hfp_ag_get_ag_indicators(hfp_connection)[i].name) 266a0ffb263SMatthias Ringwald + string_len_for_uint32(hfp_ag_get_ag_indicators(hfp_connection)[i].min_range) 267a0ffb263SMatthias Ringwald + string_len_for_uint32(hfp_ag_get_ag_indicators(hfp_connection)[i].min_range); 268ad902e3dSMatthias Ringwald } 269ad902e3dSMatthias Ringwald 270ad902e3dSMatthias Ringwald // store indicator 2711167ff83SMatthias Ringwald static void hfp_ag_indicators_string_store(hfp_connection_t * hfp_connection, int i, uint8_t * buffer, uint16_t buffer_size){ 2721167ff83SMatthias Ringwald snprintf((char *)buffer, buffer_size, "(\"%s\",(%d,%d)),", 273a0ffb263SMatthias Ringwald hfp_ag_get_ag_indicators(hfp_connection)[i].name, 274a0ffb263SMatthias Ringwald hfp_ag_get_ag_indicators(hfp_connection)[i].min_range, 275a0ffb263SMatthias Ringwald hfp_ag_get_ag_indicators(hfp_connection)[i].max_range); 2761167ff83SMatthias Ringwald ((char *)buffer)[buffer_size - 1] = 0; 2773deb3ec6SMatthias Ringwald } 278ad902e3dSMatthias Ringwald 279ad902e3dSMatthias Ringwald // structure: header [indicator [comma indicator]] footer 280a0ffb263SMatthias Ringwald static int hfp_ag_indicators_cmd_generator_num_segments(hfp_connection_t * hfp_connection){ 281a0ffb263SMatthias Ringwald int num_indicators = hfp_ag_get_ag_indicators_nr(hfp_connection); 282ad902e3dSMatthias Ringwald if (!num_indicators) return 2; 283c1ab6cc1SMatthias Ringwald return 3 + ((num_indicators-1) * 2); 2843deb3ec6SMatthias Ringwald } 285ad902e3dSMatthias Ringwald 286ad902e3dSMatthias Ringwald // get size of individual segment for hfp_ag_retrieve_indicators_cmd 287a0ffb263SMatthias Ringwald static int hfp_ag_indicators_cmd_generator_get_segment_len(hfp_connection_t * hfp_connection, int index){ 288ad902e3dSMatthias Ringwald if (index == 0) { 289ad902e3dSMatthias Ringwald return strlen(HFP_INDICATOR) + 3; // "\n\r%s:"" 290ad902e3dSMatthias Ringwald } 291ad902e3dSMatthias Ringwald index--; 292a0ffb263SMatthias Ringwald int num_indicators = hfp_ag_get_ag_indicators_nr(hfp_connection); 293ad902e3dSMatthias Ringwald int indicator_index = index >> 1; 294ad902e3dSMatthias Ringwald if ((index & 1) == 0){ 295a0ffb263SMatthias Ringwald return hfp_ag_indicators_string_size(hfp_connection, indicator_index); 296ad902e3dSMatthias Ringwald } 297c1ab6cc1SMatthias Ringwald if (indicator_index == (num_indicators - 1)){ 298ad902e3dSMatthias Ringwald return 8; // "\r\n\r\nOK\r\n" 299ad902e3dSMatthias Ringwald } 300ad902e3dSMatthias Ringwald return 1; // comma 301ad902e3dSMatthias Ringwald } 302ad902e3dSMatthias Ringwald 3031167ff83SMatthias Ringwald static void hfp_ag_indicators_cmd_generator_store_segment(hfp_connection_t * hfp_connection, int index, uint8_t * buffer, uint16_t buffer_size){ 304ad902e3dSMatthias Ringwald if (index == 0){ 305ad902e3dSMatthias Ringwald *buffer++ = '\r'; 30674386ee0SMatthias Ringwald *buffer++ = '\n'; 307ad902e3dSMatthias Ringwald int len = strlen(HFP_INDICATOR); 3086535961aSMatthias Ringwald (void)memcpy(buffer, HFP_INDICATOR, len); 309ad902e3dSMatthias Ringwald buffer += len; 310ad902e3dSMatthias Ringwald *buffer++ = ':'; 311ad902e3dSMatthias Ringwald return; 312ad902e3dSMatthias Ringwald } 313ad902e3dSMatthias Ringwald index--; 314a0ffb263SMatthias Ringwald int num_indicators = hfp_ag_get_ag_indicators_nr(hfp_connection); 315ad902e3dSMatthias Ringwald int indicator_index = index >> 1; 316ad902e3dSMatthias Ringwald if ((index & 1) == 0){ 3171167ff83SMatthias Ringwald hfp_ag_indicators_string_store(hfp_connection, indicator_index, buffer, buffer_size); 318ad902e3dSMatthias Ringwald return; 319ad902e3dSMatthias Ringwald } 320c1ab6cc1SMatthias Ringwald if (indicator_index == (num_indicators-1)){ 3216535961aSMatthias Ringwald (void)memcpy(buffer, "\r\n\r\nOK\r\n", 8); 322ad902e3dSMatthias Ringwald return; 323ad902e3dSMatthias Ringwald } 324ad902e3dSMatthias Ringwald *buffer = ','; 3253deb3ec6SMatthias Ringwald } 3263deb3ec6SMatthias Ringwald 3273deb3ec6SMatthias Ringwald static int hfp_hf_indicators_join(char * buffer, int buffer_size){ 328c1ab6cc1SMatthias Ringwald if (buffer_size < (hfp_ag_indicators_nr * 3)) return 0; 3293deb3ec6SMatthias Ringwald int i; 3303deb3ec6SMatthias Ringwald int offset = 0; 331c1ab6cc1SMatthias Ringwald for (i = 0; i < (hfp_generic_status_indicators_nr-1); i++) { 332a0ffb263SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_generic_status_indicators[i].uuid); 3333deb3ec6SMatthias Ringwald } 334a0ffb263SMatthias Ringwald if (i < hfp_generic_status_indicators_nr){ 335ae46d666SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_generic_status_indicators[i].uuid); 3363deb3ec6SMatthias Ringwald } 3373deb3ec6SMatthias Ringwald return offset; 3383deb3ec6SMatthias Ringwald } 3393deb3ec6SMatthias Ringwald 3403deb3ec6SMatthias Ringwald static int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){ 341c1ab6cc1SMatthias Ringwald if (buffer_size < (hfp_generic_status_indicators_nr * 3)) return 0; 3423deb3ec6SMatthias Ringwald int i; 3433deb3ec6SMatthias Ringwald int offset = 0; 344a0ffb263SMatthias Ringwald for (i = 0; i < hfp_generic_status_indicators_nr; i++) { 345a0ffb263SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "\r\n%s:%d,%d\r\n", HFP_GENERIC_STATUS_INDICATOR, hfp_generic_status_indicators[i].uuid, hfp_generic_status_indicators[i].state); 3463deb3ec6SMatthias Ringwald } 3473deb3ec6SMatthias Ringwald return offset; 3483deb3ec6SMatthias Ringwald } 3493deb3ec6SMatthias Ringwald 3503deb3ec6SMatthias Ringwald static int hfp_ag_indicators_status_join(char * buffer, int buffer_size){ 351c1ab6cc1SMatthias Ringwald if (buffer_size < (hfp_ag_indicators_nr * 3)) return 0; 3523deb3ec6SMatthias Ringwald int i; 3533deb3ec6SMatthias Ringwald int offset = 0; 354c1ab6cc1SMatthias Ringwald for (i = 0; i < (hfp_ag_indicators_nr-1); i++) { 3553deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status); 3563deb3ec6SMatthias Ringwald } 3573deb3ec6SMatthias Ringwald if (i<hfp_ag_indicators_nr){ 3583deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status); 3593deb3ec6SMatthias Ringwald } 3603deb3ec6SMatthias Ringwald return offset; 3613deb3ec6SMatthias Ringwald } 3623deb3ec6SMatthias Ringwald 3633deb3ec6SMatthias Ringwald static int hfp_ag_call_services_join(char * buffer, int buffer_size){ 364c1ab6cc1SMatthias Ringwald if (buffer_size < (hfp_ag_call_hold_services_nr * 3)) return 0; 3653deb3ec6SMatthias Ringwald int i; 3663deb3ec6SMatthias Ringwald int offset = snprintf(buffer, buffer_size, "("); 367c1ab6cc1SMatthias Ringwald for (i = 0; i < (hfp_ag_call_hold_services_nr-1); i++) { 3683deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]); 3693deb3ec6SMatthias Ringwald } 3703deb3ec6SMatthias Ringwald if (i<hfp_ag_call_hold_services_nr){ 3713deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%s)", hfp_ag_call_hold_services[i]); 3723deb3ec6SMatthias Ringwald } 3733deb3ec6SMatthias Ringwald return offset; 3743deb3ec6SMatthias Ringwald } 3753deb3ec6SMatthias Ringwald 376485ac19eSMilanka Ringwald static int hfp_ag_send_cmd_via_generator(uint16_t cid, hfp_connection_t * hfp_connection, 377ad902e3dSMatthias Ringwald int start_segment, int num_segments, 378a0ffb263SMatthias Ringwald int (*get_segment_len)(hfp_connection_t * hfp_connection, int segment), 3791167ff83SMatthias Ringwald void (*store_segment) (hfp_connection_t * hfp_connection, int segment, uint8_t * buffer, uint16_t buffer_size)){ 3803deb3ec6SMatthias Ringwald 381ad902e3dSMatthias Ringwald // assumes: can send now == true 382ad902e3dSMatthias Ringwald // assumes: num segments > 0 383aba39421SMatthias Ringwald // assumes: individual segments are smaller than MTU 384ad902e3dSMatthias Ringwald rfcomm_reserve_packet_buffer(); 385ad902e3dSMatthias Ringwald int mtu = rfcomm_get_max_frame_size(cid); 386ad902e3dSMatthias Ringwald uint8_t * data = rfcomm_get_outgoing_buffer(); 387ad902e3dSMatthias Ringwald int offset = 0; 388ad902e3dSMatthias Ringwald int segment = start_segment; 389ad902e3dSMatthias Ringwald while (segment < num_segments){ 390a0ffb263SMatthias Ringwald int segment_len = get_segment_len(hfp_connection, segment); 3911167ff83SMatthias Ringwald if ((offset + segment_len + 1) > mtu) break; 3921167ff83SMatthias Ringwald // append segment. As it appends a '\0', we provide a buffer one byte larger 3931167ff83SMatthias Ringwald store_segment(hfp_connection, segment, data+offset, segment_len + 1); 394ad902e3dSMatthias Ringwald offset += segment_len; 395ad902e3dSMatthias Ringwald segment++; 396ad902e3dSMatthias Ringwald } 397ad902e3dSMatthias Ringwald rfcomm_send_prepared(cid, offset); 398f20dd2aeSBjoern Hartmann #ifdef ENABLE_HFP_AT_MESSAGES 399f20dd2aeSBjoern Hartmann hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_SENT, (char *) data); 400f20dd2aeSBjoern Hartmann #endif 401ad902e3dSMatthias Ringwald return segment; 402ad902e3dSMatthias Ringwald } 4033deb3ec6SMatthias Ringwald 404ad902e3dSMatthias Ringwald // returns next segment to store 405485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * hfp_connection, int start_segment){ 406a0ffb263SMatthias Ringwald int num_segments = hfp_ag_indicators_cmd_generator_num_segments(hfp_connection); 407485ac19eSMilanka Ringwald return hfp_ag_send_cmd_via_generator(cid, hfp_connection, start_segment, num_segments, 408894d499cSMatthias Ringwald hfp_ag_indicators_cmd_generator_get_segment_len, 409894d499cSMatthias Ringwald hfp_ag_indicators_cmd_generator_store_segment); 4103deb3ec6SMatthias Ringwald } 4113deb3ec6SMatthias Ringwald 412485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_indicators_status_cmd(uint16_t cid){ 4133deb3ec6SMatthias Ringwald char buffer[40]; 41489425bfcSMilanka Ringwald const int size = sizeof(buffer); 41589425bfcSMilanka Ringwald int offset = snprintf(buffer, size, "\r\n%s:", HFP_INDICATOR); 41689425bfcSMilanka Ringwald offset += hfp_ag_indicators_status_join(buffer+offset, size-offset-9); 41789425bfcSMilanka Ringwald offset += snprintf(buffer+offset, size-offset, "\r\n\r\nOK\r\n"); 4183deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4193deb3ec6SMatthias Ringwald } 4203deb3ec6SMatthias Ringwald 421485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_can_hold_call_cmd(uint16_t cid){ 422ad902e3dSMatthias Ringwald char buffer[40]; 42389425bfcSMilanka Ringwald const int size = sizeof(buffer); 42489425bfcSMilanka Ringwald int offset = snprintf(buffer, size, "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES); 42589425bfcSMilanka Ringwald offset += hfp_ag_call_services_join(buffer+offset, size-offset-9); 42689425bfcSMilanka Ringwald offset += snprintf(buffer+offset, size-offset, "\r\n\r\nOK\r\n"); 4273deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4283deb3ec6SMatthias Ringwald } 4293deb3ec6SMatthias Ringwald 4303deb3ec6SMatthias Ringwald 431485ac19eSMilanka Ringwald static int hfp_ag_send_list_supported_generic_status_indicators_cmd(uint16_t cid){ 432485ac19eSMilanka Ringwald return hfp_ag_send_ok(cid); 4333deb3ec6SMatthias Ringwald } 4343deb3ec6SMatthias Ringwald 435485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){ 4363deb3ec6SMatthias Ringwald char buffer[40]; 43789425bfcSMilanka Ringwald const int size = sizeof(buffer); 43889425bfcSMilanka Ringwald int offset = snprintf(buffer, size, "\r\n%s:(", HFP_GENERIC_STATUS_INDICATOR); 43989425bfcSMilanka Ringwald offset += hfp_hf_indicators_join(buffer+offset, size-offset-10); 44089425bfcSMilanka Ringwald offset += snprintf(buffer+offset, size-offset, ")\r\n\r\nOK\r\n"); 4413deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4423deb3ec6SMatthias Ringwald } 4433deb3ec6SMatthias Ringwald 444485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t cid){ 4453deb3ec6SMatthias Ringwald char buffer[40]; 4461cc1d9e9SMilanka Ringwald int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer) - 7); 4471cc1d9e9SMilanka Ringwald snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n"); 4483deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4493deb3ec6SMatthias Ringwald } 4503deb3ec6SMatthias Ringwald 451485ac19eSMilanka Ringwald static int hfp_ag_send_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t * indicator){ 4523deb3ec6SMatthias Ringwald char buffer[20]; 453ff7d6aeaSMatthias Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s:%d,%d\r\n", 454ff7d6aeaSMatthias Ringwald HFP_TRANSFER_AG_INDICATOR_STATUS, indicator->index, 455ff7d6aeaSMatthias Ringwald indicator->status); 456ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 4573deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4583deb3ec6SMatthias Ringwald } 4593deb3ec6SMatthias Ringwald 460485ac19eSMilanka Ringwald static int hfp_ag_send_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){ 4615e71456cSMilanka Ringwald char buffer[41]; 4623deb3ec6SMatthias Ringwald if (strlen(op.name) == 0){ 46389425bfcSMilanka Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s:%d,,\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode); 4643deb3ec6SMatthias Ringwald } else { 46589425bfcSMilanka Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:%d,%d,", HFP_QUERY_OPERATOR_SELECTION, op.mode, op.format); 4665e71456cSMilanka Ringwald offset += snprintf(buffer+offset, 16, "%s", op.name); 46789425bfcSMilanka Ringwald snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); 4683deb3ec6SMatthias Ringwald } 4693deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4703deb3ec6SMatthias Ringwald } 4713deb3ec6SMatthias Ringwald 4721cc1d9e9SMilanka Ringwald static inline int hfp_ag_send_cmd_with_int(uint16_t cid, const char * cmd, uint8_t value){ 4731cc1d9e9SMilanka Ringwald char buffer[30]; 47489425bfcSMilanka Ringwald snprintf(buffer, sizeof(buffer), "\r\n%s:%d\r\n", cmd, value); 4751cc1d9e9SMilanka Ringwald return send_str_over_rfcomm(cid, buffer); 4761cc1d9e9SMilanka Ringwald } 4773deb3ec6SMatthias Ringwald 478485ac19eSMilanka Ringwald static int hfp_ag_send_suggest_codec_cmd(uint16_t cid, uint8_t codec){ 4791cc1d9e9SMilanka Ringwald return hfp_ag_send_cmd_with_int(cid, HFP_CONFIRM_COMMON_CODEC, codec); 4803deb3ec6SMatthias Ringwald } 4813deb3ec6SMatthias Ringwald 482485ac19eSMilanka Ringwald static int hfp_ag_send_activate_voice_recognition_cmd(uint16_t cid, uint8_t activate_voice_recognition){ 4831cc1d9e9SMilanka Ringwald return hfp_ag_send_cmd_with_int(cid, HFP_ACTIVATE_VOICE_RECOGNITION, activate_voice_recognition); 484aa4dd815SMatthias Ringwald } 485aa4dd815SMatthias Ringwald 486485ac19eSMilanka Ringwald static int hfp_ag_send_set_speaker_gain_cmd(uint16_t cid, uint8_t gain){ 4871cc1d9e9SMilanka Ringwald return hfp_ag_send_cmd_with_int(cid, HFP_SET_SPEAKER_GAIN, gain); 488aa4dd815SMatthias Ringwald } 489aa4dd815SMatthias Ringwald 490485ac19eSMilanka Ringwald static int hfp_ag_send_set_microphone_gain_cmd(uint16_t cid, uint8_t gain){ 4911cc1d9e9SMilanka Ringwald return hfp_ag_send_cmd_with_int(cid, HFP_SET_MICROPHONE_GAIN, gain); 492aa4dd815SMatthias Ringwald } 493aa4dd815SMatthias Ringwald 494485ac19eSMilanka Ringwald static int hfp_ag_send_set_response_and_hold(uint16_t cid, int state){ 4951cc1d9e9SMilanka Ringwald return hfp_ag_send_cmd_with_int(cid, HFP_RESPONSE_AND_HOLD, state); 496ce263fc8SMatthias Ringwald } 497ce263fc8SMatthias Ringwald 498a0ffb263SMatthias Ringwald static uint8_t hfp_ag_suggest_codec(hfp_connection_t *hfp_connection){ 499bc1b1537SMilanka Ringwald if (hfp_connection->sco_for_msbc_failed) return HFP_CODEC_CVSD; 500bc1b1537SMilanka Ringwald 5016a7f44bdSMilanka Ringwald if (hfp_supports_codec(HFP_CODEC_MSBC, hfp_codecs_nr, hfp_codecs)){ 5026a7f44bdSMilanka Ringwald if (hfp_supports_codec(HFP_CODEC_MSBC, hfp_connection->remote_codecs_nr, hfp_connection->remote_codecs)){ 503df327ff3SMilanka Ringwald return HFP_CODEC_MSBC; 5043deb3ec6SMatthias Ringwald } 5053deb3ec6SMatthias Ringwald } 506df327ff3SMilanka Ringwald return HFP_CODEC_CVSD; 5073deb3ec6SMatthias Ringwald } 5083deb3ec6SMatthias Ringwald 50976cc1527SMatthias Ringwald /* state machines */ 51076cc1527SMatthias Ringwald 511afac2a04SMilanka Ringwald static uint8_t hfp_ag_esco_s4_supported(hfp_connection_t * hfp_connection){ 512afac2a04SMilanka Ringwald return (hfp_connection->remote_supported_features & (1<<HFP_HFSF_ESCO_S4)) && (hfp_supported_features & (1<<HFP_AGSF_ESCO_S4)); 5137522e673SMatthias Ringwald } 5147522e673SMatthias Ringwald 515a0ffb263SMatthias Ringwald static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){ 516aa4dd815SMatthias Ringwald /* events ( == commands): 517aa4dd815SMatthias Ringwald HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs 518aa4dd815SMatthias Ringwald HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 519aa4dd815SMatthias Ringwald hf_trigger_codec_connection_setup == received BCC 520aa4dd815SMatthias Ringwald ag_trigger_codec_connection_setup == received from AG to send BCS 521aa4dd815SMatthias Ringwald HFP_CMD_HF_CONFIRMED_CODEC == received AT+BCS 522aa4dd815SMatthias Ringwald */ 523a0ffb263SMatthias Ringwald switch (hfp_connection->codecs_state){ 524*3e3b9207SMilanka Ringwald case HFP_CODECS_EXCHANGED: 525*3e3b9207SMilanka Ringwald if (hfp_connection->command == HFP_CMD_AVAILABLE_CODECS){ 526*3e3b9207SMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 527*3e3b9207SMilanka Ringwald return 1; 528*3e3b9207SMilanka Ringwald } 529*3e3b9207SMilanka Ringwald break; 530*3e3b9207SMilanka Ringwald 531aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: 532a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_AG_SEND_COMMON_CODEC; 533aa4dd815SMatthias Ringwald break; 534aa4dd815SMatthias Ringwald case HFP_CODECS_AG_RESEND_COMMON_CODEC: 535a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_AG_SEND_COMMON_CODEC; 536aa4dd815SMatthias Ringwald break; 537aa4dd815SMatthias Ringwald default: 538aa4dd815SMatthias Ringwald break; 539aa4dd815SMatthias Ringwald } 540aa4dd815SMatthias Ringwald 541a0ffb263SMatthias Ringwald switch (hfp_connection->command){ 542aa4dd815SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 543a0ffb263SMatthias Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ 544a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_RECEIVED_LIST; 545485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 546aa4dd815SMatthias Ringwald return 1; 547aa4dd815SMatthias Ringwald } 548aa4dd815SMatthias Ringwald 549a0ffb263SMatthias Ringwald switch (hfp_connection->codecs_state){ 550aa4dd815SMatthias Ringwald case HFP_CODECS_AG_SENT_COMMON_CODEC: 551a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_AG_RESEND_COMMON_CODEC; 552aa4dd815SMatthias Ringwald break; 553aa4dd815SMatthias Ringwald default: 554aa4dd815SMatthias Ringwald break; 555aa4dd815SMatthias Ringwald } 556485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 557aa4dd815SMatthias Ringwald return 1; 558aa4dd815SMatthias Ringwald 559aa4dd815SMatthias Ringwald case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 560a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; 56140e8d6c5SMatthias Ringwald hfp_connection->establish_audio_connection = 1; 562485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 563aa4dd815SMatthias Ringwald return 1; 564aa4dd815SMatthias Ringwald 565aa4dd815SMatthias Ringwald case HFP_CMD_AG_SEND_COMMON_CODEC: 566a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC; 567a0ffb263SMatthias Ringwald hfp_connection->suggested_codec = hfp_ag_suggest_codec(hfp_connection); 568485ac19eSMilanka Ringwald hfp_ag_send_suggest_codec_cmd(hfp_connection->rfcomm_cid, hfp_connection->suggested_codec); 569aa4dd815SMatthias Ringwald return 1; 570aa4dd815SMatthias Ringwald 571aa4dd815SMatthias Ringwald case HFP_CMD_HF_CONFIRMED_CODEC: 572a0ffb263SMatthias Ringwald if (hfp_connection->codec_confirmed != hfp_connection->suggested_codec){ 573a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_ERROR; 574485ac19eSMilanka Ringwald hfp_ag_send_error(hfp_connection->rfcomm_cid); 575aa4dd815SMatthias Ringwald return 1; 576aa4dd815SMatthias Ringwald } 577a0ffb263SMatthias Ringwald hfp_connection->negotiated_codec = hfp_connection->codec_confirmed; 578a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_EXCHANGED; 579c1ab6cc1SMatthias Ringwald log_info("hfp: codec confirmed: %s", (hfp_connection->negotiated_codec == HFP_CODEC_MSBC) ? "mSBC" : "CVSD"); 580485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 5817522e673SMatthias Ringwald // now, pick link settings 582afac2a04SMilanka Ringwald hfp_init_link_settings(hfp_connection, hfp_ag_esco_s4_supported(hfp_connection)); 5833721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP 5843721a235SMatthias Ringwald hfp_cc256x_prepare_for_sco(hfp_connection); 5853721a235SMatthias Ringwald #endif 586aa4dd815SMatthias Ringwald return 1; 587aa4dd815SMatthias Ringwald default: 588aa4dd815SMatthias Ringwald break; 589aa4dd815SMatthias Ringwald } 590aa4dd815SMatthias Ringwald return 0; 591aa4dd815SMatthias Ringwald } 592aa4dd815SMatthias Ringwald 593a0ffb263SMatthias Ringwald static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){ 594a0ffb263SMatthias Ringwald hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 595ca59be51SMatthias Ringwald hfp_emit_slc_connection_event(hfp_connection, 0, hfp_connection->acl_handle, hfp_connection->remote_addr); 596aa4dd815SMatthias Ringwald 597a0ffb263SMatthias Ringwald // if active call exist, set per-hfp_connection state active, too (when audio is on) 598d0c20769SMatthias Ringwald if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 599a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; 600aa4dd815SMatthias Ringwald } 601ce263fc8SMatthias Ringwald // if AG is ringing, also start ringing on the HF 602c1ab6cc1SMatthias Ringwald if ((hfp_gsm_call_status() == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) && 603505f1c30SMatthias Ringwald (hfp_gsm_callsetup_status() == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS)){ 604a0ffb263SMatthias Ringwald hfp_ag_hf_start_ringing(hfp_connection); 605ce263fc8SMatthias Ringwald } 606aa4dd815SMatthias Ringwald } 6073deb3ec6SMatthias Ringwald 608a0ffb263SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){ 609c79b4cabSMatthias Ringwald // log_info("hfp_ag_run_for_context_service_level_connection state %u, command %u", hfp_connection->state, hfp_connection->command); 610a0ffb263SMatthias Ringwald if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 611c04cf7ffSMilanka Ringwald int sent = 0; 612a0ffb263SMatthias Ringwald switch(hfp_connection->command){ 6133deb3ec6SMatthias Ringwald case HFP_CMD_SUPPORTED_FEATURES: 614a0ffb263SMatthias Ringwald switch(hfp_connection->state){ 6153deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: 616aa4dd815SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES: 617d715cf51SMatthias Ringwald hfp_hf_drop_mSBC_if_eSCO_not_supported(hfp_codecs, &hfp_codecs_nr); 618a0ffb263SMatthias Ringwald if (has_codec_negotiation_feature(hfp_connection)){ 619a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_NOTIFY_ON_CODECS; 620aa4dd815SMatthias Ringwald } else { 621a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS; 622aa4dd815SMatthias Ringwald } 623a0ffb263SMatthias Ringwald hfp_ag_exchange_supported_features_cmd(hfp_connection->rfcomm_cid); 624aa4dd815SMatthias Ringwald return 1; 6253deb3ec6SMatthias Ringwald default: 6263deb3ec6SMatthias Ringwald break; 6273deb3ec6SMatthias Ringwald } 6283deb3ec6SMatthias Ringwald break; 6293deb3ec6SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 630c04cf7ffSMilanka Ringwald sent = codecs_exchange_state_machine(hfp_connection); 631a0ffb263SMatthias Ringwald if (hfp_connection->codecs_state == HFP_CODECS_RECEIVED_LIST){ 632a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS; 6333deb3ec6SMatthias Ringwald } 634c04cf7ffSMilanka Ringwald return sent; 635aa4dd815SMatthias Ringwald 636aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS: 637a0ffb263SMatthias Ringwald if (hfp_connection->state == HFP_W4_RETRIEVE_INDICATORS) { 638473ac565SMatthias Ringwald // HF requested AG Indicators and we did expect it 63984a0c24eSMatthias Ringwald hfp_connection->send_ag_indicators_segment = 0; 640473ac565SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS; 641473ac565SMatthias Ringwald // continue below in state switch 642ad902e3dSMatthias Ringwald } 643ad902e3dSMatthias Ringwald break; 644aa4dd815SMatthias Ringwald 645aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: 646a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break; 647a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; 648485ac19eSMilanka Ringwald hfp_ag_send_retrieve_indicators_status_cmd(hfp_connection->rfcomm_cid); 649aa4dd815SMatthias Ringwald return 1; 650aa4dd815SMatthias Ringwald 6513deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 652a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE) break; 653a0ffb263SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(hfp_connection)){ 654a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; 655a0ffb263SMatthias Ringwald } else if (has_hf_indicators_feature(hfp_connection)){ 656a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 657aa4dd815SMatthias Ringwald } else { 658a0ffb263SMatthias Ringwald hfp_ag_slc_established(hfp_connection); 6593deb3ec6SMatthias Ringwald } 6608a46ec40SMatthias Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 661aa4dd815SMatthias Ringwald return 1; 6623deb3ec6SMatthias Ringwald 663aa4dd815SMatthias Ringwald case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: 664a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break; 665a0ffb263SMatthias Ringwald if (has_hf_indicators_feature(hfp_connection)){ 666a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 667aa4dd815SMatthias Ringwald } 668485ac19eSMilanka Ringwald hfp_ag_send_retrieve_can_hold_call_cmd(hfp_connection->rfcomm_cid); 669a0ffb263SMatthias Ringwald if (!has_hf_indicators_feature(hfp_connection)){ 670a0ffb263SMatthias Ringwald hfp_ag_slc_established(hfp_connection); 671ce263fc8SMatthias Ringwald } 672aa4dd815SMatthias Ringwald return 1; 673aa4dd815SMatthias Ringwald 674aa4dd815SMatthias Ringwald case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS: 675a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_W4_LIST_GENERIC_STATUS_INDICATORS) break; 676a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; 677485ac19eSMilanka Ringwald hfp_ag_send_list_supported_generic_status_indicators_cmd(hfp_connection->rfcomm_cid); 678aa4dd815SMatthias Ringwald return 1; 679aa4dd815SMatthias Ringwald 680aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS: 681a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS) break; 682a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 683485ac19eSMilanka Ringwald hfp_ag_send_retrieve_supported_generic_status_indicators_cmd(hfp_connection->rfcomm_cid); 684aa4dd815SMatthias Ringwald return 1; 685aa4dd815SMatthias Ringwald 686aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE: 687a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS) break; 688a0ffb263SMatthias Ringwald hfp_ag_slc_established(hfp_connection); 689485ac19eSMilanka Ringwald hfp_ag_send_retrieve_initital_supported_generic_status_indicators_cmd(hfp_connection->rfcomm_cid); 690aa4dd815SMatthias Ringwald return 1; 6913deb3ec6SMatthias Ringwald default: 6923deb3ec6SMatthias Ringwald break; 6933deb3ec6SMatthias Ringwald } 694473ac565SMatthias Ringwald 695473ac565SMatthias Ringwald switch (hfp_connection->state){ 696473ac565SMatthias Ringwald case HFP_RETRIEVE_INDICATORS: { 697485ac19eSMilanka Ringwald int next_segment = hfp_ag_send_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment); 698473ac565SMatthias Ringwald int num_segments = hfp_ag_indicators_cmd_generator_num_segments(hfp_connection); 699473ac565SMatthias Ringwald log_info("HFP_CMD_RETRIEVE_AG_INDICATORS next segment %u, num_segments %u", next_segment, num_segments); 700473ac565SMatthias Ringwald if (next_segment < num_segments){ 701473ac565SMatthias Ringwald // prepare sending of next segment 702473ac565SMatthias Ringwald hfp_connection->send_ag_indicators_segment = next_segment; 703473ac565SMatthias Ringwald log_info("HFP_CMD_RETRIEVE_AG_INDICATORS more. command %u, next seg %u", hfp_connection->command, next_segment); 704473ac565SMatthias Ringwald } else { 705473ac565SMatthias Ringwald // done, go to next state 706473ac565SMatthias Ringwald hfp_connection->send_ag_indicators_segment = 0; 707473ac565SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; 708473ac565SMatthias Ringwald } 709473ac565SMatthias Ringwald return 1; 710473ac565SMatthias Ringwald } 711473ac565SMatthias Ringwald default: 712473ac565SMatthias Ringwald break; 713473ac565SMatthias Ringwald } 714c04cf7ffSMilanka Ringwald return 0; 7153deb3ec6SMatthias Ringwald } 7163deb3ec6SMatthias Ringwald 717a0ffb263SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){ 718c04cf7ffSMilanka Ringwald int sent = codecs_exchange_state_machine(hfp_connection); 719c04cf7ffSMilanka Ringwald if (sent) return 1; 720aa4dd815SMatthias Ringwald 721a0ffb263SMatthias Ringwald switch(hfp_connection->command){ 722aa4dd815SMatthias Ringwald case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: 723a0ffb263SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, hfp_connection->ag_activate_voice_recognition); 724485ac19eSMilanka Ringwald hfp_ag_send_activate_voice_recognition_cmd(hfp_connection->rfcomm_cid, hfp_connection->ag_activate_voice_recognition); 725aa4dd815SMatthias Ringwald return 1; 726aa4dd815SMatthias Ringwald case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION: 727aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)){ 728a0ffb263SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, hfp_connection->ag_activate_voice_recognition); 729485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 730a0ffb263SMatthias Ringwald hfp_ag_setup_audio_connection(hfp_connection); 731aa4dd815SMatthias Ringwald } else { 732485ac19eSMilanka Ringwald hfp_ag_send_error(hfp_connection->rfcomm_cid); 733aa4dd815SMatthias Ringwald } 734aa4dd815SMatthias Ringwald return 1; 735aa4dd815SMatthias Ringwald case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING: 736485ac19eSMilanka Ringwald hfp_ag_send_change_in_band_ring_tone_setting_cmd(hfp_connection->rfcomm_cid); 737aa4dd815SMatthias Ringwald return 1; 738aa4dd815SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME: 739485ac19eSMilanka Ringwald hfp_ag_send_report_network_operator_name_cmd(hfp_connection->rfcomm_cid, hfp_connection->network_operator); 740aa4dd815SMatthias Ringwald return 1; 741aa4dd815SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT: 742a0ffb263SMatthias Ringwald if (hfp_connection->network_operator.format != 0){ 743485ac19eSMilanka Ringwald hfp_ag_send_error(hfp_connection->rfcomm_cid); 744aa4dd815SMatthias Ringwald } else { 745485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 7463deb3ec6SMatthias Ringwald } 747aa4dd815SMatthias Ringwald return 1; 748aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE: 749485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 750aa4dd815SMatthias Ringwald return 1; 7513deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR: 752a0ffb263SMatthias Ringwald if (hfp_connection->extended_audio_gateway_error){ 753a0ffb263SMatthias Ringwald hfp_connection->extended_audio_gateway_error = 0; 754485ac19eSMilanka Ringwald hfp_ag_send_report_extended_audio_gateway_error(hfp_connection->rfcomm_cid, hfp_connection->extended_audio_gateway_error_value); 755aa4dd815SMatthias Ringwald return 1; 7563deb3ec6SMatthias Ringwald } 757202c8a4cSMatthias Ringwald break; 7583deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 759485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 760ce263fc8SMatthias Ringwald return 1; 7613deb3ec6SMatthias Ringwald default: 7623deb3ec6SMatthias Ringwald break; 7633deb3ec6SMatthias Ringwald } 764aa4dd815SMatthias Ringwald return 0; 7653deb3ec6SMatthias Ringwald } 7663deb3ec6SMatthias Ringwald 767a0ffb263SMatthias Ringwald static int hfp_ag_run_for_audio_connection(hfp_connection_t * hfp_connection){ 768505f1c30SMatthias Ringwald if ((hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) || 769505f1c30SMatthias Ringwald (hfp_connection->state > HFP_W2_DISCONNECT_SCO)) return 0; 7703deb3ec6SMatthias Ringwald 771aa4dd815SMatthias Ringwald 772505f1c30SMatthias Ringwald if ((hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) && hfp_connection->release_audio_connection){ 773a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_DISCONNECTED; 774a0ffb263SMatthias Ringwald hfp_connection->release_audio_connection = 0; 775a0ffb263SMatthias Ringwald gap_disconnect(hfp_connection->sco_handle); 776aa4dd815SMatthias Ringwald return 1; 777aa4dd815SMatthias Ringwald } 778aa4dd815SMatthias Ringwald 779a0ffb263SMatthias Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 780aa4dd815SMatthias Ringwald 78129cddf58SMatthias Ringwald // accept incoming audio connection (codec negotiation is not used) 78229cddf58SMatthias Ringwald if (hfp_connection->accept_sco){ 78329cddf58SMatthias Ringwald // notify about codec selection if not done already 78429cddf58SMatthias Ringwald if (hfp_connection->negotiated_codec == 0){ 78529cddf58SMatthias Ringwald hfp_connection->negotiated_codec = HFP_CODEC_CVSD; 78629cddf58SMatthias Ringwald } 78729cddf58SMatthias Ringwald // 78829cddf58SMatthias Ringwald bool incoming_eSCO = hfp_connection->accept_sco == 2; 78929cddf58SMatthias Ringwald hfp_connection->accept_sco = 0; 79029cddf58SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_CONNECTED; 79129cddf58SMatthias Ringwald hfp_accept_synchronous_connection(hfp_connection, incoming_eSCO); 79229cddf58SMatthias Ringwald return 1; 79329cddf58SMatthias Ringwald } 79429cddf58SMatthias Ringwald 795aa4dd815SMatthias Ringwald // run codecs exchange 796c04cf7ffSMilanka Ringwald int sent = codecs_exchange_state_machine(hfp_connection); 797c04cf7ffSMilanka Ringwald if (sent) return 1; 798aa4dd815SMatthias Ringwald 799c04cf7ffSMilanka Ringwald if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return 0; 800a0ffb263SMatthias Ringwald if (hfp_connection->establish_audio_connection){ 801a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_CONNECTED; 802a0ffb263SMatthias Ringwald hfp_connection->establish_audio_connection = 0; 803eddcd308SMatthias Ringwald hfp_setup_synchronous_connection(hfp_connection); 804aa4dd815SMatthias Ringwald return 1; 805aa4dd815SMatthias Ringwald } 806aa4dd815SMatthias Ringwald return 0; 807aa4dd815SMatthias Ringwald } 808aa4dd815SMatthias Ringwald 809ec820d77SMatthias Ringwald static hfp_connection_t * hfp_ag_context_for_timer(btstack_timer_source_t * ts){ 810665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 811665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 812aa4dd815SMatthias Ringwald 813665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 814a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 815a0ffb263SMatthias Ringwald if ( & hfp_connection->hfp_timeout == ts) { 816a0ffb263SMatthias Ringwald return hfp_connection; 817aa4dd815SMatthias Ringwald } 818aa4dd815SMatthias Ringwald } 819aa4dd815SMatthias Ringwald return NULL; 820aa4dd815SMatthias Ringwald } 821aa4dd815SMatthias Ringwald 822ec820d77SMatthias Ringwald static void hfp_timeout_handler(btstack_timer_source_t * timer){ 823d63c37a1SMatthias Ringwald hfp_connection_t * hfp_connection = hfp_ag_context_for_timer(timer); 824d63c37a1SMatthias Ringwald if (!hfp_connection) return; 825aa4dd815SMatthias Ringwald 826d63c37a1SMatthias Ringwald log_info("HFP start ring timeout, con handle 0x%02x", hfp_connection->acl_handle); 827a0ffb263SMatthias Ringwald hfp_connection->ag_ring = 1; 828a0ffb263SMatthias Ringwald hfp_connection->ag_send_clip = hfp_gsm_clip_type() && hfp_connection->clip_enabled; 829aa4dd815SMatthias Ringwald 830a0ffb263SMatthias Ringwald btstack_run_loop_set_timer(& hfp_connection->hfp_timeout, 2000); // 2 seconds timeout 831a0ffb263SMatthias Ringwald btstack_run_loop_add_timer(& hfp_connection->hfp_timeout); 832aa4dd815SMatthias Ringwald 833f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 834aa4dd815SMatthias Ringwald } 835aa4dd815SMatthias Ringwald 836a0ffb263SMatthias Ringwald static void hfp_timeout_start(hfp_connection_t * hfp_connection){ 837a0ffb263SMatthias Ringwald btstack_run_loop_remove_timer(& hfp_connection->hfp_timeout); 838a0ffb263SMatthias Ringwald btstack_run_loop_set_timer_handler(& hfp_connection->hfp_timeout, hfp_timeout_handler); 839a0ffb263SMatthias Ringwald btstack_run_loop_set_timer(& hfp_connection->hfp_timeout, 2000); // 2 seconds timeout 840a0ffb263SMatthias Ringwald btstack_run_loop_add_timer(& hfp_connection->hfp_timeout); 841aa4dd815SMatthias Ringwald } 842aa4dd815SMatthias Ringwald 843a0ffb263SMatthias Ringwald static void hfp_timeout_stop(hfp_connection_t * hfp_connection){ 844a0ffb263SMatthias Ringwald log_info("HFP stop ring timeout, con handle 0x%02x", hfp_connection->acl_handle); 845a0ffb263SMatthias Ringwald btstack_run_loop_remove_timer(& hfp_connection->hfp_timeout); 846aa4dd815SMatthias Ringwald } 847aa4dd815SMatthias Ringwald 848aa4dd815SMatthias Ringwald // 849aa4dd815SMatthias Ringwald // transitition implementations for hfp_ag_call_state_machine 850aa4dd815SMatthias Ringwald // 851aa4dd815SMatthias Ringwald 852a0ffb263SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * hfp_connection){ 853aa4dd815SMatthias Ringwald if (use_in_band_tone()){ 854a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING; 855d97d752dSMilanka Ringwald hfp_ag_establish_audio_connection(hfp_connection->acl_handle); 856aa4dd815SMatthias Ringwald } else { 857a0ffb263SMatthias Ringwald hfp_timeout_start(hfp_connection); 858a0ffb263SMatthias Ringwald hfp_connection->ag_ring = 1; 859a0ffb263SMatthias Ringwald hfp_connection->ag_send_clip = hfp_gsm_clip_type() && hfp_connection->clip_enabled; 860a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_RINGING; 861ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_START_RINGINIG); 862aa4dd815SMatthias Ringwald } 863aa4dd815SMatthias Ringwald } 864aa4dd815SMatthias Ringwald 865a0ffb263SMatthias Ringwald static void hfp_ag_hf_stop_ringing(hfp_connection_t * hfp_connection){ 866a0ffb263SMatthias Ringwald hfp_connection->ag_ring = 0; 867a0ffb263SMatthias Ringwald hfp_connection->ag_send_clip = 0; 868a0ffb263SMatthias Ringwald hfp_timeout_stop(hfp_connection); 869ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_STOP_RINGINIG); 870aa4dd815SMatthias Ringwald } 871aa4dd815SMatthias Ringwald 872aa4dd815SMatthias Ringwald static void hfp_ag_trigger_incoming_call(void){ 873aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callsetup"); 874aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 875aa4dd815SMatthias Ringwald 876665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 877665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 878665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 879a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 88066c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 881a0ffb263SMatthias Ringwald hfp_ag_establish_service_level_connection(hfp_connection->remote_addr); 882a0ffb263SMatthias Ringwald if (hfp_connection->call_state == HFP_CALL_IDLE){ 883a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1); 884d63c37a1SMatthias Ringwald hfp_ag_hf_start_ringing(hfp_connection); 885aa4dd815SMatthias Ringwald } 886a0ffb263SMatthias Ringwald if (hfp_connection->call_state == HFP_CALL_ACTIVE){ 887a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_W2_SEND_CALL_WAITING; 888aa4dd815SMatthias Ringwald } 889f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 890aa4dd815SMatthias Ringwald } 891aa4dd815SMatthias Ringwald } 892aa4dd815SMatthias Ringwald 8934a2e058fSMatthias Ringwald static void hfp_ag_transfer_indicator(const char * name){ 8944a2e058fSMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name(name); 895aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 896aa4dd815SMatthias Ringwald 897665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 898665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 899665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 900a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 90166c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 902a0ffb263SMatthias Ringwald hfp_ag_establish_service_level_connection(hfp_connection->remote_addr); 903a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1); 904f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 905aa4dd815SMatthias Ringwald } 906aa4dd815SMatthias Ringwald } 907aa4dd815SMatthias Ringwald 9084a2e058fSMatthias Ringwald static void hfp_ag_transfer_callsetup_state(void){ 9094a2e058fSMatthias Ringwald hfp_ag_transfer_indicator("callsetup"); 9104a2e058fSMatthias Ringwald } 9114a2e058fSMatthias Ringwald 912aa4dd815SMatthias Ringwald static void hfp_ag_transfer_call_state(void){ 9134a2e058fSMatthias Ringwald hfp_ag_transfer_indicator("call"); 914aa4dd815SMatthias Ringwald } 915aa4dd815SMatthias Ringwald 916aa4dd815SMatthias Ringwald static void hfp_ag_transfer_callheld_state(void){ 9174a2e058fSMatthias Ringwald hfp_ag_transfer_indicator("callheld"); 918aa4dd815SMatthias Ringwald } 919aa4dd815SMatthias Ringwald 920aa4dd815SMatthias Ringwald static void hfp_ag_hf_accept_call(hfp_connection_t * source){ 921aa4dd815SMatthias Ringwald 922aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 923aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 924aa4dd815SMatthias Ringwald 925665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 926665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 927665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 928a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 92966c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 930505f1c30SMatthias Ringwald if ((hfp_connection->call_state != HFP_CALL_RINGING) && 931505f1c30SMatthias Ringwald (hfp_connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING)) continue; 932aa4dd815SMatthias Ringwald 933a0ffb263SMatthias Ringwald hfp_ag_hf_stop_ringing(hfp_connection); 934a0ffb263SMatthias Ringwald if (hfp_connection == source){ 935aa4dd815SMatthias Ringwald 936aa4dd815SMatthias Ringwald if (use_in_band_tone()){ 937a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 938aa4dd815SMatthias Ringwald } else { 939a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; 940d97d752dSMilanka Ringwald hfp_ag_establish_audio_connection(hfp_connection->acl_handle); 941aa4dd815SMatthias Ringwald } 942aa4dd815SMatthias Ringwald 943a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 944a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 945aa4dd815SMatthias Ringwald 946aa4dd815SMatthias Ringwald } else { 947a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_IDLE; 948aa4dd815SMatthias Ringwald } 949f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 950aa4dd815SMatthias Ringwald } 951aa4dd815SMatthias Ringwald } 952aa4dd815SMatthias Ringwald 953aa4dd815SMatthias Ringwald static void hfp_ag_ag_accept_call(void){ 954aa4dd815SMatthias Ringwald 955aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 956aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 957aa4dd815SMatthias Ringwald 958665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 959665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 960665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 961a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 96266c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 963a0ffb263SMatthias Ringwald if (hfp_connection->call_state != HFP_CALL_RINGING) continue; 964aa4dd815SMatthias Ringwald 965a0ffb263SMatthias Ringwald hfp_ag_hf_stop_ringing(hfp_connection); 966a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_TRIGGER_AUDIO_CONNECTION; 967aa4dd815SMatthias Ringwald 968a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 969a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 970aa4dd815SMatthias Ringwald 971f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 972aa4dd815SMatthias Ringwald break; // only single 973aa4dd815SMatthias Ringwald } 974aa4dd815SMatthias Ringwald } 975aa4dd815SMatthias Ringwald 976aa4dd815SMatthias Ringwald static void hfp_ag_trigger_reject_call(void){ 977aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 978665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 979665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 980665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 981665d90f2SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 98266c5995fSMatthias Ringwald if (connection->local_role != HFP_ROLE_AG) continue; 983505f1c30SMatthias Ringwald if ((connection->call_state != HFP_CALL_RINGING) && 984505f1c30SMatthias Ringwald (connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING)) continue; 985aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 986aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 987aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 988f0aeb307SMatthias Ringwald hfp_ag_run_for_context(connection); 989aa4dd815SMatthias Ringwald } 990aa4dd815SMatthias Ringwald } 991aa4dd815SMatthias Ringwald 992aa4dd815SMatthias Ringwald static void hfp_ag_trigger_terminate_call(void){ 993aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 994aa4dd815SMatthias Ringwald 995665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 996665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 997665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 998a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 99966c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 1000d63c37a1SMatthias Ringwald hfp_ag_establish_service_level_connection(hfp_connection->remote_addr); 1001a0ffb263SMatthias Ringwald if (hfp_connection->call_state == HFP_CALL_IDLE) continue; 1002a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_IDLE; 1003a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 10046d78145cSMatthias Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED){ 1005a0ffb263SMatthias Ringwald hfp_connection->release_audio_connection = 1; 10066d78145cSMatthias Ringwald } 1007f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 1008aa4dd815SMatthias Ringwald } 10097d81706fSMatthias Ringwald hfp_emit_simple_event(NULL, HFP_SUBEVENT_CALL_TERMINATED); 1010aa4dd815SMatthias Ringwald } 1011aa4dd815SMatthias Ringwald 10120cb5b971SMatthias Ringwald static void hfp_ag_set_callsetup_indicator(void){ 1013aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callsetup"); 1014aa4dd815SMatthias Ringwald if (!indicator){ 1015d0c20769SMatthias Ringwald log_error("hfp_ag_set_callsetup_indicator: callsetup indicator is missing"); 101645718b6fSMatthias Ringwald return; 1017aa4dd815SMatthias Ringwald }; 1018d0c20769SMatthias Ringwald indicator->status = hfp_gsm_callsetup_status(); 1019aa4dd815SMatthias Ringwald } 1020aa4dd815SMatthias Ringwald 10210cb5b971SMatthias Ringwald static void hfp_ag_set_callheld_indicator(void){ 1022d210d9c4SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callheld"); 1023d210d9c4SMatthias Ringwald if (!indicator){ 1024d210d9c4SMatthias Ringwald log_error("hfp_ag_set_callheld_state: callheld indicator is missing"); 102545718b6fSMatthias Ringwald return; 1026d210d9c4SMatthias Ringwald }; 1027d210d9c4SMatthias Ringwald indicator->status = hfp_gsm_callheld_status(); 1028d210d9c4SMatthias Ringwald } 1029d210d9c4SMatthias Ringwald 10300cb5b971SMatthias Ringwald static void hfp_ag_set_call_indicator(void){ 1031aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call"); 1032aa4dd815SMatthias Ringwald if (!indicator){ 1033aa4dd815SMatthias Ringwald log_error("hfp_ag_set_call_state: call indicator is missing"); 103445718b6fSMatthias Ringwald return; 1035aa4dd815SMatthias Ringwald }; 1036d210d9c4SMatthias Ringwald indicator->status = hfp_gsm_call_status(); 1037aa4dd815SMatthias Ringwald } 1038aa4dd815SMatthias Ringwald 1039aa4dd815SMatthias Ringwald static void hfp_ag_stop_ringing(void){ 1040665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1041665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 1042665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1043a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 104466c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 1045505f1c30SMatthias Ringwald if ((hfp_connection->call_state != HFP_CALL_RINGING) && 1046505f1c30SMatthias Ringwald (hfp_connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING)) continue; 1047a0ffb263SMatthias Ringwald hfp_ag_hf_stop_ringing(hfp_connection); 1048aa4dd815SMatthias Ringwald } 1049aa4dd815SMatthias Ringwald } 1050aa4dd815SMatthias Ringwald 1051aa4dd815SMatthias Ringwald static hfp_connection_t * hfp_ag_connection_for_call_state(hfp_call_state_t call_state){ 1052665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1053665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 1054665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1055a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 105666c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 1057a0ffb263SMatthias Ringwald if (hfp_connection->call_state == call_state) return hfp_connection; 1058aa4dd815SMatthias Ringwald } 1059aa4dd815SMatthias Ringwald return NULL; 1060aa4dd815SMatthias Ringwald } 1061aa4dd815SMatthias Ringwald 1062a5bdcda8SMatthias Ringwald static void hfp_ag_send_response_and_hold_state(hfp_response_and_hold_state_t state){ 1063665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1064665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 1065665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1066a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 106766c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 1068a0ffb263SMatthias Ringwald hfp_connection->send_response_and_hold_status = state + 1; 1069ce263fc8SMatthias Ringwald } 1070ce263fc8SMatthias Ringwald } 1071ce263fc8SMatthias Ringwald 1072a0ffb263SMatthias Ringwald static int call_setup_state_machine(hfp_connection_t * hfp_connection){ 1073aa4dd815SMatthias Ringwald int indicator_index; 1074a0ffb263SMatthias Ringwald switch (hfp_connection->call_state){ 1075aa4dd815SMatthias Ringwald case HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING: 1076a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 1077a0ffb263SMatthias Ringwald // we got event: audio hfp_connection established 1078a0ffb263SMatthias Ringwald hfp_timeout_start(hfp_connection); 1079a0ffb263SMatthias Ringwald hfp_connection->ag_ring = 1; 1080a0ffb263SMatthias Ringwald hfp_connection->ag_send_clip = hfp_gsm_clip_type() && hfp_connection->clip_enabled; 1081a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_RINGING; 1082ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_START_RINGINIG); 1083aa4dd815SMatthias Ringwald break; 1084aa4dd815SMatthias Ringwald case HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE: 1085a0ffb263SMatthias Ringwald if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 1086a0ffb263SMatthias Ringwald // we got event: audio hfp_connection established 1087a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 1088aa4dd815SMatthias Ringwald break; 1089aa4dd815SMatthias Ringwald case HFP_CALL_W2_SEND_CALL_WAITING: 1090a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_W4_CHLD; 1091a0ffb263SMatthias Ringwald hfp_ag_send_call_waiting_notification(hfp_connection->rfcomm_cid); 1092aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callsetup"); 1093a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1); 1094aa4dd815SMatthias Ringwald break; 1095aa4dd815SMatthias Ringwald default: 1096aa4dd815SMatthias Ringwald break; 1097aa4dd815SMatthias Ringwald } 1098aa4dd815SMatthias Ringwald return 0; 1099aa4dd815SMatthias Ringwald } 110039426febSMatthias Ringwald 110139426febSMatthias Ringwald // functions extracted from hfp_ag_call_sm below 110239426febSMatthias Ringwald static void hfp_ag_handle_reject_incoming_call(void){ 110339426febSMatthias Ringwald hfp_connection_t * hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); 110439426febSMatthias Ringwald if (!hfp_connection){ 110539426febSMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing hfp_connection in initiated state"); 110639426febSMatthias Ringwald return; 110739426febSMatthias Ringwald } 110839426febSMatthias Ringwald 1109f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_OUTGOING_CALL_REJECTED, 0, 0, NULL); 111039426febSMatthias Ringwald hfp_connection->call_state = HFP_CALL_IDLE; 111139426febSMatthias Ringwald hfp_connection->send_error = 1; 111239426febSMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 111339426febSMatthias Ringwald } 111439426febSMatthias Ringwald 1115a0ffb263SMatthias Ringwald // hfp_connection is used to identify originating HF 1116a0ffb263SMatthias Ringwald static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_connection){ 1117aa4dd815SMatthias Ringwald int indicator_index; 1118d210d9c4SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 1119d210d9c4SMatthias Ringwald int callheld_indicator_index = get_ag_indicator_index_for_name("callheld"); 1120d210d9c4SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 112174386ee0SMatthias Ringwald 1122aa4dd815SMatthias Ringwald switch (event){ 1123aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL: 1124d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1125aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1126d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 112712cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: 1128f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_INCOMING_CALL, 0, 0, NULL); 1129d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1130aa4dd815SMatthias Ringwald hfp_ag_trigger_incoming_call(); 113160ebb071SMilanka Ringwald log_info("AG rings"); 1132aa4dd815SMatthias Ringwald break; 1133aa4dd815SMatthias Ringwald default: 11343deb3ec6SMatthias Ringwald break; 11353deb3ec6SMatthias Ringwald } 11363deb3ec6SMatthias Ringwald break; 1137aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1138d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 113912cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: 1140f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_INCOMING_CALL, 0, 0, NULL); 1141d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1142aa4dd815SMatthias Ringwald hfp_ag_trigger_incoming_call(); 114360ebb071SMilanka Ringwald log_info("AG call waiting"); 1144aa4dd815SMatthias Ringwald break; 1145aa4dd815SMatthias Ringwald default: 11463deb3ec6SMatthias Ringwald break; 11473deb3ec6SMatthias Ringwald } 11483deb3ec6SMatthias Ringwald break; 11497bbeb3adSMilanka Ringwald default: 11507bbeb3adSMilanka Ringwald break; 1151aa4dd815SMatthias Ringwald } 1152aa4dd815SMatthias Ringwald break; 1153aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 1154d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1155aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1156d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 115712cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1158f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, 0, 0, NULL); 1159d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1160d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1161aa4dd815SMatthias Ringwald hfp_ag_ag_accept_call(); 116260ebb071SMilanka Ringwald log_info("AG answers call, accept call by GSM"); 1163aa4dd815SMatthias Ringwald break; 1164aa4dd815SMatthias Ringwald default: 11653deb3ec6SMatthias Ringwald break; 11663deb3ec6SMatthias Ringwald } 1167aa4dd815SMatthias Ringwald break; 1168aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1169d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 1170aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 117160ebb071SMilanka Ringwald log_info("AG: current call is placed on hold, incoming call gets active"); 1172f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, 0, 0, NULL); 1173d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1174d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1175ce263fc8SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1176ce263fc8SMatthias Ringwald hfp_ag_transfer_callheld_state(); 1177aa4dd815SMatthias Ringwald break; 1178aa4dd815SMatthias Ringwald default: 1179aa4dd815SMatthias Ringwald break; 1180aa4dd815SMatthias Ringwald } 1181aa4dd815SMatthias Ringwald break; 11827bbeb3adSMilanka Ringwald default: 11837bbeb3adSMilanka Ringwald break; 1184aa4dd815SMatthias Ringwald } 1185aa4dd815SMatthias Ringwald break; 1186ce263fc8SMatthias Ringwald 1187ce263fc8SMatthias Ringwald case HFP_AG_HELD_CALL_JOINED_BY_AG: 1188d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1189ce263fc8SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1190d0c20769SMatthias Ringwald switch (hfp_gsm_callheld_status()){ 1191ce263fc8SMatthias Ringwald case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED: 119260ebb071SMilanka Ringwald log_info("AG: joining held call with active call"); 1193f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_HELD_CALL_JOINED_BY_AG, 0, 0, NULL); 1194d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1195ce263fc8SMatthias Ringwald hfp_ag_transfer_callheld_state(); 1196ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CONFERENCE_CALL); 1197ce263fc8SMatthias Ringwald break; 1198ce263fc8SMatthias Ringwald default: 1199ce263fc8SMatthias Ringwald break; 1200ce263fc8SMatthias Ringwald } 1201ce263fc8SMatthias Ringwald break; 1202ce263fc8SMatthias Ringwald default: 1203ce263fc8SMatthias Ringwald break; 1204ce263fc8SMatthias Ringwald } 1205ce263fc8SMatthias Ringwald break; 1206ce263fc8SMatthias Ringwald 1207aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 1208d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1209aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1210d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 121112cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1212f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, 0, 0, NULL); 1213d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1214d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1215a0ffb263SMatthias Ringwald hfp_ag_hf_accept_call(hfp_connection); 12166323f788SMatthias Ringwald hfp_connection->ok_pending = 1; 121760ebb071SMilanka Ringwald log_info("HF answers call, accept call by GSM"); 1218ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_ANSWERED); 1219aa4dd815SMatthias Ringwald break; 1220aa4dd815SMatthias Ringwald default: 1221aa4dd815SMatthias Ringwald break; 1222aa4dd815SMatthias Ringwald } 12233deb3ec6SMatthias Ringwald break; 12243deb3ec6SMatthias Ringwald default: 12253deb3ec6SMatthias Ringwald break; 12263deb3ec6SMatthias Ringwald } 12273deb3ec6SMatthias Ringwald break; 12283deb3ec6SMatthias Ringwald 1229ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: 1230d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1231ce263fc8SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1232d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 123312cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1234f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG, 0, 0, NULL); 1235ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_active = 1; 1236ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD; 1237a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1238ce263fc8SMatthias Ringwald // as with regualr call 1239d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1240d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1241ce263fc8SMatthias Ringwald hfp_ag_ag_accept_call(); 124260ebb071SMilanka Ringwald log_info("AG response and hold - hold by AG"); 1243ce263fc8SMatthias Ringwald break; 1244ce263fc8SMatthias Ringwald default: 1245ce263fc8SMatthias Ringwald break; 1246ce263fc8SMatthias Ringwald } 1247ce263fc8SMatthias Ringwald break; 1248ce263fc8SMatthias Ringwald default: 1249ce263fc8SMatthias Ringwald break; 1250ce263fc8SMatthias Ringwald } 1251ce263fc8SMatthias Ringwald break; 1252ce263fc8SMatthias Ringwald 1253ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: 1254d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1255ce263fc8SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1256d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 125712cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1258f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, 0, 0, NULL); 1259ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_active = 1; 1260ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD; 1261a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1262ce263fc8SMatthias Ringwald // as with regualr call 1263d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1264d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1265a0ffb263SMatthias Ringwald hfp_ag_hf_accept_call(hfp_connection); 126660ebb071SMilanka Ringwald log_info("AG response and hold - hold by HF"); 1267ce263fc8SMatthias Ringwald break; 1268ce263fc8SMatthias Ringwald default: 1269ce263fc8SMatthias Ringwald break; 1270ce263fc8SMatthias Ringwald } 1271ce263fc8SMatthias Ringwald break; 1272ce263fc8SMatthias Ringwald default: 1273ce263fc8SMatthias Ringwald break; 1274ce263fc8SMatthias Ringwald } 1275ce263fc8SMatthias Ringwald break; 1276ce263fc8SMatthias Ringwald 1277ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG: 1278ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: 1279ce263fc8SMatthias Ringwald if (!hfp_ag_response_and_hold_active) break; 1280ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break; 1281f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG, 0, 0, NULL); 1282a5bdcda8SMatthias Ringwald hfp_ag_response_and_hold_active = 0; 1283ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED; 1284a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 128560ebb071SMilanka Ringwald log_info("Held Call accepted and active"); 1286ce263fc8SMatthias Ringwald break; 1287ce263fc8SMatthias Ringwald 1288ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG: 1289ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: 1290ce263fc8SMatthias Ringwald if (!hfp_ag_response_and_hold_active) break; 1291ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break; 1292f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, 0, 0, NULL); 1293a5bdcda8SMatthias Ringwald hfp_ag_response_and_hold_active = 0; 1294ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED; 1295a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1296ce263fc8SMatthias Ringwald // from terminate by ag 1297d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1298ce263fc8SMatthias Ringwald hfp_ag_trigger_terminate_call(); 1299ce263fc8SMatthias Ringwald break; 1300ce263fc8SMatthias Ringwald 1301aa4dd815SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_HF: 1302d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1303aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1304d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 130512cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1306f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_HF, 0, 0, NULL); 1307d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1308aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1309aa4dd815SMatthias Ringwald hfp_ag_trigger_reject_call(); 131060ebb071SMilanka Ringwald log_info("HF Rejected Incoming call, AG terminate call"); 1311aa4dd815SMatthias Ringwald break; 1312aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: 131312cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 1314f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_HF, 0, 0, NULL); 1315d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1316aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 131760ebb071SMilanka Ringwald log_info("AG terminate outgoing call process"); 1318202c8a4cSMatthias Ringwald break; 1319aa4dd815SMatthias Ringwald default: 1320aa4dd815SMatthias Ringwald break; 1321aa4dd815SMatthias Ringwald } 1322aa4dd815SMatthias Ringwald break; 132312cbbeeeSMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1324f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_HF, 0, 0, NULL); 13251ec112deSMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1326d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 13271ec112deSMatthias Ringwald hfp_ag_trigger_terminate_call(); 132860ebb071SMilanka Ringwald log_info("AG terminate call"); 1329aa4dd815SMatthias Ringwald break; 13307bbeb3adSMilanka Ringwald default: 13317bbeb3adSMilanka Ringwald break; 1332aa4dd815SMatthias Ringwald } 13330c1b8529SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_TERMINATED); 1334aa4dd815SMatthias Ringwald break; 13353deb3ec6SMatthias Ringwald 1336aa4dd815SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_AG: 1337d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1338aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1339d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 134012cbbeeeSMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1341f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_AG, 0, 0, NULL); 1342d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1343aa4dd815SMatthias Ringwald hfp_ag_trigger_reject_call(); 134460ebb071SMilanka Ringwald log_info("AG Rejected Incoming call, AG terminate call"); 1345aa4dd815SMatthias Ringwald break; 1346aa4dd815SMatthias Ringwald default: 1347aa4dd815SMatthias Ringwald break; 13483deb3ec6SMatthias Ringwald } 1349202c8a4cSMatthias Ringwald break; 135012cbbeeeSMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1351f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_AG, 0, 0, NULL); 1352d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1353d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1354aa4dd815SMatthias Ringwald hfp_ag_trigger_terminate_call(); 135560ebb071SMilanka Ringwald log_info("AG terminate call"); 1356aa4dd815SMatthias Ringwald break; 1357aa4dd815SMatthias Ringwald default: 13583deb3ec6SMatthias Ringwald break; 13593deb3ec6SMatthias Ringwald } 13603deb3ec6SMatthias Ringwald break; 1361aa4dd815SMatthias Ringwald case HFP_AG_CALL_DROPPED: 1362d0c20769SMatthias Ringwald switch (hfp_gsm_call_status()){ 1363aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1364d0c20769SMatthias Ringwald switch (hfp_gsm_callsetup_status()){ 1365aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1366aa4dd815SMatthias Ringwald hfp_ag_stop_ringing(); 136760ebb071SMilanka Ringwald log_info("Incoming call interrupted"); 1368aa4dd815SMatthias Ringwald break; 1369aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: 1370aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 137160ebb071SMilanka Ringwald log_info("Outgoing call interrupted\n"); 137260ebb071SMilanka Ringwald log_info("AG notify call dropped\n"); 1373aa4dd815SMatthias Ringwald break; 1374aa4dd815SMatthias Ringwald default: 13753deb3ec6SMatthias Ringwald break; 13763deb3ec6SMatthias Ringwald } 1377f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_DROPPED, 0, 0, NULL); 1378d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1379aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 138010c236bfSMatthias Ringwald hfp_ag_trigger_terminate_call(); 1381aa4dd815SMatthias Ringwald break; 1382aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1383ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_active) { 1384f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_DROPPED, 0, 0, NULL); 1385ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED; 1386a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1387ce263fc8SMatthias Ringwald } 1388f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_DROPPED, 0, 0, NULL); 1389d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1390d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1391aa4dd815SMatthias Ringwald hfp_ag_trigger_terminate_call(); 139260ebb071SMilanka Ringwald log_info("AG notify call dropped"); 1393aa4dd815SMatthias Ringwald break; 1394aa4dd815SMatthias Ringwald default: 1395aa4dd815SMatthias Ringwald break; 1396aa4dd815SMatthias Ringwald } 1397aa4dd815SMatthias Ringwald break; 1398aa4dd815SMatthias Ringwald 1399aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_INITIATED: 1400d210d9c4SMatthias Ringwald // directly reject call if number of free slots is exceeded 1401d210d9c4SMatthias Ringwald if (!hfp_gsm_call_possible()){ 1402a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 1403f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 1404d210d9c4SMatthias Ringwald break; 1405d210d9c4SMatthias Ringwald } 1406f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_OUTGOING_CALL_INITIATED, 0, 0, (const char *) &hfp_connection->line_buffer[3]); 14079cae807eSMatthias Ringwald 1408a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_OUTGOING_INITIATED; 140974386ee0SMatthias Ringwald 1410ca59be51SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, (const char *) &hfp_connection->line_buffer[3]); 1411aa4dd815SMatthias Ringwald break; 1412aa4dd815SMatthias Ringwald 14139cae807eSMatthias Ringwald case HFP_AG_OUTGOING_REDIAL_INITIATED:{ 1414d210d9c4SMatthias Ringwald // directly reject call if number of free slots is exceeded 1415d210d9c4SMatthias Ringwald if (!hfp_gsm_call_possible()){ 1416a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 1417f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 1418d210d9c4SMatthias Ringwald break; 1419d210d9c4SMatthias Ringwald } 1420d210d9c4SMatthias Ringwald 1421f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_OUTGOING_REDIAL_INITIATED, 0, 0, NULL); 1422a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_OUTGOING_INITIATED; 142374386ee0SMatthias Ringwald 142460ebb071SMilanka Ringwald log_info("Redial last number"); 14259cae807eSMatthias Ringwald char * last_dialed_number = hfp_gsm_last_dialed_number(); 1426aa4dd815SMatthias Ringwald 14279cae807eSMatthias Ringwald if (strlen(last_dialed_number) > 0){ 142860ebb071SMilanka Ringwald log_info("Last number exists: accept call"); 1429ca59be51SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, last_dialed_number); 14309cae807eSMatthias Ringwald } else { 143160ebb071SMilanka Ringwald log_info("log_infoLast number missing: reject call"); 143239426febSMatthias Ringwald hfp_ag_handle_reject_incoming_call(); 14339cae807eSMatthias Ringwald } 14349cae807eSMatthias Ringwald break; 14359cae807eSMatthias Ringwald } 1436aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_REJECTED: 143739426febSMatthias Ringwald hfp_ag_handle_reject_incoming_call(); 1438aa4dd815SMatthias Ringwald break; 1439aa4dd815SMatthias Ringwald 1440d210d9c4SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ACCEPTED:{ 1441a0ffb263SMatthias Ringwald hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); 1442a0ffb263SMatthias Ringwald if (!hfp_connection){ 1443a0ffb263SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing hfp_connection in initiated state"); 1444aa4dd815SMatthias Ringwald break; 1445aa4dd815SMatthias Ringwald } 1446aa4dd815SMatthias Ringwald 1447a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1448a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_OUTGOING_DIALING; 1449aa4dd815SMatthias Ringwald 1450aa4dd815SMatthias Ringwald // trigger callsetup to be 1451d0c20769SMatthias Ringwald int put_call_on_hold = hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; 1452f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_OUTGOING_CALL_ACCEPTED, 0, 0, NULL); 1453d210d9c4SMatthias Ringwald 1454d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1455aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callsetup"); 1456a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1); 1457aa4dd815SMatthias Ringwald 1458aa4dd815SMatthias Ringwald // put current call on hold if active 1459d210d9c4SMatthias Ringwald if (put_call_on_hold){ 146060ebb071SMilanka Ringwald log_info("AG putting current call on hold for new outgoing calllog_info"); 1461d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1462aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callheld"); 1463485ac19eSMilanka Ringwald hfp_ag_send_transfer_ag_indicators_status_cmd(hfp_connection->rfcomm_cid, &hfp_ag_indicators[indicator_index]); 1464aa4dd815SMatthias Ringwald } 1465aa4dd815SMatthias Ringwald 1466aa4dd815SMatthias Ringwald // start audio if needed 1467d97d752dSMilanka Ringwald hfp_ag_establish_audio_connection(hfp_connection->acl_handle); 1468aa4dd815SMatthias Ringwald break; 1469d210d9c4SMatthias Ringwald } 1470aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_RINGING: 1471a0ffb263SMatthias Ringwald hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); 1472a0ffb263SMatthias Ringwald if (!hfp_connection){ 1473a0ffb263SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing hfp_connection in dialing state"); 1474aa4dd815SMatthias Ringwald break; 1475aa4dd815SMatthias Ringwald } 1476d210d9c4SMatthias Ringwald 1477f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_OUTGOING_CALL_RINGING, 0, 0, NULL); 1478a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_OUTGOING_RINGING; 1479d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1480aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1481aa4dd815SMatthias Ringwald break; 1482aa4dd815SMatthias Ringwald 1483d210d9c4SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ESTABLISHED:{ 1484aa4dd815SMatthias Ringwald // get outgoing call 1485a0ffb263SMatthias Ringwald hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING); 1486a0ffb263SMatthias Ringwald if (!hfp_connection){ 1487a0ffb263SMatthias Ringwald hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); 1488aa4dd815SMatthias Ringwald } 1489a0ffb263SMatthias Ringwald if (!hfp_connection){ 1490a0ffb263SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing hfp_connection"); 1491aa4dd815SMatthias Ringwald break; 1492aa4dd815SMatthias Ringwald } 1493d210d9c4SMatthias Ringwald 1494d0c20769SMatthias Ringwald int CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS = hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS; 1495f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_OUTGOING_CALL_ESTABLISHED, 0, 0, NULL); 1496a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 1497d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1498d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1499aa4dd815SMatthias Ringwald hfp_ag_transfer_call_state(); 1500aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1501d210d9c4SMatthias Ringwald if (CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS){ 1502d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1503aa4dd815SMatthias Ringwald hfp_ag_transfer_callheld_state(); 15043deb3ec6SMatthias Ringwald } 15053deb3ec6SMatthias Ringwald break; 1506d210d9c4SMatthias Ringwald } 1507d210d9c4SMatthias Ringwald 150812cbbeeeSMatthias Ringwald case HFP_AG_CALL_HOLD_USER_BUSY: 1509f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_HOLD_USER_BUSY, 0, 0, NULL); 1510d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1511a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1512a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 151360ebb071SMilanka Ringwald log_info("AG: Call Waiting, User Busy"); 1514d210d9c4SMatthias Ringwald break; 1515d210d9c4SMatthias Ringwald 1516d210d9c4SMatthias Ringwald case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{ 1517d0c20769SMatthias Ringwald int call_setup_in_progress = hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 1518d0c20769SMatthias Ringwald int call_held = hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD; 1519d210d9c4SMatthias Ringwald 1520d210d9c4SMatthias Ringwald // Releases all active calls (if any exist) and accepts the other (held or waiting) call. 1521d0c20769SMatthias Ringwald if (call_held || call_setup_in_progress){ 1522f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection->call_index, 1523f8737b81SMatthias Ringwald 0, NULL); 1524d0c20769SMatthias Ringwald 1525d0c20769SMatthias Ringwald } 1526d0c20769SMatthias Ringwald 1527d210d9c4SMatthias Ringwald if (call_setup_in_progress){ 152860ebb071SMilanka Ringwald log_info("AG: Call Dropped, Accept new call"); 1529d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1530a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1531d210d9c4SMatthias Ringwald } else { 153260ebb071SMilanka Ringwald log_info("AG: Call Dropped, Resume held call"); 1533d210d9c4SMatthias Ringwald } 1534d210d9c4SMatthias Ringwald if (call_held){ 1535d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1536a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1537d210d9c4SMatthias Ringwald } 1538d0c20769SMatthias Ringwald 1539a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 1540d210d9c4SMatthias Ringwald break; 1541d210d9c4SMatthias Ringwald } 1542d0c20769SMatthias Ringwald 1543d210d9c4SMatthias Ringwald case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{ 1544d210d9c4SMatthias Ringwald // Places all active calls (if any exist) on hold and accepts the other (held or waiting) call. 1545d210d9c4SMatthias Ringwald // only update if callsetup changed 1546d0c20769SMatthias Ringwald int call_setup_in_progress = hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 1547f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection->call_index, 0, 1548f8737b81SMatthias Ringwald NULL); 1549d0c20769SMatthias Ringwald 1550d210d9c4SMatthias Ringwald if (call_setup_in_progress){ 155160ebb071SMilanka Ringwald log_info("AG: Call on Hold, Accept new call"); 1552d0c20769SMatthias Ringwald hfp_ag_set_callsetup_indicator(); 1553a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1554d210d9c4SMatthias Ringwald } else { 155560ebb071SMilanka Ringwald log_info("AG: Swap calls"); 1556d210d9c4SMatthias Ringwald } 1557d0c20769SMatthias Ringwald 1558d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1559d0c20769SMatthias Ringwald // hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1560a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1561a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 1562d210d9c4SMatthias Ringwald break; 1563d210d9c4SMatthias Ringwald } 1564d0c20769SMatthias Ringwald 1565d210d9c4SMatthias Ringwald case HFP_AG_CALL_HOLD_ADD_HELD_CALL: 1566d210d9c4SMatthias Ringwald // Adds a held call to the conversation. 1567d0c20769SMatthias Ringwald if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 156860ebb071SMilanka Ringwald log_info("AG: Join 3-way-call"); 1569f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_HOLD_ADD_HELD_CALL, 0, 0, NULL); 1570d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1571a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1572ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CONFERENCE_CALL); 1573d210d9c4SMatthias Ringwald } 1574a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_ACTIVE; 1575d210d9c4SMatthias Ringwald break; 1576d210d9c4SMatthias Ringwald case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS: 1577d210d9c4SMatthias Ringwald // Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer) 1578f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS, 0, 0, NULL); 157960ebb071SMilanka Ringwald log_info("AG: Transfer call -> Connect two calls and disconnect"); 1580d210d9c4SMatthias Ringwald hfp_ag_set_call_indicator(); 1581d0c20769SMatthias Ringwald hfp_ag_set_callheld_indicator(); 1582a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 1583a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1584a0ffb263SMatthias Ringwald hfp_connection->call_state = HFP_CALL_IDLE; 1585d210d9c4SMatthias Ringwald break; 1586ce263fc8SMatthias Ringwald 15873deb3ec6SMatthias Ringwald default: 15883deb3ec6SMatthias Ringwald break; 15893deb3ec6SMatthias Ringwald } 1590d210d9c4SMatthias Ringwald 1591d0c20769SMatthias Ringwald 15923deb3ec6SMatthias Ringwald } 15933deb3ec6SMatthias Ringwald 15949cae807eSMatthias Ringwald 1595a0ffb263SMatthias Ringwald static void hfp_ag_send_call_status(hfp_connection_t * hfp_connection, int call_index){ 15969cae807eSMatthias Ringwald hfp_gsm_call_t * active_call = hfp_gsm_call(call_index); 15979cae807eSMatthias Ringwald if (!active_call) return; 15989cae807eSMatthias Ringwald 15999cae807eSMatthias Ringwald int idx = active_call->index; 16009cae807eSMatthias Ringwald hfp_enhanced_call_dir_t dir = active_call->direction; 16019cae807eSMatthias Ringwald hfp_enhanced_call_status_t status = active_call->enhanced_status; 16029cae807eSMatthias Ringwald hfp_enhanced_call_mode_t mode = active_call->mode; 16039cae807eSMatthias Ringwald hfp_enhanced_call_mpty_t mpty = active_call->mpty; 16049cae807eSMatthias Ringwald uint8_t type = active_call->clip_type; 16059cae807eSMatthias Ringwald char * number = active_call->clip_number; 16069cae807eSMatthias Ringwald 16079cae807eSMatthias Ringwald char buffer[100]; 16089cae807eSMatthias Ringwald // TODO: check length of a buffer, to fit the MTU 16099cae807eSMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s: %d,%d,%d,%d,%d", HFP_LIST_CURRENT_CALLS, idx, dir, status, mode, mpty); 16109cae807eSMatthias Ringwald if (number){ 16111cc1d9e9SMilanka Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset-3, ", \"%s\",%u", number, type); 16129cae807eSMatthias Ringwald } 16139cae807eSMatthias Ringwald snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 161460ebb071SMilanka Ringwald log_info("hfp_ag_send_current_call_status 000 index %d, dir %d, status %d, mode %d, mpty %d, type %d, number %s", idx, dir, status, 16159cae807eSMatthias Ringwald mode, mpty, type, number); 1616a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer); 16179cae807eSMatthias Ringwald } 16189cae807eSMatthias Ringwald 1619473ac565SMatthias Ringwald 1620febc14f5SMatthias Ringwald // sends pending command, returns if command was sent 1621febc14f5SMatthias Ringwald static int hfp_ag_send_commands(hfp_connection_t *hfp_connection){ 162222387625SMatthias Ringwald 1623a0ffb263SMatthias Ringwald if (hfp_connection->send_status_of_current_calls){ 1624a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 0; 1625a0ffb263SMatthias Ringwald if (hfp_connection->next_call_index < hfp_gsm_get_number_of_calls()){ 1626a0ffb263SMatthias Ringwald hfp_connection->next_call_index++; 1627a0ffb263SMatthias Ringwald hfp_ag_send_call_status(hfp_connection, hfp_connection->next_call_index); 1628febc14f5SMatthias Ringwald return 1; 16299cae807eSMatthias Ringwald } else { 1630febc14f5SMatthias Ringwald // TODO: this code should be removed. check a) before setting send_status_of_current_calls, or b) right before hfp_ag_send_call_status above 1631a0ffb263SMatthias Ringwald hfp_connection->next_call_index = 0; 1632a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1633a0ffb263SMatthias Ringwald hfp_connection->send_status_of_current_calls = 0; 16349cae807eSMatthias Ringwald } 1635ce263fc8SMatthias Ringwald } 1636ce263fc8SMatthias Ringwald 1637a0ffb263SMatthias Ringwald if (hfp_connection->ag_notify_incoming_call_waiting){ 1638a0ffb263SMatthias Ringwald hfp_connection->ag_notify_incoming_call_waiting = 0; 1639a0ffb263SMatthias Ringwald hfp_ag_send_call_waiting_notification(hfp_connection->rfcomm_cid); 1640febc14f5SMatthias Ringwald return 1; 1641aa4dd815SMatthias Ringwald } 1642aa4dd815SMatthias Ringwald 1643a0ffb263SMatthias Ringwald if (hfp_connection->command == HFP_CMD_UNKNOWN){ 1644a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 0; 1645a0ffb263SMatthias Ringwald hfp_connection->send_error = 0; 1646a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1647485ac19eSMilanka Ringwald hfp_ag_send_error(hfp_connection->rfcomm_cid); 1648febc14f5SMatthias Ringwald return 1; 1649a0ffb263SMatthias Ringwald } 1650a0ffb263SMatthias Ringwald 1651a0ffb263SMatthias Ringwald if (hfp_connection->send_error){ 1652a0ffb263SMatthias Ringwald hfp_connection->send_error = 0; 1653a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1654485ac19eSMilanka Ringwald hfp_ag_send_error(hfp_connection->rfcomm_cid); 1655febc14f5SMatthias Ringwald return 1; 1656aa4dd815SMatthias Ringwald } 1657aa4dd815SMatthias Ringwald 1658ce263fc8SMatthias Ringwald // note: before update AG indicators and ok_pending 1659a0ffb263SMatthias Ringwald if (hfp_connection->send_response_and_hold_status){ 1660a0ffb263SMatthias Ringwald int status = hfp_connection->send_response_and_hold_status - 1; 1661a0ffb263SMatthias Ringwald hfp_connection->send_response_and_hold_status = 0; 1662485ac19eSMilanka Ringwald hfp_ag_send_set_response_and_hold(hfp_connection->rfcomm_cid, status); 1663febc14f5SMatthias Ringwald return 1; 1664ce263fc8SMatthias Ringwald } 1665ce263fc8SMatthias Ringwald 1666a0ffb263SMatthias Ringwald if (hfp_connection->ok_pending){ 1667a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 0; 1668a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1669485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 1670febc14f5SMatthias Ringwald return 1; 1671ce263fc8SMatthias Ringwald } 1672ce263fc8SMatthias Ringwald 1673aa4dd815SMatthias Ringwald // update AG indicators 1674a0ffb263SMatthias Ringwald if (hfp_connection->ag_indicators_status_update_bitmap){ 1675aa4dd815SMatthias Ringwald int i; 1676a0ffb263SMatthias Ringwald for (i=0;i<hfp_connection->ag_indicators_nr;i++){ 1677a0ffb263SMatthias Ringwald if (get_bit(hfp_connection->ag_indicators_status_update_bitmap, i)){ 1678a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, i, 0); 1679a0ffb263SMatthias Ringwald if (!hfp_connection->enable_status_update_for_ag_indicators) { 1680ce263fc8SMatthias Ringwald log_info("+CMER:3,0,0,0 - not sending update for '%s'", hfp_ag_indicators[i].name); 1681ce263fc8SMatthias Ringwald break; 1682ce263fc8SMatthias Ringwald } 1683485ac19eSMilanka Ringwald hfp_ag_send_transfer_ag_indicators_status_cmd(hfp_connection->rfcomm_cid, &hfp_ag_indicators[i]); 1684febc14f5SMatthias Ringwald return 1; 1685aa4dd815SMatthias Ringwald } 1686aa4dd815SMatthias Ringwald } 1687aa4dd815SMatthias Ringwald } 1688aa4dd815SMatthias Ringwald 1689a0ffb263SMatthias Ringwald if (hfp_connection->ag_ring){ 1690a0ffb263SMatthias Ringwald hfp_connection->ag_ring = 0; 1691a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1692485ac19eSMilanka Ringwald hfp_ag_send_ring(hfp_connection->rfcomm_cid); 1693febc14f5SMatthias Ringwald return 1; 1694aa4dd815SMatthias Ringwald } 1695aa4dd815SMatthias Ringwald 1696a0ffb263SMatthias Ringwald if (hfp_connection->ag_send_clip){ 1697a0ffb263SMatthias Ringwald hfp_connection->ag_send_clip = 0; 1698a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1699a0ffb263SMatthias Ringwald hfp_ag_send_clip(hfp_connection->rfcomm_cid); 1700febc14f5SMatthias Ringwald return 1; 1701aa4dd815SMatthias Ringwald } 1702aa4dd815SMatthias Ringwald 1703a0ffb263SMatthias Ringwald if (hfp_connection->send_phone_number_for_voice_tag){ 1704a0ffb263SMatthias Ringwald hfp_connection->send_phone_number_for_voice_tag = 0; 1705a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1706a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1707a0ffb263SMatthias Ringwald hfp_ag_send_phone_number_for_voice_tag_cmd(hfp_connection->rfcomm_cid); 1708febc14f5SMatthias Ringwald return 1; 1709aa4dd815SMatthias Ringwald } 1710aa4dd815SMatthias Ringwald 1711a0ffb263SMatthias Ringwald if (hfp_connection->send_subscriber_number){ 1712a0ffb263SMatthias Ringwald if (hfp_connection->next_subscriber_number_to_send < subscriber_numbers_count){ 1713a0ffb263SMatthias Ringwald hfp_phone_number_t phone = subscriber_numbers[hfp_connection->next_subscriber_number_to_send++]; 1714a0ffb263SMatthias Ringwald hfp_send_subscriber_number_cmd(hfp_connection->rfcomm_cid, phone.type, phone.number); 1715ce263fc8SMatthias Ringwald } else { 1716a0ffb263SMatthias Ringwald hfp_connection->send_subscriber_number = 0; 1717a0ffb263SMatthias Ringwald hfp_connection->next_subscriber_number_to_send = 0; 1718485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 1719ce263fc8SMatthias Ringwald } 1720a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1721febc14f5SMatthias Ringwald return 1; 1722ce263fc8SMatthias Ringwald } 1723ce263fc8SMatthias Ringwald 1724a0ffb263SMatthias Ringwald if (hfp_connection->send_microphone_gain){ 1725a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 0; 1726a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1727485ac19eSMilanka Ringwald hfp_ag_send_set_microphone_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->microphone_gain); 1728febc14f5SMatthias Ringwald return 1; 1729aa4dd815SMatthias Ringwald } 1730aa4dd815SMatthias Ringwald 1731a0ffb263SMatthias Ringwald if (hfp_connection->send_speaker_gain){ 1732a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 0; 1733a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1734485ac19eSMilanka Ringwald hfp_ag_send_set_speaker_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->speaker_gain); 1735febc14f5SMatthias Ringwald return 1; 17363deb3ec6SMatthias Ringwald } 17373deb3ec6SMatthias Ringwald 1738a0ffb263SMatthias Ringwald if (hfp_connection->send_ag_status_indicators){ 1739a0ffb263SMatthias Ringwald hfp_connection->send_ag_status_indicators = 0; 1740485ac19eSMilanka Ringwald hfp_ag_send_retrieve_indicators_status_cmd(hfp_connection->rfcomm_cid); 1741febc14f5SMatthias Ringwald return 1; 1742febc14f5SMatthias Ringwald } 1743febc14f5SMatthias Ringwald 1744febc14f5SMatthias Ringwald return 0; 1745febc14f5SMatthias Ringwald } 1746febc14f5SMatthias Ringwald 1747febc14f5SMatthias Ringwald static void hfp_ag_run_for_context(hfp_connection_t *hfp_connection){ 1748febc14f5SMatthias Ringwald 174976cc1527SMatthias Ringwald btstack_assert(hfp_connection != NULL); 175076cc1527SMatthias Ringwald btstack_assert(hfp_connection->local_role == HFP_ROLE_AG); 1751febc14f5SMatthias Ringwald 175276cc1527SMatthias Ringwald // during SDP query, RFCOMM CID is not set 175376cc1527SMatthias Ringwald if (hfp_connection->rfcomm_cid == 0) return; 1754ce263fc8SMatthias Ringwald 17553721a235SMatthias Ringwald // assert command could be sent 17563721a235SMatthias Ringwald if (hci_can_send_command_packet_now() == 0) return; 17573721a235SMatthias Ringwald 17583721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP 17593721a235SMatthias Ringwald // WBS Disassociate 17603721a235SMatthias Ringwald if (hfp_connection->cc256x_send_wbs_disassociate){ 17613721a235SMatthias Ringwald hfp_connection->cc256x_send_wbs_disassociate = false; 17623721a235SMatthias Ringwald hci_send_cmd(&hci_ti_wbs_disassociate); 17633721a235SMatthias Ringwald return; 17643721a235SMatthias Ringwald } 17653721a235SMatthias Ringwald // Write Codec Config 17663721a235SMatthias Ringwald if (hfp_connection->cc256x_send_write_codec_config){ 17673721a235SMatthias Ringwald hfp_connection->cc256x_send_write_codec_config = false; 17683721a235SMatthias Ringwald hfp_cc256x_write_codec_config(hfp_connection); 17693721a235SMatthias Ringwald return; 17703721a235SMatthias Ringwald } 17713721a235SMatthias Ringwald // WBS Associate 17723721a235SMatthias Ringwald if (hfp_connection->cc256x_send_wbs_associate){ 17733721a235SMatthias Ringwald hfp_connection->cc256x_send_wbs_associate = false; 17743721a235SMatthias Ringwald hci_send_cmd(&hci_ti_wbs_associate, hfp_connection->acl_handle); 17753721a235SMatthias Ringwald return; 17763721a235SMatthias Ringwald } 17773721a235SMatthias Ringwald #endif 1778689d4323SMatthias Ringwald #ifdef ENABLE_BCM_PCM_WBS 1779689d4323SMatthias Ringwald // Enable WBS 1780689d4323SMatthias Ringwald if (hfp_connection->bcm_send_enable_wbs){ 1781689d4323SMatthias Ringwald hfp_connection->bcm_send_enable_wbs = false; 1782689d4323SMatthias Ringwald hci_send_cmd(&hci_bcm_enable_wbs, 1, 2); 1783689d4323SMatthias Ringwald return; 1784689d4323SMatthias Ringwald } 1785689d4323SMatthias Ringwald // Write I2S/PCM params 1786689d4323SMatthias Ringwald if (hfp_connection->bcm_send_write_i2spcm_interface_param){ 1787689d4323SMatthias Ringwald hfp_connection->bcm_send_write_i2spcm_interface_param = false; 1788689d4323SMatthias Ringwald hfp_bcm_write_i2spcm_interface_param(hfp_connection); 1789689d4323SMatthias Ringwald return; 1790689d4323SMatthias Ringwald } 1791689d4323SMatthias Ringwald // Disable WBS 1792689d4323SMatthias Ringwald if (hfp_connection->bcm_send_disable_wbs){ 1793689d4323SMatthias Ringwald hfp_connection->bcm_send_disable_wbs = false; 1794689d4323SMatthias Ringwald hci_send_cmd(&hci_bcm_enable_wbs, 0, 2); 1795689d4323SMatthias Ringwald return; 1796689d4323SMatthias Ringwald } 1797689d4323SMatthias Ringwald #endif 179848e6eeeeSMatthias Ringwald #if defined (ENABLE_CC256X_ASSISTED_HFP) || defined (ENABLE_BCM_PCM_WBS) 179948e6eeeeSMatthias Ringwald if (hfp_connection->state == HFP_W4_WBS_SHUTDOWN){ 180048e6eeeeSMatthias Ringwald hfp_finalize_connection_context(hfp_connection); 180148e6eeeeSMatthias Ringwald return; 180248e6eeeeSMatthias Ringwald } 180348e6eeeeSMatthias Ringwald #endif 18043721a235SMatthias Ringwald 1805febc14f5SMatthias Ringwald if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) { 1806febc14f5SMatthias Ringwald log_info("hfp_ag_run_for_context: request can send for 0x%02x", hfp_connection->rfcomm_cid); 1807febc14f5SMatthias Ringwald rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); 1808febc14f5SMatthias Ringwald return; 1809febc14f5SMatthias Ringwald } 1810febc14f5SMatthias Ringwald 1811febc14f5SMatthias Ringwald int cmd_sent = hfp_ag_send_commands(hfp_connection); 1812febc14f5SMatthias Ringwald 1813febc14f5SMatthias Ringwald if (!cmd_sent){ 1814febc14f5SMatthias Ringwald cmd_sent = hfp_ag_run_for_context_service_level_connection(hfp_connection); 1815febc14f5SMatthias Ringwald } 1816febc14f5SMatthias Ringwald 1817c04cf7ffSMilanka Ringwald if (!cmd_sent){ 1818c04cf7ffSMilanka Ringwald cmd_sent = hfp_ag_run_for_context_service_level_connection_queries(hfp_connection); 18193deb3ec6SMatthias Ringwald } 18203deb3ec6SMatthias Ringwald 1821c04cf7ffSMilanka Ringwald if (!cmd_sent){ 1822c04cf7ffSMilanka Ringwald cmd_sent = call_setup_state_machine(hfp_connection); 1823aa4dd815SMatthias Ringwald } 1824aa4dd815SMatthias Ringwald 1825b956fff3SMatthias Ringwald // trigger codec exchange (must be before hfp_ag_run_for_audio_connection) 1826d0a0eceeSMatthias Ringwald if (!cmd_sent && (hfp_connection->command == HFP_CMD_NONE) && hfp_connection->trigger_codec_exchange){ 1827d0a0eceeSMatthias Ringwald log_info("trigger codec, command %u, codec state %u", hfp_connection->command, hfp_connection->codecs_state); 1828d0a0eceeSMatthias Ringwald switch (hfp_connection->codecs_state){ 1829d0a0eceeSMatthias Ringwald case HFP_CODECS_IDLE: 1830d0a0eceeSMatthias Ringwald case HFP_CODECS_RECEIVED_LIST: 1831d0a0eceeSMatthias Ringwald case HFP_CODECS_AG_RESEND_COMMON_CODEC: 1832d0a0eceeSMatthias Ringwald case HFP_CODECS_ERROR: 1833d0a0eceeSMatthias Ringwald hfp_connection->trigger_codec_exchange = 0; 1834d0a0eceeSMatthias Ringwald hfp_connection->command = HFP_CMD_AG_SEND_COMMON_CODEC; 18353deb3ec6SMatthias Ringwald break; 18363deb3ec6SMatthias Ringwald default: 18373deb3ec6SMatthias Ringwald break; 18383deb3ec6SMatthias Ringwald } 18393deb3ec6SMatthias Ringwald } 1840c04cf7ffSMilanka Ringwald 1841b956fff3SMatthias Ringwald if (!cmd_sent){ 1842b956fff3SMatthias Ringwald cmd_sent = hfp_ag_run_for_audio_connection(hfp_connection); 1843b956fff3SMatthias Ringwald } 1844b956fff3SMatthias Ringwald 1845b956fff3SMatthias Ringwald 1846d0a0eceeSMatthias Ringwald // disconnect 1847d0a0eceeSMatthias Ringwald if (!cmd_sent && (hfp_connection->command == HFP_CMD_NONE) && (hfp_connection->state == HFP_W2_DISCONNECT_RFCOMM)){ 1848d0a0eceeSMatthias Ringwald hfp_connection->state = HFP_W4_RFCOMM_DISCONNECTED; 1849d0a0eceeSMatthias Ringwald rfcomm_disconnect(hfp_connection->rfcomm_cid); 1850d0a0eceeSMatthias Ringwald } 1851d0a0eceeSMatthias Ringwald 1852c04cf7ffSMilanka Ringwald if (cmd_sent){ 1853a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1854473ac565SMatthias Ringwald rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); 1855473ac565SMatthias Ringwald } 18563deb3ec6SMatthias Ringwald } 1857d68dcce1SMatthias Ringwald 1858ce263fc8SMatthias Ringwald static hfp_generic_status_indicator_t *get_hf_indicator_by_number(int number){ 1859ce263fc8SMatthias Ringwald int i; 1860a0ffb263SMatthias Ringwald for (i=0;i< hfp_generic_status_indicators_nr;i++){ 1861a0ffb263SMatthias Ringwald hfp_generic_status_indicator_t * indicator = &hfp_generic_status_indicators[i]; 1862ce263fc8SMatthias Ringwald if (indicator->uuid == number){ 1863ce263fc8SMatthias Ringwald return indicator; 1864ce263fc8SMatthias Ringwald } 1865ce263fc8SMatthias Ringwald } 1866ce263fc8SMatthias Ringwald return NULL; 1867ce263fc8SMatthias Ringwald } 18683deb3ec6SMatthias Ringwald 1869e0d09929SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){ 1870c1ab6cc1SMatthias Ringwald return (byte == '\n') || (byte == '\r'); 1871e0d09929SMatthias Ringwald } 1872e0d09929SMatthias Ringwald 1873e9c22d4eSMatthias Ringwald static void hfp_ag_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 18748a46ec40SMatthias Ringwald UNUSED(packet_type); // ok: only called with RFCOMM_DATA_PACKET 18758a46ec40SMatthias Ringwald 18768a46ec40SMatthias Ringwald // assertion: size >= 1 as rfcomm.c does not deliver empty packets 18778a46ec40SMatthias Ringwald if (size < 1) return; 18789ec2630cSMatthias Ringwald 1879a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_connection_context_for_rfcomm_cid(channel); 1880a0ffb263SMatthias Ringwald if (!hfp_connection) return; 18811e35c04dSMatthias Ringwald 1882186dd3d2SMatthias Ringwald hfp_log_rfcomm_message("HFP_AG_RX", packet, size); 1883e43d1938SMatthias Ringwald #ifdef ENABLE_HFP_AT_MESSAGES 1884e43d1938SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_RECEIVED, (char *) packet); 1885e43d1938SMatthias Ringwald #endif 18861e35c04dSMatthias Ringwald 18878a46ec40SMatthias Ringwald // process messages byte-wise 18883deb3ec6SMatthias Ringwald int pos; 18893deb3ec6SMatthias Ringwald for (pos = 0; pos < size ; pos++){ 1890a0ffb263SMatthias Ringwald hfp_parse(hfp_connection, packet[pos], 0); 1891186dd3d2SMatthias Ringwald 1892e0d09929SMatthias Ringwald // parse until end of line 1893e0d09929SMatthias Ringwald if (!hfp_parser_is_end_of_line(packet[pos])) continue; 1894e0d09929SMatthias Ringwald 1895186dd3d2SMatthias Ringwald hfp_generic_status_indicator_t * indicator; 1896a0ffb263SMatthias Ringwald switch(hfp_connection->command){ 1897ce263fc8SMatthias Ringwald case HFP_CMD_RESPONSE_AND_HOLD_QUERY: 1898ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_active){ 1899a0ffb263SMatthias Ringwald hfp_connection->send_response_and_hold_status = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD + 1; 1900ce263fc8SMatthias Ringwald } 1901a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1902ce263fc8SMatthias Ringwald break; 1903ce263fc8SMatthias Ringwald case HFP_CMD_RESPONSE_AND_HOLD_COMMAND: 19040222a807SMatthias Ringwald switch(hfp_connection->ag_response_and_hold_action){ 1905ce263fc8SMatthias Ringwald case HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD: 1906a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, hfp_connection); 1907ce263fc8SMatthias Ringwald break; 1908ce263fc8SMatthias Ringwald case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED: 1909a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF, hfp_connection); 1910ce263fc8SMatthias Ringwald break; 1911ce263fc8SMatthias Ringwald case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED: 1912a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF, hfp_connection); 1913ce263fc8SMatthias Ringwald break; 1914ce263fc8SMatthias Ringwald default: 1915ce263fc8SMatthias Ringwald break; 1916ce263fc8SMatthias Ringwald } 1917a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1918ce263fc8SMatthias Ringwald break; 1919ce263fc8SMatthias Ringwald case HFP_CMD_HF_INDICATOR_STATUS: 1920a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1921ce263fc8SMatthias Ringwald // find indicator by assigned number 1922a0ffb263SMatthias Ringwald indicator = get_hf_indicator_by_number(hfp_connection->parser_indicator_index); 1923ce263fc8SMatthias Ringwald if (!indicator){ 1924a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 1925ce263fc8SMatthias Ringwald break; 1926ce263fc8SMatthias Ringwald } 1927ce263fc8SMatthias Ringwald switch (indicator->uuid){ 1928ce263fc8SMatthias Ringwald case 1: // enhanced security 19290222a807SMatthias Ringwald if (hfp_connection->parser_indicator_value > 1) { 1930a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 1931ce263fc8SMatthias Ringwald return; 1932ce263fc8SMatthias Ringwald } 1933e883851fSMatthias Ringwald log_info("HF Indicator 'enhanced security' set to %u", (unsigned int) hfp_connection->parser_indicator_value); 1934ce263fc8SMatthias Ringwald break; 1935ce263fc8SMatthias Ringwald case 2: // battery level 19360222a807SMatthias Ringwald if (hfp_connection->parser_indicator_value > 100){ 1937a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 1938ce263fc8SMatthias Ringwald return; 1939ce263fc8SMatthias Ringwald } 1940e883851fSMatthias Ringwald log_info("HF Indicator 'battery' set to %u", (unsigned int) hfp_connection->parser_indicator_value); 1941ce263fc8SMatthias Ringwald break; 1942ce263fc8SMatthias Ringwald default: 1943e883851fSMatthias Ringwald log_info("HF Indicator unknown set to %u", (unsigned int) hfp_connection->parser_indicator_value); 1944ce263fc8SMatthias Ringwald break; 1945ce263fc8SMatthias Ringwald } 1946a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1947ce263fc8SMatthias Ringwald break; 1948ce263fc8SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: 1949ce263fc8SMatthias Ringwald // expected by SLC state machine 1950a0ffb263SMatthias Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break; 1951a0ffb263SMatthias Ringwald hfp_connection->send_ag_indicators_segment = 0; 1952a0ffb263SMatthias Ringwald hfp_connection->send_ag_status_indicators = 1; 1953ce263fc8SMatthias Ringwald break; 1954ce263fc8SMatthias Ringwald case HFP_CMD_LIST_CURRENT_CALLS: 1955a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1956a0ffb263SMatthias Ringwald hfp_connection->next_call_index = 0; 1957a0ffb263SMatthias Ringwald hfp_connection->send_status_of_current_calls = 1; 1958ce263fc8SMatthias Ringwald break; 1959ce263fc8SMatthias Ringwald case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION: 1960ce263fc8SMatthias Ringwald if (subscriber_numbers_count == 0){ 1961485ac19eSMilanka Ringwald hfp_ag_send_ok(hfp_connection->rfcomm_cid); 1962ce263fc8SMatthias Ringwald break; 1963ce263fc8SMatthias Ringwald } 1964a0ffb263SMatthias Ringwald hfp_connection->next_subscriber_number_to_send = 0; 1965a0ffb263SMatthias Ringwald hfp_connection->send_subscriber_number = 1; 1966ce263fc8SMatthias Ringwald break; 1967c1797c7dSMatthias Ringwald case HFP_CMD_TRANSMIT_DTMF_CODES: 19680222a807SMatthias Ringwald { 1969a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 19700222a807SMatthias Ringwald char buffer[2]; 19710222a807SMatthias Ringwald buffer[0] = (char) hfp_connection->ag_dtmf_code; 19720222a807SMatthias Ringwald buffer[1] = 0; 19730222a807SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_TRANSMIT_DTMF_CODES, buffer); 1974c1797c7dSMatthias Ringwald break; 19750222a807SMatthias Ringwald } 1976aa4dd815SMatthias Ringwald case HFP_CMD_HF_REQUEST_PHONE_NUMBER: 1977a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1978ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG); 1979aa4dd815SMatthias Ringwald break; 1980aa4dd815SMatthias Ringwald case HFP_CMD_TURN_OFF_EC_AND_NR: 1981a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1982aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION)){ 1983a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1984a0ffb263SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION, hfp_connection->ag_echo_and_noise_reduction); 198560ebb071SMilanka Ringwald log_info("AG: EC/NR = %u", hfp_connection->ag_echo_and_noise_reduction); 1986aa4dd815SMatthias Ringwald } else { 1987a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 1988aa4dd815SMatthias Ringwald } 1989aa4dd815SMatthias Ringwald break; 1990aa4dd815SMatthias Ringwald case HFP_CMD_CALL_ANSWERED: 1991a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 199260ebb071SMilanka Ringwald log_info("HFP: ATA"); 1993a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, hfp_connection); 1994aa4dd815SMatthias Ringwald break; 1995aa4dd815SMatthias Ringwald case HFP_CMD_HANG_UP_CALL: 1996a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1997a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1998a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_HF, hfp_connection); 1999aa4dd815SMatthias Ringwald break; 2000aa4dd815SMatthias Ringwald case HFP_CMD_CALL_HOLD: { 2001a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2002a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 2003d0c20769SMatthias Ringwald 20040222a807SMatthias Ringwald switch (hfp_connection->ag_call_hold_action){ 20050222a807SMatthias Ringwald case 0: 2006d0c20769SMatthias Ringwald // Releases all held calls or sets User Determined User Busy (UDUB) for a waiting call. 2007a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_HOLD_USER_BUSY, hfp_connection); 2008aa4dd815SMatthias Ringwald break; 20090222a807SMatthias Ringwald case 1: 2010d0c20769SMatthias Ringwald // Releases all active calls (if any exist) and accepts the other (held or waiting) call. 2011d0c20769SMatthias Ringwald // Where both a held and a waiting call exist, the above procedures shall apply to the 2012d0c20769SMatthias Ringwald // waiting call (i.e., not to the held call) in conflicting situation. 2013a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection); 2014aa4dd815SMatthias Ringwald break; 20150222a807SMatthias Ringwald case 2: 2016d0c20769SMatthias Ringwald // Places all active calls (if any exist) on hold and accepts the other (held or waiting) call. 2017d0c20769SMatthias Ringwald // Where both a held and a waiting call exist, the above procedures shall apply to the 2018d0c20769SMatthias Ringwald // waiting call (i.e., not to the held call) in conflicting situation. 2019a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection); 2020aa4dd815SMatthias Ringwald break; 20210222a807SMatthias Ringwald case 3: 2022d0c20769SMatthias Ringwald // Adds a held call to the conversation. 2023a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_HOLD_ADD_HELD_CALL, hfp_connection); 2024aa4dd815SMatthias Ringwald break; 20250222a807SMatthias Ringwald case 4: 2026d0c20769SMatthias Ringwald // Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer). 2027a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS, hfp_connection); 2028aa4dd815SMatthias Ringwald break; 2029aa4dd815SMatthias Ringwald default: 2030aa4dd815SMatthias Ringwald break; 2031aa4dd815SMatthias Ringwald } 20320222a807SMatthias Ringwald hfp_connection->call_index = 0; 203335e92150SMatthias Ringwald break; 2034aa4dd815SMatthias Ringwald } 2035aa4dd815SMatthias Ringwald case HFP_CMD_CALL_PHONE_NUMBER: 2036a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2037a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_INITIATED, hfp_connection); 2038aa4dd815SMatthias Ringwald break; 2039aa4dd815SMatthias Ringwald case HFP_CMD_REDIAL_LAST_NUMBER: 2040a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2041a0ffb263SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_REDIAL_INITIATED, hfp_connection); 2042aa4dd815SMatthias Ringwald break; 2043aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_CLIP: 2044a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2045a0ffb263SMatthias Ringwald log_info("hfp: clip set, now: %u", hfp_connection->clip_enabled); 2046a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 2047aa4dd815SMatthias Ringwald break; 2048aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION: 2049a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2050a0ffb263SMatthias Ringwald log_info("hfp: call waiting notification set, now: %u", hfp_connection->call_waiting_notification_enabled); 2051a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 2052aa4dd815SMatthias Ringwald break; 2053aa4dd815SMatthias Ringwald case HFP_CMD_SET_SPEAKER_GAIN: 2054a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2055a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 205660ebb071SMilanka Ringwald log_info("HF speaker gain = %u", hfp_connection->speaker_gain); 20573db60f78SBjoern Hartmann hfp_emit_event(hfp_connection, HFP_SUBEVENT_SPEAKER_VOLUME, hfp_connection->speaker_gain); 2058aa4dd815SMatthias Ringwald break; 2059aa4dd815SMatthias Ringwald case HFP_CMD_SET_MICROPHONE_GAIN: 2060a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 2061a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 206260ebb071SMilanka Ringwald log_info("HF microphone gain = %u", hfp_connection->microphone_gain); 20632abbd98dSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_MICROPHONE_VOLUME, hfp_connection->microphone_gain); 2064aa4dd815SMatthias Ringwald break; 2065aa4dd815SMatthias Ringwald default: 2066aa4dd815SMatthias Ringwald break; 20673deb3ec6SMatthias Ringwald } 20683deb3ec6SMatthias Ringwald } 20690cef86faSMatthias Ringwald } 20703deb3ec6SMatthias Ringwald 20711c6a0fc0SMatthias Ringwald static void hfp_ag_run(void){ 2072d63c37a1SMatthias Ringwald btstack_linked_list_iterator_t it; 2073d63c37a1SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 2074d63c37a1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2075d63c37a1SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 207622387625SMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 2077f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 20783deb3ec6SMatthias Ringwald } 20793deb3ec6SMatthias Ringwald } 20803deb3ec6SMatthias Ringwald 20811c6a0fc0SMatthias Ringwald static void hfp_ag_rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 20823deb3ec6SMatthias Ringwald switch (packet_type){ 20833deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET: 2084e9c22d4eSMatthias Ringwald hfp_ag_handle_rfcomm_data(packet_type, channel, packet, size); 20853deb3ec6SMatthias Ringwald break; 20863deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 2087e30a6a47SMatthias Ringwald if (packet[0] == RFCOMM_EVENT_CAN_SEND_NOW){ 2088e30a6a47SMatthias Ringwald uint16_t rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet); 2089f0aeb307SMatthias Ringwald hfp_ag_run_for_context(get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid)); 2090e30a6a47SMatthias Ringwald return; 2091e30a6a47SMatthias Ringwald } 209227950165SMatthias Ringwald hfp_handle_rfcomm_event(packet_type, channel, packet, size, HFP_ROLE_AG); 2093aa4dd815SMatthias Ringwald break; 20943deb3ec6SMatthias Ringwald default: 20953deb3ec6SMatthias Ringwald break; 20963deb3ec6SMatthias Ringwald } 20973deb3ec6SMatthias Ringwald 20981c6a0fc0SMatthias Ringwald hfp_ag_run(); 20993deb3ec6SMatthias Ringwald } 21003deb3ec6SMatthias Ringwald 21011c6a0fc0SMatthias Ringwald static void hfp_ag_hci_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 2102405014fbSMatthias Ringwald hfp_handle_hci_event(packet_type, channel, packet, size, HFP_ROLE_AG); 21031c6a0fc0SMatthias Ringwald hfp_ag_run(); 2104405014fbSMatthias Ringwald } 2105405014fbSMatthias Ringwald 21067ca89cabSMatthias Ringwald void hfp_ag_init_codecs(int codecs_nr, const uint8_t * codecs){ 21073deb3ec6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS){ 21083deb3ec6SMatthias Ringwald log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); 21093deb3ec6SMatthias Ringwald return; 21103deb3ec6SMatthias Ringwald } 21113deb3ec6SMatthias Ringwald int i; 2112a0ffb263SMatthias Ringwald hfp_codecs_nr = codecs_nr; 21133deb3ec6SMatthias Ringwald for (i=0; i < codecs_nr; i++){ 21143deb3ec6SMatthias Ringwald hfp_codecs[i] = codecs[i]; 21153deb3ec6SMatthias Ringwald } 2116a0ffb263SMatthias Ringwald } 21173deb3ec6SMatthias Ringwald 2118a0ffb263SMatthias Ringwald void hfp_ag_init_supported_features(uint32_t supported_features){ 2119a0ffb263SMatthias Ringwald hfp_supported_features = supported_features; 2120a0ffb263SMatthias Ringwald } 21213deb3ec6SMatthias Ringwald 21227ca89cabSMatthias Ringwald void hfp_ag_init_ag_indicators(int ag_indicators_nr, const hfp_ag_indicator_t * ag_indicators){ 2123a0ffb263SMatthias Ringwald hfp_ag_indicators_nr = ag_indicators_nr; 21246535961aSMatthias Ringwald (void)memcpy(hfp_ag_indicators, ag_indicators, 21256535961aSMatthias Ringwald ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 2126a0ffb263SMatthias Ringwald } 21273deb3ec6SMatthias Ringwald 21287ca89cabSMatthias Ringwald void hfp_ag_init_hf_indicators(int hf_indicators_nr, const hfp_generic_status_indicator_t * hf_indicators){ 212925789943SMilanka Ringwald if (hf_indicators_nr > HFP_MAX_NUM_INDICATORS) return; 2130a0ffb263SMatthias Ringwald hfp_generic_status_indicators_nr = hf_indicators_nr; 21316535961aSMatthias Ringwald (void)memcpy(hfp_generic_status_indicators, hf_indicators, 21326535961aSMatthias Ringwald hf_indicators_nr * sizeof(hfp_generic_status_indicator_t)); 2133a0ffb263SMatthias Ringwald } 2134a0ffb263SMatthias Ringwald 2135a0ffb263SMatthias Ringwald void hfp_ag_init_call_hold_services(int call_hold_services_nr, const char * call_hold_services[]){ 21363deb3ec6SMatthias Ringwald hfp_ag_call_hold_services_nr = call_hold_services_nr; 21376535961aSMatthias Ringwald (void)memcpy(hfp_ag_call_hold_services, call_hold_services, 21386535961aSMatthias Ringwald call_hold_services_nr * sizeof(char *)); 2139a0ffb263SMatthias Ringwald } 2140a0ffb263SMatthias Ringwald 2141a0ffb263SMatthias Ringwald 2142a0ffb263SMatthias Ringwald void hfp_ag_init(uint16_t rfcomm_channel_nr){ 214327950165SMatthias Ringwald 2144520c92d5SMatthias Ringwald hfp_init(); 214520b2edb6SMatthias Ringwald hfp_ag_call_hold_services_nr = 0; 214620b2edb6SMatthias Ringwald hfp_ag_response_and_hold_active = 0; 214720b2edb6SMatthias Ringwald hfp_ag_indicators_nr = 0; 214820b2edb6SMatthias Ringwald hfp_codecs_nr = 0; 214920b2edb6SMatthias Ringwald hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES; 215020b2edb6SMatthias Ringwald subscriber_numbers = NULL; 215120b2edb6SMatthias Ringwald subscriber_numbers_count = 0; 2152d63c37a1SMatthias Ringwald 21531c6a0fc0SMatthias Ringwald hfp_ag_hci_event_callback_registration.callback = &hfp_ag_hci_event_packet_handler; 21541c6a0fc0SMatthias Ringwald hci_add_event_handler(&hfp_ag_hci_event_callback_registration); 215527950165SMatthias Ringwald 21561c6a0fc0SMatthias Ringwald rfcomm_register_service(&hfp_ag_rfcomm_packet_handler, rfcomm_channel_nr, 0xffff); 215727950165SMatthias Ringwald 215827950165SMatthias Ringwald // used to set packet handler for outgoing rfcomm connections - could be handled by emitting an event to us 21591c6a0fc0SMatthias Ringwald hfp_set_ag_rfcomm_packet_handler(&hfp_ag_rfcomm_packet_handler); 2160aa4dd815SMatthias Ringwald 2161d210d9c4SMatthias Ringwald hfp_gsm_init(); 21623deb3ec6SMatthias Ringwald } 21633deb3ec6SMatthias Ringwald 216420b2edb6SMatthias Ringwald void hfp_ag_deinit(void){ 216520b2edb6SMatthias Ringwald hfp_deinit(); 216620b2edb6SMatthias Ringwald hfp_gsm_deinit(); 216720b2edb6SMatthias Ringwald (void) memset(&hfp_ag_hci_event_callback_registration, 0, sizeof(btstack_packet_callback_registration_t)); 216820b2edb6SMatthias Ringwald (void) memset(&hfp_ag_callback, 0, sizeof(btstack_packet_handler_t)); 216920b2edb6SMatthias Ringwald (void) memset(&hfp_ag_call_hold_services, 0, sizeof(hfp_ag_call_hold_services)); 217020b2edb6SMatthias Ringwald (void) memset(&hfp_ag_response_and_hold_state, 0, sizeof(hfp_response_and_hold_state_t)); 217120b2edb6SMatthias Ringwald } 217220b2edb6SMatthias Ringwald 21733deb3ec6SMatthias Ringwald void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){ 2174323d3000SMatthias Ringwald hfp_establish_service_level_connection(bd_addr, BLUETOOTH_SERVICE_CLASS_HANDSFREE, HFP_ROLE_AG); 21753deb3ec6SMatthias Ringwald } 21763deb3ec6SMatthias Ringwald 2177d97d752dSMilanka Ringwald void hfp_ag_release_service_level_connection(hci_con_handle_t acl_handle){ 21789c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2179a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2180a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2181a33eb0c4SMilanka Ringwald return; 2182a33eb0c4SMilanka Ringwald } 2183a0ffb263SMatthias Ringwald hfp_release_service_level_connection(hfp_connection); 2184f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 21853deb3ec6SMatthias Ringwald } 21863deb3ec6SMatthias Ringwald 2187d97d752dSMilanka Ringwald void hfp_ag_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle, hfp_cme_error_t error){ 21889c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2189a0ffb263SMatthias Ringwald if (!hfp_connection){ 2190a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 21913deb3ec6SMatthias Ringwald return; 21923deb3ec6SMatthias Ringwald } 2193a0ffb263SMatthias Ringwald hfp_connection->extended_audio_gateway_error = 0; 2194a0ffb263SMatthias Ringwald if (!hfp_connection->enable_extended_audio_gateway_error_report){ 21953deb3ec6SMatthias Ringwald return; 21963deb3ec6SMatthias Ringwald } 2197a0ffb263SMatthias Ringwald hfp_connection->extended_audio_gateway_error = error; 2198f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 21993deb3ec6SMatthias Ringwald } 22003deb3ec6SMatthias Ringwald 2201a0ffb263SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * hfp_connection){ 22022ee45eb2SMilanka Ringwald log_info("hfp_ag_setup_audio_connection state %u", hfp_connection->state); 2203a0ffb263SMatthias Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; 2204a0ffb263SMatthias Ringwald if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO) return; 22053deb3ec6SMatthias Ringwald 2206a0ffb263SMatthias Ringwald hfp_connection->establish_audio_connection = 1; 2207a0ffb263SMatthias Ringwald if (!has_codec_negotiation_feature(hfp_connection)){ 2208d6ff09e1SMatthias Ringwald log_info("hfp_ag_establish_audio_connection - no codec negotiation feature, using CVSD"); 2209d6ff09e1SMatthias Ringwald hfp_connection->negotiated_codec = HFP_CODEC_CVSD; 2210a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_EXCHANGED; 22117522e673SMatthias Ringwald // now, pick link settings 2212afac2a04SMilanka Ringwald hfp_init_link_settings(hfp_connection, hfp_ag_esco_s4_supported(hfp_connection)); 22133721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP 22143721a235SMatthias Ringwald hfp_cc256x_prepare_for_sco(hfp_connection); 22153721a235SMatthias Ringwald #endif 22162ee45eb2SMilanka Ringwald return; 22173deb3ec6SMatthias Ringwald } 2218aa4dd815SMatthias Ringwald 22192ee45eb2SMilanka Ringwald hfp_connection->trigger_codec_exchange = 1; 2220aa4dd815SMatthias Ringwald } 2221aa4dd815SMatthias Ringwald 2222d97d752dSMilanka Ringwald void hfp_ag_establish_audio_connection(hci_con_handle_t acl_handle){ 22239c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2224a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2225a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2226a33eb0c4SMilanka Ringwald return; 2227a33eb0c4SMilanka Ringwald } 22282ee45eb2SMilanka Ringwald hfp_connection->trigger_codec_exchange = 0; 2229a0ffb263SMatthias Ringwald hfp_connection->establish_audio_connection = 0; 2230a0ffb263SMatthias Ringwald hfp_ag_setup_audio_connection(hfp_connection); 2231f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 22323deb3ec6SMatthias Ringwald } 22333deb3ec6SMatthias Ringwald 2234d97d752dSMilanka Ringwald void hfp_ag_release_audio_connection(hci_con_handle_t acl_handle){ 22359c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2236a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2237a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2238a33eb0c4SMilanka Ringwald return; 2239a33eb0c4SMilanka Ringwald } 2240a0ffb263SMatthias Ringwald hfp_release_audio_connection(hfp_connection); 2241f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 22423deb3ec6SMatthias Ringwald } 2243aa4dd815SMatthias Ringwald 2244aa4dd815SMatthias Ringwald /** 2245aa4dd815SMatthias Ringwald * @brief Enable in-band ring tone 2246aa4dd815SMatthias Ringwald */ 2247aa4dd815SMatthias Ringwald void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone){ 2248aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE) == use_in_band_ring_tone){ 2249aa4dd815SMatthias Ringwald return; 2250aa4dd815SMatthias Ringwald } 2251aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE, use_in_band_ring_tone); 2252aa4dd815SMatthias Ringwald 2253665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 2254665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 2255665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2256a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 225766c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 2258a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING; 2259f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 2260aa4dd815SMatthias Ringwald } 2261aa4dd815SMatthias Ringwald } 2262aa4dd815SMatthias Ringwald 2263aa4dd815SMatthias Ringwald /** 2264aa4dd815SMatthias Ringwald * @brief Called from GSM 2265aa4dd815SMatthias Ringwald */ 2266aa4dd815SMatthias Ringwald void hfp_ag_incoming_call(void){ 2267aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL, NULL); 2268aa4dd815SMatthias Ringwald } 2269aa4dd815SMatthias Ringwald 2270aa4dd815SMatthias Ringwald /** 2271aa4dd815SMatthias Ringwald * @brief number is stored. 2272aa4dd815SMatthias Ringwald */ 2273aa4dd815SMatthias Ringwald void hfp_ag_set_clip(uint8_t type, const char * number){ 2274f8737b81SMatthias Ringwald hfp_gsm_handler(HFP_AG_SET_CLIP, 0, type, number); 2275aa4dd815SMatthias Ringwald } 2276aa4dd815SMatthias Ringwald 2277aa4dd815SMatthias Ringwald void hfp_ag_call_dropped(void){ 2278aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL); 2279aa4dd815SMatthias Ringwald } 2280aa4dd815SMatthias Ringwald 2281aa4dd815SMatthias Ringwald // call from AG UI 2282aa4dd815SMatthias Ringwald void hfp_ag_answer_incoming_call(void){ 2283aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, NULL); 2284aa4dd815SMatthias Ringwald } 2285aa4dd815SMatthias Ringwald 2286ce263fc8SMatthias Ringwald void hfp_ag_join_held_call(void){ 2287ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_HELD_CALL_JOINED_BY_AG, NULL); 2288ce263fc8SMatthias Ringwald } 2289ce263fc8SMatthias Ringwald 2290aa4dd815SMatthias Ringwald void hfp_ag_terminate_call(void){ 2291aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_AG, NULL); 2292aa4dd815SMatthias Ringwald } 2293aa4dd815SMatthias Ringwald 2294aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_ringing(void){ 2295aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_RINGING, NULL); 2296aa4dd815SMatthias Ringwald } 2297aa4dd815SMatthias Ringwald 2298aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_established(void){ 2299aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ESTABLISHED, NULL); 2300aa4dd815SMatthias Ringwald } 2301aa4dd815SMatthias Ringwald 2302aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_rejected(void){ 2303aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_REJECTED, NULL); 2304aa4dd815SMatthias Ringwald } 2305aa4dd815SMatthias Ringwald 2306aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_accepted(void){ 2307aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ACCEPTED, NULL); 2308aa4dd815SMatthias Ringwald } 2309ce263fc8SMatthias Ringwald 2310ce263fc8SMatthias Ringwald void hfp_ag_hold_incoming_call(void){ 2311ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG, NULL); 2312ce263fc8SMatthias Ringwald } 2313ce263fc8SMatthias Ringwald 2314ce263fc8SMatthias Ringwald void hfp_ag_accept_held_incoming_call(void) { 2315ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG, NULL); 2316ce263fc8SMatthias Ringwald } 2317ce263fc8SMatthias Ringwald 2318ce263fc8SMatthias Ringwald void hfp_ag_reject_held_incoming_call(void){ 2319ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, NULL); 2320ce263fc8SMatthias Ringwald } 2321ce263fc8SMatthias Ringwald 2322aa4dd815SMatthias Ringwald static void hfp_ag_set_ag_indicator(const char * name, int value){ 2323aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name(name); 2324aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 2325aa4dd815SMatthias Ringwald hfp_ag_indicators[indicator_index].status = value; 2326aa4dd815SMatthias Ringwald 2327ce263fc8SMatthias Ringwald 2328665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 2329665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 2330665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2331a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 233266c5995fSMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_AG) continue; 2333a0ffb263SMatthias Ringwald if (! hfp_connection->ag_indicators[indicator_index].enabled) { 2334ce263fc8SMatthias Ringwald log_info("AG indicator '%s' changed to %u but not enabled", hfp_ag_indicators[indicator_index].name, value); 2335ce263fc8SMatthias Ringwald continue; 2336ce263fc8SMatthias Ringwald } 2337ce263fc8SMatthias Ringwald log_info("AG indicator '%s' changed to %u, request transfer statur", hfp_ag_indicators[indicator_index].name, value); 2338a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1); 2339f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 2340aa4dd815SMatthias Ringwald } 2341aa4dd815SMatthias Ringwald } 2342aa4dd815SMatthias Ringwald 2343aa4dd815SMatthias Ringwald void hfp_ag_set_registration_status(int status){ 2344aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("service", status); 2345aa4dd815SMatthias Ringwald } 2346aa4dd815SMatthias Ringwald 2347aa4dd815SMatthias Ringwald void hfp_ag_set_signal_strength(int strength){ 2348aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("signal", strength); 2349aa4dd815SMatthias Ringwald } 2350aa4dd815SMatthias Ringwald 2351aa4dd815SMatthias Ringwald void hfp_ag_set_roaming_status(int status){ 2352aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("roam", status); 2353aa4dd815SMatthias Ringwald } 2354aa4dd815SMatthias Ringwald 2355aa4dd815SMatthias Ringwald void hfp_ag_set_battery_level(int level){ 2356aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("battchg", level); 2357aa4dd815SMatthias Ringwald } 2358aa4dd815SMatthias Ringwald 2359d97d752dSMilanka Ringwald void hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle, int activate){ 2360aa4dd815SMatthias Ringwald if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return; 23619c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2362a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2363a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2364a33eb0c4SMilanka Ringwald return; 2365a33eb0c4SMilanka Ringwald } 2366aa4dd815SMatthias Ringwald 2367a0ffb263SMatthias Ringwald if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) { 236860ebb071SMilanka Ringwald log_info("AG cannot acivate voice recognition - not supported by HF"); 2369aa4dd815SMatthias Ringwald return; 2370aa4dd815SMatthias Ringwald } 2371aa4dd815SMatthias Ringwald 2372aa4dd815SMatthias Ringwald if (activate){ 2373d97d752dSMilanka Ringwald hfp_ag_establish_audio_connection(acl_handle); 2374aa4dd815SMatthias Ringwald } 2375aa4dd815SMatthias Ringwald 2376a0ffb263SMatthias Ringwald hfp_connection->ag_activate_voice_recognition = activate; 2377a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION; 2378f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 2379aa4dd815SMatthias Ringwald } 2380aa4dd815SMatthias Ringwald 2381d97d752dSMilanka Ringwald void hfp_ag_set_microphone_gain(hci_con_handle_t acl_handle, int gain){ 23829c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2383a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2384a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2385a33eb0c4SMilanka Ringwald return; 2386a33eb0c4SMilanka Ringwald } 2387a0ffb263SMatthias Ringwald if (hfp_connection->microphone_gain != gain){ 2388a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_SET_MICROPHONE_GAIN; 2389a0ffb263SMatthias Ringwald hfp_connection->microphone_gain = gain; 2390a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 1; 2391aa4dd815SMatthias Ringwald } 2392f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 2393aa4dd815SMatthias Ringwald } 2394aa4dd815SMatthias Ringwald 2395d97d752dSMilanka Ringwald void hfp_ag_set_speaker_gain(hci_con_handle_t acl_handle, int gain){ 23969c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2397a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2398a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2399a33eb0c4SMilanka Ringwald return; 2400a33eb0c4SMilanka Ringwald } 2401a0ffb263SMatthias Ringwald if (hfp_connection->speaker_gain != gain){ 2402a0ffb263SMatthias Ringwald hfp_connection->speaker_gain = gain; 2403a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 1; 2404aa4dd815SMatthias Ringwald } 2405f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 2406aa4dd815SMatthias Ringwald } 2407aa4dd815SMatthias Ringwald 2408d97d752dSMilanka Ringwald void hfp_ag_send_phone_number_for_voice_tag(hci_con_handle_t acl_handle, const char * number){ 24099c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2410a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2411a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2412a33eb0c4SMilanka Ringwald return; 2413a33eb0c4SMilanka Ringwald } 2414aa4dd815SMatthias Ringwald hfp_ag_set_clip(0, number); 2415a0ffb263SMatthias Ringwald hfp_connection->send_phone_number_for_voice_tag = 1; 2416aa4dd815SMatthias Ringwald } 2417aa4dd815SMatthias Ringwald 2418d97d752dSMilanka Ringwald void hfp_ag_reject_phone_number_for_voice_tag(hci_con_handle_t acl_handle){ 24199c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2420a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2421a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2422a33eb0c4SMilanka Ringwald return; 2423a33eb0c4SMilanka Ringwald } 2424a0ffb263SMatthias Ringwald hfp_connection->send_error = 1; 2425aa4dd815SMatthias Ringwald } 2426aa4dd815SMatthias Ringwald 2427d97d752dSMilanka Ringwald void hfp_ag_send_dtmf_code_done(hci_con_handle_t acl_handle){ 24289c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2429a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2430a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2431a33eb0c4SMilanka Ringwald return; 2432a33eb0c4SMilanka Ringwald } 2433a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 2434c1797c7dSMatthias Ringwald } 2435aa4dd815SMatthias Ringwald 2436ce263fc8SMatthias Ringwald void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count){ 2437ce263fc8SMatthias Ringwald subscriber_numbers = numbers; 2438ce263fc8SMatthias Ringwald subscriber_numbers_count = numbers_count; 2439ce263fc8SMatthias Ringwald } 2440ce263fc8SMatthias Ringwald 24419cae807eSMatthias Ringwald void hfp_ag_clear_last_dialed_number(void){ 24429cae807eSMatthias Ringwald hfp_gsm_clear_last_dialed_number(); 2443ce263fc8SMatthias Ringwald } 2444ce263fc8SMatthias Ringwald 2445d97d752dSMilanka Ringwald void hfp_ag_notify_incoming_call_waiting(hci_con_handle_t acl_handle){ 24469c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); 2447a33eb0c4SMilanka Ringwald if (!hfp_connection){ 2448a33eb0c4SMilanka Ringwald log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle); 2449a33eb0c4SMilanka Ringwald return; 2450a33eb0c4SMilanka Ringwald } 2451a0ffb263SMatthias Ringwald if (!hfp_connection->call_waiting_notification_enabled) return; 2452a0ffb263SMatthias Ringwald 2453a0ffb263SMatthias Ringwald hfp_connection->ag_notify_incoming_call_waiting = 1; 2454f0aeb307SMatthias Ringwald hfp_ag_run_for_context(hfp_connection); 2455a0ffb263SMatthias Ringwald } 2456ce263fc8SMatthias Ringwald 245776cc1527SMatthias Ringwald void hfp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features, int wide_band_speech){ 245876cc1527SMatthias Ringwald if (!name){ 245976cc1527SMatthias Ringwald name = default_hfp_ag_service_name; 246076cc1527SMatthias Ringwald } 246176cc1527SMatthias Ringwald hfp_create_sdp_record(service, service_record_handle, BLUETOOTH_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, rfcomm_channel_nr, name); 246276cc1527SMatthias Ringwald 246376cc1527SMatthias Ringwald /* 246476cc1527SMatthias Ringwald * 0x01 – Ability to reject a call 246576cc1527SMatthias Ringwald * 0x00 – No ability to reject a call 246676cc1527SMatthias Ringwald */ 246776cc1527SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0301); // Hands-Free Profile - Network 246876cc1527SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call); 246976cc1527SMatthias Ringwald 247076cc1527SMatthias Ringwald // Construct SupportedFeatures for SDP bitmap: 247176cc1527SMatthias Ringwald // 247276cc1527SMatthias Ringwald // "The values of the “SupportedFeatures” bitmap given in Table 5.4 shall be the same as the values 247376cc1527SMatthias Ringwald // of the Bits 0 to 4 of the unsolicited result code +BRSF" 247476cc1527SMatthias Ringwald // 247576cc1527SMatthias Ringwald // Wide band speech (bit 5) requires Codec negotiation 247676cc1527SMatthias Ringwald // 247776cc1527SMatthias Ringwald uint16_t sdp_features = supported_features & 0x1f; 247876cc1527SMatthias Ringwald if (wide_band_speech && (supported_features & (1 << HFP_AGSF_CODEC_NEGOTIATION))){ 247976cc1527SMatthias Ringwald sdp_features |= 1 << 5; 248076cc1527SMatthias Ringwald } 248176cc1527SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); // Hands-Free Profile - SupportedFeatures 248276cc1527SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, sdp_features); 248376cc1527SMatthias Ringwald } 248476cc1527SMatthias Ringwald 248576cc1527SMatthias Ringwald void hfp_ag_register_packet_handler(btstack_packet_handler_t callback){ 248676cc1527SMatthias Ringwald if (callback == NULL){ 248776cc1527SMatthias Ringwald log_error("hfp_ag_register_packet_handler called with NULL callback"); 248876cc1527SMatthias Ringwald return; 248976cc1527SMatthias Ringwald } 249076cc1527SMatthias Ringwald hfp_ag_callback = callback; 249176cc1527SMatthias Ringwald hfp_set_ag_callback(callback); 249276cc1527SMatthias Ringwald } 2493