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 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 37ab2c6ae4SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hfp_hf.c" 393deb3ec6SMatthias Ringwald 403deb3ec6SMatthias Ringwald // ***************************************************************************** 413deb3ec6SMatthias Ringwald // 42fffdd288SMatthias Ringwald // HFP Hands-Free (HF) unit 433deb3ec6SMatthias Ringwald // 443deb3ec6SMatthias Ringwald // ***************************************************************************** 453deb3ec6SMatthias Ringwald 467907f069SMatthias Ringwald #include "btstack_config.h" 473deb3ec6SMatthias Ringwald 483deb3ec6SMatthias Ringwald #include <stdint.h> 493cfa4086SMatthias Ringwald #include <stdio.h> 503deb3ec6SMatthias Ringwald #include <string.h> 513deb3ec6SMatthias Ringwald 52235946f1SMatthias Ringwald #include "bluetooth_sdp.h" 5359c6af15SMatthias Ringwald #include "btstack_debug.h" 54d4dd47ffSMatthias Ringwald #include "btstack_event.h" 553deb3ec6SMatthias Ringwald #include "btstack_memory.h" 5659c6af15SMatthias Ringwald #include "btstack_run_loop.h" 5759c6af15SMatthias Ringwald #include "classic/core.h" 5859c6af15SMatthias Ringwald #include "classic/hfp.h" 5959c6af15SMatthias Ringwald #include "classic/hfp_hf.h" 60efda0b48SMatthias Ringwald #include "classic/sdp_client_rfcomm.h" 61746ccb7eSMatthias Ringwald #include "classic/sdp_server.h" 62023f2764SMatthias Ringwald #include "classic/sdp_util.h" 6359c6af15SMatthias Ringwald #include "hci.h" 6459c6af15SMatthias Ringwald #include "hci_cmd.h" 6559c6af15SMatthias Ringwald #include "hci_dump.h" 6659c6af15SMatthias Ringwald #include "l2cap.h" 673deb3ec6SMatthias Ringwald 6820b2edb6SMatthias Ringwald // const 69aeb0f0feSMatthias Ringwald static const char hfp_hf_default_service_name[] = "Hands-Free unit"; 7020b2edb6SMatthias Ringwald 7120b2edb6SMatthias Ringwald // globals 72aeb0f0feSMatthias Ringwald 73aeb0f0feSMatthias Ringwald // higher layer callbacks 74aeb0f0feSMatthias Ringwald static btstack_packet_handler_t hfp_hf_callback; 75aeb0f0feSMatthias Ringwald 761c6a0fc0SMatthias Ringwald static btstack_packet_callback_registration_t hfp_hf_hci_event_callback_registration; 7727950165SMatthias Ringwald 78aeb0f0feSMatthias Ringwald static uint16_t hfp_hf_supported_features; 79aeb0f0feSMatthias Ringwald static uint8_t hfp_hf_codecs_nr; 80aeb0f0feSMatthias Ringwald static uint8_t hfp_hf_codecs[HFP_MAX_NUM_CODECS]; 813deb3ec6SMatthias Ringwald 82aeb0f0feSMatthias Ringwald static uint8_t hfp_hf_indicators_nr; 83aeb0f0feSMatthias Ringwald static uint8_t hfp_hf_indicators[HFP_MAX_NUM_INDICATORS]; 84aeb0f0feSMatthias Ringwald static uint32_t hfp_hf_indicators_value[HFP_MAX_NUM_INDICATORS]; 85667ec068SMatthias Ringwald 8620b2edb6SMatthias Ringwald static uint8_t hfp_hf_speaker_gain; 8720b2edb6SMatthias Ringwald static uint8_t hfp_hf_microphone_gain; 88aeb0f0feSMatthias Ringwald static char hfp_hf_phone_number[25]; 89ce263fc8SMatthias Ringwald 90*4e8ee53aSMatthias Ringwald // Apple Accessory Information 91*4e8ee53aSMatthias Ringwald static uint16_t hfp_hf_apple_vendor_id; 92*4e8ee53aSMatthias Ringwald static uint16_t hfp_hf_apple_product_id; 93*4e8ee53aSMatthias Ringwald static const char * hfp_hf_apple_version; 94*4e8ee53aSMatthias Ringwald static uint8_t hfp_hf_apple_features; 95*4e8ee53aSMatthias Ringwald 96*4e8ee53aSMatthias Ringwald 9776cc1527SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * hfp_connection){ 98aeb0f0feSMatthias Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_CODEC_NEGOTIATION); 9976cc1527SMatthias Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_CODEC_NEGOTIATION); 10076cc1527SMatthias Ringwald return hf && ag; 10176cc1527SMatthias Ringwald } 10276cc1527SMatthias Ringwald 10376cc1527SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * hfp_connection){ 104aeb0f0feSMatthias Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_THREE_WAY_CALLING); 10576cc1527SMatthias Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_THREE_WAY_CALLING); 10676cc1527SMatthias Ringwald return hf && ag; 10776cc1527SMatthias Ringwald } 10876cc1527SMatthias Ringwald 10976cc1527SMatthias Ringwald 11076cc1527SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * hfp_connection){ 111aeb0f0feSMatthias Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_HF_INDICATORS); 11276cc1527SMatthias Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_HF_INDICATORS); 11376cc1527SMatthias Ringwald return hf && ag; 11476cc1527SMatthias Ringwald } 11576cc1527SMatthias Ringwald 116fcf4ede6SMilanka Ringwald static bool hfp_hf_vra_flag_supported(hfp_connection_t * hfp_connection){ 117fcf4ede6SMilanka Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION); 118fcf4ede6SMilanka Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION); 119fcf4ede6SMilanka Ringwald return hf && ag; 120fcf4ede6SMilanka Ringwald } 121fcf4ede6SMilanka Ringwald 122fcf4ede6SMilanka Ringwald static bool hfp_hf_enhanced_vra_flag_supported(hfp_connection_t * hfp_connection){ 123fcf4ede6SMilanka Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_ENHANCED_VOICE_RECOGNITION_STATUS); 124fcf4ede6SMilanka Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_ENHANCED_VOICE_RECOGNITION_STATUS); 125fcf4ede6SMilanka Ringwald return hf && ag; 126fcf4ede6SMilanka Ringwald } 12776cc1527SMatthias Ringwald 1289c9c64c1SMatthias Ringwald static hfp_connection_t * get_hfp_hf_connection_context_for_acl_handle(uint16_t handle){ 1299c9c64c1SMatthias Ringwald btstack_linked_list_iterator_t it; 1309c9c64c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 1319c9c64c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1329c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 1339c9c64c1SMatthias Ringwald if (hfp_connection->acl_handle != handle) continue; 1349c9c64c1SMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_HF) continue; 1359c9c64c1SMatthias Ringwald return hfp_connection; 1369c9c64c1SMatthias Ringwald } 1379c9c64c1SMatthias Ringwald return NULL; 1389c9c64c1SMatthias Ringwald } 1399c9c64c1SMatthias Ringwald 140c10fde09SMatthias Ringwald /* emit functions */ 1413deb3ec6SMatthias Ringwald 142a473a009SMatthias Ringwald static void hfp_hf_emit_subscriber_information(const hfp_connection_t * hfp_connection, uint8_t status){ 143a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return; 144ab2445a0SMatthias Ringwald uint16_t bnip_number_len = btstack_min((uint16_t) strlen(hfp_connection->bnip_number), sizeof(hfp_connection->bnip_number)-1); 145c10fde09SMatthias Ringwald uint8_t event[7 + sizeof(hfp_connection->bnip_number)]; 146a0ffb263SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 147c10fde09SMatthias Ringwald event[1] = 6 + bnip_number_len; 148a473a009SMatthias Ringwald event[2] = HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION; 149d703d377SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 150d703d377SMatthias Ringwald event[5] = status; 151d703d377SMatthias Ringwald event[6] = hfp_connection->bnip_type; 152c10fde09SMatthias Ringwald memcpy(&event[7], hfp_connection->bnip_number, bnip_number_len); 153c10fde09SMatthias Ringwald event[7 + bnip_number_len] = 0; 154c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 8 + bnip_number_len); 155a0ffb263SMatthias Ringwald } 156a0ffb263SMatthias Ringwald 157598d4936SMatthias Ringwald static void hfp_hf_emit_type_number_alpha(const hfp_connection_t * hfp_connection, uint8_t event_subtype){ 158a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return; 159ab2445a0SMatthias Ringwald uint16_t bnip_number_len = btstack_min((uint16_t) strlen(hfp_connection->bnip_number), sizeof(hfp_connection->bnip_number)-1); 160598d4936SMatthias Ringwald // 10 fixed - 1 (bnip_number_len <= sizeof(hfp_connection->bnip_number)-1) + 1 (trailing \0 for line buffer) 161598d4936SMatthias Ringwald uint8_t event[10 + sizeof(hfp_connection->bnip_number) + sizeof(hfp_connection->line_buffer)]; 162ab2445a0SMatthias Ringwald uint8_t alpha_len = hfp_connection->clip_have_alpha ? (uint16_t) strlen((const char *) hfp_connection->line_buffer) : 0; 163598d4936SMatthias Ringwald uint8_t pos = 0; 164598d4936SMatthias Ringwald event[pos++] = HCI_EVENT_HFP_META; 165598d4936SMatthias Ringwald event[pos++] = 8 + bnip_number_len + alpha_len; 166598d4936SMatthias Ringwald event[pos++] = event_subtype; 167d703d377SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 168598d4936SMatthias Ringwald pos += 2; 169598d4936SMatthias Ringwald event[pos++] = hfp_connection->bnip_type; 170a45da34eSMatthias Ringwald event[pos++] = bnip_number_len + 1; 171598d4936SMatthias Ringwald memcpy(&event[7], hfp_connection->bnip_number, bnip_number_len); 172598d4936SMatthias Ringwald pos += bnip_number_len; 173598d4936SMatthias Ringwald event[pos++] = 0; 174a45da34eSMatthias Ringwald event[pos++] = alpha_len + 1; 175598d4936SMatthias Ringwald memcpy(&event[pos], hfp_connection->line_buffer, alpha_len); 176598d4936SMatthias Ringwald pos += alpha_len; 177598d4936SMatthias Ringwald event[pos++] = 0; 178598d4936SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, pos); 179a0ffb263SMatthias Ringwald } 180a0ffb263SMatthias Ringwald 181a473a009SMatthias Ringwald static void hfp_hf_emit_enhanced_call_status(const hfp_connection_t * hfp_connection){ 182a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return; 1835f5a2872SMilanka Ringwald 184ab2445a0SMatthias Ringwald uint16_t bnip_number_len = (uint16_t) strlen((const char *) hfp_connection->bnip_number); 1855f5a2872SMilanka Ringwald uint8_t event[11 + HFP_BNEP_NUM_MAX_SIZE]; 186c10fde09SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 1875f5a2872SMilanka Ringwald event[1] = 10 + bnip_number_len + 1; 188c10fde09SMatthias Ringwald event[2] = HFP_SUBEVENT_ENHANCED_CALL_STATUS; 189c10fde09SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 1905f5a2872SMilanka Ringwald event[5] = hfp_connection->clcc_idx; 1915f5a2872SMilanka Ringwald event[6] = hfp_connection->clcc_dir; 1925f5a2872SMilanka Ringwald event[7] = hfp_connection->clcc_status; 1935f5a2872SMilanka Ringwald event[8] = hfp_connection->clcc_mode; 1945f5a2872SMilanka Ringwald event[9] = hfp_connection->clcc_mpty; 1955f5a2872SMilanka Ringwald event[10] = hfp_connection->bnip_type; 1965f5a2872SMilanka Ringwald memcpy(&event[11], hfp_connection->bnip_number, bnip_number_len + 1); 1975f5a2872SMilanka Ringwald 1985f5a2872SMilanka Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 11 + bnip_number_len + 1); 199a0ffb263SMatthias Ringwald } 200a0ffb263SMatthias Ringwald 2011ac1f60fSMilanka Ringwald static void hfp_emit_ag_indicator_mapping_event(const hfp_connection_t * hfp_connection, const hfp_ag_indicator_t * indicator){ 2021ac1f60fSMilanka Ringwald if (hfp_hf_callback == NULL) return; 203c10fde09SMatthias Ringwald uint8_t event[8 + HFP_MAX_INDICATOR_DESC_SIZE]; 204ab2445a0SMatthias Ringwald uint16_t indicator_len = btstack_min((uint16_t) strlen(indicator->name), HFP_MAX_INDICATOR_DESC_SIZE-1); 205c10fde09SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 206c10fde09SMatthias Ringwald event[1] = 7 + indicator_len; 207c10fde09SMatthias Ringwald event[2] = HFP_SUBEVENT_AG_INDICATOR_MAPPING; 208c10fde09SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 209c10fde09SMatthias Ringwald event[5] = indicator->index; 210c10fde09SMatthias Ringwald event[6] = indicator->min_range; 211c10fde09SMatthias Ringwald event[7] = indicator->max_range; 212c10fde09SMatthias Ringwald memcpy(&event[8], indicator->name, indicator_len); 213c10fde09SMatthias Ringwald event[8+indicator_len] = 0; 214c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 9 + indicator_len); 2151ac1f60fSMilanka Ringwald } 21676cc1527SMatthias Ringwald 217ce3797e1SMilanka Ringwald static void hfp_emit_ag_indicator_status_event(const hfp_connection_t * hfp_connection, const hfp_ag_indicator_t * indicator){ 218a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return; 219c10fde09SMatthias Ringwald uint8_t event[12+HFP_MAX_INDICATOR_DESC_SIZE]; 220ab2445a0SMatthias Ringwald uint16_t indicator_len = btstack_min((uint16_t) strlen(indicator->name), HFP_MAX_INDICATOR_DESC_SIZE-1); 221c10fde09SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 222c10fde09SMatthias Ringwald event[1] = 11 + indicator_len; 223c10fde09SMatthias Ringwald event[2] = HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED; 224c10fde09SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 225c10fde09SMatthias Ringwald event[5] = indicator->index; 226c10fde09SMatthias Ringwald event[6] = indicator->status; 227c10fde09SMatthias Ringwald event[7] = indicator->min_range; 228c10fde09SMatthias Ringwald event[8] = indicator->max_range; 229c10fde09SMatthias Ringwald event[9] = indicator->mandatory; 230c10fde09SMatthias Ringwald event[10] = indicator->enabled; 231c10fde09SMatthias Ringwald event[11] = indicator->status_changed; 232c10fde09SMatthias Ringwald memcpy(&event[12], indicator->name, indicator_len); 233c10fde09SMatthias Ringwald event[12+indicator_len] = 0; 234c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 13 + indicator_len); 2353deb3ec6SMatthias Ringwald } 2363deb3ec6SMatthias Ringwald 237a473a009SMatthias Ringwald static void hfp_emit_network_operator_event(const hfp_connection_t * hfp_connection){ 238a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return; 239ab2445a0SMatthias Ringwald uint16_t operator_len = btstack_min((uint16_t) strlen(hfp_connection->network_operator.name), HFP_MAX_NETWORK_OPERATOR_NAME_SIZE-1); 240c10fde09SMatthias Ringwald uint8_t event[7+HFP_MAX_NETWORK_OPERATOR_NAME_SIZE]; 24176cc1527SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 24276cc1527SMatthias Ringwald event[1] = sizeof(event) - 2; 243f127324fSMilanka Ringwald event[2] = HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED; 244d703d377SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 245d703d377SMatthias Ringwald event[5] = hfp_connection->network_operator.mode; 246d703d377SMatthias Ringwald event[6] = hfp_connection->network_operator.format; 247c10fde09SMatthias Ringwald memcpy(&event[7], hfp_connection->network_operator.name, operator_len); 248c10fde09SMatthias Ringwald event[7+operator_len] = 0; 249c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 8 + operator_len); 2503deb3ec6SMatthias Ringwald } 2513deb3ec6SMatthias Ringwald 252b95cac54SMilanka Ringwald 253b95cac54SMilanka Ringwald static void hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection_t * hfp_connection){ 254b95cac54SMilanka Ringwald btstack_assert(hfp_connection != NULL); 25551aa5d5aSMilanka Ringwald uint8_t event[HFP_MAX_VR_TEXT_SIZE + 11]; 256b95cac54SMilanka Ringwald int pos = 0; 257b95cac54SMilanka Ringwald event[pos++] = HCI_EVENT_HFP_META; 258b95cac54SMilanka Ringwald event[pos++] = sizeof(event) - 2; 259b95cac54SMilanka Ringwald event[pos++] = HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_MESSAGE; 260b95cac54SMilanka Ringwald little_endian_store_16(event, pos, hfp_connection->acl_handle); 261b95cac54SMilanka Ringwald pos += 2; 262b95cac54SMilanka Ringwald little_endian_store_16(event, pos, hfp_connection->ag_msg.text_id); 263b95cac54SMilanka Ringwald pos += 2; 264b95cac54SMilanka Ringwald event[pos++] = hfp_connection->ag_msg.text_type; 265e83f1be7SMilanka Ringwald event[pos++] = hfp_connection->ag_msg.text_operation; 266b95cac54SMilanka Ringwald 26751aa5d5aSMilanka Ringwald // length, zero ending is already in message 268b95cac54SMilanka Ringwald uint8_t * value = &hfp_connection->line_buffer[0]; 26951aa5d5aSMilanka Ringwald uint16_t value_length = hfp_connection->ag_vra_msg_length; 27051aa5d5aSMilanka Ringwald 27151aa5d5aSMilanka Ringwald little_endian_store_16(event, pos, value_length); 272b95cac54SMilanka Ringwald pos += 2; 27351aa5d5aSMilanka Ringwald memcpy(&event[pos], value, value_length); 27451aa5d5aSMilanka Ringwald pos += value_length; 27551aa5d5aSMilanka Ringwald 276b95cac54SMilanka Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, pos); 277b95cac54SMilanka Ringwald } 278b95cac54SMilanka Ringwald 279892f58a8SMatthias Ringwald static void hfp_hf_emit_custom_command_event(hfp_connection_t * hfp_connection){ 280892f58a8SMatthias Ringwald btstack_assert(sizeof(hfp_connection->line_buffer) < (255-5)); 281892f58a8SMatthias Ringwald 2821a3bc516SMatthias Ringwald uint16_t line_len = (uint16_t) strlen((const char*)hfp_connection->line_buffer) + 1; 283892f58a8SMatthias Ringwald uint8_t event[7 + sizeof(hfp_connection->line_buffer)]; 284892f58a8SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 285892f58a8SMatthias Ringwald event[1] = 5 + line_len; 286892f58a8SMatthias Ringwald event[2] = HFP_SUBEVENT_CUSTOM_AT_COMMAND; 287892f58a8SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle); 288892f58a8SMatthias Ringwald little_endian_store_16(event, 5, hfp_connection->custom_at_command_id); 289892f58a8SMatthias Ringwald memcpy(&event[7], hfp_connection->line_buffer, line_len); 290892f58a8SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 7 + line_len); 291892f58a8SMatthias Ringwald } 292892f58a8SMatthias Ringwald 29376cc1527SMatthias Ringwald /* send commands */ 29489425bfcSMilanka Ringwald 29589425bfcSMilanka Ringwald static inline int hfp_hf_send_cmd(uint16_t cid, const char * cmd){ 2963deb3ec6SMatthias Ringwald char buffer[20]; 2971599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s\r", cmd); 29889425bfcSMilanka Ringwald return send_str_over_rfcomm(cid, buffer); 29989425bfcSMilanka Ringwald } 30089425bfcSMilanka Ringwald 30189425bfcSMilanka Ringwald static inline int hfp_hf_send_cmd_with_mark(uint16_t cid, const char * cmd, const char * mark){ 30289425bfcSMilanka Ringwald char buffer[20]; 3031599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s%s\r", cmd, mark); 30489425bfcSMilanka Ringwald return send_str_over_rfcomm(cid, buffer); 30589425bfcSMilanka Ringwald } 30689425bfcSMilanka Ringwald 30786da9d74SMatthias Ringwald static inline int hfp_hf_send_cmd_with_int(uint16_t cid, const char * cmd, uint16_t value){ 30889425bfcSMilanka Ringwald char buffer[40]; 3091599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=%d\r", cmd, value); 3103deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3113deb3ec6SMatthias Ringwald } 3123deb3ec6SMatthias Ringwald 3133deb3ec6SMatthias Ringwald static int hfp_hf_cmd_notify_on_codecs(uint16_t cid){ 3143deb3ec6SMatthias Ringwald char buffer[30]; 31589425bfcSMilanka Ringwald const int size = sizeof(buffer); 31689425bfcSMilanka Ringwald int offset = snprintf(buffer, size, "AT%s=", HFP_AVAILABLE_CODECS); 317aeb0f0feSMatthias Ringwald offset += join(buffer+offset, size-offset, hfp_hf_codecs, hfp_hf_codecs_nr); 3181599fe57SMatthias Ringwald offset += snprintf(buffer+offset, size-offset, "\r"); 3193deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3203deb3ec6SMatthias Ringwald } 3213deb3ec6SMatthias Ringwald 3223deb3ec6SMatthias Ringwald static int hfp_hf_cmd_activate_status_update_for_ag_indicator(uint16_t cid, uint32_t indicators_status, int indicators_nr){ 3233deb3ec6SMatthias Ringwald char buffer[50]; 32489425bfcSMilanka Ringwald const int size = sizeof(buffer); 32589425bfcSMilanka Ringwald int offset = snprintf(buffer, size, "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS); 32689425bfcSMilanka Ringwald offset += join_bitmap(buffer+offset, size-offset, indicators_status, indicators_nr); 3271599fe57SMatthias Ringwald offset += snprintf(buffer+offset, size-offset, "\r"); 3283deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3293deb3ec6SMatthias Ringwald } 3303deb3ec6SMatthias Ringwald 3313deb3ec6SMatthias Ringwald static int hfp_hf_cmd_list_supported_generic_status_indicators(uint16_t cid){ 3323deb3ec6SMatthias Ringwald char buffer[30]; 33389425bfcSMilanka Ringwald const int size = sizeof(buffer); 33489425bfcSMilanka Ringwald int offset = snprintf(buffer, size, "AT%s=", HFP_GENERIC_STATUS_INDICATOR); 335aeb0f0feSMatthias Ringwald offset += join(buffer+offset, size-offset, hfp_hf_indicators, hfp_hf_indicators_nr); 3361599fe57SMatthias Ringwald offset += snprintf(buffer+offset, size-offset, "\r"); 3373deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3383deb3ec6SMatthias Ringwald } 3393deb3ec6SMatthias Ringwald 34089425bfcSMilanka Ringwald static int hfp_hf_cmd_activate_status_update_for_all_ag_indicators(uint16_t cid, uint8_t activate){ 3413deb3ec6SMatthias Ringwald char buffer[20]; 3421599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=3,0,0,%d\r", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, activate); 343ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 344ce263fc8SMatthias Ringwald } 345ce263fc8SMatthias Ringwald 346ce263fc8SMatthias Ringwald static int hfp_hf_initiate_outgoing_call_cmd(uint16_t cid){ 347ce263fc8SMatthias Ringwald char buffer[40]; 348aeb0f0feSMatthias Ringwald snprintf(buffer, sizeof(buffer), "%s%s;\r", HFP_CALL_PHONE_NUMBER, hfp_hf_phone_number); 349ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 350ce263fc8SMatthias Ringwald } 351ce263fc8SMatthias Ringwald 352a0ffb263SMatthias Ringwald static int hfp_hf_send_memory_dial_cmd(uint16_t cid, int memory_id){ 353ce263fc8SMatthias Ringwald char buffer[40]; 3541599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "%s>%d;\r", HFP_CALL_PHONE_NUMBER, memory_id); 355ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 356ce263fc8SMatthias Ringwald } 357ce263fc8SMatthias Ringwald 358f04a0c31SMatthias Ringwald static int hfp_hf_send_chld(uint16_t cid, unsigned int number){ 35989425bfcSMilanka Ringwald char buffer[40]; 3601599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=%u\r", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, number); 361ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 362ce263fc8SMatthias Ringwald } 363ce263fc8SMatthias Ringwald 364ce263fc8SMatthias Ringwald static int hfp_hf_send_dtmf(uint16_t cid, char code){ 365ce263fc8SMatthias Ringwald char buffer[20]; 3661599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=%c\r", HFP_TRANSMIT_DTMF_CODES, code); 367ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 368ce263fc8SMatthias Ringwald } 369ce263fc8SMatthias Ringwald 37097d2cadbSMatthias Ringwald static int hfp_hf_cmd_ata(uint16_t cid){ 3711599fe57SMatthias Ringwald return send_str_over_rfcomm(cid, (char *) "ATA\r"); 37297d2cadbSMatthias Ringwald } 37397d2cadbSMatthias Ringwald 37489425bfcSMilanka Ringwald static int hfp_hf_cmd_exchange_supported_features(uint16_t cid){ 375aeb0f0feSMatthias Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_SUPPORTED_FEATURES, hfp_hf_supported_features); 37689425bfcSMilanka Ringwald } 37789425bfcSMilanka Ringwald 37889425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_indicators(uint16_t cid){ 37989425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_INDICATOR, "=?"); 38089425bfcSMilanka Ringwald } 38189425bfcSMilanka Ringwald 38289425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_indicators_status(uint16_t cid){ 38389425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_INDICATOR, "?"); 38489425bfcSMilanka Ringwald } 38589425bfcSMilanka Ringwald 38689425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_can_hold_call(uint16_t cid){ 38789425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, "=?"); 38889425bfcSMilanka Ringwald } 38989425bfcSMilanka Ringwald 39089425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_supported_generic_status_indicators(uint16_t cid){ 39189425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_GENERIC_STATUS_INDICATOR, "=?"); 39289425bfcSMilanka Ringwald } 39389425bfcSMilanka Ringwald 39489425bfcSMilanka Ringwald static int hfp_hf_cmd_list_initital_supported_generic_status_indicators(uint16_t cid){ 39589425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_GENERIC_STATUS_INDICATOR, "?"); 39689425bfcSMilanka Ringwald } 39789425bfcSMilanka Ringwald 39889425bfcSMilanka Ringwald static int hfp_hf_cmd_query_operator_name_format(uint16_t cid){ 39989425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_QUERY_OPERATOR_SELECTION, "=3,0"); 40089425bfcSMilanka Ringwald } 40189425bfcSMilanka Ringwald 40289425bfcSMilanka Ringwald static int hfp_hf_cmd_query_operator_name(uint16_t cid){ 40389425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_QUERY_OPERATOR_SELECTION, "?"); 40489425bfcSMilanka Ringwald } 40589425bfcSMilanka Ringwald 40689425bfcSMilanka Ringwald static int hfp_hf_cmd_trigger_codec_connection_setup(uint16_t cid){ 40789425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_TRIGGER_CODEC_CONNECTION_SETUP); 40889425bfcSMilanka Ringwald } 40989425bfcSMilanka Ringwald 41089425bfcSMilanka Ringwald static int hfp_hf_set_microphone_gain_cmd(uint16_t cid, int gain){ 41189425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_SET_MICROPHONE_GAIN, gain); 41289425bfcSMilanka Ringwald } 41389425bfcSMilanka Ringwald 41489425bfcSMilanka Ringwald static int hfp_hf_set_speaker_gain_cmd(uint16_t cid, int gain){ 41589425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_SET_SPEAKER_GAIN, gain); 41689425bfcSMilanka Ringwald } 41789425bfcSMilanka Ringwald 41889425bfcSMilanka Ringwald static int hfp_hf_set_calling_line_notification_cmd(uint16_t cid, uint8_t activate){ 41989425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ENABLE_CLIP, activate); 42089425bfcSMilanka Ringwald } 42189425bfcSMilanka Ringwald 42289425bfcSMilanka Ringwald static int hfp_hf_set_voice_recognition_notification_cmd(uint16_t cid, uint8_t activate){ 42389425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ACTIVATE_VOICE_RECOGNITION, activate); 42489425bfcSMilanka Ringwald } 42589425bfcSMilanka Ringwald 42689425bfcSMilanka Ringwald static int hfp_hf_set_call_waiting_notification_cmd(uint16_t cid, uint8_t activate){ 42789425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ENABLE_CALL_WAITING_NOTIFICATION, activate); 42889425bfcSMilanka Ringwald } 42989425bfcSMilanka Ringwald 43089425bfcSMilanka Ringwald static int hfp_hf_cmd_confirm_codec(uint16_t cid, uint8_t codec){ 43189425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_CONFIRM_COMMON_CODEC, codec); 43289425bfcSMilanka Ringwald } 43389425bfcSMilanka Ringwald 43489425bfcSMilanka Ringwald static int hfp_hf_cmd_enable_extended_audio_gateway_error_report(uint16_t cid, uint8_t enable){ 43589425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, enable); 43689425bfcSMilanka Ringwald } 43789425bfcSMilanka Ringwald 43889425bfcSMilanka Ringwald static int hfp_hf_send_redial_last_number_cmd(uint16_t cid){ 43989425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_REDIAL_LAST_NUMBER); 44089425bfcSMilanka Ringwald } 44189425bfcSMilanka Ringwald 44289425bfcSMilanka Ringwald static int hfp_hf_send_chup(uint16_t cid){ 44389425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_HANG_UP_CALL); 44489425bfcSMilanka Ringwald } 44589425bfcSMilanka Ringwald 446ce263fc8SMatthias Ringwald static int hfp_hf_send_binp(uint16_t cid){ 44789425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_PHONE_NUMBER_FOR_VOICE_TAG, "=1"); 448ce263fc8SMatthias Ringwald } 449ce263fc8SMatthias Ringwald 450667ec068SMatthias Ringwald static int hfp_hf_send_clcc(uint16_t cid){ 45189425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_LIST_CURRENT_CALLS); 452667ec068SMatthias Ringwald } 453667ec068SMatthias Ringwald 45476cc1527SMatthias Ringwald /* state machines */ 4553deb3ec6SMatthias Ringwald 4567f58ef6bSMatthias Ringwald static bool hfp_hf_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){ 4577f58ef6bSMatthias Ringwald if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return false; 4587f58ef6bSMatthias Ringwald if (hfp_connection->ok_pending) return false; 4597f58ef6bSMatthias Ringwald 460498a8121SMilanka Ringwald log_info("hfp_hf_run_for_context_service_level_connection state %d\n", hfp_connection->state); 461a0ffb263SMatthias Ringwald switch (hfp_connection->state){ 4623deb3ec6SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES: 463aeb0f0feSMatthias Ringwald hfp_hf_drop_mSBC_if_eSCO_not_supported(hfp_hf_codecs, &hfp_hf_codecs_nr); 464a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES; 465a0ffb263SMatthias Ringwald hfp_hf_cmd_exchange_supported_features(hfp_connection->rfcomm_cid); 4663deb3ec6SMatthias Ringwald break; 4673deb3ec6SMatthias Ringwald case HFP_NOTIFY_ON_CODECS: 468a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_NOTIFY_ON_CODECS; 469a0ffb263SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(hfp_connection->rfcomm_cid); 4703deb3ec6SMatthias Ringwald break; 4713deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS: 472a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS; 473a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_indicators(hfp_connection->rfcomm_cid); 4743deb3ec6SMatthias Ringwald break; 4753deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS_STATUS: 476a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; 477a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_indicators_status(hfp_connection->rfcomm_cid); 4783deb3ec6SMatthias Ringwald break; 4793deb3ec6SMatthias Ringwald case HFP_ENABLE_INDICATORS_STATUS_UPDATE: 480a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; 481a0ffb263SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(hfp_connection->rfcomm_cid, 1); 4823deb3ec6SMatthias Ringwald break; 4833deb3ec6SMatthias Ringwald case HFP_RETRIEVE_CAN_HOLD_CALL: 484a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; 485a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_can_hold_call(hfp_connection->rfcomm_cid); 4863deb3ec6SMatthias Ringwald break; 4873deb3ec6SMatthias Ringwald case HFP_LIST_GENERIC_STATUS_INDICATORS: 488a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 489a0ffb263SMatthias Ringwald hfp_hf_cmd_list_supported_generic_status_indicators(hfp_connection->rfcomm_cid); 4903deb3ec6SMatthias Ringwald break; 4913deb3ec6SMatthias Ringwald case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS: 492a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; 493a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_supported_generic_status_indicators(hfp_connection->rfcomm_cid); 4943deb3ec6SMatthias Ringwald break; 4953deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: 496a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 497a0ffb263SMatthias Ringwald hfp_hf_cmd_list_initital_supported_generic_status_indicators(hfp_connection->rfcomm_cid); 4983deb3ec6SMatthias Ringwald break; 4993deb3ec6SMatthias Ringwald default: 5007f58ef6bSMatthias Ringwald return false; 5013deb3ec6SMatthias Ringwald } 5027f58ef6bSMatthias Ringwald return true; 5033deb3ec6SMatthias Ringwald } 5043deb3ec6SMatthias Ringwald 505ce263fc8SMatthias Ringwald 5067f58ef6bSMatthias Ringwald static bool hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){ 5077f58ef6bSMatthias Ringwald if (hfp_connection->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return false; 508498a8121SMilanka Ringwald if (hfp_connection->ok_pending){ 5097f58ef6bSMatthias Ringwald return false; 510498a8121SMilanka Ringwald } 5117f58ef6bSMatthias Ringwald 512a0ffb263SMatthias Ringwald if (hfp_connection->enable_status_update_for_ag_indicators != 0xFF){ 513a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 514a0ffb263SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(hfp_connection->rfcomm_cid, hfp_connection->enable_status_update_for_ag_indicators); 5157f58ef6bSMatthias Ringwald return true; 516ce263fc8SMatthias Ringwald }; 5177f58ef6bSMatthias Ringwald 518a0ffb263SMatthias Ringwald if (hfp_connection->change_status_update_for_individual_ag_indicators){ 519a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 520a0ffb263SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_ag_indicator(hfp_connection->rfcomm_cid, 521a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap, 522a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_nr); 5237f58ef6bSMatthias Ringwald return true; 524ce263fc8SMatthias Ringwald } 525ce263fc8SMatthias Ringwald 526a0ffb263SMatthias Ringwald switch (hfp_connection->hf_query_operator_state){ 527ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_SET_FORMAT: 528a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_W4_SET_FORMAT_OK; 529a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 530a0ffb263SMatthias Ringwald hfp_hf_cmd_query_operator_name_format(hfp_connection->rfcomm_cid); 5317f58ef6bSMatthias Ringwald return true; 532ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_SEND_QUERY: 533a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HPF_HF_QUERY_OPERATOR_W4_RESULT; 534a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 535a0ffb263SMatthias Ringwald hfp_hf_cmd_query_operator_name(hfp_connection->rfcomm_cid); 5367f58ef6bSMatthias Ringwald return true; 537ce263fc8SMatthias Ringwald default: 538ce263fc8SMatthias Ringwald break; 539ce263fc8SMatthias Ringwald } 540ce263fc8SMatthias Ringwald 541a0ffb263SMatthias Ringwald if (hfp_connection->enable_extended_audio_gateway_error_report){ 542a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 543a0ffb263SMatthias Ringwald hfp_hf_cmd_enable_extended_audio_gateway_error_report(hfp_connection->rfcomm_cid, hfp_connection->enable_extended_audio_gateway_error_report); 5447f58ef6bSMatthias Ringwald return true; 545ce263fc8SMatthias Ringwald } 546ce263fc8SMatthias Ringwald 5477f58ef6bSMatthias Ringwald return false; 548ce263fc8SMatthias Ringwald } 549ce263fc8SMatthias Ringwald 5507f58ef6bSMatthias Ringwald static bool hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connection){ 551be55a11dSMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) { 5527f58ef6bSMatthias Ringwald return false; 553be55a11dSMilanka Ringwald } 554fd4151d1SMilanka Ringwald 5550b4debbfSMilanka Ringwald if (hfp_connection->ok_pending == 1){ 5567f58ef6bSMatthias Ringwald return false; 5570b4debbfSMilanka Ringwald } 5580b4debbfSMilanka Ringwald // voice recognition activated from AG 5590b4debbfSMilanka Ringwald if (hfp_connection->command == HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION){ 5600b4debbfSMilanka Ringwald switch(hfp_connection->vra_state_requested){ 5610b4debbfSMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: 5620b4debbfSMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF: 563de9e0ea7SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 5640b4debbfSMilanka Ringwald // ignore AG command, continue to wait for OK 5657f58ef6bSMatthias Ringwald return false; 566cf75be85SMilanka Ringwald 5670b4debbfSMilanka Ringwald default: 568b95cac54SMilanka Ringwald if (hfp_connection->ag_vra_msg_length > 0){ 569b95cac54SMilanka Ringwald hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection); 570b95cac54SMilanka Ringwald hfp_connection->ag_vra_msg_length = 0; 571b95cac54SMilanka Ringwald break; 572b95cac54SMilanka Ringwald } 573cf75be85SMilanka Ringwald switch(hfp_connection->ag_vra_state){ 574cf75be85SMilanka Ringwald case HFP_VOICE_RECOGNITION_STATE_AG_READY: 575013cc750SMilanka Ringwald switch (hfp_connection->ag_vra_status){ 576013cc750SMilanka Ringwald case 0: 5770b4debbfSMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_OFF; 578013cc750SMilanka Ringwald break; 579013cc750SMilanka Ringwald case 1: 580013cc750SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED; 581013cc750SMilanka Ringwald break; 582013cc750SMilanka Ringwald case 2: 583013cc750SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; 584013cc750SMilanka Ringwald break; 585013cc750SMilanka Ringwald default: 586013cc750SMilanka Ringwald break; 5870b4debbfSMilanka Ringwald } 5880b4debbfSMilanka Ringwald break; 589cf75be85SMilanka Ringwald default: 590cf75be85SMilanka Ringwald // state messages from AG 591cf75be85SMilanka Ringwald hfp_emit_enhanced_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); 5928d5005b5SMilanka Ringwald hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY; 593cf75be85SMilanka Ringwald break; 594cf75be85SMilanka Ringwald } 595cf75be85SMilanka Ringwald break; 5960b4debbfSMilanka Ringwald } 5970b4debbfSMilanka Ringwald hfp_connection->command = HFP_CMD_NONE; 5980b4debbfSMilanka Ringwald } 5990b4debbfSMilanka Ringwald 600498a8121SMilanka Ringwald switch (hfp_connection->vra_state_requested){ 601fdda66c0SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF: 602fdda66c0SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_OFF; 603498a8121SMilanka Ringwald hfp_connection->ok_pending = 1; 604cd7fdf75SMatthias Ringwald hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 0); 6057f58ef6bSMatthias Ringwald return true; 606fd4151d1SMilanka Ringwald 607fdda66c0SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED: 608fdda66c0SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED; 609fd4151d1SMilanka Ringwald hfp_connection->ok_pending = 1; 610cd7fdf75SMatthias Ringwald hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 1); 6117f58ef6bSMatthias Ringwald return true; 612013cc750SMilanka Ringwald 613de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 614de9e0ea7SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; 615de9e0ea7SMilanka Ringwald hfp_connection->ok_pending = 1; 616cd7fdf75SMatthias Ringwald hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 2); 6177f58ef6bSMatthias Ringwald return true; 618de9e0ea7SMilanka Ringwald 619de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF: 620de9e0ea7SMilanka Ringwald hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; 621de9e0ea7SMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state; 622de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = false; 623de9e0ea7SMilanka Ringwald if (hfp_connection->activate_voice_recognition){ 624fcf4ede6SMilanka Ringwald hfp_connection->enhanced_voice_recognition_enabled = hfp_hf_enhanced_vra_flag_supported(hfp_connection); 625de9e0ea7SMilanka Ringwald hfp_hf_activate_voice_recognition(hfp_connection->acl_handle); 626de9e0ea7SMilanka Ringwald } else { 627553a4a56SMilanka Ringwald hfp_emit_voice_recognition_disabled(hfp_connection, ERROR_CODE_SUCCESS); 628de9e0ea7SMilanka Ringwald } 629de9e0ea7SMilanka Ringwald break; 630de9e0ea7SMilanka Ringwald 631be55a11dSMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: 632498a8121SMilanka Ringwald hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; 633498a8121SMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state; 634de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = false; 635de9e0ea7SMilanka Ringwald if (hfp_connection->deactivate_voice_recognition){ 636de9e0ea7SMilanka Ringwald hfp_hf_deactivate_voice_recognition(hfp_connection->acl_handle); 637de9e0ea7SMilanka Ringwald } else { 638fcf4ede6SMilanka Ringwald hfp_connection->enhanced_voice_recognition_enabled = hfp_hf_enhanced_vra_flag_supported(hfp_connection); 63984fb9ac1SMilanka Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED){ 640553a4a56SMilanka Ringwald hfp_emit_voice_recognition_enabled(hfp_connection, ERROR_CODE_SUCCESS); 64184fb9ac1SMilanka Ringwald } else { 64284fb9ac1SMilanka Ringwald // postpone VRA event to simplify application logic 64384fb9ac1SMilanka Ringwald hfp_connection->emit_vra_enabled_after_audio_established = true; 64484fb9ac1SMilanka Ringwald } 645de9e0ea7SMilanka Ringwald } 646be55a11dSMilanka Ringwald break; 647be55a11dSMilanka Ringwald 648013cc750SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 649013cc750SMilanka Ringwald hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; 650498a8121SMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state; 651de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = false; 652de9e0ea7SMilanka Ringwald if (hfp_connection->deactivate_voice_recognition){ 653de9e0ea7SMilanka Ringwald hfp_hf_deactivate_voice_recognition(hfp_connection->acl_handle); 654de9e0ea7SMilanka Ringwald } else { 655de9e0ea7SMilanka Ringwald hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_SUCCESS); 656de9e0ea7SMilanka Ringwald } 657be55a11dSMilanka Ringwald break; 658fd4151d1SMilanka Ringwald 659be55a11dSMilanka Ringwald default: 660be55a11dSMilanka Ringwald break; 661be55a11dSMilanka Ringwald } 6627f58ef6bSMatthias Ringwald return false; 663be55a11dSMilanka Ringwald } 664be55a11dSMilanka Ringwald 665be55a11dSMilanka Ringwald 6667f58ef6bSMatthias Ringwald static bool codecs_exchange_state_machine(hfp_connection_t * hfp_connection){ 6677f58ef6bSMatthias Ringwald if (hfp_connection->ok_pending) return false; 668ce263fc8SMatthias Ringwald 669332ca98fSMatthias Ringwald if (hfp_connection->trigger_codec_exchange){ 6707f58ef6bSMatthias Ringwald hfp_connection->trigger_codec_exchange = false; 671ce263fc8SMatthias Ringwald 672a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 673a0ffb263SMatthias Ringwald hfp_hf_cmd_trigger_codec_connection_setup(hfp_connection->rfcomm_cid); 6747f58ef6bSMatthias Ringwald return true; 675332ca98fSMatthias Ringwald } 676332ca98fSMatthias Ringwald 6771cc65c4fSMatthias Ringwald if (hfp_connection->hf_send_codec_confirm){ 6781cc65c4fSMatthias Ringwald hfp_connection->hf_send_codec_confirm = false; 679ce263fc8SMatthias Ringwald 680a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 681fcb08cdbSMilanka Ringwald hfp_hf_cmd_confirm_codec(hfp_connection->rfcomm_cid, hfp_connection->codec_confirmed); 6827f58ef6bSMatthias Ringwald return true; 6831cc65c4fSMatthias Ringwald } 6841cc65c4fSMatthias Ringwald 6851cc65c4fSMatthias Ringwald if (hfp_connection->hf_send_supported_codecs){ 6861cc65c4fSMatthias Ringwald hfp_connection->hf_send_supported_codecs = false; 6871cc65c4fSMatthias Ringwald 688a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 689a0ffb263SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(hfp_connection->rfcomm_cid); 6907f58ef6bSMatthias Ringwald return true; 6911cc65c4fSMatthias Ringwald } 692ce263fc8SMatthias Ringwald 6937f58ef6bSMatthias Ringwald return false; 694ce263fc8SMatthias Ringwald } 695ce263fc8SMatthias Ringwald 6967f58ef6bSMatthias Ringwald static bool hfp_hf_run_for_audio_connection(hfp_connection_t * hfp_connection){ 697505f1c30SMatthias Ringwald if ((hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) || 6987f58ef6bSMatthias Ringwald (hfp_connection->state > HFP_W2_DISCONNECT_SCO)) return false; 699ce263fc8SMatthias Ringwald 70064f19dedSMilanka Ringwald if (hfp_connection->release_audio_connection){ 701a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_DISCONNECTED; 702a0ffb263SMatthias Ringwald hfp_connection->release_audio_connection = 0; 703a0ffb263SMatthias Ringwald gap_disconnect(hfp_connection->sco_handle); 7047f58ef6bSMatthias Ringwald return true; 705ce263fc8SMatthias Ringwald } 706ce263fc8SMatthias Ringwald 7077f58ef6bSMatthias Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return false; 708ce263fc8SMatthias Ringwald 709ce263fc8SMatthias Ringwald // run codecs exchange 7107f58ef6bSMatthias Ringwald bool done = codecs_exchange_state_machine(hfp_connection); 7117f58ef6bSMatthias Ringwald if (done) return true; 712ce263fc8SMatthias Ringwald 7137f58ef6bSMatthias Ringwald if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return false; 7147f58ef6bSMatthias Ringwald if (hfp_sco_setup_active()) return false; 71538200c1dSMilanka Ringwald if (hfp_connection->establish_audio_connection){ 71638200c1dSMilanka Ringwald hfp_connection->state = HFP_W4_SCO_CONNECTED; 71738200c1dSMilanka Ringwald hfp_connection->establish_audio_connection = 0; 71838200c1dSMilanka Ringwald hfp_setup_synchronous_connection(hfp_connection); 7197f58ef6bSMatthias Ringwald return true; 72038200c1dSMilanka Ringwald } 7217f58ef6bSMatthias Ringwald return false; 722ce263fc8SMatthias Ringwald } 723ce263fc8SMatthias Ringwald 72438200c1dSMilanka Ringwald 7257f58ef6bSMatthias Ringwald static bool call_setup_state_machine(hfp_connection_t * hfp_connection){ 726eaf2b0a1SMatthias Ringwald 7277f58ef6bSMatthias Ringwald if (hfp_connection->ok_pending) return false; 728eaf2b0a1SMatthias Ringwald 729a0ffb263SMatthias Ringwald if (hfp_connection->hf_answer_incoming_call){ 730a0ffb263SMatthias Ringwald hfp_connection->hf_answer_incoming_call = 0; 731cd7fdf75SMatthias Ringwald hfp_hf_cmd_ata(hfp_connection->rfcomm_cid); 7327f58ef6bSMatthias Ringwald return true; 733ce263fc8SMatthias Ringwald } 7347f58ef6bSMatthias Ringwald return false; 735ce263fc8SMatthias Ringwald } 736ce263fc8SMatthias Ringwald 7371c6a0fc0SMatthias Ringwald static void hfp_hf_run_for_context(hfp_connection_t * hfp_connection){ 7387522e673SMatthias Ringwald 73976cc1527SMatthias Ringwald btstack_assert(hfp_connection != NULL); 74076cc1527SMatthias Ringwald btstack_assert(hfp_connection->local_role == HFP_ROLE_HF); 74176cc1527SMatthias Ringwald 74276cc1527SMatthias Ringwald // during SDP query, RFCOMM CID is not set 74376cc1527SMatthias Ringwald if (hfp_connection->rfcomm_cid == 0) return; 74422387625SMatthias Ringwald 74584fb9ac1SMilanka Ringwald // emit postponed VRA event 74684fb9ac1SMilanka Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED && hfp_connection->emit_vra_enabled_after_audio_established){ 74784fb9ac1SMilanka Ringwald hfp_connection->emit_vra_enabled_after_audio_established = false; 74884fb9ac1SMilanka Ringwald hfp_emit_voice_recognition_enabled(hfp_connection, ERROR_CODE_SUCCESS); 74984fb9ac1SMilanka Ringwald } 75084fb9ac1SMilanka Ringwald 7513721a235SMatthias Ringwald // assert command could be sent 7523721a235SMatthias Ringwald if (hci_can_send_command_packet_now() == 0) return; 7533721a235SMatthias Ringwald 7543721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP 7553721a235SMatthias Ringwald // WBS Disassociate 7563721a235SMatthias Ringwald if (hfp_connection->cc256x_send_wbs_disassociate){ 7573721a235SMatthias Ringwald hfp_connection->cc256x_send_wbs_disassociate = false; 7583721a235SMatthias Ringwald hci_send_cmd(&hci_ti_wbs_disassociate); 7593721a235SMatthias Ringwald return; 7603721a235SMatthias Ringwald } 7613721a235SMatthias Ringwald // Write Codec Config 7623721a235SMatthias Ringwald if (hfp_connection->cc256x_send_write_codec_config){ 7633721a235SMatthias Ringwald hfp_connection->cc256x_send_write_codec_config = false; 7643721a235SMatthias Ringwald hfp_cc256x_write_codec_config(hfp_connection); 7653721a235SMatthias Ringwald return; 7663721a235SMatthias Ringwald } 7673721a235SMatthias Ringwald // WBS Associate 7683721a235SMatthias Ringwald if (hfp_connection->cc256x_send_wbs_associate){ 7693721a235SMatthias Ringwald hfp_connection->cc256x_send_wbs_associate = false; 7703721a235SMatthias Ringwald hci_send_cmd(&hci_ti_wbs_associate, hfp_connection->acl_handle); 7713721a235SMatthias Ringwald return; 7723721a235SMatthias Ringwald } 7733721a235SMatthias Ringwald #endif 774689d4323SMatthias Ringwald #ifdef ENABLE_BCM_PCM_WBS 775689d4323SMatthias Ringwald // Enable WBS 776689d4323SMatthias Ringwald if (hfp_connection->bcm_send_enable_wbs){ 777689d4323SMatthias Ringwald hfp_connection->bcm_send_enable_wbs = false; 778689d4323SMatthias Ringwald hci_send_cmd(&hci_bcm_enable_wbs, 1, 2); 779689d4323SMatthias Ringwald return; 780689d4323SMatthias Ringwald } 781689d4323SMatthias Ringwald // Write I2S/PCM params 782689d4323SMatthias Ringwald if (hfp_connection->bcm_send_write_i2spcm_interface_param){ 783689d4323SMatthias Ringwald hfp_connection->bcm_send_write_i2spcm_interface_param = false; 784689d4323SMatthias Ringwald hfp_bcm_write_i2spcm_interface_param(hfp_connection); 785689d4323SMatthias Ringwald return; 786689d4323SMatthias Ringwald } 787689d4323SMatthias Ringwald // Disable WBS 788689d4323SMatthias Ringwald if (hfp_connection->bcm_send_disable_wbs){ 789689d4323SMatthias Ringwald hfp_connection->bcm_send_disable_wbs = false; 790689d4323SMatthias Ringwald hci_send_cmd(&hci_bcm_enable_wbs, 0, 2); 791689d4323SMatthias Ringwald return; 792689d4323SMatthias Ringwald } 793689d4323SMatthias Ringwald #endif 7942b5f92fdSMatthias Ringwald #ifdef ENABLE_RTK_PCM_WBS 7952b5f92fdSMatthias Ringwald if (hfp_connection->rtk_send_sco_config){ 7962b5f92fdSMatthias Ringwald hfp_connection->rtk_send_sco_config = false; 7972b5f92fdSMatthias Ringwald if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){ 7982b5f92fdSMatthias Ringwald log_info("RTK SCO: 16k + mSBC"); 7992b5f92fdSMatthias Ringwald hci_send_cmd(&hci_rtk_configure_sco_routing, 0x81, 0x90, 0x00, 0x00, 0x1a, 0x0c, 0x00, 0x00, 0x41); 8002b5f92fdSMatthias Ringwald } else { 8012b5f92fdSMatthias Ringwald log_info("RTK SCO: 16k + CVSD"); 8022b5f92fdSMatthias Ringwald hci_send_cmd(&hci_rtk_configure_sco_routing, 0x81, 0x90, 0x00, 0x00, 0x1a, 0x0c, 0x0c, 0x00, 0x01); 8032b5f92fdSMatthias Ringwald } 8042b5f92fdSMatthias Ringwald return; 8052b5f92fdSMatthias Ringwald } 8062b5f92fdSMatthias Ringwald #endif 8075fd6f360SMatthias Ringwald #ifdef ENABLE_NXP_PCM_WBS 8085fd6f360SMatthias Ringwald if (hfp_connection->nxp_start_audio_handle != HCI_CON_HANDLE_INVALID){ 8095fd6f360SMatthias Ringwald hci_con_handle_t sco_handle = hfp_connection->nxp_start_audio_handle; 8105fd6f360SMatthias Ringwald hfp_connection->nxp_start_audio_handle = HCI_CON_HANDLE_INVALID; 8115fd6f360SMatthias Ringwald hci_send_cmd(&hci_nxp_host_pcm_i2s_audio_config, 0, 0, sco_handle, 0); 8125fd6f360SMatthias Ringwald return; 8135fd6f360SMatthias Ringwald } 8145fd6f360SMatthias Ringwald if (hfp_connection->nxp_stop_audio_handle != HCI_CON_HANDLE_INVALID){ 8155fd6f360SMatthias Ringwald hci_con_handle_t sco_handle = hfp_connection->nxp_stop_audio_handle; 8165fd6f360SMatthias Ringwald hfp_connection->nxp_stop_audio_handle = HCI_CON_HANDLE_INVALID; 8175fd6f360SMatthias Ringwald hci_send_cmd(&hci_nxp_host_pcm_i2s_audio_config, 1, 0, sco_handle, 0); 8185fd6f360SMatthias Ringwald return; 8195fd6f360SMatthias Ringwald } 8205fd6f360SMatthias Ringwald #endif 82148e6eeeeSMatthias Ringwald #if defined (ENABLE_CC256X_ASSISTED_HFP) || defined (ENABLE_BCM_PCM_WBS) 82248e6eeeeSMatthias Ringwald if (hfp_connection->state == HFP_W4_WBS_SHUTDOWN){ 82348e6eeeeSMatthias Ringwald hfp_finalize_connection_context(hfp_connection); 82448e6eeeeSMatthias Ringwald return; 82548e6eeeeSMatthias Ringwald } 82648e6eeeeSMatthias Ringwald #endif 8273721a235SMatthias Ringwald 828447743f7SMatthias Ringwald if (hfp_connection->accept_sco && (hfp_sco_setup_active() == false)){ 829cb81d35dSMatthias Ringwald bool incoming_eSCO = hfp_connection->accept_sco == 2; 8307522e673SMatthias Ringwald // notify about codec selection if not done already 8317522e673SMatthias Ringwald if (hfp_connection->negotiated_codec == 0){ 8327522e673SMatthias Ringwald hfp_connection->negotiated_codec = HFP_CODEC_CVSD; 8337522e673SMatthias Ringwald } 834cb81d35dSMatthias Ringwald hfp_accept_synchronous_connection(hfp_connection, incoming_eSCO); 8357522e673SMatthias Ringwald return; 8367522e673SMatthias Ringwald } 8377522e673SMatthias Ringwald 838d4dd47ffSMatthias Ringwald if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) { 839d4dd47ffSMatthias Ringwald rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); 840d4dd47ffSMatthias Ringwald return; 841d4dd47ffSMatthias Ringwald } 842cd7fdf75SMatthias Ringwald 843cd7fdf75SMatthias Ringwald // we can send at least an RFCOMM packet or a HCI Command now 844cd7fdf75SMatthias Ringwald 8457f58ef6bSMatthias Ringwald bool done = hfp_hf_run_for_context_service_level_connection(hfp_connection); 846ce263fc8SMatthias Ringwald if (!done){ 847a0ffb263SMatthias Ringwald done = hfp_hf_run_for_context_service_level_connection_queries(hfp_connection); 848ce263fc8SMatthias Ringwald } 849ce263fc8SMatthias Ringwald if (!done){ 850c95b5b3cSMilanka Ringwald done = hfp_hf_run_for_audio_connection(hfp_connection); 851be55a11dSMilanka Ringwald } 852be55a11dSMilanka Ringwald if (!done){ 853c95b5b3cSMilanka Ringwald done = hfp_hf_voice_recognition_state_machine(hfp_connection); 854ce263fc8SMatthias Ringwald } 855ce263fc8SMatthias Ringwald if (!done){ 856a0ffb263SMatthias Ringwald done = call_setup_state_machine(hfp_connection); 857ce263fc8SMatthias Ringwald } 858ce263fc8SMatthias Ringwald 859e2c3b58dSMilanka Ringwald // don't send a new command while ok still pending or SLC is not established 860e2c3b58dSMilanka Ringwald if (hfp_connection->ok_pending || (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED)){ 861e2c3b58dSMilanka Ringwald return; 862e2c3b58dSMilanka Ringwald } 8631016a228SMatthias Ringwald 864a0ffb263SMatthias Ringwald if (hfp_connection->send_microphone_gain){ 865a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 0; 866a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 867a0ffb263SMatthias Ringwald hfp_hf_set_microphone_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->microphone_gain); 868ce263fc8SMatthias Ringwald return; 869ce263fc8SMatthias Ringwald } 870ce263fc8SMatthias Ringwald 871a0ffb263SMatthias Ringwald if (hfp_connection->send_speaker_gain){ 872a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 0; 873a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 874a0ffb263SMatthias Ringwald hfp_hf_set_speaker_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->speaker_gain); 875ce263fc8SMatthias Ringwald return; 876ce263fc8SMatthias Ringwald } 877ce263fc8SMatthias Ringwald 878a0ffb263SMatthias Ringwald if (hfp_connection->hf_deactivate_calling_line_notification){ 879a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_calling_line_notification = 0; 880a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 881a0ffb263SMatthias Ringwald hfp_hf_set_calling_line_notification_cmd(hfp_connection->rfcomm_cid, 0); 882ce263fc8SMatthias Ringwald return; 883ce263fc8SMatthias Ringwald } 884ce263fc8SMatthias Ringwald 885a0ffb263SMatthias Ringwald if (hfp_connection->hf_activate_calling_line_notification){ 886a0ffb263SMatthias Ringwald hfp_connection->hf_activate_calling_line_notification = 0; 887a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 888a0ffb263SMatthias Ringwald hfp_hf_set_calling_line_notification_cmd(hfp_connection->rfcomm_cid, 1); 889ce263fc8SMatthias Ringwald return; 890ce263fc8SMatthias Ringwald } 891ce263fc8SMatthias Ringwald 892a0ffb263SMatthias Ringwald if (hfp_connection->hf_deactivate_echo_canceling_and_noise_reduction){ 893a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_echo_canceling_and_noise_reduction = 0; 89499af1e28SMilanka Ringwald hfp_connection->response_pending_for_command = HFP_CMD_TURN_OFF_EC_AND_NR; 895a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 896e2c3b58dSMilanka Ringwald hfp_hf_send_cmd_with_int(hfp_connection->rfcomm_cid, HFP_TURN_OFF_EC_AND_NR, 0); 897ce263fc8SMatthias Ringwald return; 898ce263fc8SMatthias Ringwald } 899ce263fc8SMatthias Ringwald 900a0ffb263SMatthias Ringwald if (hfp_connection->hf_deactivate_call_waiting_notification){ 901a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_call_waiting_notification = 0; 902a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 903a0ffb263SMatthias Ringwald hfp_hf_set_call_waiting_notification_cmd(hfp_connection->rfcomm_cid, 0); 904ce263fc8SMatthias Ringwald return; 905ce263fc8SMatthias Ringwald } 906ce263fc8SMatthias Ringwald 907a0ffb263SMatthias Ringwald if (hfp_connection->hf_activate_call_waiting_notification){ 908a0ffb263SMatthias Ringwald hfp_connection->hf_activate_call_waiting_notification = 0; 909a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 910a0ffb263SMatthias Ringwald hfp_hf_set_call_waiting_notification_cmd(hfp_connection->rfcomm_cid, 1); 911ce263fc8SMatthias Ringwald return; 912ce263fc8SMatthias Ringwald } 913ce263fc8SMatthias Ringwald 914a0ffb263SMatthias Ringwald if (hfp_connection->hf_initiate_outgoing_call){ 915a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_outgoing_call = 0; 916a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 917a0ffb263SMatthias Ringwald hfp_hf_initiate_outgoing_call_cmd(hfp_connection->rfcomm_cid); 918ce263fc8SMatthias Ringwald return; 919ce263fc8SMatthias Ringwald } 920ce263fc8SMatthias Ringwald 921a0ffb263SMatthias Ringwald if (hfp_connection->hf_initiate_memory_dialing){ 922a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_memory_dialing = 0; 923a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 924a0ffb263SMatthias Ringwald hfp_hf_send_memory_dial_cmd(hfp_connection->rfcomm_cid, hfp_connection->memory_id); 925ce263fc8SMatthias Ringwald return; 926ce263fc8SMatthias Ringwald } 927ce263fc8SMatthias Ringwald 928a0ffb263SMatthias Ringwald if (hfp_connection->hf_initiate_redial_last_number){ 929a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_redial_last_number = 0; 930a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 931a0ffb263SMatthias Ringwald hfp_hf_send_redial_last_number_cmd(hfp_connection->rfcomm_cid); 932ce263fc8SMatthias Ringwald return; 933ce263fc8SMatthias Ringwald } 934ce263fc8SMatthias Ringwald 935a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chup){ 936a0ffb263SMatthias Ringwald hfp_connection->hf_send_chup = 0; 937a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 938a0ffb263SMatthias Ringwald hfp_hf_send_chup(hfp_connection->rfcomm_cid); 939ce263fc8SMatthias Ringwald return; 940ce263fc8SMatthias Ringwald } 941ce263fc8SMatthias Ringwald 942a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_0){ 943a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_0 = 0; 944a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 945a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 0); 946ce263fc8SMatthias Ringwald return; 947ce263fc8SMatthias Ringwald } 948ce263fc8SMatthias Ringwald 949a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_1){ 950a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_1 = 0; 951a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 952a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 1); 953ce263fc8SMatthias Ringwald return; 954ce263fc8SMatthias Ringwald } 955ce263fc8SMatthias Ringwald 956a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_2){ 957a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_2 = 0; 958a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 959a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 2); 960ce263fc8SMatthias Ringwald return; 961ce263fc8SMatthias Ringwald } 962ce263fc8SMatthias Ringwald 963a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_3){ 964a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_3 = 0; 965a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 966a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 3); 967ce263fc8SMatthias Ringwald return; 968ce263fc8SMatthias Ringwald } 969ce263fc8SMatthias Ringwald 970a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_4){ 971a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_4 = 0; 972a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 973a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 4); 974ce263fc8SMatthias Ringwald return; 975ce263fc8SMatthias Ringwald } 976ce263fc8SMatthias Ringwald 977a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_x){ 978a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x = 0; 979a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 980a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, hfp_connection->hf_send_chld_x_index); 981667ec068SMatthias Ringwald return; 982667ec068SMatthias Ringwald } 983667ec068SMatthias Ringwald 984a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_dtmf_code){ 985a0ffb263SMatthias Ringwald char code = hfp_connection->hf_send_dtmf_code; 986a0ffb263SMatthias Ringwald hfp_connection->hf_send_dtmf_code = 0; 987a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 988a0ffb263SMatthias Ringwald hfp_hf_send_dtmf(hfp_connection->rfcomm_cid, code); 989c090e552SMatthias Ringwald // notify client that dtmf was sent 990c090e552SMatthias Ringwald char buffer[2]; 991c090e552SMatthias Ringwald buffer[0] = code; 992c090e552SMatthias Ringwald buffer[1] = 0; 993c090e552SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_TRANSMIT_DTMF_CODES, buffer); 994ce263fc8SMatthias Ringwald return; 995ce263fc8SMatthias Ringwald } 996ce263fc8SMatthias Ringwald 997a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_binp){ 998a0ffb263SMatthias Ringwald hfp_connection->hf_send_binp = 0; 999a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1000a0ffb263SMatthias Ringwald hfp_hf_send_binp(hfp_connection->rfcomm_cid); 1001ce263fc8SMatthias Ringwald return; 1002ce263fc8SMatthias Ringwald } 1003ce263fc8SMatthias Ringwald 1004a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_clcc){ 1005a0ffb263SMatthias Ringwald hfp_connection->hf_send_clcc = 0; 1006a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1007a0ffb263SMatthias Ringwald hfp_hf_send_clcc(hfp_connection->rfcomm_cid); 1008667ec068SMatthias Ringwald return; 1009667ec068SMatthias Ringwald } 1010667ec068SMatthias Ringwald 1011a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_rrh){ 1012a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 0; 1013667ec068SMatthias Ringwald char buffer[20]; 1014a0ffb263SMatthias Ringwald switch (hfp_connection->hf_send_rrh_command){ 1015667ec068SMatthias Ringwald case '?': 10161599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s?\r", 1017ff7d6aeaSMatthias Ringwald HFP_RESPONSE_AND_HOLD); 1018ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 1019a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer); 1020667ec068SMatthias Ringwald return; 1021667ec068SMatthias Ringwald case '0': 1022667ec068SMatthias Ringwald case '1': 1023667ec068SMatthias Ringwald case '2': 10241599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=%c\r", 1025ff7d6aeaSMatthias Ringwald HFP_RESPONSE_AND_HOLD, 1026ff7d6aeaSMatthias Ringwald hfp_connection->hf_send_rrh_command); 1027ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 1028a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer); 1029667ec068SMatthias Ringwald return; 1030667ec068SMatthias Ringwald default: 1031667ec068SMatthias Ringwald break; 1032667ec068SMatthias Ringwald } 1033667ec068SMatthias Ringwald return; 1034667ec068SMatthias Ringwald } 1035667ec068SMatthias Ringwald 1036a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_cnum){ 1037a0ffb263SMatthias Ringwald hfp_connection->hf_send_cnum = 0; 1038667ec068SMatthias Ringwald char buffer[20]; 10391599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s\r", 1040ff7d6aeaSMatthias Ringwald HFP_SUBSCRIBER_NUMBER_INFORMATION); 1041ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 1042a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer); 1043667ec068SMatthias Ringwald return; 1044667ec068SMatthias Ringwald } 1045667ec068SMatthias Ringwald 1046667ec068SMatthias Ringwald // update HF indicators 1047a0ffb263SMatthias Ringwald if (hfp_connection->generic_status_update_bitmap){ 1048667ec068SMatthias Ringwald int i; 1049aeb0f0feSMatthias Ringwald for (i=0; i < hfp_hf_indicators_nr; i++){ 1050a0ffb263SMatthias Ringwald if (get_bit(hfp_connection->generic_status_update_bitmap, i)){ 10510f716b22SMatthias Ringwald hfp_connection->generic_status_update_bitmap = store_bit(hfp_connection->generic_status_update_bitmap, i, 0); 1052a0ffb263SMatthias Ringwald if (hfp_connection->generic_status_indicators[i].state){ 1053a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1; 1054667ec068SMatthias Ringwald char buffer[30]; 10551599fe57SMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=%u,%u\r", 1056ff7d6aeaSMatthias Ringwald HFP_TRANSFER_HF_INDICATOR_STATUS, 1057aeb0f0feSMatthias Ringwald hfp_hf_indicators[i], 1058aeb0f0feSMatthias Ringwald (unsigned int)hfp_hf_indicators_value[i]); 1059ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0; 1060a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer); 1061667ec068SMatthias Ringwald } else { 1062aeb0f0feSMatthias Ringwald log_info("Not sending HF indicator %u as it is disabled", hfp_hf_indicators[i]); 1063667ec068SMatthias Ringwald } 1064667ec068SMatthias Ringwald return; 1065667ec068SMatthias Ringwald } 1066667ec068SMatthias Ringwald } 1067667ec068SMatthias Ringwald } 1068667ec068SMatthias Ringwald 1069*4e8ee53aSMatthias Ringwald if (hfp_connection->send_apple_information){ 1070*4e8ee53aSMatthias Ringwald hfp_connection->send_apple_information = false; 1071*4e8ee53aSMatthias Ringwald hfp_connection->ok_pending = 1; 1072*4e8ee53aSMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_APPLE_ACCESSORY_INFORMATION; 1073*4e8ee53aSMatthias Ringwald char buffer[40]; 1074*4e8ee53aSMatthias Ringwald snprintf(buffer, sizeof(buffer), "AT%s=%04x-%04x-%s,%u\r", HFP_APPLE_ACCESSORY_INFORMATION, 1075*4e8ee53aSMatthias Ringwald hfp_hf_apple_vendor_id, hfp_hf_apple_product_id, hfp_hf_apple_version, hfp_hf_apple_features); 1076*4e8ee53aSMatthias Ringwald (void) send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer); 1077*4e8ee53aSMatthias Ringwald return; 1078*4e8ee53aSMatthias Ringwald } 1079*4e8ee53aSMatthias Ringwald 108051a2ebdeSMatthias Ringwald if (hfp_connection->send_custom_message != NULL){ 108151a2ebdeSMatthias Ringwald const char * message = hfp_connection->send_custom_message; 108251a2ebdeSMatthias Ringwald hfp_connection->send_custom_message = NULL; 108351a2ebdeSMatthias Ringwald hfp_connection->ok_pending = 1; 108451a2ebdeSMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_CUSTOM_MESSAGE; 108551a2ebdeSMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, message); 108651a2ebdeSMatthias Ringwald return; 108751a2ebdeSMatthias Ringwald } 108851a2ebdeSMatthias Ringwald 1089ce263fc8SMatthias Ringwald if (done) return; 1090ce263fc8SMatthias Ringwald // deal with disconnect 1091a0ffb263SMatthias Ringwald switch (hfp_connection->state){ 1092ce263fc8SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM: 1093a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RFCOMM_DISCONNECTED; 1094a0ffb263SMatthias Ringwald rfcomm_disconnect(hfp_connection->rfcomm_cid); 1095ce263fc8SMatthias Ringwald break; 1096ce263fc8SMatthias Ringwald 1097ce263fc8SMatthias Ringwald default: 1098ce263fc8SMatthias Ringwald break; 1099ce263fc8SMatthias Ringwald } 1100ce263fc8SMatthias Ringwald } 1101ce263fc8SMatthias Ringwald 1102ad862247SMatthias Ringwald static void hfp_hf_slc_established(hfp_connection_t * hfp_connection){ 1103a0ffb263SMatthias Ringwald hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 11046a7f44bdSMilanka Ringwald 11057095467fSMatthias Ringwald hfp_emit_slc_connection_event(hfp_connection->local_role, 0, hfp_connection->acl_handle, hfp_connection->remote_addr); 11067522e673SMatthias Ringwald 1107184a03edSMilanka Ringwald uint8_t i; 1108184a03edSMilanka Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){ 11091ac1f60fSMilanka Ringwald hfp_emit_ag_indicator_mapping_event(hfp_connection, &hfp_connection->ag_indicators[i]); 1110184a03edSMilanka Ringwald } 1111722a85f3SMilanka Ringwald 1112722a85f3SMilanka Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){ 1113722a85f3SMilanka Ringwald hfp_connection->ag_indicators[i].status_changed = 0; 1114722a85f3SMilanka Ringwald hfp_emit_ag_indicator_status_event(hfp_connection, &hfp_connection->ag_indicators[i]); 1115722a85f3SMilanka Ringwald } 1116722a85f3SMilanka Ringwald 1117*4e8ee53aSMatthias Ringwald hfp_connection->apple_accessory_commands_supported = false; 1118*4e8ee53aSMatthias Ringwald hfp_connection->send_apple_information = hfp_hf_apple_vendor_id != 0; 1119*4e8ee53aSMatthias Ringwald 1120667ec068SMatthias Ringwald // restore volume settings 1121a0ffb263SMatthias Ringwald hfp_connection->speaker_gain = hfp_hf_speaker_gain; 1122a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 1; 1123ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_SPEAKER_VOLUME, hfp_hf_speaker_gain); 1124a0ffb263SMatthias Ringwald hfp_connection->microphone_gain = hfp_hf_microphone_gain; 1125a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 1; 1126ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_MICROPHONE_VOLUME, hfp_hf_microphone_gain); 1127ce263fc8SMatthias Ringwald } 1128ce263fc8SMatthias Ringwald 11291cc65c4fSMatthias Ringwald static void hfp_hf_handle_suggested_codec(hfp_connection_t * hfp_connection){ 1130aeb0f0feSMatthias Ringwald if (hfp_supports_codec(hfp_connection->suggested_codec, hfp_hf_codecs_nr, hfp_hf_codecs)){ 11311cc65c4fSMatthias Ringwald // Codec supported, confirm 11321cc65c4fSMatthias Ringwald hfp_connection->negotiated_codec = hfp_connection->suggested_codec; 11331cc65c4fSMatthias Ringwald hfp_connection->codec_confirmed = hfp_connection->suggested_codec; 11341cc65c4fSMatthias Ringwald log_info("hfp: codec confirmed: %s", (hfp_connection->negotiated_codec == HFP_CODEC_MSBC) ? "mSBC" : "CVSD"); 11351cc65c4fSMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_HF_CONFIRMED_CODEC; 11361cc65c4fSMatthias Ringwald 11371cc65c4fSMatthias Ringwald hfp_connection->hf_send_codec_confirm = true; 11381cc65c4fSMatthias Ringwald } else { 11391cc65c4fSMatthias Ringwald // Codec not supported, send supported codecs 11401cc65c4fSMatthias Ringwald hfp_connection->codec_confirmed = 0; 11411cc65c4fSMatthias Ringwald hfp_connection->suggested_codec = 0; 11421cc65c4fSMatthias Ringwald hfp_connection->negotiated_codec = 0; 11431cc65c4fSMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; 11441cc65c4fSMatthias Ringwald 11451cc65c4fSMatthias Ringwald hfp_connection->hf_send_supported_codecs = true; 11461cc65c4fSMatthias Ringwald } 11471cc65c4fSMatthias Ringwald } 1148*4e8ee53aSMatthias Ringwald static void hfp_hf_apple_extension_supported(hfp_connection_t * hfp_connection, bool supported){ 1149*4e8ee53aSMatthias Ringwald hfp_connection->apple_accessory_commands_supported = supported; 1150*4e8ee53aSMatthias Ringwald log_info("Apple Extension supported: %u", supported); 1151*4e8ee53aSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_APPLE_EXTENSION_SUPPORTED, hfp_hf_microphone_gain); 1152*4e8ee53aSMatthias Ringwald } 11531cc65c4fSMatthias Ringwald 1154e2c3b58dSMilanka Ringwald static bool hfp_hf_switch_on_ok_pending(hfp_connection_t *hfp_connection, uint8_t status){ 1155e2c3b58dSMilanka Ringwald bool event_emited = true; 1156e2c3b58dSMilanka Ringwald 1157b3e7b9f5SMatthias Ringwald // cache state and reset 1158b3e7b9f5SMatthias Ringwald hfp_command_t response_pending_for_command = hfp_connection->response_pending_for_command; 1159b3e7b9f5SMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_NONE; 1160b3e7b9f5SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1161b3e7b9f5SMatthias Ringwald hfp_connection->ok_pending = 0; 1162b3e7b9f5SMatthias Ringwald 1163b3e7b9f5SMatthias Ringwald switch (response_pending_for_command){ 1164e2c3b58dSMilanka Ringwald case HFP_CMD_TURN_OFF_EC_AND_NR: 1165e2c3b58dSMilanka Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_ECHO_CANCELING_AND_NOISE_REDUCTION_DEACTIVATE, status); 1166e2c3b58dSMilanka Ringwald break; 116751a2ebdeSMatthias Ringwald case HFP_CMD_CUSTOM_MESSAGE: 11687f8f1191SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_CUSTOM_AT_MESSAGE_SENT, status); 116951a2ebdeSMatthias Ringwald break; 1170*4e8ee53aSMatthias Ringwald case HFP_CMD_APPLE_ACCESSORY_INFORMATION: 1171*4e8ee53aSMatthias Ringwald hfp_hf_apple_extension_supported(hfp_connection, true); 1172*4e8ee53aSMatthias Ringwald break; 1173e2c3b58dSMilanka Ringwald default: 1174e2c3b58dSMilanka Ringwald event_emited = false; 1175e2c3b58dSMilanka Ringwald 1176a0ffb263SMatthias Ringwald switch (hfp_connection->state){ 11773deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: 1178a0ffb263SMatthias Ringwald if (has_codec_negotiation_feature(hfp_connection)){ 1179a0ffb263SMatthias Ringwald hfp_connection->state = HFP_NOTIFY_ON_CODECS; 11803deb3ec6SMatthias Ringwald break; 11813deb3ec6SMatthias Ringwald } 1182a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS; 11833deb3ec6SMatthias Ringwald break; 11843deb3ec6SMatthias Ringwald 11853deb3ec6SMatthias Ringwald case HFP_W4_NOTIFY_ON_CODECS: 1186a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS; 11873deb3ec6SMatthias Ringwald break; 11883deb3ec6SMatthias Ringwald 11893deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS: 1190a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS_STATUS; 11913deb3ec6SMatthias Ringwald break; 11923deb3ec6SMatthias Ringwald 11933deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS_STATUS: 1194a0ffb263SMatthias Ringwald hfp_connection->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE; 11953deb3ec6SMatthias Ringwald break; 11963deb3ec6SMatthias Ringwald 11973deb3ec6SMatthias Ringwald case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: 1198a0ffb263SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(hfp_connection)){ 1199a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_CAN_HOLD_CALL; 12003deb3ec6SMatthias Ringwald break; 12013deb3ec6SMatthias Ringwald } 1202a0ffb263SMatthias Ringwald if (has_hf_indicators_feature(hfp_connection)){ 1203a0ffb263SMatthias Ringwald hfp_connection->state = HFP_LIST_GENERIC_STATUS_INDICATORS; 12043deb3ec6SMatthias Ringwald break; 12053deb3ec6SMatthias Ringwald } 1206ad862247SMatthias Ringwald hfp_hf_slc_established(hfp_connection); 12073deb3ec6SMatthias Ringwald break; 12083deb3ec6SMatthias Ringwald 12093deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_CAN_HOLD_CALL: 1210a0ffb263SMatthias Ringwald if (has_hf_indicators_feature(hfp_connection)){ 1211a0ffb263SMatthias Ringwald hfp_connection->state = HFP_LIST_GENERIC_STATUS_INDICATORS; 12123deb3ec6SMatthias Ringwald break; 12133deb3ec6SMatthias Ringwald } 1214ad862247SMatthias Ringwald hfp_hf_slc_established(hfp_connection); 12153deb3ec6SMatthias Ringwald break; 12163deb3ec6SMatthias Ringwald 12173deb3ec6SMatthias Ringwald case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: 1218a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS; 12193deb3ec6SMatthias Ringwald break; 12203deb3ec6SMatthias Ringwald 12213deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: 1222a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 12233deb3ec6SMatthias Ringwald break; 12243deb3ec6SMatthias Ringwald 12253deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: 1226ad862247SMatthias Ringwald hfp_hf_slc_established(hfp_connection); 12273deb3ec6SMatthias Ringwald break; 1228ce263fc8SMatthias Ringwald case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: 1229a0ffb263SMatthias Ringwald if (hfp_connection->enable_status_update_for_ag_indicators != 0xFF){ 1230a0ffb263SMatthias Ringwald hfp_connection->enable_status_update_for_ag_indicators = 0xFF; 12316cc5b34bSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, ERROR_CODE_SUCCESS); 1232ce263fc8SMatthias Ringwald break; 1233ce263fc8SMatthias Ringwald } 12343deb3ec6SMatthias Ringwald 1235a0ffb263SMatthias Ringwald if (hfp_connection->change_status_update_for_individual_ag_indicators == 1){ 1236a0ffb263SMatthias Ringwald hfp_connection->change_status_update_for_individual_ag_indicators = 0; 12376cc5b34bSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, ERROR_CODE_SUCCESS); 1238ce263fc8SMatthias Ringwald break; 12393deb3ec6SMatthias Ringwald } 12403deb3ec6SMatthias Ringwald 1241a0ffb263SMatthias Ringwald switch (hfp_connection->hf_query_operator_state){ 1242ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_W4_SET_FORMAT_OK: 1243a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SEND_QUERY; 1244ce263fc8SMatthias Ringwald break; 1245ce263fc8SMatthias Ringwald case HPF_HF_QUERY_OPERATOR_W4_RESULT: 1246a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_FORMAT_SET; 1247a473a009SMatthias Ringwald hfp_emit_network_operator_event(hfp_connection); 1248ce263fc8SMatthias Ringwald break; 1249ce263fc8SMatthias Ringwald default: 1250ce263fc8SMatthias Ringwald break; 12513deb3ec6SMatthias Ringwald } 1252ce263fc8SMatthias Ringwald 1253a0ffb263SMatthias Ringwald if (hfp_connection->enable_extended_audio_gateway_error_report){ 1254a0ffb263SMatthias Ringwald hfp_connection->enable_extended_audio_gateway_error_report = 0; 1255ce263fc8SMatthias Ringwald break; 12563deb3ec6SMatthias Ringwald } 12573deb3ec6SMatthias Ringwald 1258a0ffb263SMatthias Ringwald switch (hfp_connection->codecs_state){ 1259aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: 1260a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; 12613deb3ec6SMatthias Ringwald break; 1262ce263fc8SMatthias Ringwald case HFP_CODECS_HF_CONFIRMED_CODEC: 1263a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_EXCHANGED; 1264ce263fc8SMatthias Ringwald break; 12653deb3ec6SMatthias Ringwald default: 12663deb3ec6SMatthias Ringwald break; 12673deb3ec6SMatthias Ringwald } 1268af97579eSMilanka Ringwald hfp_hf_voice_recognition_state_machine(hfp_connection); 1269be55a11dSMilanka Ringwald break; 1270be55a11dSMilanka Ringwald case HFP_AUDIO_CONNECTION_ESTABLISHED: 1271af97579eSMilanka Ringwald hfp_hf_voice_recognition_state_machine(hfp_connection); 12723deb3ec6SMatthias Ringwald break; 12733deb3ec6SMatthias Ringwald default: 12743deb3ec6SMatthias Ringwald break; 12753deb3ec6SMatthias Ringwald } 1276e2c3b58dSMilanka Ringwald break; 1277e2c3b58dSMilanka Ringwald } 12783deb3ec6SMatthias Ringwald 1279e2c3b58dSMilanka Ringwald return event_emited; 12803deb3ec6SMatthias Ringwald } 12813deb3ec6SMatthias Ringwald 1282a03dbc20SMilanka Ringwald static bool hfp_is_ringing(hfp_callsetup_status_t callsetup_status){ 1283a03dbc20SMilanka Ringwald switch (callsetup_status){ 1284a03dbc20SMilanka Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1285a03dbc20SMilanka Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 1286a03dbc20SMilanka Ringwald return true; 1287a03dbc20SMilanka Ringwald default: 1288a03dbc20SMilanka Ringwald return false; 1289a03dbc20SMilanka Ringwald } 1290a03dbc20SMilanka Ringwald } 1291be55a11dSMilanka Ringwald 1292b08371a9SMilanka Ringwald static void hfp_hf_handle_transfer_ag_indicator_status(hfp_connection_t * hfp_connection) { 12934562e2a2SMatthias Ringwald uint16_t i; 1294a03dbc20SMilanka Ringwald 12954562e2a2SMatthias Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){ 12964562e2a2SMatthias Ringwald if (hfp_connection->ag_indicators[i].status_changed) { 12974562e2a2SMatthias Ringwald if (strcmp(hfp_connection->ag_indicators[i].name, "callsetup") == 0){ 1298a03dbc20SMilanka Ringwald hfp_callsetup_status_t new_hf_callsetup_status = (hfp_callsetup_status_t) hfp_connection->ag_indicators[i].status; 129966093044SMilanka Ringwald bool ringing_old = hfp_is_ringing(hfp_connection->hf_callsetup_status); 1300a03dbc20SMilanka Ringwald bool ringing_new = hfp_is_ringing(new_hf_callsetup_status); 1301a03dbc20SMilanka Ringwald if (ringing_old != ringing_new){ 1302a03dbc20SMilanka Ringwald if (ringing_new){ 1303a03dbc20SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_START_RINGING); 1304a03dbc20SMilanka Ringwald } else { 1305a03dbc20SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_STOP_RINGING); 1306a03dbc20SMilanka Ringwald } 1307a03dbc20SMilanka Ringwald } 130866093044SMilanka Ringwald hfp_connection->hf_callsetup_status = new_hf_callsetup_status; 13094562e2a2SMatthias Ringwald } else if (strcmp(hfp_connection->ag_indicators[i].name, "callheld") == 0){ 131066093044SMilanka Ringwald hfp_connection->hf_callheld_status = (hfp_callheld_status_t) hfp_connection->ag_indicators[i].status; 13114562e2a2SMatthias Ringwald // avoid set but not used warning 131266093044SMilanka Ringwald (void) hfp_connection->hf_callheld_status; 13134562e2a2SMatthias Ringwald } else if (strcmp(hfp_connection->ag_indicators[i].name, "call") == 0){ 1314674ebed5SMilanka Ringwald hfp_call_status_t new_hf_call_status = (hfp_call_status_t) hfp_connection->ag_indicators[i].status; 131566093044SMilanka Ringwald if (hfp_connection->hf_call_status != new_hf_call_status){ 1316674ebed5SMilanka Ringwald if (new_hf_call_status == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS){ 1317674ebed5SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_TERMINATED); 1318674ebed5SMilanka Ringwald } else { 1319674ebed5SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_ANSWERED); 1320674ebed5SMilanka Ringwald } 1321674ebed5SMilanka Ringwald } 132266093044SMilanka Ringwald hfp_connection->hf_call_status = new_hf_call_status; 13234562e2a2SMatthias Ringwald } 13244562e2a2SMatthias Ringwald hfp_connection->ag_indicators[i].status_changed = 0; 1325ce3797e1SMilanka Ringwald hfp_emit_ag_indicator_status_event(hfp_connection, &hfp_connection->ag_indicators[i]); 13264562e2a2SMatthias Ringwald break; 13274562e2a2SMatthias Ringwald } 13284562e2a2SMatthias Ringwald } 13294562e2a2SMatthias Ringwald } 13304562e2a2SMatthias Ringwald 1331426f9988SMatthias Ringwald static void hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection){ 1332186dd3d2SMatthias Ringwald int value; 1333186dd3d2SMatthias Ringwald int i; 1334e2c3b58dSMilanka Ringwald bool event_emited; 1335e2c3b58dSMilanka Ringwald 1336125560b8SMatthias Ringwald // last argument is still in line_buffer 1337125560b8SMatthias Ringwald 1338a0ffb263SMatthias Ringwald switch (hfp_connection->command){ 1339667ec068SMatthias Ringwald case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION: 1340a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1341a473a009SMatthias Ringwald hfp_hf_emit_subscriber_information(hfp_connection, 0); 1342667ec068SMatthias Ringwald break; 1343667ec068SMatthias Ringwald case HFP_CMD_RESPONSE_AND_HOLD_STATUS: 1344a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1345ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_RESPONSE_AND_HOLD_STATUS, btstack_atoi((char *)&hfp_connection->line_buffer[0])); 1346667ec068SMatthias Ringwald break; 1347667ec068SMatthias Ringwald case HFP_CMD_LIST_CURRENT_CALLS: 1348a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1349a473a009SMatthias Ringwald hfp_hf_emit_enhanced_call_status(hfp_connection); 1350667ec068SMatthias Ringwald break; 1351ce263fc8SMatthias Ringwald case HFP_CMD_SET_SPEAKER_GAIN: 1352a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 13532308e108SMilanka Ringwald value = btstack_atoi((char*)hfp_connection->line_buffer); 1354667ec068SMatthias Ringwald hfp_hf_speaker_gain = value; 1355ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_SPEAKER_VOLUME, value); 1356ce263fc8SMatthias Ringwald break; 1357ce263fc8SMatthias Ringwald case HFP_CMD_SET_MICROPHONE_GAIN: 1358a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 13592308e108SMilanka Ringwald value = btstack_atoi((char*)hfp_connection->line_buffer); 1360667ec068SMatthias Ringwald hfp_hf_microphone_gain = value; 1361ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_MICROPHONE_VOLUME, value); 1362ce263fc8SMatthias Ringwald break; 1363ce263fc8SMatthias Ringwald case HFP_CMD_AG_SENT_PHONE_NUMBER: 1364a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1365ca59be51SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG, hfp_connection->bnip_number); 1366a0ffb263SMatthias Ringwald break; 1367a0ffb263SMatthias Ringwald case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE: 1368a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1369598d4936SMatthias Ringwald hfp_hf_emit_type_number_alpha(hfp_connection, HFP_SUBEVENT_CALL_WAITING_NOTIFICATION); 1370a0ffb263SMatthias Ringwald break; 1371a0ffb263SMatthias Ringwald case HFP_CMD_AG_SENT_CLIP_INFORMATION: 1372a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1373598d4936SMatthias Ringwald hfp_hf_emit_type_number_alpha(hfp_connection, HFP_SUBEVENT_CALLING_LINE_IDENTIFICATION_NOTIFICATION); 1374ce263fc8SMatthias Ringwald break; 1375ce263fc8SMatthias Ringwald case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR: 1376a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 13775a4785c8SMatthias Ringwald hfp_connection->ok_pending = 0; 1378a0ffb263SMatthias Ringwald hfp_connection->extended_audio_gateway_error = 0; 1379ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, hfp_connection->extended_audio_gateway_error_value); 1380ce263fc8SMatthias Ringwald break; 13810b4debbfSMilanka Ringwald case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: 13820b4debbfSMilanka Ringwald break; 1383fdda66c0SMilanka Ringwald case HFP_CMD_ERROR: 138490244c92SMilanka Ringwald switch (hfp_connection->state){ 138590244c92SMilanka Ringwald case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: 138690244c92SMilanka Ringwald switch (hfp_connection->codecs_state){ 138790244c92SMilanka Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: 1388fdda66c0SMilanka Ringwald hfp_reset_context_flags(hfp_connection); 1389f14c5dafSMatthias Ringwald hfp_emit_sco_connection_established(hfp_connection, HFP_REMOTE_REJECTS_AUDIO_CONNECTION, 13905e8e3664SMatthias Ringwald hfp_connection->negotiated_codec, 0, 0); 139190244c92SMilanka Ringwald return; 139290244c92SMilanka Ringwald default: 139390244c92SMilanka Ringwald break; 139490244c92SMilanka Ringwald } 139556f1adacSMilanka Ringwald break; 139656f1adacSMilanka Ringwald default: 139756f1adacSMilanka Ringwald break; 139856f1adacSMilanka Ringwald } 1399e2c3b58dSMilanka Ringwald 1400*4e8ee53aSMatthias Ringwald switch (hfp_connection->response_pending_for_command){ 1401*4e8ee53aSMatthias Ringwald case HFP_CMD_APPLE_ACCESSORY_INFORMATION: 1402*4e8ee53aSMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_NONE; 1403*4e8ee53aSMatthias Ringwald hfp_hf_apple_extension_supported(hfp_connection, false); 1404*4e8ee53aSMatthias Ringwald return; 1405*4e8ee53aSMatthias Ringwald default: 1406*4e8ee53aSMatthias Ringwald break; 1407*4e8ee53aSMatthias Ringwald } 1408*4e8ee53aSMatthias Ringwald 1409fdda66c0SMilanka Ringwald // handle error response for voice activation (HF initiated) 14100b4debbfSMilanka Ringwald switch(hfp_connection->vra_state_requested){ 1411de9e0ea7SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 1412de9e0ea7SMilanka Ringwald hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR); 1413be55a11dSMilanka Ringwald break; 1414be55a11dSMilanka Ringwald default: 1415e2c3b58dSMilanka Ringwald if (hfp_connection->vra_state_requested == hfp_connection->vra_state){ 1416e2c3b58dSMilanka Ringwald break; 1417e2c3b58dSMilanka Ringwald } 14180b4debbfSMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state; 1419553a4a56SMilanka Ringwald hfp_emit_voice_recognition_enabled(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR); 14200b4debbfSMilanka Ringwald hfp_reset_context_flags(hfp_connection); 14210b4debbfSMilanka Ringwald return; 1422be55a11dSMilanka Ringwald } 1423e2c3b58dSMilanka Ringwald event_emited = hfp_hf_switch_on_ok_pending(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR); 1424e2c3b58dSMilanka Ringwald if (!event_emited){ 14256cc5b34bSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, ERROR_CODE_UNSPECIFIED_ERROR); 1426e2c3b58dSMilanka Ringwald } 1427fdda66c0SMilanka Ringwald hfp_reset_context_flags(hfp_connection); 1428ce263fc8SMatthias Ringwald break; 1429fdda66c0SMilanka Ringwald 1430ce263fc8SMatthias Ringwald case HFP_CMD_OK: 1431e2c3b58dSMilanka Ringwald hfp_hf_switch_on_ok_pending(hfp_connection, ERROR_CODE_SUCCESS); 1432ce263fc8SMatthias Ringwald break; 1433ce263fc8SMatthias Ringwald case HFP_CMD_RING: 14345a4785c8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1435ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_RING); 1436ce263fc8SMatthias Ringwald break; 1437ce263fc8SMatthias Ringwald case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: 14385a4785c8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 14394562e2a2SMatthias Ringwald hfp_hf_handle_transfer_ag_indicator_status(hfp_connection); 1440ce263fc8SMatthias Ringwald break; 1441c741b032SMilanka Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: 14425a4785c8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1443184a03edSMilanka Ringwald // report status after SLC established 1444184a03edSMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ 1445184a03edSMilanka Ringwald break; 1446184a03edSMilanka Ringwald } 1447c741b032SMilanka Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){ 14481ac1f60fSMilanka Ringwald hfp_emit_ag_indicator_mapping_event(hfp_connection, &hfp_connection->ag_indicators[i]); 1449c741b032SMilanka Ringwald } 1450c741b032SMilanka Ringwald break; 14511cc65c4fSMatthias Ringwald case HFP_CMD_AG_SUGGESTED_CODEC: 14521cc65c4fSMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 14535a4785c8SMatthias Ringwald hfp_hf_handle_suggested_codec(hfp_connection); 14541cc65c4fSMatthias Ringwald break; 1455eac56539SMilanka Ringwald case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING: 1456eac56539SMilanka Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_IN_BAND_RING_TONE, get_bit(hfp_connection->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE)); 14575134fea9SMatthias Ringwald break; 1458892f58a8SMatthias Ringwald case HFP_CMD_CUSTOM_MESSAGE: 1459892f58a8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE; 1460892f58a8SMatthias Ringwald hfp_parser_reset_line_buffer(hfp_connection); 1461892f58a8SMatthias Ringwald log_info("Custom AT Command ID 0x%04x", hfp_connection->custom_at_command_id); 1462892f58a8SMatthias Ringwald hfp_hf_emit_custom_command_event(hfp_connection); 1463892f58a8SMatthias Ringwald break; 1464ce263fc8SMatthias Ringwald default: 1465ce263fc8SMatthias Ringwald break; 14663deb3ec6SMatthias Ringwald } 14670cef86faSMatthias Ringwald } 1468426f9988SMatthias Ringwald 146976cc1527SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){ 147076cc1527SMatthias Ringwald return (byte == '\n') || (byte == '\r'); 147176cc1527SMatthias Ringwald } 147276cc1527SMatthias Ringwald 14730b4debbfSMilanka Ringwald static void hfp_hf_handle_rfcomm_data(hfp_connection_t * hfp_connection, uint8_t *packet, uint16_t size){ 1474426f9988SMatthias Ringwald // assertion: size >= 1 as rfcomm.c does not deliver empty packets 1475426f9988SMatthias Ringwald if (size < 1) return; 1476426f9988SMatthias Ringwald 1477426f9988SMatthias Ringwald hfp_log_rfcomm_message("HFP_HF_RX", packet, size); 1478e43d1938SMatthias Ringwald #ifdef ENABLE_HFP_AT_MESSAGES 1479e43d1938SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_RECEIVED, (char *) packet); 1480e43d1938SMatthias Ringwald #endif 1481426f9988SMatthias Ringwald 1482426f9988SMatthias Ringwald // process messages byte-wise 1483a7ba78b0SMilanka Ringwald uint8_t pos; 1484426f9988SMatthias Ringwald for (pos = 0; pos < size; pos++){ 1485426f9988SMatthias Ringwald hfp_parse(hfp_connection, packet[pos], 1); 14861599fe57SMatthias Ringwald // parse until end of line "\r" or "\n" 1487426f9988SMatthias Ringwald if (!hfp_parser_is_end_of_line(packet[pos])) continue; 14880b4debbfSMilanka Ringwald hfp_hf_handle_rfcomm_command(hfp_connection); 14893deb3ec6SMatthias Ringwald } 1490a7ba78b0SMilanka Ringwald } 14913deb3ec6SMatthias Ringwald 14921c6a0fc0SMatthias Ringwald static void hfp_hf_run(void){ 1493665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1494665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections()); 1495665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1496a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it); 149722387625SMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_HF) continue; 14981c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 14993deb3ec6SMatthias Ringwald } 15003deb3ec6SMatthias Ringwald } 15013deb3ec6SMatthias Ringwald 15021c6a0fc0SMatthias Ringwald static void hfp_hf_rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 15030b4debbfSMilanka Ringwald hfp_connection_t * hfp_connection; 15043deb3ec6SMatthias Ringwald switch (packet_type){ 15053deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET: 15060b4debbfSMilanka Ringwald hfp_connection = get_hfp_connection_context_for_rfcomm_cid(channel); 15070b4debbfSMilanka Ringwald if (!hfp_connection) return; 15080b4debbfSMilanka Ringwald hfp_hf_handle_rfcomm_data(hfp_connection, packet, size); 15090b4debbfSMilanka Ringwald hfp_hf_run_for_context(hfp_connection); 15100b4debbfSMilanka Ringwald return; 15113deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 1512d4dd47ffSMatthias Ringwald if (packet[0] == RFCOMM_EVENT_CAN_SEND_NOW){ 1513d4dd47ffSMatthias Ringwald uint16_t rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet); 15141c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid)); 1515d4dd47ffSMatthias Ringwald return; 1516d4dd47ffSMatthias Ringwald } 151727950165SMatthias Ringwald hfp_handle_rfcomm_event(packet_type, channel, packet, size, HFP_ROLE_HF); 1518202c8a4cSMatthias Ringwald break; 15193deb3ec6SMatthias Ringwald default: 15203deb3ec6SMatthias Ringwald break; 15213deb3ec6SMatthias Ringwald } 15221c6a0fc0SMatthias Ringwald hfp_hf_run(); 15233deb3ec6SMatthias Ringwald } 15243deb3ec6SMatthias Ringwald 15251c6a0fc0SMatthias Ringwald static void hfp_hf_hci_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 1526405014fbSMatthias Ringwald hfp_handle_hci_event(packet_type, channel, packet, size, HFP_ROLE_HF); 15271c6a0fc0SMatthias Ringwald hfp_hf_run(); 1528405014fbSMatthias Ringwald } 1529405014fbSMatthias Ringwald 1530aeb0f0feSMatthias Ringwald static void hfp_hf_set_defaults(void){ 1531aeb0f0feSMatthias Ringwald hfp_hf_supported_features = HFP_DEFAULT_HF_SUPPORTED_FEATURES; 1532aeb0f0feSMatthias Ringwald hfp_hf_codecs_nr = 0; 1533aeb0f0feSMatthias Ringwald hfp_hf_speaker_gain = 9; 1534aeb0f0feSMatthias Ringwald hfp_hf_microphone_gain = 9; 1535aeb0f0feSMatthias Ringwald hfp_hf_indicators_nr = 0; 1536aeb0f0feSMatthias Ringwald } 1537aeb0f0feSMatthias Ringwald 153842aadee5SMatthias Ringwald uint8_t hfp_hf_set_default_microphone_gain(uint8_t gain){ 1539455808b3SMatthias Ringwald if (gain > 15){ 154042aadee5SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 154142aadee5SMatthias Ringwald } 154242aadee5SMatthias Ringwald hfp_hf_microphone_gain = gain; 154342aadee5SMatthias Ringwald return ERROR_CODE_SUCCESS; 154442aadee5SMatthias Ringwald } 154542aadee5SMatthias Ringwald 154642aadee5SMatthias Ringwald uint8_t hfp_hf_set_default_speaker_gain(uint8_t gain){ 1547455808b3SMatthias Ringwald if (gain > 15){ 154842aadee5SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 154942aadee5SMatthias Ringwald } 155042aadee5SMatthias Ringwald hfp_hf_speaker_gain = gain; 155142aadee5SMatthias Ringwald return ERROR_CODE_SUCCESS; 155242aadee5SMatthias Ringwald } 155342aadee5SMatthias Ringwald 1554ab2445a0SMatthias Ringwald uint8_t hfp_hf_init(uint8_t rfcomm_channel_nr){ 1555b4df8028SMilanka Ringwald uint8_t status = rfcomm_register_service(hfp_hf_rfcomm_packet_handler, rfcomm_channel_nr, 0xffff); 1556b4df8028SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 1557b4df8028SMilanka Ringwald return status; 1558b4df8028SMilanka Ringwald } 1559b4df8028SMilanka Ringwald 1560520c92d5SMatthias Ringwald hfp_init(); 1561aeb0f0feSMatthias Ringwald hfp_hf_set_defaults(); 1562d63c37a1SMatthias Ringwald 15631c6a0fc0SMatthias Ringwald hfp_hf_hci_event_callback_registration.callback = &hfp_hf_hci_event_packet_handler; 15641c6a0fc0SMatthias Ringwald hci_add_event_handler(&hfp_hf_hci_event_callback_registration); 156527950165SMatthias Ringwald 156627950165SMatthias Ringwald // used to set packet handler for outgoing rfcomm connections - could be handled by emitting an event to us 15671c6a0fc0SMatthias Ringwald hfp_set_hf_rfcomm_packet_handler(&hfp_hf_rfcomm_packet_handler); 1568b4df8028SMilanka Ringwald return ERROR_CODE_SUCCESS; 156920b2edb6SMatthias Ringwald } 157027950165SMatthias Ringwald 157120b2edb6SMatthias Ringwald void hfp_hf_deinit(void){ 157220b2edb6SMatthias Ringwald hfp_deinit(); 1573aeb0f0feSMatthias Ringwald hfp_hf_set_defaults(); 1574aeb0f0feSMatthias Ringwald 1575aeb0f0feSMatthias Ringwald hfp_hf_callback = NULL; 1576*4e8ee53aSMatthias Ringwald hfp_hf_apple_vendor_id = 0; 157720b2edb6SMatthias Ringwald (void) memset(&hfp_hf_hci_event_callback_registration, 0, sizeof(btstack_packet_callback_registration_t)); 1578aeb0f0feSMatthias Ringwald (void) memset(hfp_hf_phone_number, 0, sizeof(hfp_hf_phone_number)); 1579a0ffb263SMatthias Ringwald } 1580a0ffb263SMatthias Ringwald 1581aa10b9cbSMatthias Ringwald void hfp_hf_init_codecs(uint8_t codecs_nr, const uint8_t * codecs){ 15822be4ddd3SMatthias Ringwald btstack_assert(codecs_nr <= HFP_MAX_NUM_CODECS); 15838cd06fb6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS) return; 15843deb3ec6SMatthias Ringwald 1585aeb0f0feSMatthias Ringwald hfp_hf_codecs_nr = codecs_nr; 1586aa10b9cbSMatthias Ringwald uint8_t i; 15873deb3ec6SMatthias Ringwald for (i=0; i<codecs_nr; i++){ 1588aeb0f0feSMatthias Ringwald hfp_hf_codecs[i] = codecs[i]; 15893deb3ec6SMatthias Ringwald } 15903deb3ec6SMatthias Ringwald } 15913deb3ec6SMatthias Ringwald 1592a0ffb263SMatthias Ringwald void hfp_hf_init_supported_features(uint32_t supported_features){ 1593aeb0f0feSMatthias Ringwald hfp_hf_supported_features = supported_features; 1594a0ffb263SMatthias Ringwald } 15953deb3ec6SMatthias Ringwald 15967ca89cabSMatthias Ringwald void hfp_hf_init_hf_indicators(int indicators_nr, const uint16_t * indicators){ 1597aeb0f0feSMatthias Ringwald btstack_assert(hfp_hf_indicators_nr < HFP_MAX_NUM_INDICATORS); 1598ea63a720SMatthias Ringwald if (hfp_hf_indicators_nr > HFP_MAX_NUM_INDICATORS) return; 159968466199SMilanka Ringwald 1600aeb0f0feSMatthias Ringwald hfp_hf_indicators_nr = indicators_nr; 16013deb3ec6SMatthias Ringwald int i; 1602aeb0f0feSMatthias Ringwald for (i = 0; i < hfp_hf_indicators_nr ; i++){ 1603ab2445a0SMatthias Ringwald hfp_hf_indicators[i] = (uint8_t) indicators[i]; 16043deb3ec6SMatthias Ringwald } 160521df969bSMatthias Ringwald 160621df969bSMatthias Ringwald // store copy in hfp to setup generic_status_indicators during SLC 160721df969bSMatthias Ringwald hfp_set_hf_indicators(indicators_nr, hfp_hf_indicators); 16083deb3ec6SMatthias Ringwald } 16093deb3ec6SMatthias Ringwald 16104eb3f1d8SMilanka Ringwald uint8_t hfp_hf_establish_service_level_connection(bd_addr_t bd_addr){ 16114eb3f1d8SMilanka Ringwald return hfp_establish_service_level_connection(bd_addr, BLUETOOTH_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, HFP_ROLE_HF); 16123deb3ec6SMatthias Ringwald } 16133deb3ec6SMatthias Ringwald 1614657bc59fSMilanka Ringwald uint8_t hfp_hf_release_service_level_connection(hci_con_handle_t acl_handle){ 16159c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1616a33eb0c4SMilanka Ringwald if (!hfp_connection){ 1617657bc59fSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1618a33eb0c4SMilanka Ringwald } 16191ffa0dd9SMilanka Ringwald hfp_trigger_release_service_level_connection(hfp_connection); 16201c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1621657bc59fSMilanka Ringwald return ERROR_CODE_SUCCESS; 16223deb3ec6SMatthias Ringwald } 16233deb3ec6SMatthias Ringwald 16243c65e705SMilanka Ringwald static uint8_t hfp_hf_set_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle, uint8_t enable){ 16259c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1626a0ffb263SMatthias Ringwald if (!hfp_connection) { 16273c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 16283deb3ec6SMatthias Ringwald } 1629a0ffb263SMatthias Ringwald hfp_connection->enable_status_update_for_ag_indicators = enable; 16301c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 16313c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 16323deb3ec6SMatthias Ringwald } 16333deb3ec6SMatthias Ringwald 16343c65e705SMilanka Ringwald uint8_t hfp_hf_enable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle){ 16353c65e705SMilanka Ringwald return hfp_hf_set_status_update_for_all_ag_indicators(acl_handle, 1); 1636ce263fc8SMatthias Ringwald } 1637ce263fc8SMatthias Ringwald 16383c65e705SMilanka Ringwald uint8_t hfp_hf_disable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle){ 16393c65e705SMilanka Ringwald return hfp_hf_set_status_update_for_all_ag_indicators(acl_handle, 0); 1640ce263fc8SMatthias Ringwald } 1641ce263fc8SMatthias Ringwald 16423deb3ec6SMatthias Ringwald // TODO: returned ERROR - wrong format 16433c65e705SMilanka Ringwald uint8_t hfp_hf_set_status_update_for_individual_ag_indicators(hci_con_handle_t acl_handle, uint32_t indicators_status_bitmap){ 16449c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1645a0ffb263SMatthias Ringwald if (!hfp_connection) { 16463c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 16473deb3ec6SMatthias Ringwald } 1648a0ffb263SMatthias Ringwald hfp_connection->change_status_update_for_individual_ag_indicators = 1; 1649a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = indicators_status_bitmap; 16501c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 16513c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 16523deb3ec6SMatthias Ringwald } 16533deb3ec6SMatthias Ringwald 16543c65e705SMilanka Ringwald uint8_t hfp_hf_query_operator_selection(hci_con_handle_t acl_handle){ 16559c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1656a0ffb263SMatthias Ringwald if (!hfp_connection) { 16573c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 16583deb3ec6SMatthias Ringwald } 16593c65e705SMilanka Ringwald 1660a0ffb263SMatthias Ringwald switch (hfp_connection->hf_query_operator_state){ 1661ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_FORMAT_NOT_SET: 1662a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SET_FORMAT; 1663ce263fc8SMatthias Ringwald break; 1664ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_FORMAT_SET: 1665a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SEND_QUERY; 1666ce263fc8SMatthias Ringwald break; 1667ce263fc8SMatthias Ringwald default: 16683c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1669ce263fc8SMatthias Ringwald } 16701c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 16713c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 16723deb3ec6SMatthias Ringwald } 16733deb3ec6SMatthias Ringwald 16743c65e705SMilanka Ringwald static uint8_t hfp_hf_set_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle, uint8_t enable){ 16759c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1676a0ffb263SMatthias Ringwald if (!hfp_connection) { 16773c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 16783deb3ec6SMatthias Ringwald } 1679a0ffb263SMatthias Ringwald hfp_connection->enable_extended_audio_gateway_error_report = enable; 16801c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 16813c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 16823deb3ec6SMatthias Ringwald } 16833deb3ec6SMatthias Ringwald 1684ce263fc8SMatthias Ringwald 16853c65e705SMilanka Ringwald uint8_t hfp_hf_enable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle){ 16863c65e705SMilanka Ringwald return hfp_hf_set_report_extended_audio_gateway_error_result_code(acl_handle, 1); 1687ce263fc8SMatthias Ringwald } 1688ce263fc8SMatthias Ringwald 16893c65e705SMilanka Ringwald uint8_t hfp_hf_disable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle){ 16903c65e705SMilanka Ringwald return hfp_hf_set_report_extended_audio_gateway_error_result_code(acl_handle, 0); 1691ce263fc8SMatthias Ringwald } 1692ce263fc8SMatthias Ringwald 169338200c1dSMilanka Ringwald static uint8_t hfp_hf_esco_s4_supported(hfp_connection_t * hfp_connection){ 1694aeb0f0feSMatthias Ringwald return (hfp_connection->remote_supported_features & (1<<HFP_AGSF_ESCO_S4)) && (hfp_hf_supported_features & (1 << HFP_HFSF_ESCO_S4)); 169538200c1dSMilanka Ringwald } 1696ce263fc8SMatthias Ringwald 16973c65e705SMilanka Ringwald uint8_t hfp_hf_establish_audio_connection(hci_con_handle_t acl_handle){ 16989c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1699a33eb0c4SMilanka Ringwald if (!hfp_connection) { 17003c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1701a33eb0c4SMilanka Ringwald } 1702ce263fc8SMatthias Ringwald 17033c65e705SMilanka Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED){ 17043c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 17053c65e705SMilanka Ringwald } 17063c65e705SMilanka Ringwald 17073c65e705SMilanka Ringwald if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO){ 17083c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 17093c65e705SMilanka Ringwald } 1710f4412093SMatthias Ringwald if (has_codec_negotiation_feature(hfp_connection)) { 1711a0ffb263SMatthias Ringwald switch (hfp_connection->codecs_state) { 1712aa4dd815SMatthias Ringwald case HFP_CODECS_W4_AG_COMMON_CODEC: 1713aa4dd815SMatthias Ringwald break; 1714ec3bfc1aSMatthias Ringwald case HFP_CODECS_EXCHANGED: 1715ec3bfc1aSMatthias Ringwald hfp_connection->trigger_codec_exchange = 1; 1716ec3bfc1aSMatthias Ringwald break; 1717aa4dd815SMatthias Ringwald default: 17181cc65c4fSMatthias Ringwald hfp_connection->codec_confirmed = 0; 17191cc65c4fSMatthias Ringwald hfp_connection->suggested_codec = 0; 17201cc65c4fSMatthias Ringwald hfp_connection->negotiated_codec = 0; 17211cc65c4fSMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; 172238200c1dSMilanka Ringwald hfp_connection->trigger_codec_exchange = 1; 1723aa4dd815SMatthias Ringwald break; 17243deb3ec6SMatthias Ringwald } 1725f4412093SMatthias Ringwald } else { 1726f4412093SMatthias Ringwald log_info("no codec negotiation feature, use CVSD"); 1727f4412093SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_EXCHANGED; 1728f4412093SMatthias Ringwald hfp_connection->suggested_codec = HFP_CODEC_CVSD; 1729f4412093SMatthias Ringwald hfp_connection->codec_confirmed = hfp_connection->suggested_codec; 1730f4412093SMatthias Ringwald hfp_connection->negotiated_codec = hfp_connection->suggested_codec; 1731f4412093SMatthias Ringwald hfp_init_link_settings(hfp_connection, hfp_hf_esco_s4_supported(hfp_connection)); 1732f4412093SMatthias Ringwald hfp_connection->establish_audio_connection = 1; 1733f4412093SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_CONNECTED; 1734ce263fc8SMatthias Ringwald } 1735ce263fc8SMatthias Ringwald 17361c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 17373c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 17383deb3ec6SMatthias Ringwald } 17393deb3ec6SMatthias Ringwald 17403c65e705SMilanka Ringwald uint8_t hfp_hf_release_audio_connection(hci_con_handle_t acl_handle){ 17419c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1742a33eb0c4SMilanka Ringwald if (!hfp_connection) { 17433c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1744a33eb0c4SMilanka Ringwald } 17450b4debbfSMilanka Ringwald if (hfp_connection->vra_state == HFP_VRA_VOICE_RECOGNITION_ACTIVATED){ 17460b4debbfSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 17470b4debbfSMilanka Ringwald } 17480b4debbfSMilanka Ringwald uint8_t status = hfp_trigger_release_audio_connection(hfp_connection); 17490b4debbfSMilanka Ringwald if (status == ERROR_CODE_SUCCESS){ 17501c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 17510b4debbfSMilanka Ringwald } 17523c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 17533deb3ec6SMatthias Ringwald } 17543deb3ec6SMatthias Ringwald 17553c65e705SMilanka Ringwald uint8_t hfp_hf_answer_incoming_call(hci_con_handle_t acl_handle){ 17569c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1757a33eb0c4SMilanka Ringwald if (!hfp_connection) { 17583c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1759a33eb0c4SMilanka Ringwald } 1760ce263fc8SMatthias Ringwald 176166093044SMilanka Ringwald if (hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 1762a0ffb263SMatthias Ringwald hfp_connection->hf_answer_incoming_call = 1; 17631c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1764ce263fc8SMatthias Ringwald } else { 176566093044SMilanka Ringwald log_error("HFP HF: answering incoming call with wrong callsetup status %u", hfp_connection->hf_callsetup_status); 17663c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1767ce263fc8SMatthias Ringwald } 17683c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1769ce263fc8SMatthias Ringwald } 1770ce263fc8SMatthias Ringwald 17713c65e705SMilanka Ringwald uint8_t hfp_hf_terminate_call(hci_con_handle_t acl_handle){ 17729c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1773a33eb0c4SMilanka Ringwald if (!hfp_connection) { 17743c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1775a33eb0c4SMilanka Ringwald } 1776a0ffb263SMatthias Ringwald hfp_connection->hf_send_chup = 1; 17771c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 17783c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1779ce263fc8SMatthias Ringwald } 1780ce263fc8SMatthias Ringwald 17813c65e705SMilanka Ringwald uint8_t hfp_hf_reject_incoming_call(hci_con_handle_t acl_handle){ 17829c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1783a33eb0c4SMilanka Ringwald if (!hfp_connection) { 17843c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1785a33eb0c4SMilanka Ringwald } 1786ce263fc8SMatthias Ringwald 178766093044SMilanka Ringwald if (hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 1788a0ffb263SMatthias Ringwald hfp_connection->hf_send_chup = 1; 17891c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1790ce263fc8SMatthias Ringwald } 17913c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1792ce263fc8SMatthias Ringwald } 1793ce263fc8SMatthias Ringwald 17943c65e705SMilanka Ringwald uint8_t hfp_hf_user_busy(hci_con_handle_t acl_handle){ 17959c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1796a33eb0c4SMilanka Ringwald if (!hfp_connection) { 17973c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1798a33eb0c4SMilanka Ringwald } 1799ce263fc8SMatthias Ringwald 180066093044SMilanka Ringwald if (hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 1801a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_0 = 1; 18021c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1803ce263fc8SMatthias Ringwald } 18043c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1805ce263fc8SMatthias Ringwald } 1806ce263fc8SMatthias Ringwald 18072be52304SMatthias Ringwald uint8_t hfp_hf_terminate_held_calls(hci_con_handle_t acl_handle){ 18082be52304SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 18092be52304SMatthias Ringwald if (!hfp_connection) { 18102be52304SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 18112be52304SMatthias Ringwald } 18122be52304SMatthias Ringwald 18132be52304SMatthias Ringwald hfp_connection->hf_send_chld_0 = 1; 18142be52304SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 18152be52304SMatthias Ringwald 18162be52304SMatthias Ringwald return ERROR_CODE_SUCCESS; 18172be52304SMatthias Ringwald } 18182be52304SMatthias Ringwald 18193c65e705SMilanka Ringwald uint8_t hfp_hf_end_active_and_accept_other(hci_con_handle_t acl_handle){ 18209c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1821a33eb0c4SMilanka Ringwald if (!hfp_connection) { 18223c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1823a33eb0c4SMilanka Ringwald } 1824ce263fc8SMatthias Ringwald 182566093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) || 182666093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){ 1827a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_1 = 1; 18281c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1829ce263fc8SMatthias Ringwald } 18303c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1831ce263fc8SMatthias Ringwald } 1832ce263fc8SMatthias Ringwald 18333c65e705SMilanka Ringwald uint8_t hfp_hf_swap_calls(hci_con_handle_t acl_handle){ 18349c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1835a33eb0c4SMilanka Ringwald if (!hfp_connection) { 18363c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1837a33eb0c4SMilanka Ringwald } 1838ce263fc8SMatthias Ringwald 183966093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) || 184066093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){ 1841a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_2 = 1; 18421c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1843ce263fc8SMatthias Ringwald } 18443c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1845ce263fc8SMatthias Ringwald } 1846ce263fc8SMatthias Ringwald 18473c65e705SMilanka Ringwald uint8_t hfp_hf_join_held_call(hci_con_handle_t acl_handle){ 18489c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1849a33eb0c4SMilanka Ringwald if (!hfp_connection) { 18503c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1851a33eb0c4SMilanka Ringwald } 1852ce263fc8SMatthias Ringwald 185366093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) || 185466093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){ 1855a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_3 = 1; 18561c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1857ce263fc8SMatthias Ringwald } 18583c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1859ce263fc8SMatthias Ringwald } 1860ce263fc8SMatthias Ringwald 18613c65e705SMilanka Ringwald uint8_t hfp_hf_connect_calls(hci_con_handle_t acl_handle){ 18629c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1863a33eb0c4SMilanka Ringwald if (!hfp_connection) { 18643c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1865a33eb0c4SMilanka Ringwald } 1866ce263fc8SMatthias Ringwald 186766093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) || 186866093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){ 1869a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_4 = 1; 18701c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1871ce263fc8SMatthias Ringwald } 18723c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1873ce263fc8SMatthias Ringwald } 1874ce263fc8SMatthias Ringwald 18753c65e705SMilanka Ringwald uint8_t hfp_hf_release_call_with_index(hci_con_handle_t acl_handle, int index){ 18769c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1877a33eb0c4SMilanka Ringwald if (!hfp_connection) { 18783c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1879a33eb0c4SMilanka Ringwald } 1880667ec068SMatthias Ringwald 188166093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) || 188266093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){ 1883a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x = 1; 1884a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x_index = 10 + index; 18851c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1886667ec068SMatthias Ringwald } 18873c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1888667ec068SMatthias Ringwald } 1889667ec068SMatthias Ringwald 18903c65e705SMilanka Ringwald uint8_t hfp_hf_private_consultation_with_call(hci_con_handle_t acl_handle, int index){ 18919c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1892a33eb0c4SMilanka Ringwald if (!hfp_connection) { 18933c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1894a33eb0c4SMilanka Ringwald } 1895667ec068SMatthias Ringwald 189666093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) || 189766093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){ 1898a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x = 1; 1899a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x_index = 20 + index; 19001c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 1901667ec068SMatthias Ringwald } 19023c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1903667ec068SMatthias Ringwald } 1904ce263fc8SMatthias Ringwald 19053c65e705SMilanka Ringwald uint8_t hfp_hf_dial_number(hci_con_handle_t acl_handle, char * number){ 19069c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1907a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19083c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1909a33eb0c4SMilanka Ringwald } 1910ce263fc8SMatthias Ringwald 1911a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_outgoing_call = 1; 1912aeb0f0feSMatthias Ringwald snprintf(hfp_hf_phone_number, sizeof(hfp_hf_phone_number), "%s", number); 19131c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19143c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1915ce263fc8SMatthias Ringwald } 1916ce263fc8SMatthias Ringwald 19173c65e705SMilanka Ringwald uint8_t hfp_hf_dial_memory(hci_con_handle_t acl_handle, int memory_id){ 19189c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1919a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19203c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1921a33eb0c4SMilanka Ringwald } 1922ce263fc8SMatthias Ringwald 1923a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_memory_dialing = 1; 1924a0ffb263SMatthias Ringwald hfp_connection->memory_id = memory_id; 1925a0ffb263SMatthias Ringwald 19261c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19273c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1928ce263fc8SMatthias Ringwald } 1929ce263fc8SMatthias Ringwald 19303c65e705SMilanka Ringwald uint8_t hfp_hf_redial_last_number(hci_con_handle_t acl_handle){ 19319c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1932a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19333c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1934a33eb0c4SMilanka Ringwald } 1935ce263fc8SMatthias Ringwald 1936a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_redial_last_number = 1; 19371c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19383c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1939ce263fc8SMatthias Ringwald } 1940ce263fc8SMatthias Ringwald 19413c65e705SMilanka Ringwald uint8_t hfp_hf_activate_call_waiting_notification(hci_con_handle_t acl_handle){ 19429c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1943a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19443c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1945a33eb0c4SMilanka Ringwald } 1946ce263fc8SMatthias Ringwald 1947a0ffb263SMatthias Ringwald hfp_connection->hf_activate_call_waiting_notification = 1; 19481c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19493c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1950ce263fc8SMatthias Ringwald } 1951ce263fc8SMatthias Ringwald 1952ce263fc8SMatthias Ringwald 19533c65e705SMilanka Ringwald uint8_t hfp_hf_deactivate_call_waiting_notification(hci_con_handle_t acl_handle){ 19549c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1955a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19563c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1957a33eb0c4SMilanka Ringwald } 1958ce263fc8SMatthias Ringwald 1959a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_call_waiting_notification = 1; 19601c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19613c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1962ce263fc8SMatthias Ringwald } 1963ce263fc8SMatthias Ringwald 1964ce263fc8SMatthias Ringwald 19653c65e705SMilanka Ringwald uint8_t hfp_hf_activate_calling_line_notification(hci_con_handle_t acl_handle){ 19669c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1967a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19683c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1969a33eb0c4SMilanka Ringwald } 1970ce263fc8SMatthias Ringwald 1971a0ffb263SMatthias Ringwald hfp_connection->hf_activate_calling_line_notification = 1; 19721c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19733c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1974ce263fc8SMatthias Ringwald } 1975ce263fc8SMatthias Ringwald 19763c65e705SMilanka Ringwald uint8_t hfp_hf_deactivate_calling_line_notification(hci_con_handle_t acl_handle){ 19779c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1978a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19793c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1980a33eb0c4SMilanka Ringwald } 1981ce263fc8SMatthias Ringwald 1982a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_calling_line_notification = 1; 19831c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19843c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1985ce263fc8SMatthias Ringwald } 1986ce263fc8SMatthias Ringwald 19873c65e705SMilanka Ringwald uint8_t hfp_hf_deactivate_echo_canceling_and_noise_reduction(hci_con_handle_t acl_handle){ 19889c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 1989a33eb0c4SMilanka Ringwald if (!hfp_connection) { 19903c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1991a33eb0c4SMilanka Ringwald } 199214685fd3SMatthias Ringwald if (get_bit(hfp_connection->remote_supported_features, HFP_AGSF_EC_NR_FUNCTION) == 0){ 19936ba83b5eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 19946ba83b5eSMilanka Ringwald } 1995ce263fc8SMatthias Ringwald 1996a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_echo_canceling_and_noise_reduction = 1; 19971c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 19983c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 1999ce263fc8SMatthias Ringwald } 2000ce263fc8SMatthias Ringwald 2001acd11d4aSMilanka Ringwald uint8_t hfp_hf_activate_voice_recognition(hci_con_handle_t acl_handle){ 2002fdda66c0SMilanka Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2003fdda66c0SMilanka Ringwald if (!hfp_connection) { 2004fdda66c0SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2005be55a11dSMilanka Ringwald } 2006013cc750SMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || hfp_connection->state > HFP_AUDIO_CONNECTION_ESTABLISHED){ 2007013cc750SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2008013cc750SMilanka Ringwald } 2009acd11d4aSMilanka Ringwald 2010acd11d4aSMilanka Ringwald bool enhanced_vra_supported = hfp_hf_enhanced_vra_flag_supported(hfp_connection); 2011acd11d4aSMilanka Ringwald bool legacy_vra_supported = hfp_hf_vra_flag_supported(hfp_connection); 2012acd11d4aSMilanka Ringwald if (!enhanced_vra_supported && !legacy_vra_supported){ 2013acd11d4aSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 2014af97579eSMilanka Ringwald } 2015af97579eSMilanka Ringwald 2016498a8121SMilanka Ringwald switch (hfp_connection->vra_state){ 2017be55a11dSMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_OFF: 2018de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF: 2019fd4151d1SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED; 2020acd11d4aSMilanka Ringwald hfp_connection->enhanced_voice_recognition_enabled = enhanced_vra_supported; 2021be55a11dSMilanka Ringwald break; 2022de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF: 2023de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = true; 2024de9e0ea7SMilanka Ringwald break; 2025be55a11dSMilanka Ringwald default: 2026be55a11dSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2027be55a11dSMilanka Ringwald } 2028ce263fc8SMatthias Ringwald 2029af97579eSMilanka Ringwald hfp_hf_run_for_context(hfp_connection); 2030fdda66c0SMilanka Ringwald return ERROR_CODE_SUCCESS; 2031af97579eSMilanka Ringwald } 2032af97579eSMilanka Ringwald 2033acd11d4aSMilanka Ringwald uint8_t hfp_hf_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle){ 2034af97579eSMilanka Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2035af97579eSMilanka Ringwald if (!hfp_connection) { 2036af97579eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2037af97579eSMilanka Ringwald } 203884fb9ac1SMilanka Ringwald 203984fb9ac1SMilanka Ringwald if (hfp_connection->emit_vra_enabled_after_audio_established){ 204084fb9ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 204184fb9ac1SMilanka Ringwald } 204284fb9ac1SMilanka Ringwald 2043acd11d4aSMilanka Ringwald if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED){ 204408a0b01cSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 204508a0b01cSMilanka Ringwald } 2046acd11d4aSMilanka Ringwald 2047acd11d4aSMilanka Ringwald bool enhanced_vra_supported = hfp_hf_enhanced_vra_flag_supported(hfp_connection); 2048acd11d4aSMilanka Ringwald if (!enhanced_vra_supported){ 2049acd11d4aSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 2050acd11d4aSMilanka Ringwald } 2051acd11d4aSMilanka Ringwald 2052acd11d4aSMilanka Ringwald switch (hfp_connection->vra_state){ 2053acd11d4aSMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: 2054acd11d4aSMilanka Ringwald case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 2055acd11d4aSMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; 2056acd11d4aSMilanka Ringwald break; 2057acd11d4aSMilanka Ringwald default: 2058fdda66c0SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2059af97579eSMilanka Ringwald } 2060013cc750SMilanka Ringwald 2061acd11d4aSMilanka Ringwald hfp_hf_run_for_context(hfp_connection); 2062acd11d4aSMilanka Ringwald return ERROR_CODE_SUCCESS; 2063acd11d4aSMilanka Ringwald } 2064acd11d4aSMilanka Ringwald 2065acd11d4aSMilanka Ringwald 2066acd11d4aSMilanka Ringwald uint8_t hfp_hf_deactivate_voice_recognition(hci_con_handle_t acl_handle){ 2067acd11d4aSMilanka Ringwald // return deactivate_voice_recognition(acl_handle, false); 2068acd11d4aSMilanka Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2069acd11d4aSMilanka Ringwald if (!hfp_connection) { 2070acd11d4aSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2071acd11d4aSMilanka Ringwald } 2072acd11d4aSMilanka Ringwald 207384fb9ac1SMilanka Ringwald if (hfp_connection->emit_vra_enabled_after_audio_established){ 207484fb9ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 207584fb9ac1SMilanka Ringwald } 207684fb9ac1SMilanka Ringwald 2077acd11d4aSMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || 2078acd11d4aSMilanka Ringwald hfp_connection->state > HFP_AUDIO_CONNECTION_ESTABLISHED){ 2079acd11d4aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2080acd11d4aSMilanka Ringwald } 2081acd11d4aSMilanka Ringwald 2082acd11d4aSMilanka Ringwald bool enhanced_vra_supported = hfp_hf_enhanced_vra_flag_supported(hfp_connection); 2083acd11d4aSMilanka Ringwald bool legacy_vra_supported = hfp_hf_vra_flag_supported(hfp_connection); 2084acd11d4aSMilanka Ringwald if (!enhanced_vra_supported && !legacy_vra_supported){ 2085acd11d4aSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 2086acd11d4aSMilanka Ringwald } 2087acd11d4aSMilanka Ringwald 2088fdda66c0SMilanka Ringwald switch (hfp_connection->vra_state){ 2089de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED: 2090fdda66c0SMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: 2091de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 2092de9e0ea7SMilanka Ringwald case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 2093fdda66c0SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF; 2094fdda66c0SMilanka Ringwald break; 2095de9e0ea7SMilanka Ringwald 2096de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: 2097de9e0ea7SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: 2098de9e0ea7SMilanka Ringwald hfp_connection->deactivate_voice_recognition = true; 2099de9e0ea7SMilanka Ringwald break; 2100de9e0ea7SMilanka Ringwald 2101de9e0ea7SMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_OFF: 2102de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF: 2103de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF: 2104fdda66c0SMilanka Ringwald default: 2105fdda66c0SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2106fdda66c0SMilanka Ringwald } 2107fdda66c0SMilanka Ringwald 2108fdda66c0SMilanka Ringwald hfp_hf_run_for_context(hfp_connection); 2109fdda66c0SMilanka Ringwald return ERROR_CODE_SUCCESS; 2110af97579eSMilanka Ringwald } 2111af97579eSMilanka Ringwald 21123c65e705SMilanka Ringwald uint8_t hfp_hf_set_microphone_gain(hci_con_handle_t acl_handle, int gain){ 21139c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2114a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21153c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2116a33eb0c4SMilanka Ringwald } 2117c8626498SMilanka Ringwald 21183c65e705SMilanka Ringwald if (hfp_connection->microphone_gain == gain) { 21193c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 21203c65e705SMilanka Ringwald } 21213c65e705SMilanka Ringwald 2122c1ab6cc1SMatthias Ringwald if ((gain < 0) || (gain > 15)){ 2123a0ffb263SMatthias Ringwald log_info("Valid range for a gain is [0..15]. Currently sent: %d", gain); 21243c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2125a0ffb263SMatthias Ringwald } 21263c65e705SMilanka Ringwald 2127a0ffb263SMatthias Ringwald hfp_connection->microphone_gain = gain; 2128a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 1; 21291c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 21303c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2131ce263fc8SMatthias Ringwald } 2132ce263fc8SMatthias Ringwald 21333c65e705SMilanka Ringwald uint8_t hfp_hf_set_speaker_gain(hci_con_handle_t acl_handle, int gain){ 21349c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2135a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21363c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2137a33eb0c4SMilanka Ringwald } 2138c8626498SMilanka Ringwald 21393c65e705SMilanka Ringwald if (hfp_connection->speaker_gain == gain){ 21403c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 21413c65e705SMilanka Ringwald } 21423c65e705SMilanka Ringwald 2143c1ab6cc1SMatthias Ringwald if ((gain < 0) || (gain > 15)){ 2144a0ffb263SMatthias Ringwald log_info("Valid range for a gain is [0..15]. Currently sent: %d", gain); 21453c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2146a0ffb263SMatthias Ringwald } 21473c65e705SMilanka Ringwald 2148a0ffb263SMatthias Ringwald hfp_connection->speaker_gain = gain; 2149a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 1; 21501c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 21513c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2152ce263fc8SMatthias Ringwald } 2153ce263fc8SMatthias Ringwald 21543c65e705SMilanka Ringwald uint8_t hfp_hf_send_dtmf_code(hci_con_handle_t acl_handle, char code){ 21559c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2156a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21573c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2158a33eb0c4SMilanka Ringwald } 2159a0ffb263SMatthias Ringwald hfp_connection->hf_send_dtmf_code = code; 21601c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 21613c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2162ce263fc8SMatthias Ringwald } 2163ce263fc8SMatthias Ringwald 21643c65e705SMilanka Ringwald uint8_t hfp_hf_request_phone_number_for_voice_tag(hci_con_handle_t acl_handle){ 21659c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2166a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21673c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2168a33eb0c4SMilanka Ringwald } 2169a0ffb263SMatthias Ringwald hfp_connection->hf_send_binp = 1; 21701c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 21713c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2172ce263fc8SMatthias Ringwald } 21733deb3ec6SMatthias Ringwald 21743c65e705SMilanka Ringwald uint8_t hfp_hf_query_current_call_status(hci_con_handle_t acl_handle){ 21759c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2176a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21773c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2178a33eb0c4SMilanka Ringwald } 2179a0ffb263SMatthias Ringwald hfp_connection->hf_send_clcc = 1; 21801c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 21813c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2182667ec068SMatthias Ringwald } 2183667ec068SMatthias Ringwald 2184667ec068SMatthias Ringwald 21853c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_query_status(hci_con_handle_t acl_handle){ 21869c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2187a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21883c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2189a33eb0c4SMilanka Ringwald } 2190a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1; 2191a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '?'; 21921c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 21933c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2194667ec068SMatthias Ringwald } 2195667ec068SMatthias Ringwald 21963c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_hold_call(hci_con_handle_t acl_handle){ 21979c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2198a33eb0c4SMilanka Ringwald if (!hfp_connection) { 21993c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2200a33eb0c4SMilanka Ringwald } 2201a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1; 2202a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '0'; 22031c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 22043c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2205667ec068SMatthias Ringwald } 2206667ec068SMatthias Ringwald 22073c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_accept_held_call(hci_con_handle_t acl_handle){ 22089c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2209a33eb0c4SMilanka Ringwald if (!hfp_connection) { 22103c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2211a33eb0c4SMilanka Ringwald } 2212a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1; 2213a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '1'; 22141c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 22153c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2216667ec068SMatthias Ringwald } 2217667ec068SMatthias Ringwald 22183c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_reject_held_call(hci_con_handle_t acl_handle){ 22199c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2220a33eb0c4SMilanka Ringwald if (!hfp_connection) { 22213c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2222a33eb0c4SMilanka Ringwald } 2223a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1; 2224a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '2'; 22251c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 22263c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2227667ec068SMatthias Ringwald } 2228667ec068SMatthias Ringwald 22293c65e705SMilanka Ringwald uint8_t hfp_hf_query_subscriber_number(hci_con_handle_t acl_handle){ 22309c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2231a33eb0c4SMilanka Ringwald if (!hfp_connection) { 22323c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2233a33eb0c4SMilanka Ringwald } 2234a0ffb263SMatthias Ringwald hfp_connection->hf_send_cnum = 1; 22351c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 22363c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2237667ec068SMatthias Ringwald } 2238667ec068SMatthias Ringwald 22393c65e705SMilanka Ringwald uint8_t hfp_hf_set_hf_indicator(hci_con_handle_t acl_handle, int assigned_number, int value){ 22409c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2241a33eb0c4SMilanka Ringwald if (!hfp_connection) { 22423c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 2243a33eb0c4SMilanka Ringwald } 2244667ec068SMatthias Ringwald // find index for assigned number 2245fa4b4d2bSMatthias Ringwald uint8_t i; 2246aeb0f0feSMatthias Ringwald for (i = 0; i < hfp_hf_indicators_nr ; i++){ 2247aeb0f0feSMatthias Ringwald if (hfp_hf_indicators[i] == assigned_number){ 2248fa4b4d2bSMatthias Ringwald // check if connection ready and indicator enabled 22490f716b22SMatthias Ringwald if (hfp_connection->state > HFP_LIST_GENERIC_STATUS_INDICATORS){ 22500f716b22SMatthias Ringwald if (hfp_connection->generic_status_indicators[i].state != 0) { 2251667ec068SMatthias Ringwald // set value 2252aeb0f0feSMatthias Ringwald hfp_hf_indicators_value[i] = value; 2253667ec068SMatthias Ringwald // mark for update 2254a0ffb263SMatthias Ringwald hfp_connection->generic_status_update_bitmap |= (1 << i); 2255667ec068SMatthias Ringwald // send update 22561c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 2257a0ffb263SMatthias Ringwald } 22580f716b22SMatthias Ringwald } 2259667ec068SMatthias Ringwald } 2260667ec068SMatthias Ringwald } 22613c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS; 2262667ec068SMatthias Ringwald } 2263667ec068SMatthias Ringwald 2264*4e8ee53aSMatthias Ringwald void hfp_hf_apple_set_identification(uint16_t vendor_id, uint16_t product_id, const char * version, uint8_t features){ 2265*4e8ee53aSMatthias Ringwald hfp_hf_apple_vendor_id = vendor_id; 2266*4e8ee53aSMatthias Ringwald hfp_hf_apple_product_id = product_id; 2267*4e8ee53aSMatthias Ringwald hfp_hf_apple_version = version; 2268*4e8ee53aSMatthias Ringwald hfp_hf_apple_features = features; 2269*4e8ee53aSMatthias Ringwald } 2270*4e8ee53aSMatthias Ringwald 227151a2ebdeSMatthias Ringwald uint8_t hfp_hf_send_at_command(hci_con_handle_t acl_handle, const char * at_command){ 227251a2ebdeSMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 227351a2ebdeSMatthias Ringwald if (!hfp_connection) { 227451a2ebdeSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 227551a2ebdeSMatthias Ringwald } 227651a2ebdeSMatthias Ringwald if (hfp_connection->send_custom_message != NULL){ 227751a2ebdeSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 227851a2ebdeSMatthias Ringwald } 227951a2ebdeSMatthias Ringwald hfp_connection->send_custom_message = at_command; 228051a2ebdeSMatthias Ringwald hfp_hf_run_for_context(hfp_connection); 228151a2ebdeSMatthias Ringwald return ERROR_CODE_SUCCESS; 228251a2ebdeSMatthias Ringwald } 228351a2ebdeSMatthias Ringwald 2284d7f6b5cbSMatthias Ringwald int hfp_hf_in_band_ringtone_active(hci_con_handle_t acl_handle){ 2285d7f6b5cbSMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); 2286d7f6b5cbSMatthias Ringwald if (!hfp_connection) { 2287d7f6b5cbSMatthias Ringwald return 0; 2288d7f6b5cbSMatthias Ringwald } 2289d7f6b5cbSMatthias Ringwald return get_bit(hfp_connection->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE); 2290d7f6b5cbSMatthias Ringwald } 229176cc1527SMatthias Ringwald 2292aa10b9cbSMatthias Ringwald void hfp_hf_create_sdp_record_with_codecs(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, 2293aa10b9cbSMatthias Ringwald const char * name, uint16_t supported_features, uint8_t codecs_nr, const uint8_t * codecs){ 229476cc1527SMatthias Ringwald if (!name){ 2295aeb0f0feSMatthias Ringwald name = hfp_hf_default_service_name; 229676cc1527SMatthias Ringwald } 229776cc1527SMatthias Ringwald hfp_create_sdp_record(service, service_record_handle, BLUETOOTH_SERVICE_CLASS_HANDSFREE, rfcomm_channel_nr, name); 229876cc1527SMatthias Ringwald 229976cc1527SMatthias Ringwald // Construct SupportedFeatures for SDP bitmap: 230076cc1527SMatthias Ringwald // 230176cc1527SMatthias Ringwald // "The values of the “SupportedFeatures” bitmap given in Table 5.4 shall be the same as the values 230276cc1527SMatthias Ringwald // of the Bits 0 to 4 of the unsolicited result code +BRSF" 230376cc1527SMatthias Ringwald // 2304aa10b9cbSMatthias Ringwald // Wide band speech (bit 5) and LC3-SWB (bit 8) require Codec negotiation 230576cc1527SMatthias Ringwald // 230676cc1527SMatthias Ringwald uint16_t sdp_features = supported_features & 0x1f; 2307ef3ae4ebSMilanka Ringwald 2308ef3ae4ebSMilanka Ringwald if (supported_features & (1 << HFP_HFSF_ENHANCED_VOICE_RECOGNITION_STATUS)){ 230956f1adacSMilanka Ringwald sdp_features |= 1 << 6; 2310ef3ae4ebSMilanka Ringwald } 2311ef3ae4ebSMilanka Ringwald 2312ef3ae4ebSMilanka Ringwald if (supported_features & (1 << HFP_HFSF_VOICE_RECOGNITION_TEXT)){ 231356f1adacSMilanka Ringwald sdp_features |= 1 << 7; 2314ef3ae4ebSMilanka Ringwald } 2315ef3ae4ebSMilanka Ringwald 2316aa10b9cbSMatthias Ringwald // codecs 2317aa10b9cbSMatthias Ringwald if ((supported_features & (1 << HFP_HFSF_CODEC_NEGOTIATION)) != 0){ 2318aa10b9cbSMatthias Ringwald uint8_t i; 2319aa10b9cbSMatthias Ringwald for (i=0;i<codecs_nr;i++){ 2320aa10b9cbSMatthias Ringwald switch (codecs[i]){ 2321aa10b9cbSMatthias Ringwald case HFP_CODEC_MSBC: 2322aa10b9cbSMatthias Ringwald sdp_features |= 1 << 5; 2323aa10b9cbSMatthias Ringwald break; 2324aa10b9cbSMatthias Ringwald case HFP_CODEC_LC3_SWB: 2325aa10b9cbSMatthias Ringwald sdp_features |= 1 << 8; 2326aa10b9cbSMatthias Ringwald break; 232775389f80SMatthias Ringwald default: 232875389f80SMatthias Ringwald break; 2329aa10b9cbSMatthias Ringwald } 2330aa10b9cbSMatthias Ringwald } 2331aa10b9cbSMatthias Ringwald } 2332aa10b9cbSMatthias Ringwald 2333aa10b9cbSMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SUPPORTED_FEATURES); 233476cc1527SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, sdp_features); 233576cc1527SMatthias Ringwald } 233676cc1527SMatthias Ringwald 2337aa10b9cbSMatthias Ringwald // @deprecated, call new API 2338aa10b9cbSMatthias Ringwald void hfp_hf_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint16_t supported_features, int wide_band_speech){ 2339aa10b9cbSMatthias Ringwald uint8_t codecs_nr; 2340aa10b9cbSMatthias Ringwald const uint8_t * codecs; 2341aa10b9cbSMatthias Ringwald const uint8_t wide_band_codecs[] = { HFP_CODEC_MSBC }; 2342aa10b9cbSMatthias Ringwald if (wide_band_speech == 0){ 2343aa10b9cbSMatthias Ringwald codecs_nr = 0; 2344aa10b9cbSMatthias Ringwald codecs = NULL; 2345aa10b9cbSMatthias Ringwald } else { 2346aa10b9cbSMatthias Ringwald codecs_nr = 1; 2347aa10b9cbSMatthias Ringwald codecs = wide_band_codecs; 2348aa10b9cbSMatthias Ringwald } 2349aa10b9cbSMatthias Ringwald hfp_hf_create_sdp_record_with_codecs(service, service_record_handle, rfcomm_channel_nr, name, supported_features, codecs_nr, codecs); 2350aa10b9cbSMatthias Ringwald } 2351aa10b9cbSMatthias Ringwald 2352077c2d92SMatthias Ringwald void hfp_hf_register_custom_at_command(hfp_custom_at_command_t * custom_at_command){ 2353077c2d92SMatthias Ringwald hfp_register_custom_hf_command(custom_at_command); 2354077c2d92SMatthias Ringwald } 2355077c2d92SMatthias Ringwald 235676cc1527SMatthias Ringwald void hfp_hf_register_packet_handler(btstack_packet_handler_t callback){ 235768466199SMilanka Ringwald btstack_assert(callback != NULL); 235868466199SMilanka Ringwald 235976cc1527SMatthias Ringwald hfp_hf_callback = callback; 236076cc1527SMatthias Ringwald hfp_set_hf_callback(callback); 236176cc1527SMatthias Ringwald } 2362