13deb3ec6SMatthias Ringwald /* 23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 33deb3ec6SMatthias Ringwald * 43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 63deb3ec6SMatthias Ringwald * are met: 73deb3ec6SMatthias Ringwald * 83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 153deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183deb3ec6SMatthias Ringwald * monetary gain. 193deb3ec6SMatthias Ringwald * 203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 233deb3ec6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 243deb3ec6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 373deb3ec6SMatthias Ringwald 383deb3ec6SMatthias Ringwald // ***************************************************************************** 393deb3ec6SMatthias Ringwald // 403deb3ec6SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!) 413deb3ec6SMatthias Ringwald // 423deb3ec6SMatthias Ringwald // ***************************************************************************** 433deb3ec6SMatthias Ringwald 443deb3ec6SMatthias Ringwald #include "btstack-config.h" 453deb3ec6SMatthias Ringwald 463deb3ec6SMatthias Ringwald #include <stdint.h> 473deb3ec6SMatthias Ringwald #include <stdio.h> 483deb3ec6SMatthias Ringwald #include <stdlib.h> 493deb3ec6SMatthias Ringwald #include <string.h> 503deb3ec6SMatthias Ringwald 513deb3ec6SMatthias Ringwald #include "hci_cmds.h" 523deb3ec6SMatthias Ringwald #include "run_loop.h" 533deb3ec6SMatthias Ringwald 543deb3ec6SMatthias Ringwald #include "hci.h" 553deb3ec6SMatthias Ringwald #include "btstack_memory.h" 563deb3ec6SMatthias Ringwald #include "hci_dump.h" 573deb3ec6SMatthias Ringwald #include "l2cap.h" 583edc84c5SMatthias Ringwald #include "classic/sdp_query_rfcomm.h" 593edc84c5SMatthias Ringwald #include "classic/sdp.h" 603deb3ec6SMatthias Ringwald #include "debug.h" 613edc84c5SMatthias Ringwald #include "classic/hfp.h" 62*74386ee0SMatthias Ringwald #include "classic/hfp_gsm_model.h" 633edc84c5SMatthias Ringwald #include "classic/hfp_ag.h" 643deb3ec6SMatthias Ringwald 653deb3ec6SMatthias Ringwald static const char default_hfp_ag_service_name[] = "Voice gateway"; 66aa4dd815SMatthias Ringwald 673deb3ec6SMatthias Ringwald static uint16_t hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES; 68aa4dd815SMatthias Ringwald 693deb3ec6SMatthias Ringwald static uint8_t hfp_codecs_nr = 0; 703deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS]; 713deb3ec6SMatthias Ringwald 723deb3ec6SMatthias Ringwald static int hfp_ag_indicators_nr = 0; 733deb3ec6SMatthias Ringwald static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_AG_INDICATORS]; 743deb3ec6SMatthias Ringwald 753deb3ec6SMatthias Ringwald static int hfp_ag_call_hold_services_nr = 0; 763deb3ec6SMatthias Ringwald static char *hfp_ag_call_hold_services[6]; 773deb3ec6SMatthias Ringwald static hfp_callback_t hfp_callback; 783deb3ec6SMatthias Ringwald 79aa4dd815SMatthias Ringwald 80aa4dd815SMatthias Ringwald static hfp_call_status_t hfp_ag_call_state; 81aa4dd815SMatthias Ringwald static hfp_callsetup_status_t hfp_ag_callsetup_state; 82aa4dd815SMatthias Ringwald static hfp_callheld_status_t hfp_ag_callheld_state; 83ce263fc8SMatthias Ringwald static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state; 84ce263fc8SMatthias Ringwald static int hfp_ag_response_and_hold_active = 0; 85aa4dd815SMatthias Ringwald 86aa4dd815SMatthias Ringwald // CLIP feature 87aa4dd815SMatthias Ringwald static uint8_t clip_type; // 0 == not set 88aa4dd815SMatthias Ringwald static char clip_number[25]; // 89aa4dd815SMatthias Ringwald 90ce263fc8SMatthias Ringwald // Subcriber information entries 91ce263fc8SMatthias Ringwald static hfp_phone_number_t * subscriber_numbers = NULL; 92ce263fc8SMatthias Ringwald static int subscriber_numbers_count = 0; 93ce263fc8SMatthias Ringwald 94ce263fc8SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 95aa4dd815SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t *context); 96aa4dd815SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * connection); 97ce263fc8SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * context); 983deb3ec6SMatthias Ringwald 993deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(); 1003deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr(); 1013deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr); 1023deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr); 1033deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context); 1043deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context); 1053deb3ec6SMatthias Ringwald 1063deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context){ 1073deb3ec6SMatthias Ringwald // TODO: save only value, and value changed in the context? 1083deb3ec6SMatthias Ringwald if (context->ag_indicators_nr != hfp_ag_indicators_nr){ 1093deb3ec6SMatthias Ringwald context->ag_indicators_nr = hfp_ag_indicators_nr; 1103deb3ec6SMatthias Ringwald memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 1113deb3ec6SMatthias Ringwald } 1123deb3ec6SMatthias Ringwald return (hfp_ag_indicator_t *)&(context->ag_indicators); 1133deb3ec6SMatthias Ringwald } 1143deb3ec6SMatthias Ringwald 115aa4dd815SMatthias Ringwald static hfp_ag_indicator_t * get_ag_indicator_for_name(const char * name){ 116aa4dd815SMatthias Ringwald int i; 117aa4dd815SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr; i++){ 118aa4dd815SMatthias Ringwald if (strcmp(hfp_ag_indicators[i].name, name) == 0){ 119aa4dd815SMatthias Ringwald return &hfp_ag_indicators[i]; 120aa4dd815SMatthias Ringwald } 121aa4dd815SMatthias Ringwald } 122aa4dd815SMatthias Ringwald return NULL; 123aa4dd815SMatthias Ringwald } 124aa4dd815SMatthias Ringwald 125aa4dd815SMatthias Ringwald static int get_ag_indicator_index_for_name(const char * name){ 126aa4dd815SMatthias Ringwald int i; 127aa4dd815SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr; i++){ 128aa4dd815SMatthias Ringwald if (strcmp(hfp_ag_indicators[i].name, name) == 0){ 129aa4dd815SMatthias Ringwald return i; 130aa4dd815SMatthias Ringwald } 131aa4dd815SMatthias Ringwald } 132aa4dd815SMatthias Ringwald return -1; 133aa4dd815SMatthias Ringwald } 134aa4dd815SMatthias Ringwald 1353deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){ 1363deb3ec6SMatthias Ringwald memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t)); 1373deb3ec6SMatthias Ringwald hfp_ag_indicators_nr = indicator_nr; 1383deb3ec6SMatthias Ringwald } 1393deb3ec6SMatthias Ringwald 1403deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context){ 1413deb3ec6SMatthias Ringwald if (context->ag_indicators_nr != hfp_ag_indicators_nr){ 1423deb3ec6SMatthias Ringwald context->ag_indicators_nr = hfp_ag_indicators_nr; 1433deb3ec6SMatthias Ringwald memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 1443deb3ec6SMatthias Ringwald } 1453deb3ec6SMatthias Ringwald return context->ag_indicators_nr; 1463deb3ec6SMatthias Ringwald } 1473deb3ec6SMatthias Ringwald 1483deb3ec6SMatthias Ringwald 1493deb3ec6SMatthias Ringwald void hfp_ag_register_packet_handler(hfp_callback_t callback){ 1503deb3ec6SMatthias Ringwald if (callback == NULL){ 1513deb3ec6SMatthias Ringwald log_error("hfp_ag_register_packet_handler called with NULL callback"); 1523deb3ec6SMatthias Ringwald return; 1533deb3ec6SMatthias Ringwald } 1543deb3ec6SMatthias Ringwald hfp_callback = callback; 1553deb3ec6SMatthias Ringwald } 1563deb3ec6SMatthias Ringwald 157aa4dd815SMatthias Ringwald static int use_in_band_tone(){ 158aa4dd815SMatthias Ringwald return get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE); 1593deb3ec6SMatthias Ringwald } 1603deb3ec6SMatthias Ringwald 1613deb3ec6SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * connection){ 1623deb3ec6SMatthias Ringwald int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION); 1633deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION); 1643deb3ec6SMatthias Ringwald return hf && ag; 1653deb3ec6SMatthias Ringwald } 1663deb3ec6SMatthias Ringwald 1673deb3ec6SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){ 1683deb3ec6SMatthias Ringwald int hf = get_bit(connection->remote_supported_features, HFP_HFSF_THREE_WAY_CALLING); 1693deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_THREE_WAY_CALLING); 1703deb3ec6SMatthias Ringwald return hf && ag; 1713deb3ec6SMatthias Ringwald } 1723deb3ec6SMatthias Ringwald 1733deb3ec6SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * connection){ 1743deb3ec6SMatthias Ringwald int hf = get_bit(connection->remote_supported_features, HFP_HFSF_HF_INDICATORS); 1753deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_HF_INDICATORS); 1763deb3ec6SMatthias Ringwald return hf && ag; 1773deb3ec6SMatthias Ringwald } 1783deb3ec6SMatthias Ringwald 1799b1c3b4dSMatthias 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){ 1803deb3ec6SMatthias Ringwald if (!name){ 1813deb3ec6SMatthias Ringwald name = default_hfp_ag_service_name; 1823deb3ec6SMatthias Ringwald } 1832ef54b27SMatthias Ringwald hfp_create_sdp_record(service, service_record_handle, SDP_HandsfreeAudioGateway, rfcomm_channel_nr, name); 1843deb3ec6SMatthias Ringwald 1853deb3ec6SMatthias Ringwald /* 1863deb3ec6SMatthias Ringwald * 0x01 – Ability to reject a call 1873deb3ec6SMatthias Ringwald * 0x00 – No ability to reject a call 1883deb3ec6SMatthias Ringwald */ 189aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0301); // Hands-Free Profile - Network 190aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call); 191aa4dd815SMatthias Ringwald 192aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); // Hands-Free Profile - SupportedFeatures 193aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 194aa4dd815SMatthias Ringwald } 195aa4dd815SMatthias Ringwald 196aa4dd815SMatthias Ringwald static int hfp_ag_change_in_band_ring_tone_setting_cmd(uint16_t cid){ 197aa4dd815SMatthias Ringwald char buffer[20]; 198aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_CHANGE_IN_BAND_RING_TONE_SETTING, use_in_band_tone()); 199aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2003deb3ec6SMatthias Ringwald } 2013deb3ec6SMatthias Ringwald 2023deb3ec6SMatthias Ringwald static int hfp_ag_exchange_supported_features_cmd(uint16_t cid){ 2033deb3ec6SMatthias Ringwald char buffer[40]; 2043deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features); 2053deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2063deb3ec6SMatthias Ringwald } 2073deb3ec6SMatthias Ringwald 2083deb3ec6SMatthias Ringwald static int hfp_ag_ok(uint16_t cid){ 2093deb3ec6SMatthias Ringwald char buffer[10]; 2103deb3ec6SMatthias Ringwald sprintf(buffer, "\r\nOK\r\n"); 2113deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2123deb3ec6SMatthias Ringwald } 2133deb3ec6SMatthias Ringwald 214aa4dd815SMatthias Ringwald static int hfp_ag_ring(uint16_t cid){ 215aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, (char *) "\r\nRING\r\n"); 216aa4dd815SMatthias Ringwald } 217aa4dd815SMatthias Ringwald 218aa4dd815SMatthias Ringwald static int hfp_ag_send_clip(uint16_t cid){ 219aa4dd815SMatthias Ringwald if (!clip_type){ 220aa4dd815SMatthias Ringwald clip_number[0] = 0; 221aa4dd815SMatthias Ringwald } 222aa4dd815SMatthias Ringwald char buffer[50]; 223aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s: \"%s\",%u\r\n", HFP_ENABLE_CLIP, clip_number, clip_type); 224aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 225aa4dd815SMatthias Ringwald } 226aa4dd815SMatthias Ringwald 227ce263fc8SMatthias Ringwald static int hfp_send_subscriber_number_cmd(uint16_t cid, uint8_t type, const char * number){ 228ce263fc8SMatthias Ringwald char buffer[50]; 229ce263fc8SMatthias Ringwald sprintf(buffer, "\r\n%s: ,\"%s\",%u, , \r\n", HFP_SUBSCRIBER_NUMBER_INFORMATION, number, type); 230ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 231ce263fc8SMatthias Ringwald } 232ce263fc8SMatthias Ringwald 233c1797c7dSMatthias Ringwald static int hfp_ag_send_phone_number_for_voice_tag_cmd(uint16_t cid){ 234aa4dd815SMatthias Ringwald char buffer[50]; 235aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s: %s\r\n", HFP_PHONE_NUMBER_FOR_VOICE_TAG, clip_number); 236aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 237aa4dd815SMatthias Ringwald } 238aa4dd815SMatthias Ringwald 239aa4dd815SMatthias Ringwald static int hfp_ag_send_call_waiting_notification(uint16_t cid){ 240aa4dd815SMatthias Ringwald if (!clip_type){ 241aa4dd815SMatthias Ringwald clip_number[0] = 0; 242aa4dd815SMatthias Ringwald } 243aa4dd815SMatthias Ringwald char buffer[50]; 244aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n+CCWA: \"%s\",%u\r\n", clip_number, clip_type); 245aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 246aa4dd815SMatthias Ringwald } 247aa4dd815SMatthias Ringwald 2483deb3ec6SMatthias Ringwald static int hfp_ag_error(uint16_t cid){ 2493deb3ec6SMatthias Ringwald char buffer[10]; 2503deb3ec6SMatthias Ringwald sprintf(buffer, "\r\nERROR\r\n"); 2513deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2523deb3ec6SMatthias Ringwald } 2533deb3ec6SMatthias Ringwald 2543deb3ec6SMatthias Ringwald static int hfp_ag_report_extended_audio_gateway_error(uint16_t cid, uint8_t error){ 2553deb3ec6SMatthias Ringwald char buffer[20]; 2563deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s=%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, error); 2573deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2583deb3ec6SMatthias Ringwald } 2593deb3ec6SMatthias Ringwald 260ad902e3dSMatthias Ringwald // fast & small implementation for fixed int size 261ad902e3dSMatthias Ringwald static int string_len_for_uint32(uint32_t i){ 262ad902e3dSMatthias Ringwald if (i < 10) return 1; 263ad902e3dSMatthias Ringwald if (i < 100) return 2; 264ad902e3dSMatthias Ringwald if (i < 1000) return 3; 265ad902e3dSMatthias Ringwald if (i < 10000) return 4; 266*74386ee0SMatthias Ringwald if (i < 100000) return 5; 267ad902e3dSMatthias Ringwald if (i < 1000000) return 6; 268ad902e3dSMatthias Ringwald if (i < 10000000) return 7; 269ad902e3dSMatthias Ringwald if (i < 100000000) return 8; 270ad902e3dSMatthias Ringwald if (i < 1000000000) return 9; 271ad902e3dSMatthias Ringwald return 10; 272ad902e3dSMatthias Ringwald } 273ad902e3dSMatthias Ringwald 274ad902e3dSMatthias Ringwald // get size for indicator string 275ad902e3dSMatthias Ringwald static int hfp_ag_indicators_string_size(hfp_connection_t * context, int i){ 276ad902e3dSMatthias Ringwald // template: ("$NAME",($MIN,$MAX)) 277ad902e3dSMatthias Ringwald return 8 + strlen(get_hfp_ag_indicators(context)[i].name) 278ad902e3dSMatthias Ringwald + string_len_for_uint32(get_hfp_ag_indicators(context)[i].min_range) 279ad902e3dSMatthias Ringwald + string_len_for_uint32(get_hfp_ag_indicators(context)[i].min_range); 280ad902e3dSMatthias Ringwald } 281ad902e3dSMatthias Ringwald 282ad902e3dSMatthias Ringwald // store indicator 283*74386ee0SMatthias Ringwald static void hfp_ag_indicators_string_store(hfp_connection_t * context, int i, uint8_t * buffer){ 284ad902e3dSMatthias Ringwald sprintf((char *) buffer, "(\"%s\",(%d,%d)),", 2853deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].name, 2863deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].min_range, 2873deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].max_range); 2883deb3ec6SMatthias Ringwald } 289ad902e3dSMatthias Ringwald 290ad902e3dSMatthias Ringwald // structure: header [indicator [comma indicator]] footer 291ad902e3dSMatthias Ringwald static int hfp_ag_indicators_cmd_generator_num_segments(hfp_connection_t * context){ 292ad902e3dSMatthias Ringwald int num_indicators = get_hfp_ag_indicators_nr(context); 293ad902e3dSMatthias Ringwald if (!num_indicators) return 2; 294ad902e3dSMatthias Ringwald return 3 + (num_indicators-1) * 2; 2953deb3ec6SMatthias Ringwald } 296ad902e3dSMatthias Ringwald 297ad902e3dSMatthias Ringwald // get size of individual segment for hfp_ag_retrieve_indicators_cmd 298ad902e3dSMatthias Ringwald static int hfp_ag_indicators_cmd_generator_get_segment_len(hfp_connection_t * context, int index){ 299ad902e3dSMatthias Ringwald if (index == 0) { 300ad902e3dSMatthias Ringwald return strlen(HFP_INDICATOR) + 3; // "\n\r%s:"" 301ad902e3dSMatthias Ringwald } 302ad902e3dSMatthias Ringwald index--; 303ad902e3dSMatthias Ringwald int num_indicators = get_hfp_ag_indicators_nr(context); 304ad902e3dSMatthias Ringwald int indicator_index = index >> 1; 305ad902e3dSMatthias Ringwald if ((index & 1) == 0){ 306ad902e3dSMatthias Ringwald return hfp_ag_indicators_string_size(context, indicator_index); 307ad902e3dSMatthias Ringwald } 308ad902e3dSMatthias Ringwald if (indicator_index == num_indicators - 1){ 309ad902e3dSMatthias Ringwald return 8; // "\r\n\r\nOK\r\n" 310ad902e3dSMatthias Ringwald } 311ad902e3dSMatthias Ringwald return 1; // comma 312ad902e3dSMatthias Ringwald } 313ad902e3dSMatthias Ringwald 314ad902e3dSMatthias Ringwald static void hgp_ag_indicators_cmd_generator_store_segment(hfp_connection_t * context, int index, uint8_t * buffer){ 315ad902e3dSMatthias Ringwald if (index == 0){ 316ad902e3dSMatthias Ringwald *buffer++ = '\r'; 317*74386ee0SMatthias Ringwald *buffer++ = '\n'; 318ad902e3dSMatthias Ringwald int len = strlen(HFP_INDICATOR); 319ad902e3dSMatthias Ringwald memcpy(buffer, HFP_INDICATOR, len); 320ad902e3dSMatthias Ringwald buffer += len; 321ad902e3dSMatthias Ringwald *buffer++ = ':'; 322ad902e3dSMatthias Ringwald return; 323ad902e3dSMatthias Ringwald } 324ad902e3dSMatthias Ringwald index--; 325ad902e3dSMatthias Ringwald int num_indicators = get_hfp_ag_indicators_nr(context); 326ad902e3dSMatthias Ringwald int indicator_index = index >> 1; 327ad902e3dSMatthias Ringwald if ((index & 1) == 0){ 328ad902e3dSMatthias Ringwald hfp_ag_indicators_string_store(context, indicator_index, buffer); 329ad902e3dSMatthias Ringwald return; 330ad902e3dSMatthias Ringwald } 331ad902e3dSMatthias Ringwald if (indicator_index == num_indicators-1){ 332ad902e3dSMatthias Ringwald memcpy(buffer, "\r\n\r\nOK\r\n", 8); 333ad902e3dSMatthias Ringwald return; 334ad902e3dSMatthias Ringwald } 335ad902e3dSMatthias Ringwald *buffer = ','; 3363deb3ec6SMatthias Ringwald } 3373deb3ec6SMatthias Ringwald 3383deb3ec6SMatthias Ringwald static int hfp_hf_indicators_join(char * buffer, int buffer_size){ 3393deb3ec6SMatthias Ringwald if (buffer_size < hfp_ag_indicators_nr * 3) return 0; 3403deb3ec6SMatthias Ringwald int i; 3413deb3ec6SMatthias Ringwald int offset = 0; 3423deb3ec6SMatthias Ringwald for (i = 0; i < get_hfp_generic_status_indicators_nr()-1; i++) { 3433deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid); 3443deb3ec6SMatthias Ringwald } 3453deb3ec6SMatthias Ringwald if (i < get_hfp_generic_status_indicators_nr()){ 3463deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid); 3473deb3ec6SMatthias Ringwald } 3483deb3ec6SMatthias Ringwald return offset; 3493deb3ec6SMatthias Ringwald } 3503deb3ec6SMatthias Ringwald 3513deb3ec6SMatthias Ringwald static int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){ 3523deb3ec6SMatthias Ringwald if (buffer_size < get_hfp_generic_status_indicators_nr() * 3) return 0; 3533deb3ec6SMatthias Ringwald int i; 3543deb3ec6SMatthias Ringwald int offset = 0; 3553deb3ec6SMatthias Ringwald for (i = 0; i < get_hfp_generic_status_indicators_nr(); i++) { 3563deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "\r\n%s:%d,%d\r\n", HFP_GENERIC_STATUS_INDICATOR, get_hfp_generic_status_indicators()[i].uuid, get_hfp_generic_status_indicators()[i].state); 3573deb3ec6SMatthias Ringwald } 3583deb3ec6SMatthias Ringwald return offset; 3593deb3ec6SMatthias Ringwald } 3603deb3ec6SMatthias Ringwald 3613deb3ec6SMatthias Ringwald static int hfp_ag_indicators_status_join(char * buffer, int buffer_size){ 3623deb3ec6SMatthias Ringwald if (buffer_size < hfp_ag_indicators_nr * 3) return 0; 3633deb3ec6SMatthias Ringwald int i; 3643deb3ec6SMatthias Ringwald int offset = 0; 3653deb3ec6SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr-1; i++) { 3663deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status); 3673deb3ec6SMatthias Ringwald } 3683deb3ec6SMatthias Ringwald if (i<hfp_ag_indicators_nr){ 3693deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status); 3703deb3ec6SMatthias Ringwald } 3713deb3ec6SMatthias Ringwald return offset; 3723deb3ec6SMatthias Ringwald } 3733deb3ec6SMatthias Ringwald 3743deb3ec6SMatthias Ringwald static int hfp_ag_call_services_join(char * buffer, int buffer_size){ 3753deb3ec6SMatthias Ringwald if (buffer_size < hfp_ag_call_hold_services_nr * 3) return 0; 3763deb3ec6SMatthias Ringwald int i; 3773deb3ec6SMatthias Ringwald int offset = snprintf(buffer, buffer_size, "("); 3783deb3ec6SMatthias Ringwald for (i = 0; i < hfp_ag_call_hold_services_nr-1; i++) { 3793deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]); 3803deb3ec6SMatthias Ringwald } 3813deb3ec6SMatthias Ringwald if (i<hfp_ag_call_hold_services_nr){ 3823deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%s)", hfp_ag_call_hold_services[i]); 3833deb3ec6SMatthias Ringwald } 3843deb3ec6SMatthias Ringwald return offset; 3853deb3ec6SMatthias Ringwald } 3863deb3ec6SMatthias Ringwald 387ad902e3dSMatthias Ringwald static int hfp_ag_cmd_via_generator(uint16_t cid, hfp_connection_t * context, 388ad902e3dSMatthias Ringwald int start_segment, int num_segments, 389ad902e3dSMatthias Ringwald int (*get_segment_len)(hfp_connection_t * context, int segment), 390ad902e3dSMatthias Ringwald void (*store_segment) (hfp_connection_t * context, int segment, uint8_t * buffer)){ 3913deb3ec6SMatthias Ringwald 392ad902e3dSMatthias Ringwald // assumes: can send now == true 393ad902e3dSMatthias Ringwald // assumes: num segments > 0 394ad902e3dSMatthias Ringwald rfcomm_reserve_packet_buffer(); 395ad902e3dSMatthias Ringwald int mtu = rfcomm_get_max_frame_size(cid); 396ad902e3dSMatthias Ringwald uint8_t * data = rfcomm_get_outgoing_buffer(); 397ad902e3dSMatthias Ringwald int offset = 0; 398ad902e3dSMatthias Ringwald int segment = start_segment; 399ad902e3dSMatthias Ringwald while (segment < num_segments){ 400ad902e3dSMatthias Ringwald int segment_len = get_segment_len(context, segment); 401ad902e3dSMatthias Ringwald if (offset + segment_len <= mtu){ 402ad902e3dSMatthias Ringwald store_segment(context, segment, data+offset); 403ad902e3dSMatthias Ringwald offset += segment_len; 404ad902e3dSMatthias Ringwald segment++; 405ad902e3dSMatthias Ringwald } 406ad902e3dSMatthias Ringwald } 407ad902e3dSMatthias Ringwald rfcomm_send_prepared(cid, offset); 408ad902e3dSMatthias Ringwald return segment; 409ad902e3dSMatthias Ringwald } 4103deb3ec6SMatthias Ringwald 411ad902e3dSMatthias Ringwald // returns next segment to store 412ad902e3dSMatthias Ringwald static int hfp_ag_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * context, int start_segment){ 413ad902e3dSMatthias Ringwald int num_segments = hfp_ag_indicators_cmd_generator_num_segments(context); 414ad902e3dSMatthias Ringwald return hfp_ag_cmd_via_generator(cid, context, start_segment, num_segments, 415ad902e3dSMatthias Ringwald hfp_ag_indicators_cmd_generator_get_segment_len, hgp_ag_indicators_cmd_generator_store_segment); 4163deb3ec6SMatthias Ringwald } 4173deb3ec6SMatthias Ringwald 4183deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){ 4193deb3ec6SMatthias Ringwald char buffer[40]; 4203deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR); 4213deb3ec6SMatthias Ringwald offset += hfp_ag_indicators_status_join(buffer+offset, sizeof(buffer)-offset); 4223deb3ec6SMatthias Ringwald 4233deb3ec6SMatthias Ringwald buffer[offset] = 0; 4243deb3ec6SMatthias Ringwald 4253deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); 4263deb3ec6SMatthias Ringwald buffer[offset] = 0; 4273deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4283deb3ec6SMatthias Ringwald } 4293deb3ec6SMatthias Ringwald 4303deb3ec6SMatthias Ringwald static int hfp_ag_set_indicator_status_update_cmd(uint16_t cid, uint8_t activate){ 4313deb3ec6SMatthias Ringwald // AT\r\n%s:3,0,0,%d\r\n 4323deb3ec6SMatthias Ringwald return hfp_ag_ok(cid); 4333deb3ec6SMatthias Ringwald } 4343deb3ec6SMatthias Ringwald 4353deb3ec6SMatthias Ringwald 4363deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_can_hold_call_cmd(uint16_t cid){ 437ad902e3dSMatthias Ringwald char buffer[40]; 4383deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES); 4393deb3ec6SMatthias Ringwald offset += hfp_ag_call_services_join(buffer+offset, sizeof(buffer)-offset); 4403deb3ec6SMatthias Ringwald 4413deb3ec6SMatthias Ringwald buffer[offset] = 0; 4423deb3ec6SMatthias Ringwald 4433deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); 4443deb3ec6SMatthias Ringwald buffer[offset] = 0; 4453deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4463deb3ec6SMatthias Ringwald } 4473deb3ec6SMatthias Ringwald 4483deb3ec6SMatthias Ringwald 4493deb3ec6SMatthias Ringwald static int hfp_ag_list_supported_generic_status_indicators_cmd(uint16_t cid){ 4503deb3ec6SMatthias Ringwald return hfp_ag_ok(cid); 4513deb3ec6SMatthias Ringwald } 4523deb3ec6SMatthias Ringwald 4533deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){ 4543deb3ec6SMatthias Ringwald char buffer[40]; 455aa4dd815SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:(", HFP_GENERIC_STATUS_INDICATOR); 4563deb3ec6SMatthias Ringwald offset += hfp_hf_indicators_join(buffer+offset, sizeof(buffer)-offset); 4573deb3ec6SMatthias Ringwald 4583deb3ec6SMatthias Ringwald buffer[offset] = 0; 4593deb3ec6SMatthias Ringwald 460aa4dd815SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, ")\r\n\r\nOK\r\n"); 4613deb3ec6SMatthias Ringwald buffer[offset] = 0; 4623deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4633deb3ec6SMatthias Ringwald } 4643deb3ec6SMatthias Ringwald 4653deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t cid){ 4663deb3ec6SMatthias Ringwald char buffer[40]; 4673deb3ec6SMatthias Ringwald int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer)); 4683deb3ec6SMatthias Ringwald 4693deb3ec6SMatthias Ringwald buffer[offset] = 0; 4703deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n"); 4713deb3ec6SMatthias Ringwald buffer[offset] = 0; 4723deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4733deb3ec6SMatthias Ringwald } 4743deb3ec6SMatthias Ringwald 475aa4dd815SMatthias Ringwald static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t * indicator){ 4763deb3ec6SMatthias Ringwald char buffer[20]; 477aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d,%d\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator->index, indicator->status); 4783deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4793deb3ec6SMatthias Ringwald } 4803deb3ec6SMatthias Ringwald 4813deb3ec6SMatthias Ringwald static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){ 4823deb3ec6SMatthias Ringwald char buffer[40]; 4833deb3ec6SMatthias Ringwald if (strlen(op.name) == 0){ 4843deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d,,\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode); 4853deb3ec6SMatthias Ringwald } else { 4863deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d,%d,%s\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode, op.format, op.name); 4873deb3ec6SMatthias Ringwald } 4883deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4893deb3ec6SMatthias Ringwald } 4903deb3ec6SMatthias Ringwald 4913deb3ec6SMatthias Ringwald 4923deb3ec6SMatthias Ringwald static int hfp_ag_cmd_suggest_codec(uint16_t cid, uint8_t codec){ 4933deb3ec6SMatthias Ringwald char buffer[30]; 4943deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec); 4953deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4963deb3ec6SMatthias Ringwald } 4973deb3ec6SMatthias Ringwald 498aa4dd815SMatthias Ringwald static int hfp_ag_activate_voice_recognition_cmd(uint16_t cid, uint8_t activate_voice_recognition){ 499aa4dd815SMatthias Ringwald char buffer[30]; 500aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s: %d\r\n", HFP_ACTIVATE_VOICE_RECOGNITION, activate_voice_recognition); 501aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 502aa4dd815SMatthias Ringwald } 503aa4dd815SMatthias Ringwald 504aa4dd815SMatthias Ringwald static int hfp_ag_set_speaker_gain_cmd(uint16_t cid, uint8_t gain){ 505aa4dd815SMatthias Ringwald char buffer[30]; 506aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_SET_SPEAKER_GAIN, gain); 507aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 508aa4dd815SMatthias Ringwald } 509aa4dd815SMatthias Ringwald 510aa4dd815SMatthias Ringwald static int hfp_ag_set_microphone_gain_cmd(uint16_t cid, uint8_t gain){ 511aa4dd815SMatthias Ringwald char buffer[30]; 512aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_SET_MICROPHONE_GAIN, gain); 513aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 514aa4dd815SMatthias Ringwald } 515aa4dd815SMatthias Ringwald 516ce263fc8SMatthias Ringwald static int hfp_ag_set_response_and_hold(uint16_t cid, int state){ 517ce263fc8SMatthias Ringwald char buffer[30]; 518ce263fc8SMatthias Ringwald sprintf(buffer, "\r\n%s: %d\r\n", HFP_RESPONSE_AND_HOLD, state); 519ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 520ce263fc8SMatthias Ringwald } 521ce263fc8SMatthias Ringwald 522aa4dd815SMatthias Ringwald 5233deb3ec6SMatthias Ringwald static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){ 5243deb3ec6SMatthias Ringwald int i,j; 525aa4dd815SMatthias Ringwald uint8_t codec = HFP_CODEC_CVSD; 5263deb3ec6SMatthias Ringwald for (i = 0; i < hfp_codecs_nr; i++){ 5273deb3ec6SMatthias Ringwald for (j = 0; j < context->remote_codecs_nr; j++){ 5283deb3ec6SMatthias Ringwald if (context->remote_codecs[j] == hfp_codecs[i]){ 5293deb3ec6SMatthias Ringwald codec = context->remote_codecs[j]; 5303deb3ec6SMatthias Ringwald continue; 5313deb3ec6SMatthias Ringwald } 5323deb3ec6SMatthias Ringwald } 5333deb3ec6SMatthias Ringwald } 5343deb3ec6SMatthias Ringwald return codec; 5353deb3ec6SMatthias Ringwald } 5363deb3ec6SMatthias Ringwald 537aa4dd815SMatthias Ringwald static int codecs_exchange_state_machine(hfp_connection_t * context){ 538aa4dd815SMatthias Ringwald /* events ( == commands): 539aa4dd815SMatthias Ringwald HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs 540aa4dd815SMatthias Ringwald HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 541aa4dd815SMatthias Ringwald hf_trigger_codec_connection_setup == received BCC 542aa4dd815SMatthias Ringwald ag_trigger_codec_connection_setup == received from AG to send BCS 543aa4dd815SMatthias Ringwald HFP_CMD_HF_CONFIRMED_CODEC == received AT+BCS 544aa4dd815SMatthias Ringwald */ 545aa4dd815SMatthias Ringwald 546aa4dd815SMatthias Ringwald switch (context->codecs_state){ 547aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: 548aa4dd815SMatthias Ringwald context->command = HFP_CMD_AG_SEND_COMMON_CODEC; 549aa4dd815SMatthias Ringwald break; 550aa4dd815SMatthias Ringwald case HFP_CODECS_AG_RESEND_COMMON_CODEC: 551aa4dd815SMatthias Ringwald context->command = HFP_CMD_AG_SEND_COMMON_CODEC; 552aa4dd815SMatthias Ringwald break; 553aa4dd815SMatthias Ringwald default: 554aa4dd815SMatthias Ringwald break; 555aa4dd815SMatthias Ringwald } 556aa4dd815SMatthias Ringwald 557aa4dd815SMatthias Ringwald // printf(" -> State machine: CC\n"); 558aa4dd815SMatthias Ringwald 559aa4dd815SMatthias Ringwald switch (context->command){ 560aa4dd815SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 561aa4dd815SMatthias Ringwald //printf("HFP_CODECS_RECEIVED_LIST \n"); 562aa4dd815SMatthias Ringwald if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ 563aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_RECEIVED_LIST; 564aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 565aa4dd815SMatthias Ringwald return 1; 566aa4dd815SMatthias Ringwald } 567aa4dd815SMatthias Ringwald 568aa4dd815SMatthias Ringwald switch (context->codecs_state){ 569aa4dd815SMatthias Ringwald case HFP_CODECS_AG_SENT_COMMON_CODEC: 570aa4dd815SMatthias Ringwald case HFP_CODECS_EXCHANGED: 571aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_AG_RESEND_COMMON_CODEC; 572aa4dd815SMatthias Ringwald break; 573aa4dd815SMatthias Ringwald default: 574aa4dd815SMatthias Ringwald break; 575aa4dd815SMatthias Ringwald } 576aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 577aa4dd815SMatthias Ringwald return 1; 578aa4dd815SMatthias Ringwald 579aa4dd815SMatthias Ringwald case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 580aa4dd815SMatthias Ringwald //printf(" HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP \n"); 581aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; 582aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 583aa4dd815SMatthias Ringwald return 1; 584aa4dd815SMatthias Ringwald 585aa4dd815SMatthias Ringwald case HFP_CMD_AG_SEND_COMMON_CODEC: 586aa4dd815SMatthias Ringwald //printf(" HFP_CMD_AG_SEND_COMMON_CODEC \n"); 587aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC; 588aa4dd815SMatthias Ringwald context->suggested_codec = hfp_ag_suggest_codec(context); 589aa4dd815SMatthias Ringwald hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec); 590aa4dd815SMatthias Ringwald return 1; 591aa4dd815SMatthias Ringwald 592aa4dd815SMatthias Ringwald case HFP_CMD_HF_CONFIRMED_CODEC: 593aa4dd815SMatthias Ringwald //printf("HFP_CMD_HF_CONFIRMED_CODEC \n"); 594aa4dd815SMatthias Ringwald if (context->codec_confirmed != context->suggested_codec){ 595aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_ERROR; 596aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 597aa4dd815SMatthias Ringwald return 1; 598aa4dd815SMatthias Ringwald } 599aa4dd815SMatthias Ringwald context->negotiated_codec = context->codec_confirmed; 600aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_EXCHANGED; 601aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0); 602aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 603aa4dd815SMatthias Ringwald return 1; 604aa4dd815SMatthias Ringwald default: 605aa4dd815SMatthias Ringwald break; 606aa4dd815SMatthias Ringwald } 607aa4dd815SMatthias Ringwald return 0; 608aa4dd815SMatthias Ringwald } 609aa4dd815SMatthias Ringwald 610ce263fc8SMatthias Ringwald static void hfp_init_link_settings(hfp_connection_t * context){ 611ce263fc8SMatthias Ringwald // determine highest possible link setting 612ce263fc8SMatthias Ringwald context->link_setting = HFP_LINK_SETTINGS_D1; 613ce263fc8SMatthias Ringwald if (hci_remote_eSCO_supported(context->con_handle)){ 614ce263fc8SMatthias Ringwald context->link_setting = HFP_LINK_SETTINGS_S3; 615ce263fc8SMatthias Ringwald if ((context->remote_supported_features & (1<<HFP_HFSF_ESCO_S4)) 616ce263fc8SMatthias Ringwald && (hfp_supported_features & (1<<HFP_AGSF_ESCO_S4))){ 617ce263fc8SMatthias Ringwald context->link_setting = HFP_LINK_SETTINGS_S4; 618ce263fc8SMatthias Ringwald } 619ce263fc8SMatthias Ringwald } 620ce263fc8SMatthias Ringwald } 621ce263fc8SMatthias Ringwald 622aa4dd815SMatthias Ringwald static void hfp_ag_slc_established(hfp_connection_t * context){ 623aa4dd815SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 624aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 625aa4dd815SMatthias Ringwald 626ce263fc8SMatthias Ringwald hfp_init_link_settings(context); 627ce263fc8SMatthias Ringwald 628aa4dd815SMatthias Ringwald // if active call exist, set per-connection state active, too (when audio is on) 629aa4dd815SMatthias Ringwald if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 630aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; 631aa4dd815SMatthias Ringwald } 632ce263fc8SMatthias Ringwald // if AG is ringing, also start ringing on the HF 633ce263fc8SMatthias Ringwald if (hfp_ag_call_state == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS && 634ce263fc8SMatthias Ringwald hfp_ag_callsetup_state == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 635ce263fc8SMatthias Ringwald hfp_ag_hf_start_ringing(context); 636ce263fc8SMatthias Ringwald } 637aa4dd815SMatthias Ringwald } 6383deb3ec6SMatthias Ringwald 6393deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){ 640aa4dd815SMatthias Ringwald if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 6413deb3ec6SMatthias Ringwald int done = 0; 642aa4dd815SMatthias Ringwald // printf(" -> State machine: SLC\n"); 6433deb3ec6SMatthias Ringwald switch(context->command){ 6443deb3ec6SMatthias Ringwald case HFP_CMD_SUPPORTED_FEATURES: 6453deb3ec6SMatthias Ringwald switch(context->state){ 6463deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: 647aa4dd815SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES: 6483deb3ec6SMatthias Ringwald if (has_codec_negotiation_feature(context)){ 6493deb3ec6SMatthias Ringwald context->state = HFP_W4_NOTIFY_ON_CODECS; 650aa4dd815SMatthias Ringwald } else { 6513deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS; 652aa4dd815SMatthias Ringwald } 653aa4dd815SMatthias Ringwald hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid); 654aa4dd815SMatthias Ringwald return 1; 6553deb3ec6SMatthias Ringwald default: 6563deb3ec6SMatthias Ringwald break; 6573deb3ec6SMatthias Ringwald } 6583deb3ec6SMatthias Ringwald break; 6593deb3ec6SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 660aa4dd815SMatthias Ringwald done = codecs_exchange_state_machine(context); 6613deb3ec6SMatthias Ringwald 662aa4dd815SMatthias Ringwald if (context->codecs_state == HFP_CODECS_RECEIVED_LIST){ 663aa4dd815SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS; 6643deb3ec6SMatthias Ringwald } 665aa4dd815SMatthias Ringwald return done; 666aa4dd815SMatthias Ringwald 667aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS: 668ad902e3dSMatthias Ringwald if (context->state == HFP_W4_RETRIEVE_INDICATORS) { 669ad902e3dSMatthias Ringwald context->command = HFP_CMD_NONE; // prevent reentrance 670ad902e3dSMatthias Ringwald int next_segment = hfp_ag_retrieve_indicators_cmd_via_generator(context->rfcomm_cid, context, context->send_ag_indicators_segment); 671ad902e3dSMatthias Ringwald if (next_segment < hfp_ag_indicators_cmd_generator_num_segments(context)){ 672ad902e3dSMatthias Ringwald // prepare sending of next segment 673ad902e3dSMatthias Ringwald context->send_ag_indicators_segment = next_segment; 674ad902e3dSMatthias Ringwald context->command = HFP_CMD_RETRIEVE_AG_INDICATORS; 675ad902e3dSMatthias Ringwald } else { 676ad902e3dSMatthias Ringwald // done, go to next state 677ad902e3dSMatthias Ringwald context->send_ag_indicators_segment = 0; 6783deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; 679ad902e3dSMatthias Ringwald } 680aa4dd815SMatthias Ringwald return 1; 681ad902e3dSMatthias Ringwald } 682ad902e3dSMatthias Ringwald break; 683aa4dd815SMatthias Ringwald 684aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: 685aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break; 6863deb3ec6SMatthias Ringwald context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; 687aa4dd815SMatthias Ringwald hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); 688aa4dd815SMatthias Ringwald return 1; 689aa4dd815SMatthias Ringwald 6903deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 691aa4dd815SMatthias Ringwald if (context->state != HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE) break; 6923deb3ec6SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(context)){ 6933deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; 694aa4dd815SMatthias Ringwald } else if (has_hf_indicators_feature(context)){ 6953deb3ec6SMatthias Ringwald context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 696aa4dd815SMatthias Ringwald } else { 697aa4dd815SMatthias Ringwald hfp_ag_slc_established(context); 6983deb3ec6SMatthias Ringwald } 699aa4dd815SMatthias Ringwald hfp_ag_set_indicator_status_update_cmd(context->rfcomm_cid, 1); 700aa4dd815SMatthias Ringwald return 1; 7013deb3ec6SMatthias Ringwald 702aa4dd815SMatthias Ringwald case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: 703aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break; 704aa4dd815SMatthias Ringwald if (has_hf_indicators_feature(context)){ 705aa4dd815SMatthias Ringwald context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 706aa4dd815SMatthias Ringwald } 707aa4dd815SMatthias Ringwald hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid); 708ce263fc8SMatthias Ringwald if (!has_hf_indicators_feature(context)){ 709ce263fc8SMatthias Ringwald hfp_ag_slc_established(context); 710ce263fc8SMatthias Ringwald } 711aa4dd815SMatthias Ringwald return 1; 712aa4dd815SMatthias Ringwald 713aa4dd815SMatthias Ringwald case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS: 714aa4dd815SMatthias Ringwald if (context->state != HFP_W4_LIST_GENERIC_STATUS_INDICATORS) break; 715aa4dd815SMatthias Ringwald context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; 716aa4dd815SMatthias Ringwald hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid); 717aa4dd815SMatthias Ringwald return 1; 718aa4dd815SMatthias Ringwald 719aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS: 720aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS) break; 721aa4dd815SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 722aa4dd815SMatthias Ringwald hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid); 723aa4dd815SMatthias Ringwald return 1; 724aa4dd815SMatthias Ringwald 725aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE: 726aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS) break; 727aa4dd815SMatthias Ringwald hfp_ag_slc_established(context); 728aa4dd815SMatthias Ringwald hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); 729aa4dd815SMatthias Ringwald return 1; 7303deb3ec6SMatthias Ringwald default: 7313deb3ec6SMatthias Ringwald break; 7323deb3ec6SMatthias Ringwald } 7333deb3ec6SMatthias Ringwald return done; 7343deb3ec6SMatthias Ringwald } 7353deb3ec6SMatthias Ringwald 7363deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){ 737aa4dd815SMatthias Ringwald // if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 7383deb3ec6SMatthias Ringwald 739aa4dd815SMatthias Ringwald int done = codecs_exchange_state_machine(context); 740aa4dd815SMatthias Ringwald if (done) return done; 741aa4dd815SMatthias Ringwald 742aa4dd815SMatthias Ringwald // printf(" -> State machine: SLC Queries\n"); 7433deb3ec6SMatthias Ringwald switch(context->command){ 744aa4dd815SMatthias Ringwald case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: 745aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, context->ag_activate_voice_recognition); 746aa4dd815SMatthias Ringwald hfp_ag_activate_voice_recognition_cmd(context->rfcomm_cid, context->ag_activate_voice_recognition); 747aa4dd815SMatthias Ringwald return 1; 748aa4dd815SMatthias Ringwald case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION: 749aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)){ 750aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, context->ag_activate_voice_recognition); 7513deb3ec6SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 752aa4dd815SMatthias Ringwald hfp_ag_setup_audio_connection(context); 753aa4dd815SMatthias Ringwald } else { 754aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 755aa4dd815SMatthias Ringwald } 756aa4dd815SMatthias Ringwald return 1; 757aa4dd815SMatthias Ringwald case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING: 758aa4dd815SMatthias Ringwald hfp_ag_change_in_band_ring_tone_setting_cmd(context->rfcomm_cid); 759aa4dd815SMatthias Ringwald return 1; 760aa4dd815SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME: 761aa4dd815SMatthias Ringwald hfp_ag_report_network_operator_name_cmd(context->rfcomm_cid, context->network_operator); 762aa4dd815SMatthias Ringwald return 1; 763aa4dd815SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT: 7643deb3ec6SMatthias Ringwald if (context->network_operator.format != 0){ 7653deb3ec6SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 766aa4dd815SMatthias Ringwald } else { 7673deb3ec6SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 7683deb3ec6SMatthias Ringwald } 769aa4dd815SMatthias Ringwald return 1; 770aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE: 7713deb3ec6SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 772aa4dd815SMatthias Ringwald return 1; 7733deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR: 7743deb3ec6SMatthias Ringwald if (context->extended_audio_gateway_error){ 7753deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = 0; 776aa4dd815SMatthias Ringwald hfp_ag_report_extended_audio_gateway_error(context->rfcomm_cid, context->extended_audio_gateway_error); 777aa4dd815SMatthias Ringwald return 1; 7783deb3ec6SMatthias Ringwald } 7793deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 780ce263fc8SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 781ce263fc8SMatthias Ringwald return 1; 7823deb3ec6SMatthias Ringwald default: 7833deb3ec6SMatthias Ringwald break; 7843deb3ec6SMatthias Ringwald } 785aa4dd815SMatthias Ringwald return 0; 7863deb3ec6SMatthias Ringwald } 7873deb3ec6SMatthias Ringwald 788aa4dd815SMatthias Ringwald static int hfp_ag_run_for_audio_connection(hfp_connection_t * context){ 789aa4dd815SMatthias Ringwald if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || 790aa4dd815SMatthias Ringwald context->state > HFP_W2_DISCONNECT_SCO) return 0; 7913deb3ec6SMatthias Ringwald 792aa4dd815SMatthias Ringwald 793aa4dd815SMatthias Ringwald if (context->state == HFP_AUDIO_CONNECTION_ESTABLISHED && context->release_audio_connection){ 794aa4dd815SMatthias Ringwald context->state = HFP_W4_SCO_DISCONNECTED; 795aa4dd815SMatthias Ringwald context->release_audio_connection = 0; 796aa4dd815SMatthias Ringwald gap_disconnect(context->sco_handle); 797aa4dd815SMatthias Ringwald return 1; 798aa4dd815SMatthias Ringwald } 799aa4dd815SMatthias Ringwald 800aa4dd815SMatthias Ringwald if (context->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 801aa4dd815SMatthias Ringwald 802aa4dd815SMatthias Ringwald // run codecs exchange 803aa4dd815SMatthias Ringwald int done = codecs_exchange_state_machine(context); 804aa4dd815SMatthias Ringwald if (done) return done; 805aa4dd815SMatthias Ringwald // printf(" -> State machine: Audio Connection\n"); 806aa4dd815SMatthias Ringwald 807aa4dd815SMatthias Ringwald if (context->codecs_state != HFP_CODECS_EXCHANGED) return done; 808aa4dd815SMatthias Ringwald if (context->establish_audio_connection){ 809aa4dd815SMatthias Ringwald context->state = HFP_W4_SCO_CONNECTED; 810aa4dd815SMatthias Ringwald context->establish_audio_connection = 0; 811ce263fc8SMatthias Ringwald hfp_setup_synchronous_connection(context->con_handle, context->link_setting); 812aa4dd815SMatthias Ringwald return 1; 813aa4dd815SMatthias Ringwald } 814aa4dd815SMatthias Ringwald return 0; 815aa4dd815SMatthias Ringwald } 816aa4dd815SMatthias Ringwald 817aa4dd815SMatthias Ringwald static hfp_connection_t * hfp_ag_context_for_timer(timer_source_t * ts){ 818aa4dd815SMatthias Ringwald linked_list_iterator_t it; 819aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 820aa4dd815SMatthias Ringwald 821aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 822aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 823aa4dd815SMatthias Ringwald if ( &connection->hfp_timeout == ts) { 824aa4dd815SMatthias Ringwald return connection; 825aa4dd815SMatthias Ringwald } 826aa4dd815SMatthias Ringwald } 827aa4dd815SMatthias Ringwald return NULL; 828aa4dd815SMatthias Ringwald } 829aa4dd815SMatthias Ringwald 830aa4dd815SMatthias Ringwald static void hfp_timeout_handler(timer_source_t * timer){ 831aa4dd815SMatthias Ringwald hfp_connection_t * context = hfp_ag_context_for_timer(timer); 832aa4dd815SMatthias Ringwald if (!context) return; 833aa4dd815SMatthias Ringwald 834aa4dd815SMatthias Ringwald log_info("HFP start ring timeout, con handle 0x%02x", context->con_handle); 835aa4dd815SMatthias Ringwald context->ag_ring = 1; 836aa4dd815SMatthias Ringwald context->ag_send_clip = clip_type && context->clip_enabled; 837aa4dd815SMatthias Ringwald 838aa4dd815SMatthias Ringwald run_loop_set_timer(&context->hfp_timeout, 2000); // 5 seconds timeout 839aa4dd815SMatthias Ringwald run_loop_add_timer(&context->hfp_timeout); 840aa4dd815SMatthias Ringwald 841aa4dd815SMatthias Ringwald hfp_run_for_context(context); 842aa4dd815SMatthias Ringwald } 843aa4dd815SMatthias Ringwald 844aa4dd815SMatthias Ringwald static void hfp_timeout_start(hfp_connection_t * context){ 845aa4dd815SMatthias Ringwald run_loop_remove_timer(&context->hfp_timeout); 846aa4dd815SMatthias Ringwald run_loop_set_timer_handler(&context->hfp_timeout, hfp_timeout_handler); 847aa4dd815SMatthias Ringwald run_loop_set_timer(&context->hfp_timeout, 2000); // 5 seconds timeout 848aa4dd815SMatthias Ringwald run_loop_add_timer(&context->hfp_timeout); 849aa4dd815SMatthias Ringwald } 850aa4dd815SMatthias Ringwald 851aa4dd815SMatthias Ringwald static void hfp_timeout_stop(hfp_connection_t * context){ 852aa4dd815SMatthias Ringwald log_info("HFP stop ring timeout, con handle 0x%02x", context->con_handle); 853aa4dd815SMatthias Ringwald run_loop_remove_timer(&context->hfp_timeout); 854aa4dd815SMatthias Ringwald } 855aa4dd815SMatthias Ringwald 856aa4dd815SMatthias Ringwald // 857aa4dd815SMatthias Ringwald // transitition implementations for hfp_ag_call_state_machine 858aa4dd815SMatthias Ringwald // 859aa4dd815SMatthias Ringwald 860aa4dd815SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * context){ 861aa4dd815SMatthias Ringwald if (use_in_band_tone()){ 862aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING; 863aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(context->remote_addr); 864aa4dd815SMatthias Ringwald } else { 865ce263fc8SMatthias Ringwald hfp_timeout_start(context); 866ce263fc8SMatthias Ringwald context->ag_ring = 1; 867ce263fc8SMatthias Ringwald context->ag_send_clip = clip_type && context->clip_enabled; 868aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_RINGING; 869aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0); 870aa4dd815SMatthias Ringwald } 871aa4dd815SMatthias Ringwald } 872aa4dd815SMatthias Ringwald 873aa4dd815SMatthias Ringwald static void hfp_ag_hf_stop_ringing(hfp_connection_t * context){ 874aa4dd815SMatthias Ringwald context->ag_ring = 0; 875aa4dd815SMatthias Ringwald context->ag_send_clip = 0; 876aa4dd815SMatthias Ringwald hfp_timeout_stop(context); 877aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_STOP_RINGINIG, 0); 878aa4dd815SMatthias Ringwald } 879aa4dd815SMatthias Ringwald 880aa4dd815SMatthias Ringwald static void hfp_ag_trigger_incoming_call(void){ 881aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callsetup"); 882aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 883aa4dd815SMatthias Ringwald 884aa4dd815SMatthias Ringwald linked_list_iterator_t it; 885aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 886aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 887aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 888aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 889aa4dd815SMatthias Ringwald if (connection->call_state == HFP_CALL_IDLE){ 890aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 891aa4dd815SMatthias Ringwald hfp_ag_hf_start_ringing(connection); 892aa4dd815SMatthias Ringwald } 893aa4dd815SMatthias Ringwald if (connection->call_state == HFP_CALL_ACTIVE){ 894aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_W2_SEND_CALL_WAITING; 895aa4dd815SMatthias Ringwald } 896aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 897aa4dd815SMatthias Ringwald } 898aa4dd815SMatthias Ringwald } 899aa4dd815SMatthias Ringwald 900aa4dd815SMatthias Ringwald static void hfp_ag_transfer_callsetup_state(void){ 901aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callsetup"); 902aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 903aa4dd815SMatthias Ringwald 904aa4dd815SMatthias Ringwald linked_list_iterator_t it; 905aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 906aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 907aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 908aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 909aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 910aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 911aa4dd815SMatthias Ringwald } 912aa4dd815SMatthias Ringwald } 913aa4dd815SMatthias Ringwald 914aa4dd815SMatthias Ringwald static void hfp_ag_transfer_call_state(void){ 915aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("call"); 916aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 917aa4dd815SMatthias Ringwald 918aa4dd815SMatthias Ringwald linked_list_iterator_t it; 919aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 920aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 921aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 922aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 923aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 924aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 925aa4dd815SMatthias Ringwald } 926aa4dd815SMatthias Ringwald } 927aa4dd815SMatthias Ringwald 928aa4dd815SMatthias Ringwald static void hfp_ag_transfer_callheld_state(void){ 929aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callheld"); 930aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 931aa4dd815SMatthias Ringwald 932aa4dd815SMatthias Ringwald linked_list_iterator_t it; 933aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 934aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 935aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 936aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 937aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 938aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 939aa4dd815SMatthias Ringwald } 940aa4dd815SMatthias Ringwald } 941aa4dd815SMatthias Ringwald 942aa4dd815SMatthias Ringwald static void hfp_ag_hf_accept_call(hfp_connection_t * source){ 943aa4dd815SMatthias Ringwald 944aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 945aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 946aa4dd815SMatthias Ringwald 947aa4dd815SMatthias Ringwald linked_list_iterator_t it; 948aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 949aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 950aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 951aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING && 952aa4dd815SMatthias Ringwald connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue; 953aa4dd815SMatthias Ringwald 954aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 955aa4dd815SMatthias Ringwald if (connection == source){ 956aa4dd815SMatthias Ringwald connection->ok_pending = 1; 957aa4dd815SMatthias Ringwald 958aa4dd815SMatthias Ringwald if (use_in_band_tone()){ 959aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_ACTIVE; 960aa4dd815SMatthias Ringwald } else { 961aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; 962aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(connection->remote_addr); 963aa4dd815SMatthias Ringwald } 964aa4dd815SMatthias Ringwald 965aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 966aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 967aa4dd815SMatthias Ringwald 968aa4dd815SMatthias Ringwald } else { 969aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 970aa4dd815SMatthias Ringwald } 971aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 972aa4dd815SMatthias Ringwald } 973aa4dd815SMatthias Ringwald } 974aa4dd815SMatthias Ringwald 975aa4dd815SMatthias Ringwald static void hfp_ag_ag_accept_call(void){ 976aa4dd815SMatthias Ringwald 977aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 978aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 979aa4dd815SMatthias Ringwald 980aa4dd815SMatthias Ringwald linked_list_iterator_t it; 981aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 982aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 983aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 984aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING) continue; 985aa4dd815SMatthias Ringwald 986aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 987aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_TRIGGER_AUDIO_CONNECTION; 988aa4dd815SMatthias Ringwald 989aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 990aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 991aa4dd815SMatthias Ringwald 992aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 993aa4dd815SMatthias Ringwald break; // only single 994aa4dd815SMatthias Ringwald } 995aa4dd815SMatthias Ringwald } 996aa4dd815SMatthias Ringwald 997aa4dd815SMatthias Ringwald static void hfp_ag_trigger_reject_call(void){ 998aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 999aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1000aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1001aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1002aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1003aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING && 1004aa4dd815SMatthias Ringwald connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue; 1005aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 1006aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1007aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 1008aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1009aa4dd815SMatthias Ringwald } 1010aa4dd815SMatthias Ringwald } 1011aa4dd815SMatthias Ringwald 1012aa4dd815SMatthias Ringwald static void hfp_ag_trigger_terminate_call(void){ 1013aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 1014aa4dd815SMatthias Ringwald 1015aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1016aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1017aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1018aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1019aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 1020aa4dd815SMatthias Ringwald if (connection->call_state == HFP_CALL_IDLE) continue; 1021aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 1022aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 1023ce263fc8SMatthias Ringwald connection->release_audio_connection = 1; 1024aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1025aa4dd815SMatthias Ringwald } 1026aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CALL_TERMINATED, 0); 1027aa4dd815SMatthias Ringwald } 1028aa4dd815SMatthias Ringwald 1029aa4dd815SMatthias Ringwald static void hfp_ag_set_callsetup_state(hfp_callsetup_status_t state){ 1030aa4dd815SMatthias Ringwald hfp_ag_callsetup_state = state; 1031aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callsetup"); 1032aa4dd815SMatthias Ringwald if (!indicator){ 1033aa4dd815SMatthias Ringwald log_error("hfp_ag_set_callsetup_state: callsetup indicator is missing"); 1034aa4dd815SMatthias Ringwald }; 1035aa4dd815SMatthias Ringwald indicator->status = state; 1036aa4dd815SMatthias Ringwald } 1037aa4dd815SMatthias Ringwald 1038aa4dd815SMatthias Ringwald static void hfp_ag_set_callheld_state(hfp_callheld_status_t state){ 1039aa4dd815SMatthias Ringwald hfp_ag_callheld_state = state; 1040aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callheld"); 1041aa4dd815SMatthias Ringwald if (!indicator){ 1042aa4dd815SMatthias Ringwald log_error("hfp_ag_set_callheld_state: callheld indicator is missing"); 1043aa4dd815SMatthias Ringwald }; 1044aa4dd815SMatthias Ringwald indicator->status = state; 1045aa4dd815SMatthias Ringwald } 1046aa4dd815SMatthias Ringwald 1047aa4dd815SMatthias Ringwald static void hfp_ag_set_call_state(hfp_call_status_t state){ 1048aa4dd815SMatthias Ringwald hfp_ag_call_state = state; 1049aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call"); 1050aa4dd815SMatthias Ringwald if (!indicator){ 1051aa4dd815SMatthias Ringwald log_error("hfp_ag_set_call_state: call indicator is missing"); 1052aa4dd815SMatthias Ringwald }; 1053aa4dd815SMatthias Ringwald indicator->status = state; 1054aa4dd815SMatthias Ringwald } 1055aa4dd815SMatthias Ringwald 1056aa4dd815SMatthias Ringwald static void hfp_ag_stop_ringing(void){ 1057aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1058aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1059aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1060aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1061aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING && 1062aa4dd815SMatthias Ringwald connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue; 1063aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 1064aa4dd815SMatthias Ringwald } 1065aa4dd815SMatthias Ringwald } 1066aa4dd815SMatthias Ringwald 1067aa4dd815SMatthias Ringwald static hfp_connection_t * hfp_ag_connection_for_call_state(hfp_call_state_t call_state){ 1068aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1069aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1070aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1071aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1072aa4dd815SMatthias Ringwald if (connection->call_state == call_state) return connection; 1073aa4dd815SMatthias Ringwald } 1074aa4dd815SMatthias Ringwald return NULL; 1075aa4dd815SMatthias Ringwald } 1076aa4dd815SMatthias Ringwald 1077a5bdcda8SMatthias Ringwald static void hfp_ag_send_response_and_hold_state(hfp_response_and_hold_state_t state){ 1078ce263fc8SMatthias Ringwald linked_list_iterator_t it; 1079ce263fc8SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1080ce263fc8SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1081ce263fc8SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1082a5bdcda8SMatthias Ringwald connection->send_response_and_hold_status = state + 1; 1083ce263fc8SMatthias Ringwald } 1084ce263fc8SMatthias Ringwald } 1085ce263fc8SMatthias Ringwald 1086aa4dd815SMatthias Ringwald static int call_setup_state_machine(hfp_connection_t * connection){ 1087aa4dd815SMatthias Ringwald int indicator_index; 1088aa4dd815SMatthias Ringwald switch (connection->call_state){ 1089aa4dd815SMatthias Ringwald case HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING: 1090aa4dd815SMatthias Ringwald if (connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 1091aa4dd815SMatthias Ringwald // we got event: audio connection established 1092ce263fc8SMatthias Ringwald hfp_timeout_start(connection); 1093ce263fc8SMatthias Ringwald connection->ag_ring = 1; 1094ce263fc8SMatthias Ringwald connection->ag_send_clip = clip_type && connection->clip_enabled; 1095ce263fc8SMatthias Ringwald connection->call_state = HFP_CALL_RINGING; 1096aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_RINGING; 1097aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0); 1098aa4dd815SMatthias Ringwald break; 1099aa4dd815SMatthias Ringwald case HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE: 1100aa4dd815SMatthias Ringwald if (connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 1101aa4dd815SMatthias Ringwald // we got event: audio connection established 1102aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_ACTIVE; 1103aa4dd815SMatthias Ringwald break; 1104aa4dd815SMatthias Ringwald case HFP_CALL_W2_SEND_CALL_WAITING: 1105aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_W4_CHLD; 1106aa4dd815SMatthias Ringwald hfp_ag_send_call_waiting_notification(connection->rfcomm_cid); 1107aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callsetup"); 1108aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 1109aa4dd815SMatthias Ringwald break; 1110aa4dd815SMatthias Ringwald default: 1111aa4dd815SMatthias Ringwald break; 1112aa4dd815SMatthias Ringwald } 1113aa4dd815SMatthias Ringwald return 0; 1114aa4dd815SMatthias Ringwald } 1115aa4dd815SMatthias Ringwald // connection is used to identify originating HF 1116aa4dd815SMatthias Ringwald static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connection){ 1117aa4dd815SMatthias Ringwald int indicator_index; 1118*74386ee0SMatthias Ringwald 1119aa4dd815SMatthias Ringwald switch (event){ 1120aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL: 1121aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1122aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1123aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1124aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: 1125aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); 1126aa4dd815SMatthias Ringwald hfp_ag_trigger_incoming_call(); 1127aa4dd815SMatthias Ringwald printf("AG rings\n"); 1128aa4dd815SMatthias Ringwald break; 1129aa4dd815SMatthias Ringwald default: 11303deb3ec6SMatthias Ringwald break; 11313deb3ec6SMatthias Ringwald } 11323deb3ec6SMatthias Ringwald break; 1133aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1134aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1135aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: 1136aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); 1137aa4dd815SMatthias Ringwald hfp_ag_trigger_incoming_call(); 1138aa4dd815SMatthias Ringwald printf("AG call waiting\n"); 1139aa4dd815SMatthias Ringwald break; 1140aa4dd815SMatthias Ringwald default: 11413deb3ec6SMatthias Ringwald break; 11423deb3ec6SMatthias Ringwald } 11433deb3ec6SMatthias Ringwald break; 1144aa4dd815SMatthias Ringwald } 1145aa4dd815SMatthias Ringwald break; 1146aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 1147aa4dd815SMatthias Ringwald // clear CLIP 1148aa4dd815SMatthias Ringwald clip_type = 0; 1149aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1150aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1151aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1152aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1153aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1154aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1155aa4dd815SMatthias Ringwald hfp_ag_ag_accept_call(); 1156aa4dd815SMatthias Ringwald printf("AG answers call, accept call by GSM\n"); 1157aa4dd815SMatthias Ringwald break; 1158aa4dd815SMatthias Ringwald default: 11593deb3ec6SMatthias Ringwald break; 11603deb3ec6SMatthias Ringwald } 1161aa4dd815SMatthias Ringwald break; 1162aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1163aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1164aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1165aa4dd815SMatthias Ringwald printf("AG: current call is placed on hold, incoming call gets active\n"); 1166aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1167aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1168ce263fc8SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1169ce263fc8SMatthias Ringwald hfp_ag_transfer_callheld_state(); 1170aa4dd815SMatthias Ringwald break; 1171aa4dd815SMatthias Ringwald default: 1172aa4dd815SMatthias Ringwald break; 1173aa4dd815SMatthias Ringwald } 1174aa4dd815SMatthias Ringwald break; 1175aa4dd815SMatthias Ringwald } 1176aa4dd815SMatthias Ringwald break; 1177ce263fc8SMatthias Ringwald 1178ce263fc8SMatthias Ringwald case HFP_AG_HELD_CALL_JOINED_BY_AG: 1179ce263fc8SMatthias Ringwald switch (hfp_ag_call_state){ 1180ce263fc8SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1181ce263fc8SMatthias Ringwald switch (hfp_ag_callheld_state){ 1182ce263fc8SMatthias Ringwald case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED: 1183ce263fc8SMatthias Ringwald printf("AG: joining held call with active call\n"); 1184ce263fc8SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1185ce263fc8SMatthias Ringwald hfp_ag_transfer_callheld_state(); 1186a5bdcda8SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0); 1187ce263fc8SMatthias Ringwald break; 1188ce263fc8SMatthias Ringwald default: 1189ce263fc8SMatthias Ringwald break; 1190ce263fc8SMatthias Ringwald } 1191ce263fc8SMatthias Ringwald break; 1192ce263fc8SMatthias Ringwald default: 1193ce263fc8SMatthias Ringwald break; 1194ce263fc8SMatthias Ringwald } 1195ce263fc8SMatthias Ringwald break; 1196ce263fc8SMatthias Ringwald 1197aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 1198aa4dd815SMatthias Ringwald // clear CLIP 1199aa4dd815SMatthias Ringwald clip_type = 0; 1200aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1201aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1202aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1203aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1204aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1205aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1206aa4dd815SMatthias Ringwald hfp_ag_hf_accept_call(connection); 1207aa4dd815SMatthias Ringwald printf("HF answers call, accept call by GSM\n"); 1208ce263fc8SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_CMD_CALL_ANSWERED, 0); 1209aa4dd815SMatthias Ringwald break; 1210aa4dd815SMatthias Ringwald default: 1211aa4dd815SMatthias Ringwald break; 1212aa4dd815SMatthias Ringwald } 12133deb3ec6SMatthias Ringwald break; 12143deb3ec6SMatthias Ringwald default: 12153deb3ec6SMatthias Ringwald break; 12163deb3ec6SMatthias Ringwald } 12173deb3ec6SMatthias Ringwald break; 12183deb3ec6SMatthias Ringwald 1219ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: 1220ce263fc8SMatthias Ringwald // clear CLIP 1221ce263fc8SMatthias Ringwald clip_type = 0; 1222ce263fc8SMatthias Ringwald switch (hfp_ag_call_state){ 1223ce263fc8SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1224ce263fc8SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1225ce263fc8SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1226ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_active = 1; 1227ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD; 1228a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1229ce263fc8SMatthias Ringwald // as with regualr call 1230ce263fc8SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1231ce263fc8SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1232ce263fc8SMatthias Ringwald hfp_ag_ag_accept_call(); 1233ce263fc8SMatthias Ringwald printf("AG response and hold - hold by AG\n"); 1234ce263fc8SMatthias Ringwald break; 1235ce263fc8SMatthias Ringwald default: 1236ce263fc8SMatthias Ringwald break; 1237ce263fc8SMatthias Ringwald } 1238ce263fc8SMatthias Ringwald break; 1239ce263fc8SMatthias Ringwald default: 1240ce263fc8SMatthias Ringwald break; 1241ce263fc8SMatthias Ringwald } 1242ce263fc8SMatthias Ringwald break; 1243ce263fc8SMatthias Ringwald 1244ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: 1245ce263fc8SMatthias Ringwald // clear CLIP 1246ce263fc8SMatthias Ringwald clip_type = 0; 1247ce263fc8SMatthias Ringwald switch (hfp_ag_call_state){ 1248ce263fc8SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1249ce263fc8SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1250ce263fc8SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1251ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_active = 1; 1252ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD; 1253a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1254ce263fc8SMatthias Ringwald // as with regualr call 1255ce263fc8SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1256ce263fc8SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1257ce263fc8SMatthias Ringwald hfp_ag_hf_accept_call(connection); 1258ce263fc8SMatthias Ringwald printf("AG response and hold - hold by HF\n"); 1259ce263fc8SMatthias Ringwald break; 1260ce263fc8SMatthias Ringwald default: 1261ce263fc8SMatthias Ringwald break; 1262ce263fc8SMatthias Ringwald } 1263ce263fc8SMatthias Ringwald break; 1264ce263fc8SMatthias Ringwald default: 1265ce263fc8SMatthias Ringwald break; 1266ce263fc8SMatthias Ringwald } 1267ce263fc8SMatthias Ringwald break; 1268ce263fc8SMatthias Ringwald 1269ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG: 1270ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: 1271ce263fc8SMatthias Ringwald if (!hfp_ag_response_and_hold_active) break; 1272ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break; 1273a5bdcda8SMatthias Ringwald hfp_ag_response_and_hold_active = 0; 1274ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED; 1275a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1276ce263fc8SMatthias Ringwald printf("Held Call accepted and active\n"); 1277ce263fc8SMatthias Ringwald break; 1278ce263fc8SMatthias Ringwald 1279ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG: 1280ce263fc8SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: 1281ce263fc8SMatthias Ringwald if (!hfp_ag_response_and_hold_active) break; 1282ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break; 1283a5bdcda8SMatthias Ringwald hfp_ag_response_and_hold_active = 0; 1284ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED; 1285a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1286ce263fc8SMatthias Ringwald // from terminate by ag 1287ce263fc8SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1288ce263fc8SMatthias Ringwald hfp_ag_trigger_terminate_call(); 1289ce263fc8SMatthias Ringwald break; 1290ce263fc8SMatthias Ringwald 1291aa4dd815SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_HF: 1292aa4dd815SMatthias Ringwald // clear CLIP 1293aa4dd815SMatthias Ringwald clip_type = 0; 1294aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1295aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1296aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1297aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1298aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1299aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1300aa4dd815SMatthias Ringwald hfp_ag_trigger_reject_call(); 1301aa4dd815SMatthias Ringwald printf("HF Rejected Incoming call, AG terminate call\n"); 1302aa4dd815SMatthias Ringwald break; 1303aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: 1304aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 1305aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1306aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1307aa4dd815SMatthias Ringwald printf("AG terminate outgoing call process\n"); 1308aa4dd815SMatthias Ringwald default: 1309aa4dd815SMatthias Ringwald break; 1310aa4dd815SMatthias Ringwald } 1311aa4dd815SMatthias Ringwald break; 1312aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1313aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1314aa4dd815SMatthias Ringwald hfp_ag_transfer_call_state(); 1315484fb8b6SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 1316aa4dd815SMatthias Ringwald printf("AG terminate call\n"); 1317aa4dd815SMatthias Ringwald break; 1318aa4dd815SMatthias Ringwald } 1319aa4dd815SMatthias Ringwald break; 13203deb3ec6SMatthias Ringwald 1321aa4dd815SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_AG: 1322aa4dd815SMatthias Ringwald // clear CLIP 1323aa4dd815SMatthias Ringwald clip_type = 0; 1324aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1325aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1326aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1327aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1328aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1329aa4dd815SMatthias Ringwald hfp_ag_trigger_reject_call(); 1330aa4dd815SMatthias Ringwald printf("AG Rejected Incoming call, AG terminate call\n"); 1331aa4dd815SMatthias Ringwald break; 1332aa4dd815SMatthias Ringwald default: 1333aa4dd815SMatthias Ringwald break; 13343deb3ec6SMatthias Ringwald } 1335aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1336aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1337aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1338aa4dd815SMatthias Ringwald hfp_ag_trigger_terminate_call(); 1339aa4dd815SMatthias Ringwald printf("AG terminate call\n"); 1340aa4dd815SMatthias Ringwald break; 1341aa4dd815SMatthias Ringwald default: 13423deb3ec6SMatthias Ringwald break; 13433deb3ec6SMatthias Ringwald } 13443deb3ec6SMatthias Ringwald break; 1345aa4dd815SMatthias Ringwald case HFP_AG_CALL_DROPPED: 1346aa4dd815SMatthias Ringwald // clear CLIP 1347aa4dd815SMatthias Ringwald clip_type = 0; 1348aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1349aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1350aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1351aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1352aa4dd815SMatthias Ringwald hfp_ag_stop_ringing(); 1353aa4dd815SMatthias Ringwald printf("Incoming call interrupted\n"); 1354aa4dd815SMatthias Ringwald break; 1355aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: 1356aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 1357aa4dd815SMatthias Ringwald printf("Outgoing call interrupted\n"); 1358aa4dd815SMatthias Ringwald printf("AG notify call dropped\n"); 1359aa4dd815SMatthias Ringwald break; 1360aa4dd815SMatthias Ringwald default: 13613deb3ec6SMatthias Ringwald break; 13623deb3ec6SMatthias Ringwald } 1363aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1364aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1365aa4dd815SMatthias Ringwald break; 1366aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1367ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_active) { 1368ce263fc8SMatthias Ringwald hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED; 1369a5bdcda8SMatthias Ringwald hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state); 1370ce263fc8SMatthias Ringwald } 1371aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1372aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1373aa4dd815SMatthias Ringwald hfp_ag_trigger_terminate_call(); 1374aa4dd815SMatthias Ringwald printf("AG notify call dropped\n"); 1375aa4dd815SMatthias Ringwald break; 1376aa4dd815SMatthias Ringwald default: 1377aa4dd815SMatthias Ringwald break; 1378aa4dd815SMatthias Ringwald } 1379aa4dd815SMatthias Ringwald break; 1380aa4dd815SMatthias Ringwald 1381aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_INITIATED: 1382*74386ee0SMatthias Ringwald hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_INITIATED); 1383aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_INITIATED; 1384*74386ee0SMatthias Ringwald 1385aa4dd815SMatthias Ringwald hfp_emit_string_event(hfp_callback, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, (const char *) &connection->line_buffer[3]); 1386aa4dd815SMatthias Ringwald break; 1387aa4dd815SMatthias Ringwald 1388aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_REDIAL_INITIATED: 1389*74386ee0SMatthias Ringwald hfp_gsm_handle_event(HFP_AG_OUTGOING_REDIAL_INITIATED); 1390aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_INITIATED; 1391*74386ee0SMatthias Ringwald 1392aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_REDIAL_LAST_NUMBER, 0); 1393aa4dd815SMatthias Ringwald break; 1394aa4dd815SMatthias Ringwald 1395aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_REJECTED: 1396*74386ee0SMatthias Ringwald hfp_gsm_handle_event(HFP_AG_OUTGOING_CALL_REJECTED); 1397aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); 1398aa4dd815SMatthias Ringwald if (!connection){ 1399aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); 1400aa4dd815SMatthias Ringwald break; 1401aa4dd815SMatthias Ringwald } 1402aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 1403aa4dd815SMatthias Ringwald connection->send_error = 1; 1404aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1405aa4dd815SMatthias Ringwald break; 1406aa4dd815SMatthias Ringwald 1407aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ACCEPTED: 1408*74386ee0SMatthias Ringwald // hfp_gsm_handle_event(); 1409aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); 1410aa4dd815SMatthias Ringwald if (!connection){ 1411aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); 1412aa4dd815SMatthias Ringwald break; 1413aa4dd815SMatthias Ringwald } 1414aa4dd815SMatthias Ringwald 1415aa4dd815SMatthias Ringwald connection->ok_pending = 1; 1416aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_DIALING; 1417aa4dd815SMatthias Ringwald 1418aa4dd815SMatthias Ringwald // trigger callsetup to be 1419aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE); 1420aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callsetup"); 1421aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 1422aa4dd815SMatthias Ringwald 1423aa4dd815SMatthias Ringwald // put current call on hold if active 1424aa4dd815SMatthias Ringwald if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 1425aa4dd815SMatthias Ringwald printf("AG putting current call on hold for new outgoing call\n"); 1426aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS); 1427aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callheld"); 1428aa4dd815SMatthias Ringwald hfp_ag_transfer_ag_indicators_status_cmd(connection->rfcomm_cid, &hfp_ag_indicators[indicator_index]); 1429aa4dd815SMatthias Ringwald } 1430aa4dd815SMatthias Ringwald 1431aa4dd815SMatthias Ringwald // start audio if needed 1432aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(connection->remote_addr); 1433aa4dd815SMatthias Ringwald break; 1434aa4dd815SMatthias Ringwald 1435aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_RINGING: 1436*74386ee0SMatthias Ringwald // hfp_gsm_handle_event(); 1437aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); 1438aa4dd815SMatthias Ringwald if (!connection){ 1439aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection in dialing state"); 1440aa4dd815SMatthias Ringwald break; 1441aa4dd815SMatthias Ringwald } 1442aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_RINGING; 1443aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE); 1444aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1445aa4dd815SMatthias Ringwald break; 1446aa4dd815SMatthias Ringwald 1447aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ESTABLISHED: 1448*74386ee0SMatthias Ringwald // hfp_gsm_handle_event(); 1449aa4dd815SMatthias Ringwald // get outgoing call 1450aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING); 1451aa4dd815SMatthias Ringwald if (!connection){ 1452aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); 1453aa4dd815SMatthias Ringwald } 1454aa4dd815SMatthias Ringwald if (!connection){ 1455aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection"); 1456aa4dd815SMatthias Ringwald break; 1457aa4dd815SMatthias Ringwald } 1458aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_ACTIVE; 1459aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1460aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1461aa4dd815SMatthias Ringwald hfp_ag_transfer_call_state(); 1462aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1463aa4dd815SMatthias Ringwald if (hfp_ag_callheld_state == HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS){ 1464aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1465aa4dd815SMatthias Ringwald hfp_ag_transfer_callheld_state(); 14663deb3ec6SMatthias Ringwald } 14673deb3ec6SMatthias Ringwald break; 1468ce263fc8SMatthias Ringwald 14693deb3ec6SMatthias Ringwald default: 14703deb3ec6SMatthias Ringwald break; 14713deb3ec6SMatthias Ringwald } 14723deb3ec6SMatthias Ringwald } 14733deb3ec6SMatthias Ringwald 14743deb3ec6SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t *context){ 14753deb3ec6SMatthias Ringwald if (!context) return; 14763deb3ec6SMatthias Ringwald if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; 14773deb3ec6SMatthias Ringwald 1478ce263fc8SMatthias Ringwald if (context->send_status_of_current_calls){ 1479ce263fc8SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL, 0); 1480ce263fc8SMatthias Ringwald return; 1481ce263fc8SMatthias Ringwald } 1482ce263fc8SMatthias Ringwald 1483aa4dd815SMatthias Ringwald if (context->command == HFP_CMD_UNKNOWN){ 1484aa4dd815SMatthias Ringwald context->ok_pending = 0; 1485aa4dd815SMatthias Ringwald context->send_error = 0; 14863deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 1487aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 1488aa4dd815SMatthias Ringwald return; 1489aa4dd815SMatthias Ringwald } 1490aa4dd815SMatthias Ringwald 14913deb3ec6SMatthias Ringwald if (context->send_error){ 14923deb3ec6SMatthias Ringwald context->send_error = 0; 14933deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 1494aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 1495aa4dd815SMatthias Ringwald return; 1496aa4dd815SMatthias Ringwald } 1497aa4dd815SMatthias Ringwald 1498ce263fc8SMatthias Ringwald // note: before update AG indicators and ok_pending 1499ce263fc8SMatthias Ringwald if (context->send_response_and_hold_status){ 1500a5bdcda8SMatthias Ringwald int status = context->send_response_and_hold_status - 1; 1501ce263fc8SMatthias Ringwald context->send_response_and_hold_status = 0; 1502a5bdcda8SMatthias Ringwald hfp_ag_set_response_and_hold(context->rfcomm_cid, status); 1503ce263fc8SMatthias Ringwald return; 1504ce263fc8SMatthias Ringwald } 1505ce263fc8SMatthias Ringwald 1506ce263fc8SMatthias Ringwald if (context->ok_pending){ 1507ce263fc8SMatthias Ringwald context->ok_pending = 0; 1508ce263fc8SMatthias Ringwald context->command = HFP_CMD_NONE; 1509ce263fc8SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 1510ce263fc8SMatthias Ringwald return; 1511ce263fc8SMatthias Ringwald } 1512ce263fc8SMatthias Ringwald 1513aa4dd815SMatthias Ringwald // update AG indicators 1514aa4dd815SMatthias Ringwald if (context->ag_indicators_status_update_bitmap){ 1515aa4dd815SMatthias Ringwald int i; 1516aa4dd815SMatthias Ringwald for (i=0;i<context->ag_indicators_nr;i++){ 1517aa4dd815SMatthias Ringwald if (get_bit(context->ag_indicators_status_update_bitmap, i)){ 1518aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, i, 0); 1519ce263fc8SMatthias Ringwald if (!context->enable_status_update_for_ag_indicators) { 1520ce263fc8SMatthias Ringwald log_info("+CMER:3,0,0,0 - not sending update for '%s'", hfp_ag_indicators[i].name); 1521ce263fc8SMatthias Ringwald break; 1522ce263fc8SMatthias Ringwald } 1523aa4dd815SMatthias Ringwald hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, &hfp_ag_indicators[i]); 1524aa4dd815SMatthias Ringwald return; 1525aa4dd815SMatthias Ringwald } 1526aa4dd815SMatthias Ringwald } 1527aa4dd815SMatthias Ringwald } 1528aa4dd815SMatthias Ringwald 1529aa4dd815SMatthias Ringwald if (context->ag_ring){ 1530aa4dd815SMatthias Ringwald context->ag_ring = 0; 1531aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1532aa4dd815SMatthias Ringwald hfp_ag_ring(context->rfcomm_cid); 1533aa4dd815SMatthias Ringwald return; 1534aa4dd815SMatthias Ringwald } 1535aa4dd815SMatthias Ringwald 1536aa4dd815SMatthias Ringwald if (context->ag_send_clip){ 1537aa4dd815SMatthias Ringwald context->ag_send_clip = 0; 1538aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1539aa4dd815SMatthias Ringwald hfp_ag_send_clip(context->rfcomm_cid); 1540aa4dd815SMatthias Ringwald return; 1541aa4dd815SMatthias Ringwald } 1542aa4dd815SMatthias Ringwald 1543aa4dd815SMatthias Ringwald if (context->send_phone_number_for_voice_tag){ 1544aa4dd815SMatthias Ringwald context->send_phone_number_for_voice_tag = 0; 1545aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1546aa4dd815SMatthias Ringwald context->ok_pending = 1; 1547c1797c7dSMatthias Ringwald hfp_ag_send_phone_number_for_voice_tag_cmd(context->rfcomm_cid); 1548aa4dd815SMatthias Ringwald return; 1549aa4dd815SMatthias Ringwald } 1550aa4dd815SMatthias Ringwald 1551ce263fc8SMatthias Ringwald if (context->send_subscriber_number){ 1552ce263fc8SMatthias Ringwald if (context->next_subscriber_number_to_send < subscriber_numbers_count){ 1553ce263fc8SMatthias Ringwald hfp_phone_number_t phone = subscriber_numbers[context->next_subscriber_number_to_send++]; 1554ce263fc8SMatthias Ringwald hfp_send_subscriber_number_cmd(context->rfcomm_cid, phone.type, phone.number); 1555ce263fc8SMatthias Ringwald } else { 1556ce263fc8SMatthias Ringwald context->send_subscriber_number = 0; 1557ce263fc8SMatthias Ringwald context->next_subscriber_number_to_send = 0; 1558ce263fc8SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 1559ce263fc8SMatthias Ringwald } 1560ce263fc8SMatthias Ringwald context->command = HFP_CMD_NONE; 1561ce263fc8SMatthias Ringwald } 1562ce263fc8SMatthias Ringwald 1563aa4dd815SMatthias Ringwald if (context->send_microphone_gain){ 1564aa4dd815SMatthias Ringwald context->send_microphone_gain = 0; 1565aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1566aa4dd815SMatthias Ringwald hfp_ag_set_microphone_gain_cmd(context->rfcomm_cid, context->microphone_gain); 1567aa4dd815SMatthias Ringwald return; 1568aa4dd815SMatthias Ringwald } 1569aa4dd815SMatthias Ringwald 1570aa4dd815SMatthias Ringwald if (context->send_speaker_gain){ 1571aa4dd815SMatthias Ringwald context->send_speaker_gain = 0; 1572aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1573aa4dd815SMatthias Ringwald hfp_ag_set_speaker_gain_cmd(context->rfcomm_cid, context->speaker_gain); 15743deb3ec6SMatthias Ringwald return; 15753deb3ec6SMatthias Ringwald } 15763deb3ec6SMatthias Ringwald 1577ce263fc8SMatthias Ringwald if (context->send_ag_status_indicators){ 1578ce263fc8SMatthias Ringwald context->send_ag_status_indicators = 0; 1579ad902e3dSMatthias Ringwald hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); 1580ce263fc8SMatthias Ringwald return; 1581ce263fc8SMatthias Ringwald } 1582ce263fc8SMatthias Ringwald 15833deb3ec6SMatthias Ringwald int done = hfp_ag_run_for_context_service_level_connection(context); 1584aa4dd815SMatthias Ringwald if (!done){ 15853deb3ec6SMatthias Ringwald done = hfp_ag_run_for_context_service_level_connection_queries(context); 15863deb3ec6SMatthias Ringwald } 15873deb3ec6SMatthias Ringwald 1588aa4dd815SMatthias Ringwald if (!done){ 1589aa4dd815SMatthias Ringwald done = call_setup_state_machine(context); 1590aa4dd815SMatthias Ringwald } 1591aa4dd815SMatthias Ringwald 1592aa4dd815SMatthias Ringwald if (!done){ 1593aa4dd815SMatthias Ringwald done = hfp_ag_run_for_audio_connection(context); 1594aa4dd815SMatthias Ringwald } 15953deb3ec6SMatthias Ringwald 15963deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_NONE && !done){ 1597aa4dd815SMatthias Ringwald // log_info("context->command == HFP_CMD_NONE"); 15983deb3ec6SMatthias Ringwald switch(context->state){ 15993deb3ec6SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM: 16003deb3ec6SMatthias Ringwald context->state = HFP_W4_RFCOMM_DISCONNECTED; 16013deb3ec6SMatthias Ringwald rfcomm_disconnect_internal(context->rfcomm_cid); 16023deb3ec6SMatthias Ringwald break; 16033deb3ec6SMatthias Ringwald default: 16043deb3ec6SMatthias Ringwald break; 16053deb3ec6SMatthias Ringwald } 16063deb3ec6SMatthias Ringwald } 16073deb3ec6SMatthias Ringwald if (done){ 16083deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 16093deb3ec6SMatthias Ringwald } 16103deb3ec6SMatthias Ringwald } 1611ce263fc8SMatthias Ringwald static hfp_generic_status_indicator_t *get_hf_indicator_by_number(int number){ 1612ce263fc8SMatthias Ringwald int i; 1613ce263fc8SMatthias Ringwald for (i=0;i< get_hfp_generic_status_indicators_nr();i++){ 1614ce263fc8SMatthias Ringwald hfp_generic_status_indicator_t * indicator = &get_hfp_generic_status_indicators()[i]; 1615ce263fc8SMatthias Ringwald if (indicator->uuid == number){ 1616ce263fc8SMatthias Ringwald return indicator; 1617ce263fc8SMatthias Ringwald } 1618ce263fc8SMatthias Ringwald } 1619ce263fc8SMatthias Ringwald return NULL; 1620ce263fc8SMatthias Ringwald } 16213deb3ec6SMatthias Ringwald 1622aa4dd815SMatthias Ringwald static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 16233deb3ec6SMatthias Ringwald hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel); 16243deb3ec6SMatthias Ringwald if (!context) return; 16251e35c04dSMatthias Ringwald 16261e35c04dSMatthias Ringwald char last_char = packet[size-1]; 16271e35c04dSMatthias Ringwald packet[size-1] = 0; 16281e35c04dSMatthias Ringwald log_info("HFP_RX %s", packet); 16291e35c04dSMatthias Ringwald packet[size-1] = last_char; 16301e35c04dSMatthias Ringwald 16313deb3ec6SMatthias Ringwald int pos; 16323deb3ec6SMatthias Ringwald for (pos = 0; pos < size ; pos++){ 1633aa4dd815SMatthias Ringwald hfp_parse(context, packet[pos], 0); 1634aa4dd815SMatthias Ringwald } 1635ce263fc8SMatthias Ringwald hfp_generic_status_indicator_t * indicator; 1636ce263fc8SMatthias Ringwald int value; 1637aa4dd815SMatthias Ringwald switch(context->command){ 1638ce263fc8SMatthias Ringwald case HFP_CMD_RESPONSE_AND_HOLD_QUERY: 1639ce263fc8SMatthias Ringwald if (hfp_ag_response_and_hold_active){ 1640a5bdcda8SMatthias Ringwald context->send_response_and_hold_status = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD + 1; 1641ce263fc8SMatthias Ringwald } 1642ce263fc8SMatthias Ringwald context->ok_pending = 1; 1643ce263fc8SMatthias Ringwald break; 1644ce263fc8SMatthias Ringwald case HFP_CMD_RESPONSE_AND_HOLD_COMMAND: 1645ce263fc8SMatthias Ringwald value = atoi((char *)&context->line_buffer[0]); 1646ce263fc8SMatthias Ringwald printf("HF Response and Hold: %u\n", value); 1647ce263fc8SMatthias Ringwald switch(value){ 1648ce263fc8SMatthias Ringwald case HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD: 1649ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, context); 1650ce263fc8SMatthias Ringwald break; 1651ce263fc8SMatthias Ringwald case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED: 1652ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF, context); 1653ce263fc8SMatthias Ringwald break; 1654ce263fc8SMatthias Ringwald case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED: 1655ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF, context); 1656ce263fc8SMatthias Ringwald break; 1657ce263fc8SMatthias Ringwald default: 1658ce263fc8SMatthias Ringwald break; 1659ce263fc8SMatthias Ringwald } 1660ce263fc8SMatthias Ringwald context->ok_pending = 1; 1661ce263fc8SMatthias Ringwald break; 1662ce263fc8SMatthias Ringwald case HFP_CMD_HF_INDICATOR_STATUS: 1663ce263fc8SMatthias Ringwald context->command = HFP_CMD_NONE; 1664ce263fc8SMatthias Ringwald // find indicator by assigned number 1665ce263fc8SMatthias Ringwald indicator = get_hf_indicator_by_number(context->parser_indicator_index); 1666ce263fc8SMatthias Ringwald if (!indicator){ 1667ce263fc8SMatthias Ringwald context->send_error = 1; 1668ce263fc8SMatthias Ringwald break; 1669ce263fc8SMatthias Ringwald } 1670ce263fc8SMatthias Ringwald value = atoi((char *)&context->line_buffer[0]); 1671ce263fc8SMatthias Ringwald switch (indicator->uuid){ 1672ce263fc8SMatthias Ringwald case 1: // enhanced security 1673ce263fc8SMatthias Ringwald if (value > 1) { 1674ce263fc8SMatthias Ringwald context->send_error = 1; 1675ce263fc8SMatthias Ringwald return; 1676ce263fc8SMatthias Ringwald } 1677ce263fc8SMatthias Ringwald printf("HF Indicator 'enhanced security' set to %u\n", value); 1678ce263fc8SMatthias Ringwald break; 1679ce263fc8SMatthias Ringwald case 2: // battery level 1680ce263fc8SMatthias Ringwald if (value > 100){ 1681ce263fc8SMatthias Ringwald context->send_error = 1; 1682ce263fc8SMatthias Ringwald return; 1683ce263fc8SMatthias Ringwald } 1684ce263fc8SMatthias Ringwald printf("HF Indicator 'battery' set to %u\n", value); 1685ce263fc8SMatthias Ringwald break; 1686ce263fc8SMatthias Ringwald default: 1687ce263fc8SMatthias Ringwald printf("HF Indicator unknown set to %u\n", value); 1688ce263fc8SMatthias Ringwald break; 1689ce263fc8SMatthias Ringwald } 1690ce263fc8SMatthias Ringwald context->ok_pending = 1; 1691ce263fc8SMatthias Ringwald break; 1692ce263fc8SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: 1693ce263fc8SMatthias Ringwald // expected by SLC state machine 1694ce263fc8SMatthias Ringwald if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break; 1695ad902e3dSMatthias Ringwald context->send_ag_indicators_segment = 0; 1696ce263fc8SMatthias Ringwald context->send_ag_status_indicators = 1; 1697ce263fc8SMatthias Ringwald break; 1698ce263fc8SMatthias Ringwald case HFP_CMD_LIST_CURRENT_CALLS: 1699ce263fc8SMatthias Ringwald context->command = HFP_CMD_NONE; 1700ce263fc8SMatthias Ringwald context->send_status_of_current_calls = 1; 1701ce263fc8SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_TRANSMIT_STATUS_OF_CURRENT_CALL, 0); 1702ce263fc8SMatthias Ringwald break; 1703ce263fc8SMatthias Ringwald case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION: 1704ce263fc8SMatthias Ringwald if (subscriber_numbers_count == 0){ 1705ce263fc8SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 1706ce263fc8SMatthias Ringwald break; 1707ce263fc8SMatthias Ringwald } 1708ce263fc8SMatthias Ringwald context->next_subscriber_number_to_send = 0; 1709ce263fc8SMatthias Ringwald context->send_subscriber_number = 1; 1710ce263fc8SMatthias Ringwald break; 1711c1797c7dSMatthias Ringwald case HFP_CMD_TRANSMIT_DTMF_CODES: 1712c1797c7dSMatthias Ringwald context->command = HFP_CMD_NONE; 1713c1797c7dSMatthias Ringwald hfp_emit_string_event(hfp_callback, HFP_SUBEVENT_TRANSMIT_DTMF_CODES, (const char *) &context->line_buffer[0]); 1714c1797c7dSMatthias Ringwald break; 1715aa4dd815SMatthias Ringwald case HFP_CMD_HF_REQUEST_PHONE_NUMBER: 1716c1797c7dSMatthias Ringwald context->command = HFP_CMD_NONE; 1717aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG, 0); 1718aa4dd815SMatthias Ringwald break; 1719aa4dd815SMatthias Ringwald case HFP_CMD_TURN_OFF_EC_AND_NR: 1720c1797c7dSMatthias Ringwald context->command = HFP_CMD_NONE; 1721aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION)){ 1722aa4dd815SMatthias Ringwald context->ok_pending = 1; 1723aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION, context->ag_echo_and_noise_reduction); 1724aa4dd815SMatthias Ringwald printf("AG: EC/NR = %u\n", context->ag_echo_and_noise_reduction); 1725aa4dd815SMatthias Ringwald } else { 1726aa4dd815SMatthias Ringwald context->send_error = 1; 1727aa4dd815SMatthias Ringwald } 1728aa4dd815SMatthias Ringwald break; 1729aa4dd815SMatthias Ringwald case HFP_CMD_CALL_ANSWERED: 1730aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1731aa4dd815SMatthias Ringwald printf("HFP: ATA\n"); 1732aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, context); 1733aa4dd815SMatthias Ringwald break; 1734aa4dd815SMatthias Ringwald case HFP_CMD_HANG_UP_CALL: 1735aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1736aa4dd815SMatthias Ringwald context->ok_pending = 1; 1737aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_HF, context); 1738aa4dd815SMatthias Ringwald break; 1739aa4dd815SMatthias Ringwald case HFP_CMD_CALL_HOLD: { 1740aa4dd815SMatthias Ringwald // TODO: fully implement this 1741aa4dd815SMatthias Ringwald log_error("HFP: unhandled call hold type %c", context->line_buffer[0]); 1742aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 1743aa4dd815SMatthias Ringwald int callheld_indicator_index = get_ag_indicator_index_for_name("callheld"); 1744aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 1745aa4dd815SMatthias Ringwald switch (context->line_buffer[0]){ 1746aa4dd815SMatthias Ringwald case '0': 1747aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1748aa4dd815SMatthias Ringwald context->ok_pending = 1; 1749aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1750aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1751aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1752aa4dd815SMatthias Ringwald printf("AG: Call Waiting, User Busy\n"); 1753aa4dd815SMatthias Ringwald break; 1754aa4dd815SMatthias Ringwald case '1': 1755aa4dd815SMatthias Ringwald // Releases all active calls (if any exist) and accepts the other (held or waiting) call. 1756aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1757aa4dd815SMatthias Ringwald context->ok_pending = 1; 1758aa4dd815SMatthias Ringwald if (hfp_ag_callsetup_state != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 1759aa4dd815SMatthias Ringwald printf("AG: Call Dropped, Accept new call\n"); 1760aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1761aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1762aa4dd815SMatthias Ringwald } else { 1763aa4dd815SMatthias Ringwald printf("AG: Call Dropped, Resume held call\n"); 1764aa4dd815SMatthias Ringwald } 1765aa4dd815SMatthias Ringwald if (hfp_ag_callheld_state != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 1766aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1767aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1768aa4dd815SMatthias Ringwald } 1769aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1770aa4dd815SMatthias Ringwald break; 1771aa4dd815SMatthias Ringwald case '2': 1772aa4dd815SMatthias Ringwald // Places all active calls (if any exist) on hold and accepts the other (held or waiting) call. 1773aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1774aa4dd815SMatthias Ringwald context->ok_pending = 1; 1775aa4dd815SMatthias Ringwald // only update if callsetup changed 1776aa4dd815SMatthias Ringwald if (hfp_ag_callsetup_state != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 1777aa4dd815SMatthias Ringwald printf("AG: Call on Hold, Accept new call\n"); 1778aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1779aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1780aa4dd815SMatthias Ringwald } else { 1781aa4dd815SMatthias Ringwald printf("AG: Swap calls\n"); 1782aa4dd815SMatthias Ringwald } 1783aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1784aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1785aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1786aa4dd815SMatthias Ringwald break; 1787aa4dd815SMatthias Ringwald case '3': 1788aa4dd815SMatthias Ringwald // Adds a held call to the conversation. 1789aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1790aa4dd815SMatthias Ringwald context->ok_pending = 1; 1791aa4dd815SMatthias Ringwald if (hfp_ag_callheld_state != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 1792aa4dd815SMatthias Ringwald printf("AG: Join 3-way-call\n"); 1793aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1794aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1795ce263fc8SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CONFERENCE_CALL, 0); 1796aa4dd815SMatthias Ringwald } 1797aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1798aa4dd815SMatthias Ringwald break; 1799aa4dd815SMatthias Ringwald case '4': 1800aa4dd815SMatthias Ringwald // Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer) 1801aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1802aa4dd815SMatthias Ringwald context->ok_pending = 1; 1803aa4dd815SMatthias Ringwald printf("AG: Transfer call -> Connect two calls and disconnect\n"); 1804aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1805aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1806aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, call_indicator_index, 1); 1807aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1808aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_IDLE; 1809aa4dd815SMatthias Ringwald break; 1810aa4dd815SMatthias Ringwald default: 1811aa4dd815SMatthias Ringwald break; 1812aa4dd815SMatthias Ringwald } 1813aa4dd815SMatthias Ringwald break; 1814aa4dd815SMatthias Ringwald } 1815aa4dd815SMatthias Ringwald case HFP_CMD_CALL_PHONE_NUMBER: 1816aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1817aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_INITIATED, context); 1818aa4dd815SMatthias Ringwald break; 1819aa4dd815SMatthias Ringwald case HFP_CMD_REDIAL_LAST_NUMBER: 1820aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1821aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_REDIAL_INITIATED, context); 1822aa4dd815SMatthias Ringwald break; 1823aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_CLIP: 1824aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1825aa4dd815SMatthias Ringwald context->clip_enabled = context->line_buffer[8] != '0'; 1826aa4dd815SMatthias Ringwald log_info("hfp: clip set, now: %u", context->clip_enabled); 1827aa4dd815SMatthias Ringwald context->ok_pending = 1; 1828aa4dd815SMatthias Ringwald break; 1829aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION: 1830aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1831aa4dd815SMatthias Ringwald context->call_waiting_notification_enabled = context->line_buffer[8] != '0'; 1832aa4dd815SMatthias Ringwald log_info("hfp: call waiting notification set, now: %u", context->call_waiting_notification_enabled); 1833aa4dd815SMatthias Ringwald context->ok_pending = 1; 1834aa4dd815SMatthias Ringwald break; 1835aa4dd815SMatthias Ringwald case HFP_CMD_SET_SPEAKER_GAIN: 1836aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1837aa4dd815SMatthias Ringwald context->ok_pending = 1; 1838aa4dd815SMatthias Ringwald printf("HF speaker gain = %u\n", context->speaker_gain); 1839aa4dd815SMatthias Ringwald break; 1840aa4dd815SMatthias Ringwald case HFP_CMD_SET_MICROPHONE_GAIN: 1841aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1842aa4dd815SMatthias Ringwald context->ok_pending = 1; 1843aa4dd815SMatthias Ringwald printf("HF microphone gain = %u\n", context->microphone_gain); 1844aa4dd815SMatthias Ringwald break; 1845aa4dd815SMatthias Ringwald default: 1846aa4dd815SMatthias Ringwald break; 18473deb3ec6SMatthias Ringwald } 18483deb3ec6SMatthias Ringwald } 18493deb3ec6SMatthias Ringwald 1850aa4dd815SMatthias Ringwald static void hfp_run(void){ 18513deb3ec6SMatthias Ringwald linked_list_iterator_t it; 18523deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 18533deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 18543deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 18553deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 18563deb3ec6SMatthias Ringwald } 18573deb3ec6SMatthias Ringwald } 18583deb3ec6SMatthias Ringwald 1859ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 18603deb3ec6SMatthias Ringwald switch (packet_type){ 18613deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET: 1862aa4dd815SMatthias Ringwald hfp_handle_rfcomm_data(packet_type, channel, packet, size); 18633deb3ec6SMatthias Ringwald break; 18643deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 18653deb3ec6SMatthias Ringwald hfp_handle_hci_event(hfp_callback, packet_type, packet, size); 1866aa4dd815SMatthias Ringwald break; 18673deb3ec6SMatthias Ringwald default: 18683deb3ec6SMatthias Ringwald break; 18693deb3ec6SMatthias Ringwald } 18703deb3ec6SMatthias Ringwald 18713deb3ec6SMatthias Ringwald hfp_run(); 18723deb3ec6SMatthias Ringwald } 18733deb3ec6SMatthias Ringwald 18741e35c04dSMatthias Ringwald static void hfp_ag_set_ag_indicators(hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr){ 18751e35c04dSMatthias Ringwald hfp_ag_indicators_nr = ag_indicators_nr; 18761e35c04dSMatthias Ringwald memcpy(hfp_ag_indicators, ag_indicators, ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 18771e35c04dSMatthias Ringwald } 18781e35c04dSMatthias Ringwald 18793deb3ec6SMatthias Ringwald void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, 18803deb3ec6SMatthias Ringwald uint8_t * codecs, int codecs_nr, 18813deb3ec6SMatthias Ringwald hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr, 18823deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr, 18833deb3ec6SMatthias Ringwald const char *call_hold_services[], int call_hold_services_nr){ 18843deb3ec6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS){ 18853deb3ec6SMatthias Ringwald log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); 18863deb3ec6SMatthias Ringwald return; 18873deb3ec6SMatthias Ringwald } 1888aa4dd815SMatthias Ringwald l2cap_init(); 1889aa4dd815SMatthias Ringwald l2cap_register_packet_handler(packet_handler); 1890aa4dd815SMatthias Ringwald 1891e4dd59a7SMatthias Ringwald rfcomm_register_packet_handler(packet_handler); 1892aa4dd815SMatthias Ringwald 18933deb3ec6SMatthias Ringwald hfp_init(rfcomm_channel_nr); 18943deb3ec6SMatthias Ringwald 18953deb3ec6SMatthias Ringwald hfp_supported_features = supported_features; 18963deb3ec6SMatthias Ringwald hfp_codecs_nr = codecs_nr; 18973deb3ec6SMatthias Ringwald 18983deb3ec6SMatthias Ringwald int i; 18993deb3ec6SMatthias Ringwald for (i=0; i<codecs_nr; i++){ 19003deb3ec6SMatthias Ringwald hfp_codecs[i] = codecs[i]; 19013deb3ec6SMatthias Ringwald } 19023deb3ec6SMatthias Ringwald 19031e35c04dSMatthias Ringwald hfp_ag_set_ag_indicators(ag_indicators, ag_indicators_nr); 19043deb3ec6SMatthias Ringwald 19053deb3ec6SMatthias Ringwald set_hfp_generic_status_indicators(hf_indicators, hf_indicators_nr); 19063deb3ec6SMatthias Ringwald 19073deb3ec6SMatthias Ringwald hfp_ag_call_hold_services_nr = call_hold_services_nr; 19083deb3ec6SMatthias Ringwald memcpy(hfp_ag_call_hold_services, call_hold_services, call_hold_services_nr * sizeof(char *)); 1909aa4dd815SMatthias Ringwald 1910aa4dd815SMatthias Ringwald hfp_ag_call_state = HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; 1911aa4dd815SMatthias Ringwald hfp_ag_callsetup_state = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 1912aa4dd815SMatthias Ringwald hfp_ag_callheld_state = HFP_CALLHELD_STATUS_NO_CALLS_HELD; 19133deb3ec6SMatthias Ringwald } 19143deb3ec6SMatthias Ringwald 19153deb3ec6SMatthias Ringwald void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){ 19163deb3ec6SMatthias Ringwald hfp_establish_service_level_connection(bd_addr, SDP_Handsfree); 19173deb3ec6SMatthias Ringwald } 19183deb3ec6SMatthias Ringwald 19193deb3ec6SMatthias Ringwald void hfp_ag_release_service_level_connection(bd_addr_t bd_addr){ 19203deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 19213deb3ec6SMatthias Ringwald hfp_release_service_level_connection(connection); 19223deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 19233deb3ec6SMatthias Ringwald } 19243deb3ec6SMatthias Ringwald 19253deb3ec6SMatthias Ringwald void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error){ 19263deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 19273deb3ec6SMatthias Ringwald if (!connection){ 19283deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 19293deb3ec6SMatthias Ringwald return; 19303deb3ec6SMatthias Ringwald } 19313deb3ec6SMatthias Ringwald connection->extended_audio_gateway_error = 0; 19323deb3ec6SMatthias Ringwald if (!connection->enable_extended_audio_gateway_error_report){ 19333deb3ec6SMatthias Ringwald return; 19343deb3ec6SMatthias Ringwald } 19353deb3ec6SMatthias Ringwald connection->extended_audio_gateway_error = error; 19363deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 19373deb3ec6SMatthias Ringwald } 19383deb3ec6SMatthias Ringwald 1939aa4dd815SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * connection){ 19403deb3ec6SMatthias Ringwald if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; 19413deb3ec6SMatthias Ringwald if (connection->state >= HFP_W2_DISCONNECT_SCO) return; 19423deb3ec6SMatthias Ringwald 19433deb3ec6SMatthias Ringwald connection->establish_audio_connection = 1; 1944aa4dd815SMatthias Ringwald 1945aa4dd815SMatthias Ringwald if (!has_codec_negotiation_feature(connection)){ 1946aa4dd815SMatthias Ringwald log_info("hfp_ag_establish_audio_connection - no codec negotiation feature, using defaults"); 1947aa4dd815SMatthias Ringwald connection->codecs_state = HFP_CODECS_EXCHANGED; 19483deb3ec6SMatthias Ringwald } 1949aa4dd815SMatthias Ringwald 1950aa4dd815SMatthias Ringwald switch (connection->codecs_state){ 1951aa4dd815SMatthias Ringwald case HFP_CODECS_IDLE: 1952aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_LIST: 1953aa4dd815SMatthias Ringwald case HFP_CODECS_AG_RESEND_COMMON_CODEC: 1954aa4dd815SMatthias Ringwald case HFP_CODECS_ERROR: 1955aa4dd815SMatthias Ringwald connection->command = HFP_CMD_AG_SEND_COMMON_CODEC; 1956aa4dd815SMatthias Ringwald break; 1957aa4dd815SMatthias Ringwald default: 1958aa4dd815SMatthias Ringwald break; 1959aa4dd815SMatthias Ringwald } 1960aa4dd815SMatthias Ringwald } 1961aa4dd815SMatthias Ringwald 1962aa4dd815SMatthias Ringwald void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){ 1963aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(bd_addr); 1964aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1965aa4dd815SMatthias Ringwald 1966aa4dd815SMatthias Ringwald connection->establish_audio_connection = 0; 1967aa4dd815SMatthias Ringwald hfp_ag_setup_audio_connection(connection); 19683deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 19693deb3ec6SMatthias Ringwald } 19703deb3ec6SMatthias Ringwald 19713deb3ec6SMatthias Ringwald void hfp_ag_release_audio_connection(bd_addr_t bd_addr){ 19723deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 19733deb3ec6SMatthias Ringwald hfp_release_audio_connection(connection); 19743deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 19753deb3ec6SMatthias Ringwald } 1976aa4dd815SMatthias Ringwald 1977aa4dd815SMatthias Ringwald /** 1978aa4dd815SMatthias Ringwald * @brief Enable in-band ring tone 1979aa4dd815SMatthias Ringwald */ 1980aa4dd815SMatthias Ringwald void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone){ 1981aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE) == use_in_band_ring_tone){ 1982aa4dd815SMatthias Ringwald return; 1983aa4dd815SMatthias Ringwald } 1984aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE, use_in_band_ring_tone); 1985aa4dd815SMatthias Ringwald 1986aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1987aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1988aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1989aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1990aa4dd815SMatthias Ringwald connection->command = HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING; 1991aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1992aa4dd815SMatthias Ringwald } 1993aa4dd815SMatthias Ringwald } 1994aa4dd815SMatthias Ringwald 1995aa4dd815SMatthias Ringwald /** 1996aa4dd815SMatthias Ringwald * @brief Called from GSM 1997aa4dd815SMatthias Ringwald */ 1998aa4dd815SMatthias Ringwald void hfp_ag_incoming_call(void){ 1999aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL, NULL); 2000aa4dd815SMatthias Ringwald } 2001aa4dd815SMatthias Ringwald 2002aa4dd815SMatthias Ringwald /** 2003aa4dd815SMatthias Ringwald * @brief number is stored. 2004aa4dd815SMatthias Ringwald */ 2005aa4dd815SMatthias Ringwald void hfp_ag_set_clip(uint8_t type, const char * number){ 2006aa4dd815SMatthias Ringwald clip_type = type; 2007aa4dd815SMatthias Ringwald // copy and terminate 2008aa4dd815SMatthias Ringwald strncpy(clip_number, number, sizeof(clip_number)); 2009aa4dd815SMatthias Ringwald clip_number[sizeof(clip_number)-1] = '\0'; 2010aa4dd815SMatthias Ringwald } 2011aa4dd815SMatthias Ringwald 2012aa4dd815SMatthias Ringwald void hfp_ag_call_dropped(void){ 2013aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL); 2014aa4dd815SMatthias Ringwald } 2015aa4dd815SMatthias Ringwald 2016aa4dd815SMatthias Ringwald // call from AG UI 2017aa4dd815SMatthias Ringwald void hfp_ag_answer_incoming_call(void){ 2018aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, NULL); 2019aa4dd815SMatthias Ringwald } 2020aa4dd815SMatthias Ringwald 2021ce263fc8SMatthias Ringwald void hfp_ag_join_held_call(void){ 2022ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_HELD_CALL_JOINED_BY_AG, NULL); 2023ce263fc8SMatthias Ringwald } 2024ce263fc8SMatthias Ringwald 2025aa4dd815SMatthias Ringwald void hfp_ag_terminate_call(void){ 2026aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_AG, NULL); 2027aa4dd815SMatthias Ringwald } 2028aa4dd815SMatthias Ringwald 2029aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_ringing(void){ 2030aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_RINGING, NULL); 2031aa4dd815SMatthias Ringwald } 2032aa4dd815SMatthias Ringwald 2033aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_established(void){ 2034aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ESTABLISHED, NULL); 2035aa4dd815SMatthias Ringwald } 2036aa4dd815SMatthias Ringwald 2037aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_rejected(void){ 2038aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_REJECTED, NULL); 2039aa4dd815SMatthias Ringwald } 2040aa4dd815SMatthias Ringwald 2041aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_accepted(void){ 2042aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ACCEPTED, NULL); 2043aa4dd815SMatthias Ringwald } 2044ce263fc8SMatthias Ringwald 2045ce263fc8SMatthias Ringwald void hfp_ag_hold_incoming_call(void){ 2046ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG, NULL); 2047ce263fc8SMatthias Ringwald } 2048ce263fc8SMatthias Ringwald 2049ce263fc8SMatthias Ringwald void hfp_ag_accept_held_incoming_call(void) { 2050ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG, NULL); 2051ce263fc8SMatthias Ringwald } 2052ce263fc8SMatthias Ringwald 2053ce263fc8SMatthias Ringwald void hfp_ag_reject_held_incoming_call(void){ 2054ce263fc8SMatthias Ringwald hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, NULL); 2055ce263fc8SMatthias Ringwald } 2056ce263fc8SMatthias Ringwald 2057aa4dd815SMatthias Ringwald static void hfp_ag_set_ag_indicator(const char * name, int value){ 2058aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name(name); 2059aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 2060aa4dd815SMatthias Ringwald hfp_ag_indicators[indicator_index].status = value; 2061aa4dd815SMatthias Ringwald 2062ce263fc8SMatthias Ringwald 2063aa4dd815SMatthias Ringwald linked_list_iterator_t it; 2064aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 2065aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 2066aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 2067ce263fc8SMatthias Ringwald if (!connection->ag_indicators[indicator_index].enabled) { 2068ce263fc8SMatthias Ringwald log_info("AG indicator '%s' changed to %u but not enabled", hfp_ag_indicators[indicator_index].name, value); 2069ce263fc8SMatthias Ringwald continue; 2070ce263fc8SMatthias Ringwald } 2071ce263fc8SMatthias Ringwald log_info("AG indicator '%s' changed to %u, request transfer statur", hfp_ag_indicators[indicator_index].name, value); 2072aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 2073aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 2074aa4dd815SMatthias Ringwald } 2075aa4dd815SMatthias Ringwald } 2076aa4dd815SMatthias Ringwald 2077aa4dd815SMatthias Ringwald /* 2078aa4dd815SMatthias Ringwald * @brief 2079aa4dd815SMatthias Ringwald */ 2080aa4dd815SMatthias Ringwald void hfp_ag_set_registration_status(int status){ 2081aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("service", status); 2082aa4dd815SMatthias Ringwald } 2083aa4dd815SMatthias Ringwald 2084aa4dd815SMatthias Ringwald /* 2085aa4dd815SMatthias Ringwald * @brief 2086aa4dd815SMatthias Ringwald */ 2087aa4dd815SMatthias Ringwald void hfp_ag_set_signal_strength(int strength){ 2088aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("signal", strength); 2089aa4dd815SMatthias Ringwald } 2090aa4dd815SMatthias Ringwald 2091aa4dd815SMatthias Ringwald /* 2092aa4dd815SMatthias Ringwald * @brief 2093aa4dd815SMatthias Ringwald */ 2094aa4dd815SMatthias Ringwald void hfp_ag_set_roaming_status(int status){ 2095aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("roam", status); 2096aa4dd815SMatthias Ringwald } 2097aa4dd815SMatthias Ringwald 2098aa4dd815SMatthias Ringwald /* 2099aa4dd815SMatthias Ringwald * @brief 2100aa4dd815SMatthias Ringwald */ 2101aa4dd815SMatthias Ringwald void hfp_ag_set_battery_level(int level){ 2102aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("battchg", level); 2103aa4dd815SMatthias Ringwald } 2104aa4dd815SMatthias Ringwald 2105aa4dd815SMatthias Ringwald /* 2106aa4dd815SMatthias Ringwald * @brief 2107aa4dd815SMatthias Ringwald */ 2108aa4dd815SMatthias Ringwald void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate){ 2109aa4dd815SMatthias Ringwald if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return; 2110aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2111aa4dd815SMatthias Ringwald 2112aa4dd815SMatthias Ringwald if (!get_bit(connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) { 2113aa4dd815SMatthias Ringwald printf("AG cannot acivate voice recognition - not supported by HF\n"); 2114aa4dd815SMatthias Ringwald return; 2115aa4dd815SMatthias Ringwald } 2116aa4dd815SMatthias Ringwald 2117aa4dd815SMatthias Ringwald if (activate){ 2118aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(bd_addr); 2119aa4dd815SMatthias Ringwald } 2120aa4dd815SMatthias Ringwald 2121aa4dd815SMatthias Ringwald connection->ag_activate_voice_recognition = activate; 2122aa4dd815SMatthias Ringwald connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION; 2123aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 2124aa4dd815SMatthias Ringwald } 2125aa4dd815SMatthias Ringwald 2126aa4dd815SMatthias Ringwald /* 2127aa4dd815SMatthias Ringwald * @brief 2128aa4dd815SMatthias Ringwald */ 2129aa4dd815SMatthias Ringwald void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain){ 2130aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2131aa4dd815SMatthias Ringwald if (connection->microphone_gain != gain){ 2132aa4dd815SMatthias Ringwald connection->command = HFP_CMD_SET_MICROPHONE_GAIN; 2133aa4dd815SMatthias Ringwald connection->microphone_gain = gain; 2134aa4dd815SMatthias Ringwald connection->send_microphone_gain = 1; 2135aa4dd815SMatthias Ringwald } 2136ce263fc8SMatthias Ringwald hfp_run_for_context(connection); 2137aa4dd815SMatthias Ringwald } 2138aa4dd815SMatthias Ringwald 2139aa4dd815SMatthias Ringwald /* 2140aa4dd815SMatthias Ringwald * @brief 2141aa4dd815SMatthias Ringwald */ 2142aa4dd815SMatthias Ringwald void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain){ 2143aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2144aa4dd815SMatthias Ringwald if (connection->speaker_gain != gain){ 2145aa4dd815SMatthias Ringwald connection->speaker_gain = gain; 2146aa4dd815SMatthias Ringwald connection->send_speaker_gain = 1; 2147aa4dd815SMatthias Ringwald } 2148ce263fc8SMatthias Ringwald hfp_run_for_context(connection); 2149aa4dd815SMatthias Ringwald } 2150aa4dd815SMatthias Ringwald 2151aa4dd815SMatthias Ringwald /* 2152aa4dd815SMatthias Ringwald * @brief 2153aa4dd815SMatthias Ringwald */ 2154aa4dd815SMatthias Ringwald void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number){ 2155aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2156aa4dd815SMatthias Ringwald hfp_ag_set_clip(0, number); 2157aa4dd815SMatthias Ringwald connection->send_phone_number_for_voice_tag = 1; 2158aa4dd815SMatthias Ringwald } 2159aa4dd815SMatthias Ringwald 2160aa4dd815SMatthias Ringwald void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr){ 2161aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2162aa4dd815SMatthias Ringwald connection->send_error = 1; 2163aa4dd815SMatthias Ringwald } 2164aa4dd815SMatthias Ringwald 2165c1797c7dSMatthias Ringwald void hfp_ag_send_dtmf_code_done(bd_addr_t bd_addr){ 2166c1797c7dSMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2167c1797c7dSMatthias Ringwald connection->ok_pending = 1; 2168c1797c7dSMatthias Ringwald } 2169aa4dd815SMatthias Ringwald 2170ce263fc8SMatthias Ringwald void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count){ 2171ce263fc8SMatthias Ringwald subscriber_numbers = numbers; 2172ce263fc8SMatthias Ringwald subscriber_numbers_count = numbers_count; 2173ce263fc8SMatthias Ringwald } 2174ce263fc8SMatthias Ringwald 2175ce263fc8SMatthias Ringwald void hfp_ag_send_current_call_status(bd_addr_t bd_addr, int idx, hfp_enhanced_call_dir_t dir, 2176ce263fc8SMatthias Ringwald hfp_enhanced_call_status_t status, hfp_enhanced_call_mode_t mode, 2177ce263fc8SMatthias Ringwald hfp_enhanced_call_mpty_t mpty, uint8_t type, const char * number){ 2178ce263fc8SMatthias Ringwald 2179ce263fc8SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2180ce263fc8SMatthias Ringwald 2181ce263fc8SMatthias Ringwald char buffer[100]; 2182*74386ee0SMatthias Ringwald // TODO: check length of a buffer, to fit the MTU 2183ce263fc8SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s: %d,%d,%d,%d,%d", HFP_LIST_CURRENT_CALLS, idx, dir, status, mode, mpty); 2184ce263fc8SMatthias Ringwald if (number){ 2185ce263fc8SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, ", \"%s\",%u", number, type); 2186ce263fc8SMatthias Ringwald } 2187ce263fc8SMatthias Ringwald snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n"); 2188ce263fc8SMatthias Ringwald send_str_over_rfcomm(connection->rfcomm_cid, buffer); 2189ce263fc8SMatthias Ringwald } 2190ce263fc8SMatthias Ringwald 2191ce263fc8SMatthias Ringwald 2192ce263fc8SMatthias Ringwald void hfp_ag_send_current_call_status_done(bd_addr_t bd_addr){ 2193ce263fc8SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 2194ce263fc8SMatthias Ringwald connection->ok_pending = 1; 2195ce263fc8SMatthias Ringwald connection->send_status_of_current_calls = 0; 2196ce263fc8SMatthias Ringwald } 2197ce263fc8SMatthias Ringwald 2198