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
904e8ee53aSMatthias Ringwald // Apple Accessory Information
914e8ee53aSMatthias Ringwald static uint16_t hfp_hf_apple_vendor_id;
924e8ee53aSMatthias Ringwald static uint16_t hfp_hf_apple_product_id;
934e8ee53aSMatthias Ringwald static const char * hfp_hf_apple_version;
944e8ee53aSMatthias Ringwald static uint8_t hfp_hf_apple_features;
95910dced5SMatthias Ringwald static int8_t hfp_hf_apple_battery_level;
96910dced5SMatthias Ringwald static int8_t hfp_hf_apple_docked;
974e8ee53aSMatthias Ringwald
984e8ee53aSMatthias Ringwald
has_codec_negotiation_feature(hfp_connection_t * hfp_connection)9976cc1527SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * hfp_connection){
100aeb0f0feSMatthias Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
10176cc1527SMatthias Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
10276cc1527SMatthias Ringwald return hf && ag;
10376cc1527SMatthias Ringwald }
10476cc1527SMatthias Ringwald
has_call_waiting_and_3way_calling_feature(hfp_connection_t * hfp_connection)10576cc1527SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * hfp_connection){
106aeb0f0feSMatthias Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_THREE_WAY_CALLING);
10776cc1527SMatthias Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_THREE_WAY_CALLING);
10876cc1527SMatthias Ringwald return hf && ag;
10976cc1527SMatthias Ringwald }
11076cc1527SMatthias Ringwald
11176cc1527SMatthias Ringwald
has_hf_indicators_feature(hfp_connection_t * hfp_connection)11276cc1527SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * hfp_connection){
113aeb0f0feSMatthias Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_HF_INDICATORS);
11476cc1527SMatthias Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_HF_INDICATORS);
11576cc1527SMatthias Ringwald return hf && ag;
11676cc1527SMatthias Ringwald }
11776cc1527SMatthias Ringwald
hfp_hf_vra_flag_supported(hfp_connection_t * hfp_connection)118fcf4ede6SMilanka Ringwald static bool hfp_hf_vra_flag_supported(hfp_connection_t * hfp_connection){
119fcf4ede6SMilanka Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION);
120fcf4ede6SMilanka Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION);
121fcf4ede6SMilanka Ringwald return hf && ag;
122fcf4ede6SMilanka Ringwald }
123fcf4ede6SMilanka Ringwald
hfp_hf_enhanced_vra_flag_supported(hfp_connection_t * hfp_connection)124fcf4ede6SMilanka Ringwald static bool hfp_hf_enhanced_vra_flag_supported(hfp_connection_t * hfp_connection){
125fcf4ede6SMilanka Ringwald int hf = get_bit(hfp_hf_supported_features, HFP_HFSF_ENHANCED_VOICE_RECOGNITION_STATUS);
126fcf4ede6SMilanka Ringwald int ag = get_bit(hfp_connection->remote_supported_features, HFP_AGSF_ENHANCED_VOICE_RECOGNITION_STATUS);
127fcf4ede6SMilanka Ringwald return hf && ag;
128fcf4ede6SMilanka Ringwald }
12976cc1527SMatthias Ringwald
get_hfp_hf_connection_context_for_acl_handle(uint16_t handle)1309c9c64c1SMatthias Ringwald static hfp_connection_t * get_hfp_hf_connection_context_for_acl_handle(uint16_t handle){
1319c9c64c1SMatthias Ringwald btstack_linked_list_iterator_t it;
1329c9c64c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections());
1339c9c64c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){
1349c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
1359c9c64c1SMatthias Ringwald if (hfp_connection->acl_handle != handle) continue;
1369c9c64c1SMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_HF) continue;
1379c9c64c1SMatthias Ringwald return hfp_connection;
1389c9c64c1SMatthias Ringwald }
1399c9c64c1SMatthias Ringwald return NULL;
1409c9c64c1SMatthias Ringwald }
1419c9c64c1SMatthias Ringwald
142c10fde09SMatthias Ringwald /* emit functions */
1433deb3ec6SMatthias Ringwald
hfp_hf_emit_subscriber_information(const hfp_connection_t * hfp_connection,uint8_t status)144a473a009SMatthias Ringwald static void hfp_hf_emit_subscriber_information(const hfp_connection_t * hfp_connection, uint8_t status){
145a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return;
146ab2445a0SMatthias Ringwald uint16_t bnip_number_len = btstack_min((uint16_t) strlen(hfp_connection->bnip_number), sizeof(hfp_connection->bnip_number)-1);
147c10fde09SMatthias Ringwald uint8_t event[7 + sizeof(hfp_connection->bnip_number)];
148a0ffb263SMatthias Ringwald event[0] = HCI_EVENT_HFP_META;
149c10fde09SMatthias Ringwald event[1] = 6 + bnip_number_len;
150a473a009SMatthias Ringwald event[2] = HFP_SUBEVENT_SUBSCRIBER_NUMBER_INFORMATION;
151d703d377SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
152d703d377SMatthias Ringwald event[5] = status;
153d703d377SMatthias Ringwald event[6] = hfp_connection->bnip_type;
154c10fde09SMatthias Ringwald memcpy(&event[7], hfp_connection->bnip_number, bnip_number_len);
155c10fde09SMatthias Ringwald event[7 + bnip_number_len] = 0;
156c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 8 + bnip_number_len);
157a0ffb263SMatthias Ringwald }
158a0ffb263SMatthias Ringwald
hfp_hf_emit_type_number_alpha(const hfp_connection_t * hfp_connection,uint8_t event_subtype)159598d4936SMatthias Ringwald static void hfp_hf_emit_type_number_alpha(const hfp_connection_t * hfp_connection, uint8_t event_subtype){
160a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return;
161ab2445a0SMatthias Ringwald uint16_t bnip_number_len = btstack_min((uint16_t) strlen(hfp_connection->bnip_number), sizeof(hfp_connection->bnip_number)-1);
162598d4936SMatthias Ringwald // 10 fixed - 1 (bnip_number_len <= sizeof(hfp_connection->bnip_number)-1) + 1 (trailing \0 for line buffer)
163598d4936SMatthias Ringwald uint8_t event[10 + sizeof(hfp_connection->bnip_number) + sizeof(hfp_connection->line_buffer)];
164ab2445a0SMatthias Ringwald uint8_t alpha_len = hfp_connection->clip_have_alpha ? (uint16_t) strlen((const char *) hfp_connection->line_buffer) : 0;
165598d4936SMatthias Ringwald uint8_t pos = 0;
166598d4936SMatthias Ringwald event[pos++] = HCI_EVENT_HFP_META;
167598d4936SMatthias Ringwald event[pos++] = 8 + bnip_number_len + alpha_len;
168598d4936SMatthias Ringwald event[pos++] = event_subtype;
169d703d377SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
170598d4936SMatthias Ringwald pos += 2;
171598d4936SMatthias Ringwald event[pos++] = hfp_connection->bnip_type;
172a45da34eSMatthias Ringwald event[pos++] = bnip_number_len + 1;
173598d4936SMatthias Ringwald memcpy(&event[7], hfp_connection->bnip_number, bnip_number_len);
174598d4936SMatthias Ringwald pos += bnip_number_len;
175598d4936SMatthias Ringwald event[pos++] = 0;
176a45da34eSMatthias Ringwald event[pos++] = alpha_len + 1;
177598d4936SMatthias Ringwald memcpy(&event[pos], hfp_connection->line_buffer, alpha_len);
178598d4936SMatthias Ringwald pos += alpha_len;
179598d4936SMatthias Ringwald event[pos++] = 0;
180598d4936SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, pos);
181a0ffb263SMatthias Ringwald }
182a0ffb263SMatthias Ringwald
hfp_hf_emit_enhanced_call_status(const hfp_connection_t * hfp_connection)183a473a009SMatthias Ringwald static void hfp_hf_emit_enhanced_call_status(const hfp_connection_t * hfp_connection){
184a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return;
1855f5a2872SMilanka Ringwald
186ab2445a0SMatthias Ringwald uint16_t bnip_number_len = (uint16_t) strlen((const char *) hfp_connection->bnip_number);
1875f5a2872SMilanka Ringwald uint8_t event[11 + HFP_BNEP_NUM_MAX_SIZE];
188c10fde09SMatthias Ringwald event[0] = HCI_EVENT_HFP_META;
1895f5a2872SMilanka Ringwald event[1] = 10 + bnip_number_len + 1;
190c10fde09SMatthias Ringwald event[2] = HFP_SUBEVENT_ENHANCED_CALL_STATUS;
191c10fde09SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
1925f5a2872SMilanka Ringwald event[5] = hfp_connection->clcc_idx;
1935f5a2872SMilanka Ringwald event[6] = hfp_connection->clcc_dir;
1945f5a2872SMilanka Ringwald event[7] = hfp_connection->clcc_status;
1955f5a2872SMilanka Ringwald event[8] = hfp_connection->clcc_mode;
1965f5a2872SMilanka Ringwald event[9] = hfp_connection->clcc_mpty;
1975f5a2872SMilanka Ringwald event[10] = hfp_connection->bnip_type;
1985f5a2872SMilanka Ringwald memcpy(&event[11], hfp_connection->bnip_number, bnip_number_len + 1);
1995f5a2872SMilanka Ringwald
2005f5a2872SMilanka Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 11 + bnip_number_len + 1);
201a0ffb263SMatthias Ringwald }
202a0ffb263SMatthias Ringwald
hfp_emit_ag_indicator_mapping_event(const hfp_connection_t * hfp_connection,const hfp_ag_indicator_t * indicator)2031ac1f60fSMilanka Ringwald static void hfp_emit_ag_indicator_mapping_event(const hfp_connection_t * hfp_connection, const hfp_ag_indicator_t * indicator){
2041ac1f60fSMilanka Ringwald if (hfp_hf_callback == NULL) return;
205c10fde09SMatthias Ringwald uint8_t event[8 + HFP_MAX_INDICATOR_DESC_SIZE];
206ab2445a0SMatthias Ringwald uint16_t indicator_len = btstack_min((uint16_t) strlen(indicator->name), HFP_MAX_INDICATOR_DESC_SIZE-1);
207c10fde09SMatthias Ringwald event[0] = HCI_EVENT_HFP_META;
208c10fde09SMatthias Ringwald event[1] = 7 + indicator_len;
209c10fde09SMatthias Ringwald event[2] = HFP_SUBEVENT_AG_INDICATOR_MAPPING;
210c10fde09SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
211c10fde09SMatthias Ringwald event[5] = indicator->index;
212c10fde09SMatthias Ringwald event[6] = indicator->min_range;
213c10fde09SMatthias Ringwald event[7] = indicator->max_range;
214c10fde09SMatthias Ringwald memcpy(&event[8], indicator->name, indicator_len);
215c10fde09SMatthias Ringwald event[8+indicator_len] = 0;
216c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 9 + indicator_len);
2171ac1f60fSMilanka Ringwald }
21876cc1527SMatthias Ringwald
hfp_emit_ag_indicator_status_event(const hfp_connection_t * hfp_connection,const hfp_ag_indicator_t * indicator)219ce3797e1SMilanka Ringwald static void hfp_emit_ag_indicator_status_event(const hfp_connection_t * hfp_connection, const hfp_ag_indicator_t * indicator){
220a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return;
221c10fde09SMatthias Ringwald uint8_t event[12+HFP_MAX_INDICATOR_DESC_SIZE];
222ab2445a0SMatthias Ringwald uint16_t indicator_len = btstack_min((uint16_t) strlen(indicator->name), HFP_MAX_INDICATOR_DESC_SIZE-1);
223c10fde09SMatthias Ringwald event[0] = HCI_EVENT_HFP_META;
224c10fde09SMatthias Ringwald event[1] = 11 + indicator_len;
225c10fde09SMatthias Ringwald event[2] = HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED;
226c10fde09SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
227c10fde09SMatthias Ringwald event[5] = indicator->index;
228c10fde09SMatthias Ringwald event[6] = indicator->status;
229c10fde09SMatthias Ringwald event[7] = indicator->min_range;
230c10fde09SMatthias Ringwald event[8] = indicator->max_range;
231c10fde09SMatthias Ringwald event[9] = indicator->mandatory;
232c10fde09SMatthias Ringwald event[10] = indicator->enabled;
233c10fde09SMatthias Ringwald event[11] = indicator->status_changed;
234c10fde09SMatthias Ringwald memcpy(&event[12], indicator->name, indicator_len);
235c10fde09SMatthias Ringwald event[12+indicator_len] = 0;
236c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 13 + indicator_len);
2373deb3ec6SMatthias Ringwald }
2383deb3ec6SMatthias Ringwald
hfp_emit_network_operator_event(const hfp_connection_t * hfp_connection)239a473a009SMatthias Ringwald static void hfp_emit_network_operator_event(const hfp_connection_t * hfp_connection){
240a473a009SMatthias Ringwald if (hfp_hf_callback == NULL) return;
241ab2445a0SMatthias Ringwald uint16_t operator_len = btstack_min((uint16_t) strlen(hfp_connection->network_operator.name), HFP_MAX_NETWORK_OPERATOR_NAME_SIZE-1);
242c10fde09SMatthias Ringwald uint8_t event[7+HFP_MAX_NETWORK_OPERATOR_NAME_SIZE];
24376cc1527SMatthias Ringwald event[0] = HCI_EVENT_HFP_META;
24476cc1527SMatthias Ringwald event[1] = sizeof(event) - 2;
245f127324fSMilanka Ringwald event[2] = HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED;
246d703d377SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
247d703d377SMatthias Ringwald event[5] = hfp_connection->network_operator.mode;
248d703d377SMatthias Ringwald event[6] = hfp_connection->network_operator.format;
249c10fde09SMatthias Ringwald memcpy(&event[7], hfp_connection->network_operator.name, operator_len);
250c10fde09SMatthias Ringwald event[7+operator_len] = 0;
251c10fde09SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 8 + operator_len);
2523deb3ec6SMatthias Ringwald }
2533deb3ec6SMatthias Ringwald
254b95cac54SMilanka Ringwald
hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection_t * hfp_connection)255b95cac54SMilanka Ringwald static void hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection_t * hfp_connection){
256b95cac54SMilanka Ringwald btstack_assert(hfp_connection != NULL);
25751aa5d5aSMilanka Ringwald uint8_t event[HFP_MAX_VR_TEXT_SIZE + 11];
258b95cac54SMilanka Ringwald int pos = 0;
259b95cac54SMilanka Ringwald event[pos++] = HCI_EVENT_HFP_META;
260b95cac54SMilanka Ringwald event[pos++] = sizeof(event) - 2;
261b95cac54SMilanka Ringwald event[pos++] = HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_MESSAGE;
262b95cac54SMilanka Ringwald little_endian_store_16(event, pos, hfp_connection->acl_handle);
263b95cac54SMilanka Ringwald pos += 2;
264b95cac54SMilanka Ringwald little_endian_store_16(event, pos, hfp_connection->ag_msg.text_id);
265b95cac54SMilanka Ringwald pos += 2;
266b95cac54SMilanka Ringwald event[pos++] = hfp_connection->ag_msg.text_type;
267e83f1be7SMilanka Ringwald event[pos++] = hfp_connection->ag_msg.text_operation;
268b95cac54SMilanka Ringwald
26951aa5d5aSMilanka Ringwald // length, zero ending is already in message
270b95cac54SMilanka Ringwald uint8_t * value = &hfp_connection->line_buffer[0];
27151aa5d5aSMilanka Ringwald uint16_t value_length = hfp_connection->ag_vra_msg_length;
27251aa5d5aSMilanka Ringwald
27351aa5d5aSMilanka Ringwald little_endian_store_16(event, pos, value_length);
274b95cac54SMilanka Ringwald pos += 2;
27551aa5d5aSMilanka Ringwald memcpy(&event[pos], value, value_length);
27651aa5d5aSMilanka Ringwald pos += value_length;
27751aa5d5aSMilanka Ringwald
278b95cac54SMilanka Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, pos);
279b95cac54SMilanka Ringwald }
280b95cac54SMilanka Ringwald
hfp_hf_emit_custom_command_event(hfp_connection_t * hfp_connection)281892f58a8SMatthias Ringwald static void hfp_hf_emit_custom_command_event(hfp_connection_t * hfp_connection){
282892f58a8SMatthias Ringwald btstack_assert(sizeof(hfp_connection->line_buffer) < (255-5));
283892f58a8SMatthias Ringwald
2841a3bc516SMatthias Ringwald uint16_t line_len = (uint16_t) strlen((const char*)hfp_connection->line_buffer) + 1;
285892f58a8SMatthias Ringwald uint8_t event[7 + sizeof(hfp_connection->line_buffer)];
286892f58a8SMatthias Ringwald event[0] = HCI_EVENT_HFP_META;
287892f58a8SMatthias Ringwald event[1] = 5 + line_len;
288892f58a8SMatthias Ringwald event[2] = HFP_SUBEVENT_CUSTOM_AT_COMMAND;
289892f58a8SMatthias Ringwald little_endian_store_16(event, 3, hfp_connection->acl_handle);
290892f58a8SMatthias Ringwald little_endian_store_16(event, 5, hfp_connection->custom_at_command_id);
291892f58a8SMatthias Ringwald memcpy(&event[7], hfp_connection->line_buffer, line_len);
292892f58a8SMatthias Ringwald (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, 7 + line_len);
293892f58a8SMatthias Ringwald }
294892f58a8SMatthias Ringwald
29576cc1527SMatthias Ringwald /* send commands */
29689425bfcSMilanka Ringwald
hfp_hf_send_cmd(uint16_t cid,const char * cmd)29789425bfcSMilanka Ringwald static inline int hfp_hf_send_cmd(uint16_t cid, const char * cmd){
2983deb3ec6SMatthias Ringwald char buffer[20];
299865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s\r", cmd);
30089425bfcSMilanka Ringwald return send_str_over_rfcomm(cid, buffer);
30189425bfcSMilanka Ringwald }
30289425bfcSMilanka Ringwald
hfp_hf_send_cmd_with_mark(uint16_t cid,const char * cmd,const char * mark)30389425bfcSMilanka Ringwald static inline int hfp_hf_send_cmd_with_mark(uint16_t cid, const char * cmd, const char * mark){
30489425bfcSMilanka Ringwald char buffer[20];
305865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s%s\r", cmd, mark);
30689425bfcSMilanka Ringwald return send_str_over_rfcomm(cid, buffer);
30789425bfcSMilanka Ringwald }
30889425bfcSMilanka Ringwald
hfp_hf_send_cmd_with_int(uint16_t cid,const char * cmd,uint16_t value)30986da9d74SMatthias Ringwald static inline int hfp_hf_send_cmd_with_int(uint16_t cid, const char * cmd, uint16_t value){
31089425bfcSMilanka Ringwald char buffer[40];
311865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=%d\r", cmd, value);
3123deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
3133deb3ec6SMatthias Ringwald }
3143deb3ec6SMatthias Ringwald
hfp_hf_cmd_notify_on_codecs(uint16_t cid)3153deb3ec6SMatthias Ringwald static int hfp_hf_cmd_notify_on_codecs(uint16_t cid){
3163deb3ec6SMatthias Ringwald char buffer[30];
31789425bfcSMilanka Ringwald const int size = sizeof(buffer);
318865e2b54SMatthias Ringwald int offset = btstack_snprintf_assert_complete(buffer, size, "AT%s=", HFP_AVAILABLE_CODECS);
319aeb0f0feSMatthias Ringwald offset += join(buffer+offset, size-offset, hfp_hf_codecs, hfp_hf_codecs_nr);
320865e2b54SMatthias Ringwald offset += btstack_snprintf_assert_complete(buffer+offset, size-offset, "\r");
3213deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
3223deb3ec6SMatthias Ringwald }
3233deb3ec6SMatthias Ringwald
hfp_hf_cmd_activate_status_update_for_ag_indicator(uint16_t cid,uint32_t indicators_status,int indicators_nr)3243deb3ec6SMatthias Ringwald static int hfp_hf_cmd_activate_status_update_for_ag_indicator(uint16_t cid, uint32_t indicators_status, int indicators_nr){
3253deb3ec6SMatthias Ringwald char buffer[50];
32689425bfcSMilanka Ringwald const int size = sizeof(buffer);
327865e2b54SMatthias Ringwald int offset = btstack_snprintf_assert_complete(buffer, size, "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
32889425bfcSMilanka Ringwald offset += join_bitmap(buffer+offset, size-offset, indicators_status, indicators_nr);
329865e2b54SMatthias Ringwald offset += btstack_snprintf_assert_complete(buffer+offset, size-offset, "\r");
3303deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
3313deb3ec6SMatthias Ringwald }
3323deb3ec6SMatthias Ringwald
hfp_hf_cmd_list_supported_generic_status_indicators(uint16_t cid)3333deb3ec6SMatthias Ringwald static int hfp_hf_cmd_list_supported_generic_status_indicators(uint16_t cid){
3343deb3ec6SMatthias Ringwald char buffer[30];
33589425bfcSMilanka Ringwald const int size = sizeof(buffer);
336865e2b54SMatthias Ringwald int offset = btstack_snprintf_assert_complete(buffer, size, "AT%s=", HFP_GENERIC_STATUS_INDICATOR);
337aeb0f0feSMatthias Ringwald offset += join(buffer+offset, size-offset, hfp_hf_indicators, hfp_hf_indicators_nr);
338865e2b54SMatthias Ringwald offset += btstack_snprintf_assert_complete(buffer+offset, size-offset, "\r");
3393deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
3403deb3ec6SMatthias Ringwald }
3413deb3ec6SMatthias Ringwald
hfp_hf_cmd_activate_status_update_for_all_ag_indicators(uint16_t cid,uint8_t activate)34289425bfcSMilanka Ringwald static int hfp_hf_cmd_activate_status_update_for_all_ag_indicators(uint16_t cid, uint8_t activate){
3433deb3ec6SMatthias Ringwald char buffer[20];
344865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=3,0,0,%d\r", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, activate);
345ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
346ce263fc8SMatthias Ringwald }
347ce263fc8SMatthias Ringwald
hfp_hf_initiate_outgoing_call_cmd(uint16_t cid)348ce263fc8SMatthias Ringwald static int hfp_hf_initiate_outgoing_call_cmd(uint16_t cid){
349ce263fc8SMatthias Ringwald char buffer[40];
350865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "%s%s;\r", HFP_CALL_PHONE_NUMBER, hfp_hf_phone_number);
351ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
352ce263fc8SMatthias Ringwald }
353ce263fc8SMatthias Ringwald
hfp_hf_send_memory_dial_cmd(uint16_t cid,int memory_id)354a0ffb263SMatthias Ringwald static int hfp_hf_send_memory_dial_cmd(uint16_t cid, int memory_id){
355ce263fc8SMatthias Ringwald char buffer[40];
356865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "%s>%d;\r", HFP_CALL_PHONE_NUMBER, memory_id);
357ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
358ce263fc8SMatthias Ringwald }
359ce263fc8SMatthias Ringwald
hfp_hf_send_chld(uint16_t cid,unsigned int number)360f04a0c31SMatthias Ringwald static int hfp_hf_send_chld(uint16_t cid, unsigned int number){
36189425bfcSMilanka Ringwald char buffer[40];
362865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=%u\r", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, number);
363ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
364ce263fc8SMatthias Ringwald }
365ce263fc8SMatthias Ringwald
hfp_hf_send_dtmf(uint16_t cid,char code)366ce263fc8SMatthias Ringwald static int hfp_hf_send_dtmf(uint16_t cid, char code){
367ce263fc8SMatthias Ringwald char buffer[20];
368865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=%c\r", HFP_TRANSMIT_DTMF_CODES, code);
369ce263fc8SMatthias Ringwald return send_str_over_rfcomm(cid, buffer);
370ce263fc8SMatthias Ringwald }
371ce263fc8SMatthias Ringwald
hfp_hf_cmd_ata(uint16_t cid)37297d2cadbSMatthias Ringwald static int hfp_hf_cmd_ata(uint16_t cid){
3731599fe57SMatthias Ringwald return send_str_over_rfcomm(cid, (char *) "ATA\r");
37497d2cadbSMatthias Ringwald }
37597d2cadbSMatthias Ringwald
hfp_hf_cmd_exchange_supported_features(uint16_t cid)37689425bfcSMilanka Ringwald static int hfp_hf_cmd_exchange_supported_features(uint16_t cid){
377aeb0f0feSMatthias Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_SUPPORTED_FEATURES, hfp_hf_supported_features);
37889425bfcSMilanka Ringwald }
37989425bfcSMilanka Ringwald
hfp_hf_cmd_retrieve_indicators(uint16_t cid)38089425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_indicators(uint16_t cid){
38189425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_INDICATOR, "=?");
38289425bfcSMilanka Ringwald }
38389425bfcSMilanka Ringwald
hfp_hf_cmd_retrieve_indicators_status(uint16_t cid)38489425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_indicators_status(uint16_t cid){
38589425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_INDICATOR, "?");
38689425bfcSMilanka Ringwald }
38789425bfcSMilanka Ringwald
hfp_hf_cmd_retrieve_can_hold_call(uint16_t cid)38889425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_can_hold_call(uint16_t cid){
38989425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, "=?");
39089425bfcSMilanka Ringwald }
39189425bfcSMilanka Ringwald
hfp_hf_cmd_retrieve_supported_generic_status_indicators(uint16_t cid)39289425bfcSMilanka Ringwald static int hfp_hf_cmd_retrieve_supported_generic_status_indicators(uint16_t cid){
39389425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_GENERIC_STATUS_INDICATOR, "=?");
39489425bfcSMilanka Ringwald }
39589425bfcSMilanka Ringwald
hfp_hf_cmd_list_initital_supported_generic_status_indicators(uint16_t cid)39689425bfcSMilanka Ringwald static int hfp_hf_cmd_list_initital_supported_generic_status_indicators(uint16_t cid){
39789425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_GENERIC_STATUS_INDICATOR, "?");
39889425bfcSMilanka Ringwald }
39989425bfcSMilanka Ringwald
hfp_hf_cmd_query_operator_name_format(uint16_t cid)40089425bfcSMilanka Ringwald static int hfp_hf_cmd_query_operator_name_format(uint16_t cid){
40189425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_QUERY_OPERATOR_SELECTION, "=3,0");
40289425bfcSMilanka Ringwald }
40389425bfcSMilanka Ringwald
hfp_hf_cmd_query_operator_name(uint16_t cid)40489425bfcSMilanka Ringwald static int hfp_hf_cmd_query_operator_name(uint16_t cid){
40589425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_QUERY_OPERATOR_SELECTION, "?");
40689425bfcSMilanka Ringwald }
40789425bfcSMilanka Ringwald
hfp_hf_cmd_trigger_codec_connection_setup(uint16_t cid)40889425bfcSMilanka Ringwald static int hfp_hf_cmd_trigger_codec_connection_setup(uint16_t cid){
40989425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_TRIGGER_CODEC_CONNECTION_SETUP);
41089425bfcSMilanka Ringwald }
41189425bfcSMilanka Ringwald
hfp_hf_set_microphone_gain_cmd(uint16_t cid,int gain)41289425bfcSMilanka Ringwald static int hfp_hf_set_microphone_gain_cmd(uint16_t cid, int gain){
41389425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_SET_MICROPHONE_GAIN, gain);
41489425bfcSMilanka Ringwald }
41589425bfcSMilanka Ringwald
hfp_hf_set_speaker_gain_cmd(uint16_t cid,int gain)41689425bfcSMilanka Ringwald static int hfp_hf_set_speaker_gain_cmd(uint16_t cid, int gain){
41789425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_SET_SPEAKER_GAIN, gain);
41889425bfcSMilanka Ringwald }
41989425bfcSMilanka Ringwald
hfp_hf_set_calling_line_notification_cmd(uint16_t cid,uint8_t activate)42089425bfcSMilanka Ringwald static int hfp_hf_set_calling_line_notification_cmd(uint16_t cid, uint8_t activate){
42189425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ENABLE_CLIP, activate);
42289425bfcSMilanka Ringwald }
42389425bfcSMilanka Ringwald
hfp_hf_set_voice_recognition_notification_cmd(uint16_t cid,uint8_t activate)42489425bfcSMilanka Ringwald static int hfp_hf_set_voice_recognition_notification_cmd(uint16_t cid, uint8_t activate){
42589425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ACTIVATE_VOICE_RECOGNITION, activate);
42689425bfcSMilanka Ringwald }
42789425bfcSMilanka Ringwald
hfp_hf_set_call_waiting_notification_cmd(uint16_t cid,uint8_t activate)42889425bfcSMilanka Ringwald static int hfp_hf_set_call_waiting_notification_cmd(uint16_t cid, uint8_t activate){
42989425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ENABLE_CALL_WAITING_NOTIFICATION, activate);
43089425bfcSMilanka Ringwald }
43189425bfcSMilanka Ringwald
hfp_hf_cmd_confirm_codec(uint16_t cid,uint8_t codec)43289425bfcSMilanka Ringwald static int hfp_hf_cmd_confirm_codec(uint16_t cid, uint8_t codec){
43389425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_CONFIRM_COMMON_CODEC, codec);
43489425bfcSMilanka Ringwald }
43589425bfcSMilanka Ringwald
hfp_hf_cmd_enable_extended_audio_gateway_error_report(uint16_t cid,uint8_t enable)43689425bfcSMilanka Ringwald static int hfp_hf_cmd_enable_extended_audio_gateway_error_report(uint16_t cid, uint8_t enable){
43789425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_int(cid, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, enable);
43889425bfcSMilanka Ringwald }
43989425bfcSMilanka Ringwald
hfp_hf_send_redial_last_number_cmd(uint16_t cid)44089425bfcSMilanka Ringwald static int hfp_hf_send_redial_last_number_cmd(uint16_t cid){
44189425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_REDIAL_LAST_NUMBER);
44289425bfcSMilanka Ringwald }
44389425bfcSMilanka Ringwald
hfp_hf_send_chup(uint16_t cid)44489425bfcSMilanka Ringwald static int hfp_hf_send_chup(uint16_t cid){
44589425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_HANG_UP_CALL);
44689425bfcSMilanka Ringwald }
44789425bfcSMilanka Ringwald
hfp_hf_send_binp(uint16_t cid)448ce263fc8SMatthias Ringwald static int hfp_hf_send_binp(uint16_t cid){
44989425bfcSMilanka Ringwald return hfp_hf_send_cmd_with_mark(cid, HFP_PHONE_NUMBER_FOR_VOICE_TAG, "=1");
450ce263fc8SMatthias Ringwald }
451ce263fc8SMatthias Ringwald
hfp_hf_send_clcc(uint16_t cid)452667ec068SMatthias Ringwald static int hfp_hf_send_clcc(uint16_t cid){
45389425bfcSMilanka Ringwald return hfp_hf_send_cmd(cid, HFP_LIST_CURRENT_CALLS);
454667ec068SMatthias Ringwald }
455667ec068SMatthias Ringwald
45676cc1527SMatthias Ringwald /* state machines */
4573deb3ec6SMatthias Ringwald
hfp_hf_run_for_context_service_level_connection(hfp_connection_t * hfp_connection)4587f58ef6bSMatthias Ringwald static bool hfp_hf_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){
4597f58ef6bSMatthias Ringwald if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return false;
4607f58ef6bSMatthias Ringwald if (hfp_connection->ok_pending) return false;
4617f58ef6bSMatthias Ringwald
462498a8121SMilanka Ringwald log_info("hfp_hf_run_for_context_service_level_connection state %d\n", hfp_connection->state);
463a0ffb263SMatthias Ringwald switch (hfp_connection->state){
4643deb3ec6SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES:
465aeb0f0feSMatthias Ringwald hfp_hf_drop_mSBC_if_eSCO_not_supported(hfp_hf_codecs, &hfp_hf_codecs_nr);
466a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
467a0ffb263SMatthias Ringwald hfp_hf_cmd_exchange_supported_features(hfp_connection->rfcomm_cid);
4683deb3ec6SMatthias Ringwald break;
4693deb3ec6SMatthias Ringwald case HFP_NOTIFY_ON_CODECS:
470a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_NOTIFY_ON_CODECS;
471a0ffb263SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(hfp_connection->rfcomm_cid);
4723deb3ec6SMatthias Ringwald break;
4733deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS:
474a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS;
475a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_indicators(hfp_connection->rfcomm_cid);
4763deb3ec6SMatthias Ringwald break;
4773deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INDICATORS_STATUS:
478a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
479a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_indicators_status(hfp_connection->rfcomm_cid);
4803deb3ec6SMatthias Ringwald break;
4813deb3ec6SMatthias Ringwald case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
482a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
483a0ffb263SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(hfp_connection->rfcomm_cid, 1);
4843deb3ec6SMatthias Ringwald break;
4853deb3ec6SMatthias Ringwald case HFP_RETRIEVE_CAN_HOLD_CALL:
486a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
487a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_can_hold_call(hfp_connection->rfcomm_cid);
4883deb3ec6SMatthias Ringwald break;
4893deb3ec6SMatthias Ringwald case HFP_LIST_GENERIC_STATUS_INDICATORS:
490a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
491a0ffb263SMatthias Ringwald hfp_hf_cmd_list_supported_generic_status_indicators(hfp_connection->rfcomm_cid);
4923deb3ec6SMatthias Ringwald break;
4933deb3ec6SMatthias Ringwald case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
494a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
495a0ffb263SMatthias Ringwald hfp_hf_cmd_retrieve_supported_generic_status_indicators(hfp_connection->rfcomm_cid);
4963deb3ec6SMatthias Ringwald break;
4973deb3ec6SMatthias Ringwald case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
498a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
499a0ffb263SMatthias Ringwald hfp_hf_cmd_list_initital_supported_generic_status_indicators(hfp_connection->rfcomm_cid);
5003deb3ec6SMatthias Ringwald break;
5013deb3ec6SMatthias Ringwald default:
5027f58ef6bSMatthias Ringwald return false;
5033deb3ec6SMatthias Ringwald }
5047f58ef6bSMatthias Ringwald return true;
5053deb3ec6SMatthias Ringwald }
5063deb3ec6SMatthias Ringwald
507ce263fc8SMatthias Ringwald
hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection)5087f58ef6bSMatthias Ringwald static bool hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){
5097f58ef6bSMatthias Ringwald if (hfp_connection->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return false;
510498a8121SMilanka Ringwald if (hfp_connection->ok_pending){
5117f58ef6bSMatthias Ringwald return false;
512498a8121SMilanka Ringwald }
5137f58ef6bSMatthias Ringwald
514a0ffb263SMatthias Ringwald if (hfp_connection->enable_status_update_for_ag_indicators != 0xFF){
515a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
516a0ffb263SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_all_ag_indicators(hfp_connection->rfcomm_cid, hfp_connection->enable_status_update_for_ag_indicators);
5177f58ef6bSMatthias Ringwald return true;
518ce263fc8SMatthias Ringwald };
5197f58ef6bSMatthias Ringwald
520a0ffb263SMatthias Ringwald if (hfp_connection->change_status_update_for_individual_ag_indicators){
521a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
522a0ffb263SMatthias Ringwald hfp_hf_cmd_activate_status_update_for_ag_indicator(hfp_connection->rfcomm_cid,
523a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap,
524a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_nr);
5257f58ef6bSMatthias Ringwald return true;
526ce263fc8SMatthias Ringwald }
527ce263fc8SMatthias Ringwald
528a0ffb263SMatthias Ringwald switch (hfp_connection->hf_query_operator_state){
529ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_SET_FORMAT:
530a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_W4_SET_FORMAT_OK;
531a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
532a0ffb263SMatthias Ringwald hfp_hf_cmd_query_operator_name_format(hfp_connection->rfcomm_cid);
5337f58ef6bSMatthias Ringwald return true;
534ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_SEND_QUERY:
535a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HPF_HF_QUERY_OPERATOR_W4_RESULT;
536a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
537a0ffb263SMatthias Ringwald hfp_hf_cmd_query_operator_name(hfp_connection->rfcomm_cid);
5387f58ef6bSMatthias Ringwald return true;
539ce263fc8SMatthias Ringwald default:
540ce263fc8SMatthias Ringwald break;
541ce263fc8SMatthias Ringwald }
542ce263fc8SMatthias Ringwald
543a0ffb263SMatthias Ringwald if (hfp_connection->enable_extended_audio_gateway_error_report){
544a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
545a0ffb263SMatthias Ringwald hfp_hf_cmd_enable_extended_audio_gateway_error_report(hfp_connection->rfcomm_cid, hfp_connection->enable_extended_audio_gateway_error_report);
5467f58ef6bSMatthias Ringwald return true;
547ce263fc8SMatthias Ringwald }
548ce263fc8SMatthias Ringwald
5497f58ef6bSMatthias Ringwald return false;
550ce263fc8SMatthias Ringwald }
551ce263fc8SMatthias Ringwald
hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connection)5527f58ef6bSMatthias Ringwald static bool hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connection){
553be55a11dSMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) {
5547f58ef6bSMatthias Ringwald return false;
555be55a11dSMilanka Ringwald }
556fd4151d1SMilanka Ringwald
5570b4debbfSMilanka Ringwald if (hfp_connection->ok_pending == 1){
5587f58ef6bSMatthias Ringwald return false;
5590b4debbfSMilanka Ringwald }
5600b4debbfSMilanka Ringwald // voice recognition activated from AG
5610b4debbfSMilanka Ringwald if (hfp_connection->command == HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION){
5620b4debbfSMilanka Ringwald switch(hfp_connection->vra_state_requested){
5630b4debbfSMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED:
5640b4debbfSMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF:
565de9e0ea7SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
5660b4debbfSMilanka Ringwald // ignore AG command, continue to wait for OK
5677f58ef6bSMatthias Ringwald return false;
568cf75be85SMilanka Ringwald
5690b4debbfSMilanka Ringwald default:
570b95cac54SMilanka Ringwald if (hfp_connection->ag_vra_msg_length > 0){
571b95cac54SMilanka Ringwald hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection);
572b95cac54SMilanka Ringwald hfp_connection->ag_vra_msg_length = 0;
573b95cac54SMilanka Ringwald break;
574b95cac54SMilanka Ringwald }
575cf75be85SMilanka Ringwald switch(hfp_connection->ag_vra_state){
576cf75be85SMilanka Ringwald case HFP_VOICE_RECOGNITION_STATE_AG_READY:
577013cc750SMilanka Ringwald switch (hfp_connection->ag_vra_status){
578013cc750SMilanka Ringwald case 0:
5790b4debbfSMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_OFF;
580013cc750SMilanka Ringwald break;
581013cc750SMilanka Ringwald case 1:
582013cc750SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED;
583013cc750SMilanka Ringwald break;
584013cc750SMilanka Ringwald case 2:
585013cc750SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO;
586013cc750SMilanka Ringwald break;
587013cc750SMilanka Ringwald default:
588013cc750SMilanka Ringwald break;
5890b4debbfSMilanka Ringwald }
5900b4debbfSMilanka Ringwald break;
591cf75be85SMilanka Ringwald default:
592cf75be85SMilanka Ringwald // state messages from AG
593cf75be85SMilanka Ringwald hfp_emit_enhanced_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS);
5948d5005b5SMilanka Ringwald hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY;
595cf75be85SMilanka Ringwald break;
596cf75be85SMilanka Ringwald }
597cf75be85SMilanka Ringwald break;
5980b4debbfSMilanka Ringwald }
5990b4debbfSMilanka Ringwald hfp_connection->command = HFP_CMD_NONE;
6000b4debbfSMilanka Ringwald }
6010b4debbfSMilanka Ringwald
602498a8121SMilanka Ringwald switch (hfp_connection->vra_state_requested){
603fdda66c0SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF:
604fdda66c0SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_OFF;
605498a8121SMilanka Ringwald hfp_connection->ok_pending = 1;
606cd7fdf75SMatthias Ringwald hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 0);
6077f58ef6bSMatthias Ringwald return true;
608fd4151d1SMilanka Ringwald
609fdda66c0SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED:
610fdda66c0SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED;
611fd4151d1SMilanka Ringwald hfp_connection->ok_pending = 1;
612cd7fdf75SMatthias Ringwald hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 1);
6137f58ef6bSMatthias Ringwald return true;
614013cc750SMilanka Ringwald
615de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
616de9e0ea7SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO;
617de9e0ea7SMilanka Ringwald hfp_connection->ok_pending = 1;
618cd7fdf75SMatthias Ringwald hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 2);
6197f58ef6bSMatthias Ringwald return true;
620de9e0ea7SMilanka Ringwald
621de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF:
622de9e0ea7SMilanka Ringwald hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF;
623de9e0ea7SMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state;
624de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = false;
625de9e0ea7SMilanka Ringwald if (hfp_connection->activate_voice_recognition){
626fcf4ede6SMilanka Ringwald hfp_connection->enhanced_voice_recognition_enabled = hfp_hf_enhanced_vra_flag_supported(hfp_connection);
627de9e0ea7SMilanka Ringwald hfp_hf_activate_voice_recognition(hfp_connection->acl_handle);
628de9e0ea7SMilanka Ringwald } else {
629553a4a56SMilanka Ringwald hfp_emit_voice_recognition_disabled(hfp_connection, ERROR_CODE_SUCCESS);
630de9e0ea7SMilanka Ringwald }
631de9e0ea7SMilanka Ringwald break;
632de9e0ea7SMilanka Ringwald
633be55a11dSMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED:
634498a8121SMilanka Ringwald hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_ACTIVATED;
635498a8121SMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state;
636de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = false;
637de9e0ea7SMilanka Ringwald if (hfp_connection->deactivate_voice_recognition){
638de9e0ea7SMilanka Ringwald hfp_hf_deactivate_voice_recognition(hfp_connection->acl_handle);
639de9e0ea7SMilanka Ringwald } else {
640fcf4ede6SMilanka Ringwald hfp_connection->enhanced_voice_recognition_enabled = hfp_hf_enhanced_vra_flag_supported(hfp_connection);
64184fb9ac1SMilanka Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED){
642553a4a56SMilanka Ringwald hfp_emit_voice_recognition_enabled(hfp_connection, ERROR_CODE_SUCCESS);
64384fb9ac1SMilanka Ringwald } else {
64484fb9ac1SMilanka Ringwald // postpone VRA event to simplify application logic
64584fb9ac1SMilanka Ringwald hfp_connection->emit_vra_enabled_after_audio_established = true;
64684fb9ac1SMilanka Ringwald }
647de9e0ea7SMilanka Ringwald }
648be55a11dSMilanka Ringwald break;
649be55a11dSMilanka Ringwald
650013cc750SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
651013cc750SMilanka Ringwald hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO;
652498a8121SMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state;
653de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = false;
654de9e0ea7SMilanka Ringwald if (hfp_connection->deactivate_voice_recognition){
655de9e0ea7SMilanka Ringwald hfp_hf_deactivate_voice_recognition(hfp_connection->acl_handle);
656de9e0ea7SMilanka Ringwald } else {
657de9e0ea7SMilanka Ringwald hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_SUCCESS);
658de9e0ea7SMilanka Ringwald }
659be55a11dSMilanka Ringwald break;
660fd4151d1SMilanka Ringwald
661be55a11dSMilanka Ringwald default:
662be55a11dSMilanka Ringwald break;
663be55a11dSMilanka Ringwald }
6647f58ef6bSMatthias Ringwald return false;
665be55a11dSMilanka Ringwald }
666be55a11dSMilanka Ringwald
667be55a11dSMilanka Ringwald
codecs_exchange_state_machine(hfp_connection_t * hfp_connection)6687f58ef6bSMatthias Ringwald static bool codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
6697f58ef6bSMatthias Ringwald if (hfp_connection->ok_pending) return false;
670ce263fc8SMatthias Ringwald
671332ca98fSMatthias Ringwald if (hfp_connection->trigger_codec_exchange){
6727f58ef6bSMatthias Ringwald hfp_connection->trigger_codec_exchange = false;
673ce263fc8SMatthias Ringwald
674a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
675a0ffb263SMatthias Ringwald hfp_hf_cmd_trigger_codec_connection_setup(hfp_connection->rfcomm_cid);
6767f58ef6bSMatthias Ringwald return true;
677332ca98fSMatthias Ringwald }
678332ca98fSMatthias Ringwald
6791cc65c4fSMatthias Ringwald if (hfp_connection->hf_send_codec_confirm){
6801cc65c4fSMatthias Ringwald hfp_connection->hf_send_codec_confirm = false;
681ce263fc8SMatthias Ringwald
682a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
683fcb08cdbSMilanka Ringwald hfp_hf_cmd_confirm_codec(hfp_connection->rfcomm_cid, hfp_connection->codec_confirmed);
6847f58ef6bSMatthias Ringwald return true;
6851cc65c4fSMatthias Ringwald }
6861cc65c4fSMatthias Ringwald
6871cc65c4fSMatthias Ringwald if (hfp_connection->hf_send_supported_codecs){
6881cc65c4fSMatthias Ringwald hfp_connection->hf_send_supported_codecs = false;
6891cc65c4fSMatthias Ringwald
690a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
691a0ffb263SMatthias Ringwald hfp_hf_cmd_notify_on_codecs(hfp_connection->rfcomm_cid);
6927f58ef6bSMatthias Ringwald return true;
6931cc65c4fSMatthias Ringwald }
694ce263fc8SMatthias Ringwald
6957f58ef6bSMatthias Ringwald return false;
696ce263fc8SMatthias Ringwald }
697ce263fc8SMatthias Ringwald
hfp_hf_run_for_audio_connection(hfp_connection_t * hfp_connection)6987f58ef6bSMatthias Ringwald static bool hfp_hf_run_for_audio_connection(hfp_connection_t * hfp_connection){
699505f1c30SMatthias Ringwald if ((hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) ||
7007f58ef6bSMatthias Ringwald (hfp_connection->state > HFP_W2_DISCONNECT_SCO)) return false;
701ce263fc8SMatthias Ringwald
70264f19dedSMilanka Ringwald if (hfp_connection->release_audio_connection){
703a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_DISCONNECTED;
704a0ffb263SMatthias Ringwald hfp_connection->release_audio_connection = 0;
705a0ffb263SMatthias Ringwald gap_disconnect(hfp_connection->sco_handle);
7067f58ef6bSMatthias Ringwald return true;
707ce263fc8SMatthias Ringwald }
708ce263fc8SMatthias Ringwald
7097f58ef6bSMatthias Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return false;
710ce263fc8SMatthias Ringwald
711ce263fc8SMatthias Ringwald // run codecs exchange
7127f58ef6bSMatthias Ringwald bool done = codecs_exchange_state_machine(hfp_connection);
7137f58ef6bSMatthias Ringwald if (done) return true;
714ce263fc8SMatthias Ringwald
7157f58ef6bSMatthias Ringwald if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return false;
7167f58ef6bSMatthias Ringwald if (hfp_sco_setup_active()) return false;
71738200c1dSMilanka Ringwald if (hfp_connection->establish_audio_connection){
71838200c1dSMilanka Ringwald hfp_connection->state = HFP_W4_SCO_CONNECTED;
71938200c1dSMilanka Ringwald hfp_connection->establish_audio_connection = 0;
72038200c1dSMilanka Ringwald hfp_setup_synchronous_connection(hfp_connection);
7217f58ef6bSMatthias Ringwald return true;
72238200c1dSMilanka Ringwald }
7237f58ef6bSMatthias Ringwald return false;
724ce263fc8SMatthias Ringwald }
725ce263fc8SMatthias Ringwald
72638200c1dSMilanka Ringwald
call_setup_state_machine(hfp_connection_t * hfp_connection)7277f58ef6bSMatthias Ringwald static bool call_setup_state_machine(hfp_connection_t * hfp_connection){
728eaf2b0a1SMatthias Ringwald
7297f58ef6bSMatthias Ringwald if (hfp_connection->ok_pending) return false;
730eaf2b0a1SMatthias Ringwald
731a0ffb263SMatthias Ringwald if (hfp_connection->hf_answer_incoming_call){
732a0ffb263SMatthias Ringwald hfp_connection->hf_answer_incoming_call = 0;
733cd7fdf75SMatthias Ringwald hfp_hf_cmd_ata(hfp_connection->rfcomm_cid);
7347f58ef6bSMatthias Ringwald return true;
735ce263fc8SMatthias Ringwald }
7367f58ef6bSMatthias Ringwald return false;
737ce263fc8SMatthias Ringwald }
738ce263fc8SMatthias Ringwald
hfp_hf_run_for_context(hfp_connection_t * hfp_connection)7391c6a0fc0SMatthias Ringwald static void hfp_hf_run_for_context(hfp_connection_t * hfp_connection){
7407522e673SMatthias Ringwald
74176cc1527SMatthias Ringwald btstack_assert(hfp_connection != NULL);
74276cc1527SMatthias Ringwald btstack_assert(hfp_connection->local_role == HFP_ROLE_HF);
74376cc1527SMatthias Ringwald
74476cc1527SMatthias Ringwald // during SDP query, RFCOMM CID is not set
74576cc1527SMatthias Ringwald if (hfp_connection->rfcomm_cid == 0) return;
74622387625SMatthias Ringwald
74784fb9ac1SMilanka Ringwald // emit postponed VRA event
74884fb9ac1SMilanka Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED && hfp_connection->emit_vra_enabled_after_audio_established){
74984fb9ac1SMilanka Ringwald hfp_connection->emit_vra_enabled_after_audio_established = false;
75084fb9ac1SMilanka Ringwald hfp_emit_voice_recognition_enabled(hfp_connection, ERROR_CODE_SUCCESS);
75184fb9ac1SMilanka Ringwald }
75284fb9ac1SMilanka Ringwald
7533721a235SMatthias Ringwald // assert command could be sent
7543721a235SMatthias Ringwald if (hci_can_send_command_packet_now() == 0) return;
7553721a235SMatthias Ringwald
7563721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP
7573721a235SMatthias Ringwald // WBS Disassociate
7583721a235SMatthias Ringwald if (hfp_connection->cc256x_send_wbs_disassociate){
7593721a235SMatthias Ringwald hfp_connection->cc256x_send_wbs_disassociate = false;
7603721a235SMatthias Ringwald hci_send_cmd(&hci_ti_wbs_disassociate);
7613721a235SMatthias Ringwald return;
7623721a235SMatthias Ringwald }
7633721a235SMatthias Ringwald // Write Codec Config
7643721a235SMatthias Ringwald if (hfp_connection->cc256x_send_write_codec_config){
7653721a235SMatthias Ringwald hfp_connection->cc256x_send_write_codec_config = false;
7663721a235SMatthias Ringwald hfp_cc256x_write_codec_config(hfp_connection);
7673721a235SMatthias Ringwald return;
7683721a235SMatthias Ringwald }
7693721a235SMatthias Ringwald // WBS Associate
7703721a235SMatthias Ringwald if (hfp_connection->cc256x_send_wbs_associate){
7713721a235SMatthias Ringwald hfp_connection->cc256x_send_wbs_associate = false;
7723721a235SMatthias Ringwald hci_send_cmd(&hci_ti_wbs_associate, hfp_connection->acl_handle);
7733721a235SMatthias Ringwald return;
7743721a235SMatthias Ringwald }
7753721a235SMatthias Ringwald #endif
776689d4323SMatthias Ringwald #ifdef ENABLE_BCM_PCM_WBS
777689d4323SMatthias Ringwald // Enable WBS
778689d4323SMatthias Ringwald if (hfp_connection->bcm_send_enable_wbs){
779689d4323SMatthias Ringwald hfp_connection->bcm_send_enable_wbs = false;
780689d4323SMatthias Ringwald hci_send_cmd(&hci_bcm_enable_wbs, 1, 2);
781689d4323SMatthias Ringwald return;
782689d4323SMatthias Ringwald }
783689d4323SMatthias Ringwald // Write I2S/PCM params
784689d4323SMatthias Ringwald if (hfp_connection->bcm_send_write_i2spcm_interface_param){
785689d4323SMatthias Ringwald hfp_connection->bcm_send_write_i2spcm_interface_param = false;
786689d4323SMatthias Ringwald hfp_bcm_write_i2spcm_interface_param(hfp_connection);
787689d4323SMatthias Ringwald return;
788689d4323SMatthias Ringwald }
789689d4323SMatthias Ringwald // Disable WBS
790689d4323SMatthias Ringwald if (hfp_connection->bcm_send_disable_wbs){
791689d4323SMatthias Ringwald hfp_connection->bcm_send_disable_wbs = false;
792689d4323SMatthias Ringwald hci_send_cmd(&hci_bcm_enable_wbs, 0, 2);
793689d4323SMatthias Ringwald return;
794689d4323SMatthias Ringwald }
795689d4323SMatthias Ringwald #endif
7962b5f92fdSMatthias Ringwald #ifdef ENABLE_RTK_PCM_WBS
7972b5f92fdSMatthias Ringwald if (hfp_connection->rtk_send_sco_config){
7982b5f92fdSMatthias Ringwald hfp_connection->rtk_send_sco_config = false;
7992b5f92fdSMatthias Ringwald if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){
8002b5f92fdSMatthias Ringwald log_info("RTK SCO: 16k + mSBC");
8012b5f92fdSMatthias Ringwald hci_send_cmd(&hci_rtk_configure_sco_routing, 0x81, 0x90, 0x00, 0x00, 0x1a, 0x0c, 0x00, 0x00, 0x41);
8022b5f92fdSMatthias Ringwald } else {
8032b5f92fdSMatthias Ringwald log_info("RTK SCO: 16k + CVSD");
8042b5f92fdSMatthias Ringwald hci_send_cmd(&hci_rtk_configure_sco_routing, 0x81, 0x90, 0x00, 0x00, 0x1a, 0x0c, 0x0c, 0x00, 0x01);
8052b5f92fdSMatthias Ringwald }
8062b5f92fdSMatthias Ringwald return;
8072b5f92fdSMatthias Ringwald }
8082b5f92fdSMatthias Ringwald #endif
8095fd6f360SMatthias Ringwald #ifdef ENABLE_NXP_PCM_WBS
8105fd6f360SMatthias Ringwald if (hfp_connection->nxp_start_audio_handle != HCI_CON_HANDLE_INVALID){
8115fd6f360SMatthias Ringwald hci_con_handle_t sco_handle = hfp_connection->nxp_start_audio_handle;
8125fd6f360SMatthias Ringwald hfp_connection->nxp_start_audio_handle = HCI_CON_HANDLE_INVALID;
8135fd6f360SMatthias Ringwald hci_send_cmd(&hci_nxp_host_pcm_i2s_audio_config, 0, 0, sco_handle, 0);
8145fd6f360SMatthias Ringwald return;
8155fd6f360SMatthias Ringwald }
8165fd6f360SMatthias Ringwald if (hfp_connection->nxp_stop_audio_handle != HCI_CON_HANDLE_INVALID){
8175fd6f360SMatthias Ringwald hci_con_handle_t sco_handle = hfp_connection->nxp_stop_audio_handle;
8185fd6f360SMatthias Ringwald hfp_connection->nxp_stop_audio_handle = HCI_CON_HANDLE_INVALID;
8195fd6f360SMatthias Ringwald hci_send_cmd(&hci_nxp_host_pcm_i2s_audio_config, 1, 0, sco_handle, 0);
8205fd6f360SMatthias Ringwald return;
8215fd6f360SMatthias Ringwald }
8225fd6f360SMatthias Ringwald #endif
82348e6eeeeSMatthias Ringwald #if defined (ENABLE_CC256X_ASSISTED_HFP) || defined (ENABLE_BCM_PCM_WBS)
82448e6eeeeSMatthias Ringwald if (hfp_connection->state == HFP_W4_WBS_SHUTDOWN){
82548e6eeeeSMatthias Ringwald hfp_finalize_connection_context(hfp_connection);
82648e6eeeeSMatthias Ringwald return;
82748e6eeeeSMatthias Ringwald }
82848e6eeeeSMatthias Ringwald #endif
8293721a235SMatthias Ringwald
830447743f7SMatthias Ringwald if (hfp_connection->accept_sco && (hfp_sco_setup_active() == false)){
831cb81d35dSMatthias Ringwald bool incoming_eSCO = hfp_connection->accept_sco == 2;
8327522e673SMatthias Ringwald // notify about codec selection if not done already
8337522e673SMatthias Ringwald if (hfp_connection->negotiated_codec == 0){
8347522e673SMatthias Ringwald hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
8357522e673SMatthias Ringwald }
836cb81d35dSMatthias Ringwald hfp_accept_synchronous_connection(hfp_connection, incoming_eSCO);
8377522e673SMatthias Ringwald return;
8387522e673SMatthias Ringwald }
8397522e673SMatthias Ringwald
840d4dd47ffSMatthias Ringwald if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) {
841d4dd47ffSMatthias Ringwald rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
842d4dd47ffSMatthias Ringwald return;
843d4dd47ffSMatthias Ringwald }
844cd7fdf75SMatthias Ringwald
845cd7fdf75SMatthias Ringwald // we can send at least an RFCOMM packet or a HCI Command now
846cd7fdf75SMatthias Ringwald
8477f58ef6bSMatthias Ringwald bool done = hfp_hf_run_for_context_service_level_connection(hfp_connection);
848ce263fc8SMatthias Ringwald if (!done){
849a0ffb263SMatthias Ringwald done = hfp_hf_run_for_context_service_level_connection_queries(hfp_connection);
850ce263fc8SMatthias Ringwald }
851ce263fc8SMatthias Ringwald if (!done){
852c95b5b3cSMilanka Ringwald done = hfp_hf_run_for_audio_connection(hfp_connection);
853be55a11dSMilanka Ringwald }
854be55a11dSMilanka Ringwald if (!done){
855c95b5b3cSMilanka Ringwald done = hfp_hf_voice_recognition_state_machine(hfp_connection);
856ce263fc8SMatthias Ringwald }
857ce263fc8SMatthias Ringwald if (!done){
858a0ffb263SMatthias Ringwald done = call_setup_state_machine(hfp_connection);
859ce263fc8SMatthias Ringwald }
860ce263fc8SMatthias Ringwald
861e2c3b58dSMilanka Ringwald // don't send a new command while ok still pending or SLC is not established
862e2c3b58dSMilanka Ringwald if (hfp_connection->ok_pending || (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED)){
863e2c3b58dSMilanka Ringwald return;
864e2c3b58dSMilanka Ringwald }
8651016a228SMatthias Ringwald
866a0ffb263SMatthias Ringwald if (hfp_connection->send_microphone_gain){
867a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 0;
868a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
869a0ffb263SMatthias Ringwald hfp_hf_set_microphone_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->microphone_gain);
870ce263fc8SMatthias Ringwald return;
871ce263fc8SMatthias Ringwald }
872ce263fc8SMatthias Ringwald
873a0ffb263SMatthias Ringwald if (hfp_connection->send_speaker_gain){
874a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 0;
875a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
876a0ffb263SMatthias Ringwald hfp_hf_set_speaker_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->speaker_gain);
877ce263fc8SMatthias Ringwald return;
878ce263fc8SMatthias Ringwald }
879ce263fc8SMatthias Ringwald
880a0ffb263SMatthias Ringwald if (hfp_connection->hf_deactivate_calling_line_notification){
881a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_calling_line_notification = 0;
882a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
883a0ffb263SMatthias Ringwald hfp_hf_set_calling_line_notification_cmd(hfp_connection->rfcomm_cid, 0);
884ce263fc8SMatthias Ringwald return;
885ce263fc8SMatthias Ringwald }
886ce263fc8SMatthias Ringwald
887a0ffb263SMatthias Ringwald if (hfp_connection->hf_activate_calling_line_notification){
888a0ffb263SMatthias Ringwald hfp_connection->hf_activate_calling_line_notification = 0;
889a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
890a0ffb263SMatthias Ringwald hfp_hf_set_calling_line_notification_cmd(hfp_connection->rfcomm_cid, 1);
891ce263fc8SMatthias Ringwald return;
892ce263fc8SMatthias Ringwald }
893ce263fc8SMatthias Ringwald
894a0ffb263SMatthias Ringwald if (hfp_connection->hf_deactivate_echo_canceling_and_noise_reduction){
895a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_echo_canceling_and_noise_reduction = 0;
89699af1e28SMilanka Ringwald hfp_connection->response_pending_for_command = HFP_CMD_TURN_OFF_EC_AND_NR;
897a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
898e2c3b58dSMilanka Ringwald hfp_hf_send_cmd_with_int(hfp_connection->rfcomm_cid, HFP_TURN_OFF_EC_AND_NR, 0);
899ce263fc8SMatthias Ringwald return;
900ce263fc8SMatthias Ringwald }
901ce263fc8SMatthias Ringwald
902a0ffb263SMatthias Ringwald if (hfp_connection->hf_deactivate_call_waiting_notification){
903a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_call_waiting_notification = 0;
904a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
905a0ffb263SMatthias Ringwald hfp_hf_set_call_waiting_notification_cmd(hfp_connection->rfcomm_cid, 0);
906ce263fc8SMatthias Ringwald return;
907ce263fc8SMatthias Ringwald }
908ce263fc8SMatthias Ringwald
909a0ffb263SMatthias Ringwald if (hfp_connection->hf_activate_call_waiting_notification){
910a0ffb263SMatthias Ringwald hfp_connection->hf_activate_call_waiting_notification = 0;
911a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
912a0ffb263SMatthias Ringwald hfp_hf_set_call_waiting_notification_cmd(hfp_connection->rfcomm_cid, 1);
913ce263fc8SMatthias Ringwald return;
914ce263fc8SMatthias Ringwald }
915ce263fc8SMatthias Ringwald
916a0ffb263SMatthias Ringwald if (hfp_connection->hf_initiate_outgoing_call){
917a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_outgoing_call = 0;
918a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
919a0ffb263SMatthias Ringwald hfp_hf_initiate_outgoing_call_cmd(hfp_connection->rfcomm_cid);
920ce263fc8SMatthias Ringwald return;
921ce263fc8SMatthias Ringwald }
922ce263fc8SMatthias Ringwald
923a0ffb263SMatthias Ringwald if (hfp_connection->hf_initiate_memory_dialing){
924a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_memory_dialing = 0;
925a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
926a0ffb263SMatthias Ringwald hfp_hf_send_memory_dial_cmd(hfp_connection->rfcomm_cid, hfp_connection->memory_id);
927ce263fc8SMatthias Ringwald return;
928ce263fc8SMatthias Ringwald }
929ce263fc8SMatthias Ringwald
930a0ffb263SMatthias Ringwald if (hfp_connection->hf_initiate_redial_last_number){
931a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_redial_last_number = 0;
932a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
933a0ffb263SMatthias Ringwald hfp_hf_send_redial_last_number_cmd(hfp_connection->rfcomm_cid);
934ce263fc8SMatthias Ringwald return;
935ce263fc8SMatthias Ringwald }
936ce263fc8SMatthias Ringwald
937a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chup){
938a0ffb263SMatthias Ringwald hfp_connection->hf_send_chup = 0;
939a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
940a0ffb263SMatthias Ringwald hfp_hf_send_chup(hfp_connection->rfcomm_cid);
941ce263fc8SMatthias Ringwald return;
942ce263fc8SMatthias Ringwald }
943ce263fc8SMatthias Ringwald
944a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_0){
945a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_0 = 0;
946a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
947a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 0);
948ce263fc8SMatthias Ringwald return;
949ce263fc8SMatthias Ringwald }
950ce263fc8SMatthias Ringwald
951a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_1){
952a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_1 = 0;
953a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
954a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 1);
955ce263fc8SMatthias Ringwald return;
956ce263fc8SMatthias Ringwald }
957ce263fc8SMatthias Ringwald
958a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_2){
959a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_2 = 0;
960a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
961a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 2);
962ce263fc8SMatthias Ringwald return;
963ce263fc8SMatthias Ringwald }
964ce263fc8SMatthias Ringwald
965a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_3){
966a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_3 = 0;
967a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
968a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 3);
969ce263fc8SMatthias Ringwald return;
970ce263fc8SMatthias Ringwald }
971ce263fc8SMatthias Ringwald
972a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_4){
973a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_4 = 0;
974a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
975a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, 4);
976ce263fc8SMatthias Ringwald return;
977ce263fc8SMatthias Ringwald }
978ce263fc8SMatthias Ringwald
979a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_chld_x){
980a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x = 0;
981a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
982a0ffb263SMatthias Ringwald hfp_hf_send_chld(hfp_connection->rfcomm_cid, hfp_connection->hf_send_chld_x_index);
983667ec068SMatthias Ringwald return;
984667ec068SMatthias Ringwald }
985667ec068SMatthias Ringwald
986a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_dtmf_code){
987a0ffb263SMatthias Ringwald char code = hfp_connection->hf_send_dtmf_code;
988a0ffb263SMatthias Ringwald hfp_connection->hf_send_dtmf_code = 0;
989a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
990a0ffb263SMatthias Ringwald hfp_hf_send_dtmf(hfp_connection->rfcomm_cid, code);
991c090e552SMatthias Ringwald // notify client that dtmf was sent
992c090e552SMatthias Ringwald char buffer[2];
993c090e552SMatthias Ringwald buffer[0] = code;
994c090e552SMatthias Ringwald buffer[1] = 0;
995c090e552SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_TRANSMIT_DTMF_CODES, buffer);
996ce263fc8SMatthias Ringwald return;
997ce263fc8SMatthias Ringwald }
998ce263fc8SMatthias Ringwald
999a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_binp){
1000a0ffb263SMatthias Ringwald hfp_connection->hf_send_binp = 0;
1001a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
1002a0ffb263SMatthias Ringwald hfp_hf_send_binp(hfp_connection->rfcomm_cid);
1003ce263fc8SMatthias Ringwald return;
1004ce263fc8SMatthias Ringwald }
1005ce263fc8SMatthias Ringwald
1006a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_clcc){
1007a0ffb263SMatthias Ringwald hfp_connection->hf_send_clcc = 0;
1008a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
1009a0ffb263SMatthias Ringwald hfp_hf_send_clcc(hfp_connection->rfcomm_cid);
1010667ec068SMatthias Ringwald return;
1011667ec068SMatthias Ringwald }
1012667ec068SMatthias Ringwald
1013a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_rrh){
1014a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 0;
1015667ec068SMatthias Ringwald char buffer[20];
1016a0ffb263SMatthias Ringwald switch (hfp_connection->hf_send_rrh_command){
1017667ec068SMatthias Ringwald case '?':
1018865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s?\r",
1019ff7d6aeaSMatthias Ringwald HFP_RESPONSE_AND_HOLD);
1020ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0;
1021a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
1022667ec068SMatthias Ringwald return;
1023667ec068SMatthias Ringwald case '0':
1024667ec068SMatthias Ringwald case '1':
1025667ec068SMatthias Ringwald case '2':
1026865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=%c\r",
1027ff7d6aeaSMatthias Ringwald HFP_RESPONSE_AND_HOLD,
1028ff7d6aeaSMatthias Ringwald hfp_connection->hf_send_rrh_command);
1029ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0;
1030a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
1031667ec068SMatthias Ringwald return;
1032667ec068SMatthias Ringwald default:
1033667ec068SMatthias Ringwald break;
1034667ec068SMatthias Ringwald }
1035667ec068SMatthias Ringwald return;
1036667ec068SMatthias Ringwald }
1037667ec068SMatthias Ringwald
1038a0ffb263SMatthias Ringwald if (hfp_connection->hf_send_cnum){
1039a0ffb263SMatthias Ringwald hfp_connection->hf_send_cnum = 0;
1040667ec068SMatthias Ringwald char buffer[20];
1041865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s\r",
1042ff7d6aeaSMatthias Ringwald HFP_SUBSCRIBER_NUMBER_INFORMATION);
1043ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0;
1044a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
1045667ec068SMatthias Ringwald return;
1046667ec068SMatthias Ringwald }
1047667ec068SMatthias Ringwald
1048667ec068SMatthias Ringwald // update HF indicators
1049a0ffb263SMatthias Ringwald if (hfp_connection->generic_status_update_bitmap){
1050667ec068SMatthias Ringwald int i;
1051aeb0f0feSMatthias Ringwald for (i=0; i < hfp_hf_indicators_nr; i++){
1052a0ffb263SMatthias Ringwald if (get_bit(hfp_connection->generic_status_update_bitmap, i)){
10530f716b22SMatthias Ringwald hfp_connection->generic_status_update_bitmap = store_bit(hfp_connection->generic_status_update_bitmap, i, 0);
1054a0ffb263SMatthias Ringwald if (hfp_connection->generic_status_indicators[i].state){
1055a0ffb263SMatthias Ringwald hfp_connection->ok_pending = 1;
1056667ec068SMatthias Ringwald char buffer[30];
1057865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=%u,%u\r",
1058ff7d6aeaSMatthias Ringwald HFP_TRANSFER_HF_INDICATOR_STATUS,
1059aeb0f0feSMatthias Ringwald hfp_hf_indicators[i],
1060aeb0f0feSMatthias Ringwald (unsigned int)hfp_hf_indicators_value[i]);
1061ff7d6aeaSMatthias Ringwald buffer[sizeof(buffer) - 1] = 0;
1062a0ffb263SMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
1063667ec068SMatthias Ringwald } else {
1064aeb0f0feSMatthias Ringwald log_info("Not sending HF indicator %u as it is disabled", hfp_hf_indicators[i]);
1065667ec068SMatthias Ringwald }
1066667ec068SMatthias Ringwald return;
1067667ec068SMatthias Ringwald }
1068667ec068SMatthias Ringwald }
1069667ec068SMatthias Ringwald }
1070667ec068SMatthias Ringwald
10714e8ee53aSMatthias Ringwald if (hfp_connection->send_apple_information){
10724e8ee53aSMatthias Ringwald hfp_connection->send_apple_information = false;
10734e8ee53aSMatthias Ringwald hfp_connection->ok_pending = 1;
10744e8ee53aSMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_APPLE_ACCESSORY_INFORMATION;
10754e8ee53aSMatthias Ringwald char buffer[40];
1076865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=%04x-%04x-%s,%u\r", HFP_APPLE_ACCESSORY_INFORMATION,
10774e8ee53aSMatthias Ringwald hfp_hf_apple_vendor_id, hfp_hf_apple_product_id, hfp_hf_apple_version, hfp_hf_apple_features);
10784e8ee53aSMatthias Ringwald (void) send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
10794e8ee53aSMatthias Ringwald return;
10804e8ee53aSMatthias Ringwald }
10814e8ee53aSMatthias Ringwald
1082910dced5SMatthias Ringwald if (hfp_connection->apple_accessory_commands_supported){
1083910dced5SMatthias Ringwald uint8_t num_apple_values = 0;
1084910dced5SMatthias Ringwald uint8_t first_key = 0;
1085910dced5SMatthias Ringwald uint8_t first_value = 0;
1086910dced5SMatthias Ringwald if (hfp_connection->apple_accessory_battery_level >= 0){
1087910dced5SMatthias Ringwald num_apple_values++;
1088910dced5SMatthias Ringwald first_key = 1;
1089910dced5SMatthias Ringwald first_value = hfp_connection->apple_accessory_battery_level;
1090910dced5SMatthias Ringwald }
1091910dced5SMatthias Ringwald if (hfp_connection->apple_accessory_docked >= 0){
1092910dced5SMatthias Ringwald num_apple_values++;
1093910dced5SMatthias Ringwald first_key = 2;
1094910dced5SMatthias Ringwald first_value = hfp_connection->apple_accessory_docked;
1095910dced5SMatthias Ringwald }
1096910dced5SMatthias Ringwald if (num_apple_values > 0){
1097910dced5SMatthias Ringwald char buffer[40];
1098910dced5SMatthias Ringwald switch (num_apple_values){
1099910dced5SMatthias Ringwald case 1:
1100865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=1,%u,%u\r", HFP_APPLE_ACCESSORY_STATE,
1101910dced5SMatthias Ringwald first_key, first_value);
1102910dced5SMatthias Ringwald break;
1103910dced5SMatthias Ringwald case 2:
1104865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(buffer, sizeof(buffer), "AT%s=2,1,%u,2,%u\r", HFP_APPLE_ACCESSORY_STATE,
1105910dced5SMatthias Ringwald hfp_connection->apple_accessory_battery_level, hfp_connection->apple_accessory_docked);
1106910dced5SMatthias Ringwald break;
1107910dced5SMatthias Ringwald default:
1108910dced5SMatthias Ringwald btstack_unreachable();
1109910dced5SMatthias Ringwald break;
1110910dced5SMatthias Ringwald }
1111910dced5SMatthias Ringwald // clear
1112910dced5SMatthias Ringwald hfp_connection->apple_accessory_battery_level = -1;
1113910dced5SMatthias Ringwald hfp_connection->apple_accessory_docked = -1;
1114910dced5SMatthias Ringwald // construct
1115910dced5SMatthias Ringwald hfp_connection->ok_pending = 1;
1116910dced5SMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_APPLE_ACCESSORY_STATE;
1117910dced5SMatthias Ringwald (void) send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
1118910dced5SMatthias Ringwald return;
1119910dced5SMatthias Ringwald }
1120910dced5SMatthias Ringwald }
1121910dced5SMatthias Ringwald
112251a2ebdeSMatthias Ringwald if (hfp_connection->send_custom_message != NULL){
112351a2ebdeSMatthias Ringwald const char * message = hfp_connection->send_custom_message;
112451a2ebdeSMatthias Ringwald hfp_connection->send_custom_message = NULL;
112551a2ebdeSMatthias Ringwald hfp_connection->ok_pending = 1;
112651a2ebdeSMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_CUSTOM_MESSAGE;
112751a2ebdeSMatthias Ringwald send_str_over_rfcomm(hfp_connection->rfcomm_cid, message);
112851a2ebdeSMatthias Ringwald return;
112951a2ebdeSMatthias Ringwald }
113051a2ebdeSMatthias Ringwald
1131ce263fc8SMatthias Ringwald if (done) return;
1132ce263fc8SMatthias Ringwald // deal with disconnect
1133a0ffb263SMatthias Ringwald switch (hfp_connection->state){
1134ce263fc8SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM:
1135a0ffb263SMatthias Ringwald hfp_connection->state = HFP_W4_RFCOMM_DISCONNECTED;
1136a0ffb263SMatthias Ringwald rfcomm_disconnect(hfp_connection->rfcomm_cid);
1137ce263fc8SMatthias Ringwald break;
1138ce263fc8SMatthias Ringwald
1139ce263fc8SMatthias Ringwald default:
1140ce263fc8SMatthias Ringwald break;
1141ce263fc8SMatthias Ringwald }
1142ce263fc8SMatthias Ringwald }
1143ce263fc8SMatthias Ringwald
1144910dced5SMatthias Ringwald
hfp_hf_apple_trigger_send(void)1145910dced5SMatthias Ringwald static void hfp_hf_apple_trigger_send(void){
1146910dced5SMatthias Ringwald btstack_linked_list_iterator_t it;
1147910dced5SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections());
1148910dced5SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){
1149910dced5SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
1150910dced5SMatthias Ringwald if (hfp_connection->local_role == HFP_ROLE_HF) {
1151910dced5SMatthias Ringwald hfp_connection->apple_accessory_battery_level = hfp_hf_apple_battery_level;
1152910dced5SMatthias Ringwald hfp_connection->apple_accessory_docked = hfp_hf_apple_docked;
1153910dced5SMatthias Ringwald }
1154910dced5SMatthias Ringwald }
1155910dced5SMatthias Ringwald }
1156910dced5SMatthias Ringwald
hfp_hf_slc_established(hfp_connection_t * hfp_connection)1157ad862247SMatthias Ringwald static void hfp_hf_slc_established(hfp_connection_t * hfp_connection){
1158a0ffb263SMatthias Ringwald hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
11596a7f44bdSMilanka Ringwald
11607095467fSMatthias Ringwald hfp_emit_slc_connection_event(hfp_connection->local_role, 0, hfp_connection->acl_handle, hfp_connection->remote_addr);
11617522e673SMatthias Ringwald
1162184a03edSMilanka Ringwald uint8_t i;
1163184a03edSMilanka Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){
11641ac1f60fSMilanka Ringwald hfp_emit_ag_indicator_mapping_event(hfp_connection, &hfp_connection->ag_indicators[i]);
1165184a03edSMilanka Ringwald }
1166722a85f3SMilanka Ringwald
1167722a85f3SMilanka Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){
1168722a85f3SMilanka Ringwald hfp_connection->ag_indicators[i].status_changed = 0;
1169722a85f3SMilanka Ringwald hfp_emit_ag_indicator_status_event(hfp_connection, &hfp_connection->ag_indicators[i]);
1170722a85f3SMilanka Ringwald }
1171722a85f3SMilanka Ringwald
11724e8ee53aSMatthias Ringwald hfp_connection->apple_accessory_commands_supported = false;
11734e8ee53aSMatthias Ringwald hfp_connection->send_apple_information = hfp_hf_apple_vendor_id != 0;
11744e8ee53aSMatthias Ringwald
1175667ec068SMatthias Ringwald // restore volume settings
1176a0ffb263SMatthias Ringwald hfp_connection->speaker_gain = hfp_hf_speaker_gain;
1177a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 1;
1178ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_SPEAKER_VOLUME, hfp_hf_speaker_gain);
1179a0ffb263SMatthias Ringwald hfp_connection->microphone_gain = hfp_hf_microphone_gain;
1180a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 1;
1181ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_MICROPHONE_VOLUME, hfp_hf_microphone_gain);
1182ce263fc8SMatthias Ringwald }
1183ce263fc8SMatthias Ringwald
hfp_hf_handle_suggested_codec(hfp_connection_t * hfp_connection)11841cc65c4fSMatthias Ringwald static void hfp_hf_handle_suggested_codec(hfp_connection_t * hfp_connection){
1185aeb0f0feSMatthias Ringwald if (hfp_supports_codec(hfp_connection->suggested_codec, hfp_hf_codecs_nr, hfp_hf_codecs)){
11861cc65c4fSMatthias Ringwald // Codec supported, confirm
11871cc65c4fSMatthias Ringwald hfp_connection->negotiated_codec = hfp_connection->suggested_codec;
11881cc65c4fSMatthias Ringwald hfp_connection->codec_confirmed = hfp_connection->suggested_codec;
11891cc65c4fSMatthias Ringwald log_info("hfp: codec confirmed: %s", (hfp_connection->negotiated_codec == HFP_CODEC_MSBC) ? "mSBC" : "CVSD");
11901cc65c4fSMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_HF_CONFIRMED_CODEC;
11911cc65c4fSMatthias Ringwald
11921cc65c4fSMatthias Ringwald hfp_connection->hf_send_codec_confirm = true;
11931cc65c4fSMatthias Ringwald } else {
11941cc65c4fSMatthias Ringwald // Codec not supported, send supported codecs
11951cc65c4fSMatthias Ringwald hfp_connection->codec_confirmed = 0;
11961cc65c4fSMatthias Ringwald hfp_connection->suggested_codec = 0;
11971cc65c4fSMatthias Ringwald hfp_connection->negotiated_codec = 0;
11981cc65c4fSMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC;
11991cc65c4fSMatthias Ringwald
12001cc65c4fSMatthias Ringwald hfp_connection->hf_send_supported_codecs = true;
12011cc65c4fSMatthias Ringwald }
12021cc65c4fSMatthias Ringwald }
hfp_hf_apple_extension_supported(hfp_connection_t * hfp_connection,bool supported)12034e8ee53aSMatthias Ringwald static void hfp_hf_apple_extension_supported(hfp_connection_t * hfp_connection, bool supported){
12044e8ee53aSMatthias Ringwald hfp_connection->apple_accessory_commands_supported = supported;
12054e8ee53aSMatthias Ringwald log_info("Apple Extension supported: %u", supported);
12064e8ee53aSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_APPLE_EXTENSION_SUPPORTED, hfp_hf_microphone_gain);
12074e8ee53aSMatthias Ringwald }
12081cc65c4fSMatthias Ringwald
hfp_hf_switch_on_ok_pending(hfp_connection_t * hfp_connection,uint8_t status)1209e2c3b58dSMilanka Ringwald static bool hfp_hf_switch_on_ok_pending(hfp_connection_t *hfp_connection, uint8_t status){
1210e2c3b58dSMilanka Ringwald bool event_emited = true;
1211e2c3b58dSMilanka Ringwald
1212b3e7b9f5SMatthias Ringwald // cache state and reset
1213b3e7b9f5SMatthias Ringwald hfp_command_t response_pending_for_command = hfp_connection->response_pending_for_command;
1214b3e7b9f5SMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_NONE;
1215b3e7b9f5SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1216b3e7b9f5SMatthias Ringwald hfp_connection->ok_pending = 0;
1217b3e7b9f5SMatthias Ringwald
1218b3e7b9f5SMatthias Ringwald switch (response_pending_for_command){
1219e2c3b58dSMilanka Ringwald case HFP_CMD_TURN_OFF_EC_AND_NR:
1220e2c3b58dSMilanka Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_ECHO_CANCELING_AND_NOISE_REDUCTION_DEACTIVATE, status);
1221e2c3b58dSMilanka Ringwald break;
122251a2ebdeSMatthias Ringwald case HFP_CMD_CUSTOM_MESSAGE:
12237f8f1191SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_CUSTOM_AT_MESSAGE_SENT, status);
122451a2ebdeSMatthias Ringwald break;
12254e8ee53aSMatthias Ringwald case HFP_CMD_APPLE_ACCESSORY_INFORMATION:
12264e8ee53aSMatthias Ringwald hfp_hf_apple_extension_supported(hfp_connection, true);
12274e8ee53aSMatthias Ringwald break;
1228e2c3b58dSMilanka Ringwald default:
1229e2c3b58dSMilanka Ringwald event_emited = false;
1230e2c3b58dSMilanka Ringwald
1231a0ffb263SMatthias Ringwald switch (hfp_connection->state){
12323deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
1233a0ffb263SMatthias Ringwald if (has_codec_negotiation_feature(hfp_connection)){
1234a0ffb263SMatthias Ringwald hfp_connection->state = HFP_NOTIFY_ON_CODECS;
12353deb3ec6SMatthias Ringwald break;
12363deb3ec6SMatthias Ringwald }
1237a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS;
12383deb3ec6SMatthias Ringwald break;
12393deb3ec6SMatthias Ringwald
12403deb3ec6SMatthias Ringwald case HFP_W4_NOTIFY_ON_CODECS:
1241a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS;
12423deb3ec6SMatthias Ringwald break;
12433deb3ec6SMatthias Ringwald
12443deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS:
1245a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INDICATORS_STATUS;
12463deb3ec6SMatthias Ringwald break;
12473deb3ec6SMatthias Ringwald
12483deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INDICATORS_STATUS:
1249a0ffb263SMatthias Ringwald hfp_connection->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE;
12503deb3ec6SMatthias Ringwald break;
12513deb3ec6SMatthias Ringwald
12523deb3ec6SMatthias Ringwald case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
1253a0ffb263SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(hfp_connection)){
1254a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_CAN_HOLD_CALL;
12553deb3ec6SMatthias Ringwald break;
12563deb3ec6SMatthias Ringwald }
1257a0ffb263SMatthias Ringwald if (has_hf_indicators_feature(hfp_connection)){
1258a0ffb263SMatthias Ringwald hfp_connection->state = HFP_LIST_GENERIC_STATUS_INDICATORS;
12593deb3ec6SMatthias Ringwald break;
12603deb3ec6SMatthias Ringwald }
1261ad862247SMatthias Ringwald hfp_hf_slc_established(hfp_connection);
12623deb3ec6SMatthias Ringwald break;
12633deb3ec6SMatthias Ringwald
12643deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
1265a0ffb263SMatthias Ringwald if (has_hf_indicators_feature(hfp_connection)){
1266a0ffb263SMatthias Ringwald hfp_connection->state = HFP_LIST_GENERIC_STATUS_INDICATORS;
12673deb3ec6SMatthias Ringwald break;
12683deb3ec6SMatthias Ringwald }
1269ad862247SMatthias Ringwald hfp_hf_slc_established(hfp_connection);
12703deb3ec6SMatthias Ringwald break;
12713deb3ec6SMatthias Ringwald
12723deb3ec6SMatthias Ringwald case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
1273a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS;
12743deb3ec6SMatthias Ringwald break;
12753deb3ec6SMatthias Ringwald
12763deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
1277a0ffb263SMatthias Ringwald hfp_connection->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
12783deb3ec6SMatthias Ringwald break;
12793deb3ec6SMatthias Ringwald
12803deb3ec6SMatthias Ringwald case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
1281ad862247SMatthias Ringwald hfp_hf_slc_established(hfp_connection);
12823deb3ec6SMatthias Ringwald break;
1283ce263fc8SMatthias Ringwald case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
1284a0ffb263SMatthias Ringwald if (hfp_connection->enable_status_update_for_ag_indicators != 0xFF){
1285a0ffb263SMatthias Ringwald hfp_connection->enable_status_update_for_ag_indicators = 0xFF;
12866cc5b34bSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, ERROR_CODE_SUCCESS);
1287ce263fc8SMatthias Ringwald break;
1288ce263fc8SMatthias Ringwald }
12893deb3ec6SMatthias Ringwald
1290a0ffb263SMatthias Ringwald if (hfp_connection->change_status_update_for_individual_ag_indicators == 1){
1291a0ffb263SMatthias Ringwald hfp_connection->change_status_update_for_individual_ag_indicators = 0;
12926cc5b34bSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, ERROR_CODE_SUCCESS);
1293ce263fc8SMatthias Ringwald break;
12943deb3ec6SMatthias Ringwald }
12953deb3ec6SMatthias Ringwald
1296a0ffb263SMatthias Ringwald switch (hfp_connection->hf_query_operator_state){
1297ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_W4_SET_FORMAT_OK:
1298a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SEND_QUERY;
1299ce263fc8SMatthias Ringwald break;
1300ce263fc8SMatthias Ringwald case HPF_HF_QUERY_OPERATOR_W4_RESULT:
1301a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_FORMAT_SET;
1302a473a009SMatthias Ringwald hfp_emit_network_operator_event(hfp_connection);
1303ce263fc8SMatthias Ringwald break;
1304ce263fc8SMatthias Ringwald default:
1305ce263fc8SMatthias Ringwald break;
13063deb3ec6SMatthias Ringwald }
1307ce263fc8SMatthias Ringwald
1308a0ffb263SMatthias Ringwald if (hfp_connection->enable_extended_audio_gateway_error_report){
1309a0ffb263SMatthias Ringwald hfp_connection->enable_extended_audio_gateway_error_report = 0;
1310ce263fc8SMatthias Ringwald break;
13113deb3ec6SMatthias Ringwald }
13123deb3ec6SMatthias Ringwald
1313a0ffb263SMatthias Ringwald switch (hfp_connection->codecs_state){
1314aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE:
1315a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC;
13163deb3ec6SMatthias Ringwald break;
1317ce263fc8SMatthias Ringwald case HFP_CODECS_HF_CONFIRMED_CODEC:
1318a0ffb263SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_EXCHANGED;
1319ce263fc8SMatthias Ringwald break;
13203deb3ec6SMatthias Ringwald default:
13213deb3ec6SMatthias Ringwald break;
13223deb3ec6SMatthias Ringwald }
1323af97579eSMilanka Ringwald hfp_hf_voice_recognition_state_machine(hfp_connection);
1324be55a11dSMilanka Ringwald break;
1325be55a11dSMilanka Ringwald case HFP_AUDIO_CONNECTION_ESTABLISHED:
1326af97579eSMilanka Ringwald hfp_hf_voice_recognition_state_machine(hfp_connection);
13273deb3ec6SMatthias Ringwald break;
13283deb3ec6SMatthias Ringwald default:
13293deb3ec6SMatthias Ringwald break;
13303deb3ec6SMatthias Ringwald }
1331e2c3b58dSMilanka Ringwald break;
1332e2c3b58dSMilanka Ringwald }
13333deb3ec6SMatthias Ringwald
1334e2c3b58dSMilanka Ringwald return event_emited;
13353deb3ec6SMatthias Ringwald }
13363deb3ec6SMatthias Ringwald
hfp_is_ringing(hfp_callsetup_status_t callsetup_status)1337a03dbc20SMilanka Ringwald static bool hfp_is_ringing(hfp_callsetup_status_t callsetup_status){
1338a03dbc20SMilanka Ringwald switch (callsetup_status){
1339a03dbc20SMilanka Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1340a03dbc20SMilanka Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE:
1341a03dbc20SMilanka Ringwald return true;
1342a03dbc20SMilanka Ringwald default:
1343a03dbc20SMilanka Ringwald return false;
1344a03dbc20SMilanka Ringwald }
1345a03dbc20SMilanka Ringwald }
1346be55a11dSMilanka Ringwald
hfp_hf_handle_transfer_ag_indicator_status(hfp_connection_t * hfp_connection)1347b08371a9SMilanka Ringwald static void hfp_hf_handle_transfer_ag_indicator_status(hfp_connection_t * hfp_connection) {
13484562e2a2SMatthias Ringwald uint16_t i;
1349a03dbc20SMilanka Ringwald
13504562e2a2SMatthias Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){
13514562e2a2SMatthias Ringwald if (hfp_connection->ag_indicators[i].status_changed) {
13524562e2a2SMatthias Ringwald if (strcmp(hfp_connection->ag_indicators[i].name, "callsetup") == 0){
1353a03dbc20SMilanka Ringwald hfp_callsetup_status_t new_hf_callsetup_status = (hfp_callsetup_status_t) hfp_connection->ag_indicators[i].status;
135466093044SMilanka Ringwald bool ringing_old = hfp_is_ringing(hfp_connection->hf_callsetup_status);
1355a03dbc20SMilanka Ringwald bool ringing_new = hfp_is_ringing(new_hf_callsetup_status);
1356a03dbc20SMilanka Ringwald if (ringing_old != ringing_new){
1357a03dbc20SMilanka Ringwald if (ringing_new){
1358a03dbc20SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_START_RINGING);
1359a03dbc20SMilanka Ringwald } else {
1360a03dbc20SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_STOP_RINGING);
1361a03dbc20SMilanka Ringwald }
1362a03dbc20SMilanka Ringwald }
136366093044SMilanka Ringwald hfp_connection->hf_callsetup_status = new_hf_callsetup_status;
13644562e2a2SMatthias Ringwald } else if (strcmp(hfp_connection->ag_indicators[i].name, "callheld") == 0){
136566093044SMilanka Ringwald hfp_connection->hf_callheld_status = (hfp_callheld_status_t) hfp_connection->ag_indicators[i].status;
13664562e2a2SMatthias Ringwald // avoid set but not used warning
136766093044SMilanka Ringwald (void) hfp_connection->hf_callheld_status;
13684562e2a2SMatthias Ringwald } else if (strcmp(hfp_connection->ag_indicators[i].name, "call") == 0){
1369674ebed5SMilanka Ringwald hfp_call_status_t new_hf_call_status = (hfp_call_status_t) hfp_connection->ag_indicators[i].status;
137066093044SMilanka Ringwald if (hfp_connection->hf_call_status != new_hf_call_status){
1371674ebed5SMilanka Ringwald if (new_hf_call_status == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS){
1372674ebed5SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_TERMINATED);
1373674ebed5SMilanka Ringwald } else {
1374674ebed5SMilanka Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_ANSWERED);
1375674ebed5SMilanka Ringwald }
1376674ebed5SMilanka Ringwald }
137766093044SMilanka Ringwald hfp_connection->hf_call_status = new_hf_call_status;
13784562e2a2SMatthias Ringwald }
13794562e2a2SMatthias Ringwald hfp_connection->ag_indicators[i].status_changed = 0;
1380ce3797e1SMilanka Ringwald hfp_emit_ag_indicator_status_event(hfp_connection, &hfp_connection->ag_indicators[i]);
13814562e2a2SMatthias Ringwald break;
13824562e2a2SMatthias Ringwald }
13834562e2a2SMatthias Ringwald }
13844562e2a2SMatthias Ringwald }
13854562e2a2SMatthias Ringwald
hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection)1386426f9988SMatthias Ringwald static void hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection){
1387186dd3d2SMatthias Ringwald int value;
1388186dd3d2SMatthias Ringwald int i;
1389e2c3b58dSMilanka Ringwald bool event_emited;
1390e2c3b58dSMilanka Ringwald
1391125560b8SMatthias Ringwald // last argument is still in line_buffer
1392125560b8SMatthias Ringwald
1393a0ffb263SMatthias Ringwald switch (hfp_connection->command){
1394667ec068SMatthias Ringwald case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION:
1395a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1396a473a009SMatthias Ringwald hfp_hf_emit_subscriber_information(hfp_connection, 0);
1397667ec068SMatthias Ringwald break;
1398667ec068SMatthias Ringwald case HFP_CMD_RESPONSE_AND_HOLD_STATUS:
1399a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1400ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_RESPONSE_AND_HOLD_STATUS, btstack_atoi((char *)&hfp_connection->line_buffer[0]));
1401667ec068SMatthias Ringwald break;
1402667ec068SMatthias Ringwald case HFP_CMD_LIST_CURRENT_CALLS:
1403a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1404a473a009SMatthias Ringwald hfp_hf_emit_enhanced_call_status(hfp_connection);
1405667ec068SMatthias Ringwald break;
1406ce263fc8SMatthias Ringwald case HFP_CMD_SET_SPEAKER_GAIN:
1407a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
14082308e108SMilanka Ringwald value = btstack_atoi((char*)hfp_connection->line_buffer);
1409667ec068SMatthias Ringwald hfp_hf_speaker_gain = value;
1410ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_SPEAKER_VOLUME, value);
1411ce263fc8SMatthias Ringwald break;
1412ce263fc8SMatthias Ringwald case HFP_CMD_SET_MICROPHONE_GAIN:
1413a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
14142308e108SMilanka Ringwald value = btstack_atoi((char*)hfp_connection->line_buffer);
1415667ec068SMatthias Ringwald hfp_hf_microphone_gain = value;
1416ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_MICROPHONE_VOLUME, value);
1417ce263fc8SMatthias Ringwald break;
1418ce263fc8SMatthias Ringwald case HFP_CMD_AG_SENT_PHONE_NUMBER:
1419a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1420ca59be51SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_NUMBER_FOR_VOICE_TAG, hfp_connection->bnip_number);
1421a0ffb263SMatthias Ringwald break;
1422a0ffb263SMatthias Ringwald case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
1423a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1424598d4936SMatthias Ringwald hfp_hf_emit_type_number_alpha(hfp_connection, HFP_SUBEVENT_CALL_WAITING_NOTIFICATION);
1425a0ffb263SMatthias Ringwald break;
1426a0ffb263SMatthias Ringwald case HFP_CMD_AG_SENT_CLIP_INFORMATION:
1427a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1428598d4936SMatthias Ringwald hfp_hf_emit_type_number_alpha(hfp_connection, HFP_SUBEVENT_CALLING_LINE_IDENTIFICATION_NOTIFICATION);
1429ce263fc8SMatthias Ringwald break;
1430ce263fc8SMatthias Ringwald case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR:
1431a0ffb263SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
14325a4785c8SMatthias Ringwald hfp_connection->ok_pending = 0;
1433a0ffb263SMatthias Ringwald hfp_connection->extended_audio_gateway_error = 0;
1434ca59be51SMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, hfp_connection->extended_audio_gateway_error_value);
1435ce263fc8SMatthias Ringwald break;
14360b4debbfSMilanka Ringwald case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
14370b4debbfSMilanka Ringwald break;
1438fdda66c0SMilanka Ringwald case HFP_CMD_ERROR:
143990244c92SMilanka Ringwald switch (hfp_connection->state){
144090244c92SMilanka Ringwald case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
144190244c92SMilanka Ringwald switch (hfp_connection->codecs_state){
144290244c92SMilanka Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE:
1443fdda66c0SMilanka Ringwald hfp_reset_context_flags(hfp_connection);
1444f14c5dafSMatthias Ringwald hfp_emit_sco_connection_established(hfp_connection, HFP_REMOTE_REJECTS_AUDIO_CONNECTION,
14455e8e3664SMatthias Ringwald hfp_connection->negotiated_codec, 0, 0);
144690244c92SMilanka Ringwald return;
144790244c92SMilanka Ringwald default:
144890244c92SMilanka Ringwald break;
144990244c92SMilanka Ringwald }
145056f1adacSMilanka Ringwald break;
145156f1adacSMilanka Ringwald default:
145256f1adacSMilanka Ringwald break;
145356f1adacSMilanka Ringwald }
1454e2c3b58dSMilanka Ringwald
14554e8ee53aSMatthias Ringwald switch (hfp_connection->response_pending_for_command){
14564e8ee53aSMatthias Ringwald case HFP_CMD_APPLE_ACCESSORY_INFORMATION:
14574e8ee53aSMatthias Ringwald hfp_connection->response_pending_for_command = HFP_CMD_NONE;
14584e8ee53aSMatthias Ringwald hfp_hf_apple_extension_supported(hfp_connection, false);
14594e8ee53aSMatthias Ringwald return;
14604e8ee53aSMatthias Ringwald default:
14614e8ee53aSMatthias Ringwald break;
14624e8ee53aSMatthias Ringwald }
14634e8ee53aSMatthias Ringwald
1464fdda66c0SMilanka Ringwald // handle error response for voice activation (HF initiated)
14650b4debbfSMilanka Ringwald switch(hfp_connection->vra_state_requested){
1466de9e0ea7SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
1467de9e0ea7SMilanka Ringwald hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR);
1468be55a11dSMilanka Ringwald break;
1469be55a11dSMilanka Ringwald default:
1470e2c3b58dSMilanka Ringwald if (hfp_connection->vra_state_requested == hfp_connection->vra_state){
1471e2c3b58dSMilanka Ringwald break;
1472e2c3b58dSMilanka Ringwald }
14730b4debbfSMilanka Ringwald hfp_connection->vra_state_requested = hfp_connection->vra_state;
1474553a4a56SMilanka Ringwald hfp_emit_voice_recognition_enabled(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR);
14750b4debbfSMilanka Ringwald hfp_reset_context_flags(hfp_connection);
14760b4debbfSMilanka Ringwald return;
1477be55a11dSMilanka Ringwald }
1478e2c3b58dSMilanka Ringwald event_emited = hfp_hf_switch_on_ok_pending(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR);
1479e2c3b58dSMilanka Ringwald if (!event_emited){
14806cc5b34bSMatthias Ringwald hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, ERROR_CODE_UNSPECIFIED_ERROR);
1481e2c3b58dSMilanka Ringwald }
1482fdda66c0SMilanka Ringwald hfp_reset_context_flags(hfp_connection);
1483ce263fc8SMatthias Ringwald break;
1484fdda66c0SMilanka Ringwald
1485ce263fc8SMatthias Ringwald case HFP_CMD_OK:
1486e2c3b58dSMilanka Ringwald hfp_hf_switch_on_ok_pending(hfp_connection, ERROR_CODE_SUCCESS);
1487ce263fc8SMatthias Ringwald break;
1488ce263fc8SMatthias Ringwald case HFP_CMD_RING:
14895a4785c8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1490ca59be51SMatthias Ringwald hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_RING);
1491ce263fc8SMatthias Ringwald break;
1492ce263fc8SMatthias Ringwald case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
14935a4785c8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
14944562e2a2SMatthias Ringwald hfp_hf_handle_transfer_ag_indicator_status(hfp_connection);
1495ce263fc8SMatthias Ringwald break;
1496c741b032SMilanka Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
14975a4785c8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1498184a03edSMilanka Ringwald // report status after SLC established
1499184a03edSMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){
1500184a03edSMilanka Ringwald break;
1501184a03edSMilanka Ringwald }
1502c741b032SMilanka Ringwald for (i = 0; i < hfp_connection->ag_indicators_nr; i++){
15031ac1f60fSMilanka Ringwald hfp_emit_ag_indicator_mapping_event(hfp_connection, &hfp_connection->ag_indicators[i]);
1504c741b032SMilanka Ringwald }
1505c741b032SMilanka Ringwald break;
15061cc65c4fSMatthias Ringwald case HFP_CMD_AG_SUGGESTED_CODEC:
15071cc65c4fSMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
15085a4785c8SMatthias Ringwald hfp_hf_handle_suggested_codec(hfp_connection);
15091cc65c4fSMatthias Ringwald break;
1510eac56539SMilanka Ringwald case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
1511eac56539SMilanka 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));
15125134fea9SMatthias Ringwald break;
1513892f58a8SMatthias Ringwald case HFP_CMD_CUSTOM_MESSAGE:
1514892f58a8SMatthias Ringwald hfp_connection->command = HFP_CMD_NONE;
1515892f58a8SMatthias Ringwald hfp_parser_reset_line_buffer(hfp_connection);
1516892f58a8SMatthias Ringwald log_info("Custom AT Command ID 0x%04x", hfp_connection->custom_at_command_id);
1517892f58a8SMatthias Ringwald hfp_hf_emit_custom_command_event(hfp_connection);
1518892f58a8SMatthias Ringwald break;
1519ce263fc8SMatthias Ringwald default:
1520ce263fc8SMatthias Ringwald break;
15213deb3ec6SMatthias Ringwald }
15220cef86faSMatthias Ringwald }
1523426f9988SMatthias Ringwald
hfp_parser_is_end_of_line(uint8_t byte)152476cc1527SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){
152576cc1527SMatthias Ringwald return (byte == '\n') || (byte == '\r');
152676cc1527SMatthias Ringwald }
152776cc1527SMatthias Ringwald
hfp_hf_handle_rfcomm_data(hfp_connection_t * hfp_connection,uint8_t * packet,uint16_t size)15280b4debbfSMilanka Ringwald static void hfp_hf_handle_rfcomm_data(hfp_connection_t * hfp_connection, uint8_t *packet, uint16_t size){
1529426f9988SMatthias Ringwald // assertion: size >= 1 as rfcomm.c does not deliver empty packets
1530426f9988SMatthias Ringwald if (size < 1) return;
1531426f9988SMatthias Ringwald
1532426f9988SMatthias Ringwald hfp_log_rfcomm_message("HFP_HF_RX", packet, size);
1533e43d1938SMatthias Ringwald #ifdef ENABLE_HFP_AT_MESSAGES
1534e43d1938SMatthias Ringwald hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_RECEIVED, (char *) packet);
1535e43d1938SMatthias Ringwald #endif
1536426f9988SMatthias Ringwald
1537426f9988SMatthias Ringwald // process messages byte-wise
1538a7ba78b0SMilanka Ringwald uint8_t pos;
1539426f9988SMatthias Ringwald for (pos = 0; pos < size; pos++){
1540426f9988SMatthias Ringwald hfp_parse(hfp_connection, packet[pos], 1);
15411599fe57SMatthias Ringwald // parse until end of line "\r" or "\n"
1542426f9988SMatthias Ringwald if (!hfp_parser_is_end_of_line(packet[pos])) continue;
15430b4debbfSMilanka Ringwald hfp_hf_handle_rfcomm_command(hfp_connection);
15443deb3ec6SMatthias Ringwald }
1545a7ba78b0SMilanka Ringwald }
15463deb3ec6SMatthias Ringwald
hfp_hf_run(void)15471c6a0fc0SMatthias Ringwald static void hfp_hf_run(void){
1548665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it;
1549665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, hfp_get_connections());
1550665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){
1551a0ffb263SMatthias Ringwald hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
155222387625SMatthias Ringwald if (hfp_connection->local_role != HFP_ROLE_HF) continue;
15531c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
15543deb3ec6SMatthias Ringwald }
15553deb3ec6SMatthias Ringwald }
15563deb3ec6SMatthias Ringwald
hfp_hf_rfcomm_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)15571c6a0fc0SMatthias Ringwald static void hfp_hf_rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
15580b4debbfSMilanka Ringwald hfp_connection_t * hfp_connection;
15593deb3ec6SMatthias Ringwald switch (packet_type){
15603deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET:
15610b4debbfSMilanka Ringwald hfp_connection = get_hfp_connection_context_for_rfcomm_cid(channel);
15620b4debbfSMilanka Ringwald if (!hfp_connection) return;
15630b4debbfSMilanka Ringwald hfp_hf_handle_rfcomm_data(hfp_connection, packet, size);
15640b4debbfSMilanka Ringwald hfp_hf_run_for_context(hfp_connection);
15650b4debbfSMilanka Ringwald return;
15663deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET:
1567d4dd47ffSMatthias Ringwald if (packet[0] == RFCOMM_EVENT_CAN_SEND_NOW){
1568d4dd47ffSMatthias Ringwald uint16_t rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet);
15691c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid));
1570d4dd47ffSMatthias Ringwald return;
1571d4dd47ffSMatthias Ringwald }
157227950165SMatthias Ringwald hfp_handle_rfcomm_event(packet_type, channel, packet, size, HFP_ROLE_HF);
1573202c8a4cSMatthias Ringwald break;
15743deb3ec6SMatthias Ringwald default:
15753deb3ec6SMatthias Ringwald break;
15763deb3ec6SMatthias Ringwald }
15771c6a0fc0SMatthias Ringwald hfp_hf_run();
15783deb3ec6SMatthias Ringwald }
15793deb3ec6SMatthias Ringwald
hfp_hf_hci_event_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)15801c6a0fc0SMatthias Ringwald static void hfp_hf_hci_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
1581405014fbSMatthias Ringwald hfp_handle_hci_event(packet_type, channel, packet, size, HFP_ROLE_HF);
15821c6a0fc0SMatthias Ringwald hfp_hf_run();
1583405014fbSMatthias Ringwald }
1584405014fbSMatthias Ringwald
hfp_hf_set_defaults(void)1585aeb0f0feSMatthias Ringwald static void hfp_hf_set_defaults(void){
1586aeb0f0feSMatthias Ringwald hfp_hf_supported_features = HFP_DEFAULT_HF_SUPPORTED_FEATURES;
1587aeb0f0feSMatthias Ringwald hfp_hf_codecs_nr = 0;
1588aeb0f0feSMatthias Ringwald hfp_hf_speaker_gain = 9;
1589aeb0f0feSMatthias Ringwald hfp_hf_microphone_gain = 9;
1590aeb0f0feSMatthias Ringwald hfp_hf_indicators_nr = 0;
1591910dced5SMatthias Ringwald // Apple extension
1592910dced5SMatthias Ringwald hfp_hf_apple_docked = -1;
1593910dced5SMatthias Ringwald hfp_hf_apple_battery_level = -1;
1594aeb0f0feSMatthias Ringwald }
1595aeb0f0feSMatthias Ringwald
hfp_hf_set_default_microphone_gain(uint8_t gain)159642aadee5SMatthias Ringwald uint8_t hfp_hf_set_default_microphone_gain(uint8_t gain){
1597455808b3SMatthias Ringwald if (gain > 15){
159842aadee5SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
159942aadee5SMatthias Ringwald }
160042aadee5SMatthias Ringwald hfp_hf_microphone_gain = gain;
160142aadee5SMatthias Ringwald return ERROR_CODE_SUCCESS;
160242aadee5SMatthias Ringwald }
160342aadee5SMatthias Ringwald
hfp_hf_set_default_speaker_gain(uint8_t gain)160442aadee5SMatthias Ringwald uint8_t hfp_hf_set_default_speaker_gain(uint8_t gain){
1605455808b3SMatthias Ringwald if (gain > 15){
160642aadee5SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
160742aadee5SMatthias Ringwald }
160842aadee5SMatthias Ringwald hfp_hf_speaker_gain = gain;
160942aadee5SMatthias Ringwald return ERROR_CODE_SUCCESS;
161042aadee5SMatthias Ringwald }
161142aadee5SMatthias Ringwald
hfp_hf_init(uint8_t rfcomm_channel_nr)1612ab2445a0SMatthias Ringwald uint8_t hfp_hf_init(uint8_t rfcomm_channel_nr){
1613b4df8028SMilanka Ringwald uint8_t status = rfcomm_register_service(hfp_hf_rfcomm_packet_handler, rfcomm_channel_nr, 0xffff);
1614b4df8028SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){
1615b4df8028SMilanka Ringwald return status;
1616b4df8028SMilanka Ringwald }
1617b4df8028SMilanka Ringwald
1618520c92d5SMatthias Ringwald hfp_init();
1619aeb0f0feSMatthias Ringwald hfp_hf_set_defaults();
1620d63c37a1SMatthias Ringwald
16211c6a0fc0SMatthias Ringwald hfp_hf_hci_event_callback_registration.callback = &hfp_hf_hci_event_packet_handler;
16221c6a0fc0SMatthias Ringwald hci_add_event_handler(&hfp_hf_hci_event_callback_registration);
162327950165SMatthias Ringwald
162427950165SMatthias Ringwald // used to set packet handler for outgoing rfcomm connections - could be handled by emitting an event to us
16251c6a0fc0SMatthias Ringwald hfp_set_hf_rfcomm_packet_handler(&hfp_hf_rfcomm_packet_handler);
1626b4df8028SMilanka Ringwald return ERROR_CODE_SUCCESS;
162720b2edb6SMatthias Ringwald }
162827950165SMatthias Ringwald
hfp_hf_deinit(void)162920b2edb6SMatthias Ringwald void hfp_hf_deinit(void){
163020b2edb6SMatthias Ringwald hfp_deinit();
1631aeb0f0feSMatthias Ringwald hfp_hf_set_defaults();
1632aeb0f0feSMatthias Ringwald
1633aeb0f0feSMatthias Ringwald hfp_hf_callback = NULL;
16344e8ee53aSMatthias Ringwald hfp_hf_apple_vendor_id = 0;
163520b2edb6SMatthias Ringwald (void) memset(&hfp_hf_hci_event_callback_registration, 0, sizeof(btstack_packet_callback_registration_t));
1636aeb0f0feSMatthias Ringwald (void) memset(hfp_hf_phone_number, 0, sizeof(hfp_hf_phone_number));
1637a0ffb263SMatthias Ringwald }
1638a0ffb263SMatthias Ringwald
hfp_hf_init_codecs(uint8_t codecs_nr,const uint8_t * codecs)1639aa10b9cbSMatthias Ringwald void hfp_hf_init_codecs(uint8_t codecs_nr, const uint8_t * codecs){
16402be4ddd3SMatthias Ringwald btstack_assert(codecs_nr <= HFP_MAX_NUM_CODECS);
16418cd06fb6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS) return;
16423deb3ec6SMatthias Ringwald
1643aeb0f0feSMatthias Ringwald hfp_hf_codecs_nr = codecs_nr;
1644aa10b9cbSMatthias Ringwald uint8_t i;
16453deb3ec6SMatthias Ringwald for (i=0; i<codecs_nr; i++){
1646aeb0f0feSMatthias Ringwald hfp_hf_codecs[i] = codecs[i];
16473deb3ec6SMatthias Ringwald }
16483deb3ec6SMatthias Ringwald }
16493deb3ec6SMatthias Ringwald
hfp_hf_init_supported_features(uint32_t supported_features)1650a0ffb263SMatthias Ringwald void hfp_hf_init_supported_features(uint32_t supported_features){
1651aeb0f0feSMatthias Ringwald hfp_hf_supported_features = supported_features;
1652a0ffb263SMatthias Ringwald }
16533deb3ec6SMatthias Ringwald
hfp_hf_init_hf_indicators(int indicators_nr,const uint16_t * indicators)16547ca89cabSMatthias Ringwald void hfp_hf_init_hf_indicators(int indicators_nr, const uint16_t * indicators){
1655aeb0f0feSMatthias Ringwald btstack_assert(hfp_hf_indicators_nr < HFP_MAX_NUM_INDICATORS);
1656ea63a720SMatthias Ringwald if (hfp_hf_indicators_nr > HFP_MAX_NUM_INDICATORS) return;
165768466199SMilanka Ringwald
1658aeb0f0feSMatthias Ringwald hfp_hf_indicators_nr = indicators_nr;
16593deb3ec6SMatthias Ringwald int i;
1660aeb0f0feSMatthias Ringwald for (i = 0; i < hfp_hf_indicators_nr ; i++){
1661ab2445a0SMatthias Ringwald hfp_hf_indicators[i] = (uint8_t) indicators[i];
16623deb3ec6SMatthias Ringwald }
166321df969bSMatthias Ringwald
166421df969bSMatthias Ringwald // store copy in hfp to setup generic_status_indicators during SLC
166521df969bSMatthias Ringwald hfp_set_hf_indicators(indicators_nr, hfp_hf_indicators);
16663deb3ec6SMatthias Ringwald }
16673deb3ec6SMatthias Ringwald
hfp_hf_establish_service_level_connection(bd_addr_t bd_addr)16684eb3f1d8SMilanka Ringwald uint8_t hfp_hf_establish_service_level_connection(bd_addr_t bd_addr){
16694eb3f1d8SMilanka Ringwald return hfp_establish_service_level_connection(bd_addr, BLUETOOTH_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, HFP_ROLE_HF);
16703deb3ec6SMatthias Ringwald }
16713deb3ec6SMatthias Ringwald
hfp_hf_release_service_level_connection(hci_con_handle_t acl_handle)1672657bc59fSMilanka Ringwald uint8_t hfp_hf_release_service_level_connection(hci_con_handle_t acl_handle){
16739c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1674a33eb0c4SMilanka Ringwald if (!hfp_connection){
1675657bc59fSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1676a33eb0c4SMilanka Ringwald }
16771ffa0dd9SMilanka Ringwald hfp_trigger_release_service_level_connection(hfp_connection);
16781c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1679657bc59fSMilanka Ringwald return ERROR_CODE_SUCCESS;
16803deb3ec6SMatthias Ringwald }
16813deb3ec6SMatthias Ringwald
hfp_hf_set_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle,uint8_t enable)16823c65e705SMilanka Ringwald static uint8_t hfp_hf_set_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle, uint8_t enable){
16839c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1684a0ffb263SMatthias Ringwald if (!hfp_connection) {
16853c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
16863deb3ec6SMatthias Ringwald }
1687a0ffb263SMatthias Ringwald hfp_connection->enable_status_update_for_ag_indicators = enable;
16881c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
16893c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
16903deb3ec6SMatthias Ringwald }
16913deb3ec6SMatthias Ringwald
hfp_hf_enable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle)16923c65e705SMilanka Ringwald uint8_t hfp_hf_enable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle){
16933c65e705SMilanka Ringwald return hfp_hf_set_status_update_for_all_ag_indicators(acl_handle, 1);
1694ce263fc8SMatthias Ringwald }
1695ce263fc8SMatthias Ringwald
hfp_hf_disable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle)16963c65e705SMilanka Ringwald uint8_t hfp_hf_disable_status_update_for_all_ag_indicators(hci_con_handle_t acl_handle){
16973c65e705SMilanka Ringwald return hfp_hf_set_status_update_for_all_ag_indicators(acl_handle, 0);
1698ce263fc8SMatthias Ringwald }
1699ce263fc8SMatthias Ringwald
17003deb3ec6SMatthias Ringwald // TODO: returned ERROR - wrong format
hfp_hf_set_status_update_for_individual_ag_indicators(hci_con_handle_t acl_handle,uint32_t indicators_status_bitmap)17013c65e705SMilanka Ringwald uint8_t hfp_hf_set_status_update_for_individual_ag_indicators(hci_con_handle_t acl_handle, uint32_t indicators_status_bitmap){
17029c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1703a0ffb263SMatthias Ringwald if (!hfp_connection) {
17043c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
17053deb3ec6SMatthias Ringwald }
1706a0ffb263SMatthias Ringwald hfp_connection->change_status_update_for_individual_ag_indicators = 1;
1707a0ffb263SMatthias Ringwald hfp_connection->ag_indicators_status_update_bitmap = indicators_status_bitmap;
17081c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
17093c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
17103deb3ec6SMatthias Ringwald }
17113deb3ec6SMatthias Ringwald
hfp_hf_query_operator_selection(hci_con_handle_t acl_handle)17123c65e705SMilanka Ringwald uint8_t hfp_hf_query_operator_selection(hci_con_handle_t acl_handle){
17139c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1714a0ffb263SMatthias Ringwald if (!hfp_connection) {
17153c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
17163deb3ec6SMatthias Ringwald }
17173c65e705SMilanka Ringwald
1718a0ffb263SMatthias Ringwald switch (hfp_connection->hf_query_operator_state){
1719ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_FORMAT_NOT_SET:
1720a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SET_FORMAT;
1721ce263fc8SMatthias Ringwald break;
1722ce263fc8SMatthias Ringwald case HFP_HF_QUERY_OPERATOR_FORMAT_SET:
1723a0ffb263SMatthias Ringwald hfp_connection->hf_query_operator_state = HFP_HF_QUERY_OPERATOR_SEND_QUERY;
1724ce263fc8SMatthias Ringwald break;
1725ce263fc8SMatthias Ringwald default:
17263c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
1727ce263fc8SMatthias Ringwald }
17281c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
17293c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
17303deb3ec6SMatthias Ringwald }
17313deb3ec6SMatthias Ringwald
hfp_hf_set_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle,uint8_t enable)17323c65e705SMilanka Ringwald static uint8_t hfp_hf_set_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle, uint8_t enable){
17339c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1734a0ffb263SMatthias Ringwald if (!hfp_connection) {
17353c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
17363deb3ec6SMatthias Ringwald }
1737a0ffb263SMatthias Ringwald hfp_connection->enable_extended_audio_gateway_error_report = enable;
17381c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
17393c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
17403deb3ec6SMatthias Ringwald }
17413deb3ec6SMatthias Ringwald
1742ce263fc8SMatthias Ringwald
hfp_hf_enable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle)17433c65e705SMilanka Ringwald uint8_t hfp_hf_enable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle){
17443c65e705SMilanka Ringwald return hfp_hf_set_report_extended_audio_gateway_error_result_code(acl_handle, 1);
1745ce263fc8SMatthias Ringwald }
1746ce263fc8SMatthias Ringwald
hfp_hf_disable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle)17473c65e705SMilanka Ringwald uint8_t hfp_hf_disable_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle){
17483c65e705SMilanka Ringwald return hfp_hf_set_report_extended_audio_gateway_error_result_code(acl_handle, 0);
1749ce263fc8SMatthias Ringwald }
1750ce263fc8SMatthias Ringwald
hfp_hf_esco_s4_supported(hfp_connection_t * hfp_connection)175138200c1dSMilanka Ringwald static uint8_t hfp_hf_esco_s4_supported(hfp_connection_t * hfp_connection){
1752aeb0f0feSMatthias Ringwald return (hfp_connection->remote_supported_features & (1<<HFP_AGSF_ESCO_S4)) && (hfp_hf_supported_features & (1 << HFP_HFSF_ESCO_S4));
175338200c1dSMilanka Ringwald }
1754ce263fc8SMatthias Ringwald
hfp_hf_establish_audio_connection(hci_con_handle_t acl_handle)17553c65e705SMilanka Ringwald uint8_t hfp_hf_establish_audio_connection(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
17613c65e705SMilanka Ringwald if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED){
17623c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
17633c65e705SMilanka Ringwald }
17643c65e705SMilanka Ringwald
17653c65e705SMilanka Ringwald if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO){
17663c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
17673c65e705SMilanka Ringwald }
1768f4412093SMatthias Ringwald if (has_codec_negotiation_feature(hfp_connection)) {
1769a0ffb263SMatthias Ringwald switch (hfp_connection->codecs_state) {
1770aa4dd815SMatthias Ringwald case HFP_CODECS_W4_AG_COMMON_CODEC:
1771aa4dd815SMatthias Ringwald break;
1772ec3bfc1aSMatthias Ringwald case HFP_CODECS_EXCHANGED:
1773ec3bfc1aSMatthias Ringwald hfp_connection->trigger_codec_exchange = 1;
1774ec3bfc1aSMatthias Ringwald break;
1775aa4dd815SMatthias Ringwald default:
17761cc65c4fSMatthias Ringwald hfp_connection->codec_confirmed = 0;
17771cc65c4fSMatthias Ringwald hfp_connection->suggested_codec = 0;
17781cc65c4fSMatthias Ringwald hfp_connection->negotiated_codec = 0;
17791cc65c4fSMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE;
178038200c1dSMilanka Ringwald hfp_connection->trigger_codec_exchange = 1;
1781aa4dd815SMatthias Ringwald break;
17823deb3ec6SMatthias Ringwald }
1783f4412093SMatthias Ringwald } else {
1784f4412093SMatthias Ringwald log_info("no codec negotiation feature, use CVSD");
1785f4412093SMatthias Ringwald hfp_connection->codecs_state = HFP_CODECS_EXCHANGED;
1786f4412093SMatthias Ringwald hfp_connection->suggested_codec = HFP_CODEC_CVSD;
1787f4412093SMatthias Ringwald hfp_connection->codec_confirmed = hfp_connection->suggested_codec;
1788f4412093SMatthias Ringwald hfp_connection->negotiated_codec = hfp_connection->suggested_codec;
1789f4412093SMatthias Ringwald hfp_init_link_settings(hfp_connection, hfp_hf_esco_s4_supported(hfp_connection));
1790f4412093SMatthias Ringwald hfp_connection->establish_audio_connection = 1;
1791f4412093SMatthias Ringwald hfp_connection->state = HFP_W4_SCO_CONNECTED;
1792ce263fc8SMatthias Ringwald }
1793ce263fc8SMatthias Ringwald
17941c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
17953c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
17963deb3ec6SMatthias Ringwald }
17973deb3ec6SMatthias Ringwald
hfp_hf_release_audio_connection(hci_con_handle_t acl_handle)17983c65e705SMilanka Ringwald uint8_t hfp_hf_release_audio_connection(hci_con_handle_t acl_handle){
17999c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1800a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18013c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1802a33eb0c4SMilanka Ringwald }
18030b4debbfSMilanka Ringwald if (hfp_connection->vra_state == HFP_VRA_VOICE_RECOGNITION_ACTIVATED){
18040b4debbfSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
18050b4debbfSMilanka Ringwald }
18060b4debbfSMilanka Ringwald uint8_t status = hfp_trigger_release_audio_connection(hfp_connection);
18070b4debbfSMilanka Ringwald if (status == ERROR_CODE_SUCCESS){
18081c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
18090b4debbfSMilanka Ringwald }
18103c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
18113deb3ec6SMatthias Ringwald }
18123deb3ec6SMatthias Ringwald
hfp_hf_answer_incoming_call(hci_con_handle_t acl_handle)18133c65e705SMilanka Ringwald uint8_t hfp_hf_answer_incoming_call(hci_con_handle_t acl_handle){
18149c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1815a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18163c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1817a33eb0c4SMilanka Ringwald }
1818ce263fc8SMatthias Ringwald
181966093044SMilanka Ringwald if (hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
1820a0ffb263SMatthias Ringwald hfp_connection->hf_answer_incoming_call = 1;
18211c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1822ce263fc8SMatthias Ringwald } else {
182366093044SMilanka Ringwald log_error("HFP HF: answering incoming call with wrong callsetup status %u", hfp_connection->hf_callsetup_status);
18243c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
1825ce263fc8SMatthias Ringwald }
18263c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1827ce263fc8SMatthias Ringwald }
1828ce263fc8SMatthias Ringwald
hfp_hf_terminate_call(hci_con_handle_t acl_handle)18293c65e705SMilanka Ringwald uint8_t hfp_hf_terminate_call(hci_con_handle_t acl_handle){
18309c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1831a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18323c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1833a33eb0c4SMilanka Ringwald }
1834a0ffb263SMatthias Ringwald hfp_connection->hf_send_chup = 1;
18351c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
18363c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1837ce263fc8SMatthias Ringwald }
1838ce263fc8SMatthias Ringwald
hfp_hf_reject_incoming_call(hci_con_handle_t acl_handle)18393c65e705SMilanka Ringwald uint8_t hfp_hf_reject_incoming_call(hci_con_handle_t acl_handle){
18409c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1841a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18423c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1843a33eb0c4SMilanka Ringwald }
1844ce263fc8SMatthias Ringwald
184566093044SMilanka Ringwald if (hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
1846a0ffb263SMatthias Ringwald hfp_connection->hf_send_chup = 1;
18471c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1848ce263fc8SMatthias Ringwald }
18493c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1850ce263fc8SMatthias Ringwald }
1851ce263fc8SMatthias Ringwald
hfp_hf_user_busy(hci_con_handle_t acl_handle)18523c65e705SMilanka Ringwald uint8_t hfp_hf_user_busy(hci_con_handle_t acl_handle){
18539c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1854a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18553c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1856a33eb0c4SMilanka Ringwald }
1857ce263fc8SMatthias Ringwald
185866093044SMilanka Ringwald if (hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
1859a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_0 = 1;
18601c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1861ce263fc8SMatthias Ringwald }
18623c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1863ce263fc8SMatthias Ringwald }
1864ce263fc8SMatthias Ringwald
hfp_hf_terminate_held_calls(hci_con_handle_t acl_handle)18652be52304SMatthias Ringwald uint8_t hfp_hf_terminate_held_calls(hci_con_handle_t acl_handle){
18662be52304SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
18672be52304SMatthias Ringwald if (!hfp_connection) {
18682be52304SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
18692be52304SMatthias Ringwald }
18702be52304SMatthias Ringwald
18712be52304SMatthias Ringwald hfp_connection->hf_send_chld_0 = 1;
18722be52304SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
18732be52304SMatthias Ringwald
18742be52304SMatthias Ringwald return ERROR_CODE_SUCCESS;
18752be52304SMatthias Ringwald }
18762be52304SMatthias Ringwald
hfp_hf_end_active_and_accept_other(hci_con_handle_t acl_handle)18773c65e705SMilanka Ringwald uint8_t hfp_hf_end_active_and_accept_other(hci_con_handle_t acl_handle){
18789c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1879a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18803c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1881a33eb0c4SMilanka Ringwald }
1882ce263fc8SMatthias Ringwald
188366093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) ||
188466093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
1885a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_1 = 1;
18861c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1887ce263fc8SMatthias Ringwald }
18883c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1889ce263fc8SMatthias Ringwald }
1890ce263fc8SMatthias Ringwald
hfp_hf_swap_calls(hci_con_handle_t acl_handle)18913c65e705SMilanka Ringwald uint8_t hfp_hf_swap_calls(hci_con_handle_t acl_handle){
18929c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1893a33eb0c4SMilanka Ringwald if (!hfp_connection) {
18943c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1895a33eb0c4SMilanka Ringwald }
1896ce263fc8SMatthias Ringwald
189766093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) ||
189866093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
1899a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_2 = 1;
19001c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1901ce263fc8SMatthias Ringwald }
19023c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1903ce263fc8SMatthias Ringwald }
1904ce263fc8SMatthias Ringwald
hfp_hf_join_held_call(hci_con_handle_t acl_handle)19053c65e705SMilanka Ringwald uint8_t hfp_hf_join_held_call(hci_con_handle_t acl_handle){
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
191166093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) ||
191266093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
1913a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_3 = 1;
19141c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1915ce263fc8SMatthias Ringwald }
19163c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1917ce263fc8SMatthias Ringwald }
1918ce263fc8SMatthias Ringwald
hfp_hf_connect_calls(hci_con_handle_t acl_handle)19193c65e705SMilanka Ringwald uint8_t hfp_hf_connect_calls(hci_con_handle_t acl_handle){
19209c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1921a33eb0c4SMilanka Ringwald if (!hfp_connection) {
19223c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1923a33eb0c4SMilanka Ringwald }
1924ce263fc8SMatthias Ringwald
192566093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) ||
192666093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
1927a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_4 = 1;
19281c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1929ce263fc8SMatthias Ringwald }
19303c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1931ce263fc8SMatthias Ringwald }
1932ce263fc8SMatthias Ringwald
hfp_hf_release_call_with_index(hci_con_handle_t acl_handle,int index)19333c65e705SMilanka Ringwald uint8_t hfp_hf_release_call_with_index(hci_con_handle_t acl_handle, int index){
19349c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1935a33eb0c4SMilanka Ringwald if (!hfp_connection) {
19363c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1937a33eb0c4SMilanka Ringwald }
1938667ec068SMatthias Ringwald
193966093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) ||
194066093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
1941a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x = 1;
1942a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x_index = 10 + index;
19431c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1944667ec068SMatthias Ringwald }
19453c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1946667ec068SMatthias Ringwald }
1947667ec068SMatthias Ringwald
hfp_hf_private_consultation_with_call(hci_con_handle_t acl_handle,int index)19483c65e705SMilanka Ringwald uint8_t hfp_hf_private_consultation_with_call(hci_con_handle_t acl_handle, int index){
19499c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1950a33eb0c4SMilanka Ringwald if (!hfp_connection) {
19513c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1952a33eb0c4SMilanka Ringwald }
1953667ec068SMatthias Ringwald
195466093044SMilanka Ringwald if ((hfp_connection->hf_callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) ||
195566093044SMilanka Ringwald (hfp_connection->hf_call_status == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
1956a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x = 1;
1957a0ffb263SMatthias Ringwald hfp_connection->hf_send_chld_x_index = 20 + index;
19581c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
1959667ec068SMatthias Ringwald }
19603c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1961667ec068SMatthias Ringwald }
1962ce263fc8SMatthias Ringwald
hfp_hf_dial_number(hci_con_handle_t acl_handle,char * number)19633c65e705SMilanka Ringwald uint8_t hfp_hf_dial_number(hci_con_handle_t acl_handle, char * number){
19649c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1965a33eb0c4SMilanka Ringwald if (!hfp_connection) {
19663c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1967a33eb0c4SMilanka Ringwald }
1968ce263fc8SMatthias Ringwald
1969a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_outgoing_call = 1;
1970865e2b54SMatthias Ringwald btstack_snprintf_assert_complete(hfp_hf_phone_number, sizeof(hfp_hf_phone_number), "%s", number);
19711c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
19723c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1973ce263fc8SMatthias Ringwald }
1974ce263fc8SMatthias Ringwald
hfp_hf_dial_memory(hci_con_handle_t acl_handle,int memory_id)19753c65e705SMilanka Ringwald uint8_t hfp_hf_dial_memory(hci_con_handle_t acl_handle, int memory_id){
19769c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1977a33eb0c4SMilanka Ringwald if (!hfp_connection) {
19783c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1979a33eb0c4SMilanka Ringwald }
1980ce263fc8SMatthias Ringwald
1981a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_memory_dialing = 1;
1982a0ffb263SMatthias Ringwald hfp_connection->memory_id = memory_id;
1983a0ffb263SMatthias Ringwald
19841c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
19853c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1986ce263fc8SMatthias Ringwald }
1987ce263fc8SMatthias Ringwald
hfp_hf_redial_last_number(hci_con_handle_t acl_handle)19883c65e705SMilanka Ringwald uint8_t hfp_hf_redial_last_number(hci_con_handle_t acl_handle){
19899c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
1990a33eb0c4SMilanka Ringwald if (!hfp_connection) {
19913c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1992a33eb0c4SMilanka Ringwald }
1993ce263fc8SMatthias Ringwald
1994a0ffb263SMatthias Ringwald hfp_connection->hf_initiate_redial_last_number = 1;
19951c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
19963c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
1997ce263fc8SMatthias Ringwald }
1998ce263fc8SMatthias Ringwald
hfp_hf_activate_call_waiting_notification(hci_con_handle_t acl_handle)19993c65e705SMilanka Ringwald uint8_t hfp_hf_activate_call_waiting_notification(hci_con_handle_t acl_handle){
20009c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2001a33eb0c4SMilanka Ringwald if (!hfp_connection) {
20023c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2003a33eb0c4SMilanka Ringwald }
2004ce263fc8SMatthias Ringwald
2005a0ffb263SMatthias Ringwald hfp_connection->hf_activate_call_waiting_notification = 1;
20061c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
20073c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2008ce263fc8SMatthias Ringwald }
2009ce263fc8SMatthias Ringwald
2010ce263fc8SMatthias Ringwald
hfp_hf_deactivate_call_waiting_notification(hci_con_handle_t acl_handle)20113c65e705SMilanka Ringwald uint8_t hfp_hf_deactivate_call_waiting_notification(hci_con_handle_t acl_handle){
20129c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2013a33eb0c4SMilanka Ringwald if (!hfp_connection) {
20143c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2015a33eb0c4SMilanka Ringwald }
2016ce263fc8SMatthias Ringwald
2017a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_call_waiting_notification = 1;
20181c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
20193c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2020ce263fc8SMatthias Ringwald }
2021ce263fc8SMatthias Ringwald
2022ce263fc8SMatthias Ringwald
hfp_hf_activate_calling_line_notification(hci_con_handle_t acl_handle)20233c65e705SMilanka Ringwald uint8_t hfp_hf_activate_calling_line_notification(hci_con_handle_t acl_handle){
20249c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2025a33eb0c4SMilanka Ringwald if (!hfp_connection) {
20263c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2027a33eb0c4SMilanka Ringwald }
2028ce263fc8SMatthias Ringwald
2029a0ffb263SMatthias Ringwald hfp_connection->hf_activate_calling_line_notification = 1;
20301c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
20313c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2032ce263fc8SMatthias Ringwald }
2033ce263fc8SMatthias Ringwald
hfp_hf_deactivate_calling_line_notification(hci_con_handle_t acl_handle)20343c65e705SMilanka Ringwald uint8_t hfp_hf_deactivate_calling_line_notification(hci_con_handle_t acl_handle){
20359c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2036a33eb0c4SMilanka Ringwald if (!hfp_connection) {
20373c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2038a33eb0c4SMilanka Ringwald }
2039ce263fc8SMatthias Ringwald
2040a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_calling_line_notification = 1;
20411c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
20423c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2043ce263fc8SMatthias Ringwald }
2044ce263fc8SMatthias Ringwald
hfp_hf_deactivate_echo_canceling_and_noise_reduction(hci_con_handle_t acl_handle)20453c65e705SMilanka Ringwald uint8_t hfp_hf_deactivate_echo_canceling_and_noise_reduction(hci_con_handle_t acl_handle){
20469c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2047a33eb0c4SMilanka Ringwald if (!hfp_connection) {
20483c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2049a33eb0c4SMilanka Ringwald }
205014685fd3SMatthias Ringwald if (get_bit(hfp_connection->remote_supported_features, HFP_AGSF_EC_NR_FUNCTION) == 0){
20516ba83b5eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
20526ba83b5eSMilanka Ringwald }
2053ce263fc8SMatthias Ringwald
2054a0ffb263SMatthias Ringwald hfp_connection->hf_deactivate_echo_canceling_and_noise_reduction = 1;
20551c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
20563c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2057ce263fc8SMatthias Ringwald }
2058ce263fc8SMatthias Ringwald
hfp_hf_activate_voice_recognition(hci_con_handle_t acl_handle)2059acd11d4aSMilanka Ringwald uint8_t hfp_hf_activate_voice_recognition(hci_con_handle_t acl_handle){
2060fdda66c0SMilanka Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2061fdda66c0SMilanka Ringwald if (!hfp_connection) {
2062fdda66c0SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2063be55a11dSMilanka Ringwald }
2064013cc750SMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || hfp_connection->state > HFP_AUDIO_CONNECTION_ESTABLISHED){
2065013cc750SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2066013cc750SMilanka Ringwald }
2067acd11d4aSMilanka Ringwald
2068acd11d4aSMilanka Ringwald bool enhanced_vra_supported = hfp_hf_enhanced_vra_flag_supported(hfp_connection);
2069acd11d4aSMilanka Ringwald bool legacy_vra_supported = hfp_hf_vra_flag_supported(hfp_connection);
2070acd11d4aSMilanka Ringwald if (!enhanced_vra_supported && !legacy_vra_supported){
2071acd11d4aSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
2072af97579eSMilanka Ringwald }
2073af97579eSMilanka Ringwald
2074498a8121SMilanka Ringwald switch (hfp_connection->vra_state){
2075be55a11dSMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_OFF:
2076de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF:
2077fd4151d1SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED;
2078acd11d4aSMilanka Ringwald hfp_connection->enhanced_voice_recognition_enabled = enhanced_vra_supported;
2079be55a11dSMilanka Ringwald break;
2080de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF:
2081de9e0ea7SMilanka Ringwald hfp_connection->activate_voice_recognition = true;
2082de9e0ea7SMilanka Ringwald break;
2083be55a11dSMilanka Ringwald default:
2084be55a11dSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2085be55a11dSMilanka Ringwald }
2086ce263fc8SMatthias Ringwald
2087af97579eSMilanka Ringwald hfp_hf_run_for_context(hfp_connection);
2088fdda66c0SMilanka Ringwald return ERROR_CODE_SUCCESS;
2089af97579eSMilanka Ringwald }
2090af97579eSMilanka Ringwald
hfp_hf_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle)2091acd11d4aSMilanka Ringwald uint8_t hfp_hf_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle){
2092af97579eSMilanka Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2093af97579eSMilanka Ringwald if (!hfp_connection) {
2094af97579eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2095af97579eSMilanka Ringwald }
209684fb9ac1SMilanka Ringwald
209784fb9ac1SMilanka Ringwald if (hfp_connection->emit_vra_enabled_after_audio_established){
209884fb9ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
209984fb9ac1SMilanka Ringwald }
210084fb9ac1SMilanka Ringwald
2101acd11d4aSMilanka Ringwald if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED){
210208a0b01cSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
210308a0b01cSMilanka Ringwald }
2104acd11d4aSMilanka Ringwald
2105acd11d4aSMilanka Ringwald bool enhanced_vra_supported = hfp_hf_enhanced_vra_flag_supported(hfp_connection);
2106acd11d4aSMilanka Ringwald if (!enhanced_vra_supported){
2107acd11d4aSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
2108acd11d4aSMilanka Ringwald }
2109acd11d4aSMilanka Ringwald
2110acd11d4aSMilanka Ringwald switch (hfp_connection->vra_state){
2111acd11d4aSMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
2112acd11d4aSMilanka Ringwald case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
2113acd11d4aSMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO;
2114acd11d4aSMilanka Ringwald break;
2115acd11d4aSMilanka Ringwald default:
2116fdda66c0SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2117af97579eSMilanka Ringwald }
2118013cc750SMilanka Ringwald
2119acd11d4aSMilanka Ringwald hfp_hf_run_for_context(hfp_connection);
2120acd11d4aSMilanka Ringwald return ERROR_CODE_SUCCESS;
2121acd11d4aSMilanka Ringwald }
2122acd11d4aSMilanka Ringwald
2123acd11d4aSMilanka Ringwald
hfp_hf_deactivate_voice_recognition(hci_con_handle_t acl_handle)2124acd11d4aSMilanka Ringwald uint8_t hfp_hf_deactivate_voice_recognition(hci_con_handle_t acl_handle){
2125acd11d4aSMilanka Ringwald // return deactivate_voice_recognition(acl_handle, false);
2126acd11d4aSMilanka Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2127acd11d4aSMilanka Ringwald if (!hfp_connection) {
2128acd11d4aSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2129acd11d4aSMilanka Ringwald }
2130acd11d4aSMilanka Ringwald
213184fb9ac1SMilanka Ringwald if (hfp_connection->emit_vra_enabled_after_audio_established){
213284fb9ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
213384fb9ac1SMilanka Ringwald }
213484fb9ac1SMilanka Ringwald
2135acd11d4aSMilanka Ringwald if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
2136acd11d4aSMilanka Ringwald hfp_connection->state > HFP_AUDIO_CONNECTION_ESTABLISHED){
2137acd11d4aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2138acd11d4aSMilanka Ringwald }
2139acd11d4aSMilanka Ringwald
2140acd11d4aSMilanka Ringwald bool enhanced_vra_supported = hfp_hf_enhanced_vra_flag_supported(hfp_connection);
2141acd11d4aSMilanka Ringwald bool legacy_vra_supported = hfp_hf_vra_flag_supported(hfp_connection);
2142acd11d4aSMilanka Ringwald if (!enhanced_vra_supported && !legacy_vra_supported){
2143acd11d4aSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
2144acd11d4aSMilanka Ringwald }
2145acd11d4aSMilanka Ringwald
2146fdda66c0SMilanka Ringwald switch (hfp_connection->vra_state){
2147de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED:
2148fdda66c0SMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
2149de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
2150de9e0ea7SMilanka Ringwald case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
2151fdda66c0SMilanka Ringwald hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF;
2152fdda66c0SMilanka Ringwald break;
2153de9e0ea7SMilanka Ringwald
2154de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED:
2155de9e0ea7SMilanka Ringwald case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO:
2156de9e0ea7SMilanka Ringwald hfp_connection->deactivate_voice_recognition = true;
2157de9e0ea7SMilanka Ringwald break;
2158de9e0ea7SMilanka Ringwald
2159de9e0ea7SMilanka Ringwald case HFP_VRA_VOICE_RECOGNITION_OFF:
2160de9e0ea7SMilanka Ringwald case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF:
2161de9e0ea7SMilanka Ringwald case HFP_VRA_W4_VOICE_RECOGNITION_OFF:
2162fdda66c0SMilanka Ringwald default:
2163fdda66c0SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2164fdda66c0SMilanka Ringwald }
2165fdda66c0SMilanka Ringwald
2166fdda66c0SMilanka Ringwald hfp_hf_run_for_context(hfp_connection);
2167fdda66c0SMilanka Ringwald return ERROR_CODE_SUCCESS;
2168af97579eSMilanka Ringwald }
2169af97579eSMilanka Ringwald
hfp_hf_set_microphone_gain(hci_con_handle_t acl_handle,int gain)21703c65e705SMilanka Ringwald uint8_t hfp_hf_set_microphone_gain(hci_con_handle_t acl_handle, int gain){
21719c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2172a33eb0c4SMilanka Ringwald if (!hfp_connection) {
21733c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2174a33eb0c4SMilanka Ringwald }
2175c8626498SMilanka Ringwald
21763c65e705SMilanka Ringwald if (hfp_connection->microphone_gain == gain) {
21773c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
21783c65e705SMilanka Ringwald }
21793c65e705SMilanka Ringwald
2180c1ab6cc1SMatthias Ringwald if ((gain < 0) || (gain > 15)){
2181a0ffb263SMatthias Ringwald log_info("Valid range for a gain is [0..15]. Currently sent: %d", gain);
21823c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2183a0ffb263SMatthias Ringwald }
21843c65e705SMilanka Ringwald
2185a0ffb263SMatthias Ringwald hfp_connection->microphone_gain = gain;
2186a0ffb263SMatthias Ringwald hfp_connection->send_microphone_gain = 1;
21871c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
21883c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2189ce263fc8SMatthias Ringwald }
2190ce263fc8SMatthias Ringwald
hfp_hf_set_speaker_gain(hci_con_handle_t acl_handle,int gain)21913c65e705SMilanka Ringwald uint8_t hfp_hf_set_speaker_gain(hci_con_handle_t acl_handle, int gain){
21929c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2193a33eb0c4SMilanka Ringwald if (!hfp_connection) {
21943c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2195a33eb0c4SMilanka Ringwald }
2196c8626498SMilanka Ringwald
21973c65e705SMilanka Ringwald if (hfp_connection->speaker_gain == gain){
21983c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
21993c65e705SMilanka Ringwald }
22003c65e705SMilanka Ringwald
2201c1ab6cc1SMatthias Ringwald if ((gain < 0) || (gain > 15)){
2202a0ffb263SMatthias Ringwald log_info("Valid range for a gain is [0..15]. Currently sent: %d", gain);
22033c65e705SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2204a0ffb263SMatthias Ringwald }
22053c65e705SMilanka Ringwald
2206a0ffb263SMatthias Ringwald hfp_connection->speaker_gain = gain;
2207a0ffb263SMatthias Ringwald hfp_connection->send_speaker_gain = 1;
22081c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22093c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2210ce263fc8SMatthias Ringwald }
2211ce263fc8SMatthias Ringwald
hfp_hf_send_dtmf_code(hci_con_handle_t acl_handle,char code)22123c65e705SMilanka Ringwald uint8_t hfp_hf_send_dtmf_code(hci_con_handle_t acl_handle, char code){
22139c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2214a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22153c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2216a33eb0c4SMilanka Ringwald }
2217a0ffb263SMatthias Ringwald hfp_connection->hf_send_dtmf_code = code;
22181c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22193c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2220ce263fc8SMatthias Ringwald }
2221ce263fc8SMatthias Ringwald
hfp_hf_request_phone_number_for_voice_tag(hci_con_handle_t acl_handle)22223c65e705SMilanka Ringwald uint8_t hfp_hf_request_phone_number_for_voice_tag(hci_con_handle_t acl_handle){
22239c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2224a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22253c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2226a33eb0c4SMilanka Ringwald }
2227a0ffb263SMatthias Ringwald hfp_connection->hf_send_binp = 1;
22281c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22293c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2230ce263fc8SMatthias Ringwald }
22313deb3ec6SMatthias Ringwald
hfp_hf_query_current_call_status(hci_con_handle_t acl_handle)22323c65e705SMilanka Ringwald uint8_t hfp_hf_query_current_call_status(hci_con_handle_t acl_handle){
22339c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2234a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22353c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2236a33eb0c4SMilanka Ringwald }
2237a0ffb263SMatthias Ringwald hfp_connection->hf_send_clcc = 1;
22381c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22393c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2240667ec068SMatthias Ringwald }
2241667ec068SMatthias Ringwald
2242667ec068SMatthias Ringwald
hfp_hf_rrh_query_status(hci_con_handle_t acl_handle)22433c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_query_status(hci_con_handle_t acl_handle){
22449c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2245a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22463c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2247a33eb0c4SMilanka Ringwald }
2248a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1;
2249a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '?';
22501c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22513c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2252667ec068SMatthias Ringwald }
2253667ec068SMatthias Ringwald
hfp_hf_rrh_hold_call(hci_con_handle_t acl_handle)22543c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_hold_call(hci_con_handle_t acl_handle){
22559c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2256a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22573c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2258a33eb0c4SMilanka Ringwald }
2259a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1;
2260a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '0';
22611c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22623c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2263667ec068SMatthias Ringwald }
2264667ec068SMatthias Ringwald
hfp_hf_rrh_accept_held_call(hci_con_handle_t acl_handle)22653c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_accept_held_call(hci_con_handle_t acl_handle){
22669c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2267a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22683c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2269a33eb0c4SMilanka Ringwald }
2270a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1;
2271a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '1';
22721c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22733c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2274667ec068SMatthias Ringwald }
2275667ec068SMatthias Ringwald
hfp_hf_rrh_reject_held_call(hci_con_handle_t acl_handle)22763c65e705SMilanka Ringwald uint8_t hfp_hf_rrh_reject_held_call(hci_con_handle_t acl_handle){
22779c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2278a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22793c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2280a33eb0c4SMilanka Ringwald }
2281a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh = 1;
2282a0ffb263SMatthias Ringwald hfp_connection->hf_send_rrh_command = '2';
22831c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22843c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2285667ec068SMatthias Ringwald }
2286667ec068SMatthias Ringwald
hfp_hf_query_subscriber_number(hci_con_handle_t acl_handle)22873c65e705SMilanka Ringwald uint8_t hfp_hf_query_subscriber_number(hci_con_handle_t acl_handle){
22889c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2289a33eb0c4SMilanka Ringwald if (!hfp_connection) {
22903c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2291a33eb0c4SMilanka Ringwald }
2292a0ffb263SMatthias Ringwald hfp_connection->hf_send_cnum = 1;
22931c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
22943c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2295667ec068SMatthias Ringwald }
2296667ec068SMatthias Ringwald
hfp_hf_set_hf_indicator(hci_con_handle_t acl_handle,int assigned_number,int value)22973c65e705SMilanka Ringwald uint8_t hfp_hf_set_hf_indicator(hci_con_handle_t acl_handle, int assigned_number, int value){
22989c9c64c1SMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2299a33eb0c4SMilanka Ringwald if (!hfp_connection) {
23003c65e705SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
2301a33eb0c4SMilanka Ringwald }
2302667ec068SMatthias Ringwald // find index for assigned number
2303fa4b4d2bSMatthias Ringwald uint8_t i;
2304aeb0f0feSMatthias Ringwald for (i = 0; i < hfp_hf_indicators_nr ; i++){
2305aeb0f0feSMatthias Ringwald if (hfp_hf_indicators[i] == assigned_number){
2306fa4b4d2bSMatthias Ringwald // check if connection ready and indicator enabled
23070f716b22SMatthias Ringwald if (hfp_connection->state > HFP_LIST_GENERIC_STATUS_INDICATORS){
23080f716b22SMatthias Ringwald if (hfp_connection->generic_status_indicators[i].state != 0) {
2309667ec068SMatthias Ringwald // set value
2310aeb0f0feSMatthias Ringwald hfp_hf_indicators_value[i] = value;
2311667ec068SMatthias Ringwald // mark for update
2312a0ffb263SMatthias Ringwald hfp_connection->generic_status_update_bitmap |= (1 << i);
2313667ec068SMatthias Ringwald // send update
23141c6a0fc0SMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
2315*fd8c0098SMilanka Ringwald break;
2316a0ffb263SMatthias Ringwald }
23170f716b22SMatthias Ringwald }
2318667ec068SMatthias Ringwald }
2319667ec068SMatthias Ringwald }
2320*fd8c0098SMilanka Ringwald if (i == hfp_hf_indicators_nr){
2321*fd8c0098SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
2322*fd8c0098SMilanka Ringwald }
23233c65e705SMilanka Ringwald return ERROR_CODE_SUCCESS;
2324667ec068SMatthias Ringwald }
2325667ec068SMatthias Ringwald
hfp_hf_apple_set_identification(uint16_t vendor_id,uint16_t product_id,const char * version,uint8_t features)23264e8ee53aSMatthias Ringwald void hfp_hf_apple_set_identification(uint16_t vendor_id, uint16_t product_id, const char * version, uint8_t features){
23274e8ee53aSMatthias Ringwald hfp_hf_apple_vendor_id = vendor_id;
23284e8ee53aSMatthias Ringwald hfp_hf_apple_product_id = product_id;
23294e8ee53aSMatthias Ringwald hfp_hf_apple_version = version;
23304e8ee53aSMatthias Ringwald hfp_hf_apple_features = features;
23314e8ee53aSMatthias Ringwald }
23324e8ee53aSMatthias Ringwald
hfp_hf_apple_set_battery_level(uint8_t battery_level)2333910dced5SMatthias Ringwald uint8_t hfp_hf_apple_set_battery_level(uint8_t battery_level){
2334910dced5SMatthias Ringwald if (battery_level > 9) {
2335910dced5SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
2336910dced5SMatthias Ringwald }
2337910dced5SMatthias Ringwald hfp_hf_apple_battery_level = (int8_t) battery_level;
2338910dced5SMatthias Ringwald hfp_hf_apple_trigger_send();
2339910dced5SMatthias Ringwald return ERROR_CODE_SUCCESS;
2340910dced5SMatthias Ringwald }
2341910dced5SMatthias Ringwald
hfp_hf_apple_set_docked_state(uint8_t docked)2342910dced5SMatthias Ringwald uint8_t hfp_hf_apple_set_docked_state(uint8_t docked){
2343910dced5SMatthias Ringwald if (docked > 1) {
2344910dced5SMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
2345910dced5SMatthias Ringwald }
2346910dced5SMatthias Ringwald hfp_hf_apple_docked = (int8_t) docked;
2347910dced5SMatthias Ringwald hfp_hf_apple_trigger_send();
2348910dced5SMatthias Ringwald return ERROR_CODE_SUCCESS;
2349910dced5SMatthias Ringwald }
2350910dced5SMatthias Ringwald
hfp_hf_send_at_command(hci_con_handle_t acl_handle,const char * at_command)235151a2ebdeSMatthias Ringwald uint8_t hfp_hf_send_at_command(hci_con_handle_t acl_handle, const char * at_command){
235251a2ebdeSMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
235351a2ebdeSMatthias Ringwald if (!hfp_connection) {
235451a2ebdeSMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
235551a2ebdeSMatthias Ringwald }
235651a2ebdeSMatthias Ringwald if (hfp_connection->send_custom_message != NULL){
235751a2ebdeSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED;
235851a2ebdeSMatthias Ringwald }
235951a2ebdeSMatthias Ringwald hfp_connection->send_custom_message = at_command;
236051a2ebdeSMatthias Ringwald hfp_hf_run_for_context(hfp_connection);
236151a2ebdeSMatthias Ringwald return ERROR_CODE_SUCCESS;
236251a2ebdeSMatthias Ringwald }
236351a2ebdeSMatthias Ringwald
hfp_hf_in_band_ringtone_active(hci_con_handle_t acl_handle)2364d7f6b5cbSMatthias Ringwald int hfp_hf_in_band_ringtone_active(hci_con_handle_t acl_handle){
2365d7f6b5cbSMatthias Ringwald hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle);
2366d7f6b5cbSMatthias Ringwald if (!hfp_connection) {
2367d7f6b5cbSMatthias Ringwald return 0;
2368d7f6b5cbSMatthias Ringwald }
2369d7f6b5cbSMatthias Ringwald return get_bit(hfp_connection->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE);
2370d7f6b5cbSMatthias Ringwald }
237176cc1527SMatthias Ringwald
hfp_hf_create_sdp_record_with_codecs(uint8_t * service,uint32_t service_record_handle,int rfcomm_channel_nr,const char * name,uint16_t supported_features,uint8_t codecs_nr,const uint8_t * codecs)2372aa10b9cbSMatthias Ringwald void hfp_hf_create_sdp_record_with_codecs(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr,
2373aa10b9cbSMatthias Ringwald const char * name, uint16_t supported_features, uint8_t codecs_nr, const uint8_t * codecs){
237476cc1527SMatthias Ringwald if (!name){
2375aeb0f0feSMatthias Ringwald name = hfp_hf_default_service_name;
237676cc1527SMatthias Ringwald }
237776cc1527SMatthias Ringwald hfp_create_sdp_record(service, service_record_handle, BLUETOOTH_SERVICE_CLASS_HANDSFREE, rfcomm_channel_nr, name);
237876cc1527SMatthias Ringwald
237976cc1527SMatthias Ringwald // Construct SupportedFeatures for SDP bitmap:
238076cc1527SMatthias Ringwald //
238176cc1527SMatthias Ringwald // "The values of the “SupportedFeatures” bitmap given in Table 5.4 shall be the same as the values
238276cc1527SMatthias Ringwald // of the Bits 0 to 4 of the unsolicited result code +BRSF"
238376cc1527SMatthias Ringwald //
2384aa10b9cbSMatthias Ringwald // Wide band speech (bit 5) and LC3-SWB (bit 8) require Codec negotiation
238576cc1527SMatthias Ringwald //
238676cc1527SMatthias Ringwald uint16_t sdp_features = supported_features & 0x1f;
2387ef3ae4ebSMilanka Ringwald
2388ef3ae4ebSMilanka Ringwald if (supported_features & (1 << HFP_HFSF_ENHANCED_VOICE_RECOGNITION_STATUS)){
238956f1adacSMilanka Ringwald sdp_features |= 1 << 6;
2390ef3ae4ebSMilanka Ringwald }
2391ef3ae4ebSMilanka Ringwald
2392ef3ae4ebSMilanka Ringwald if (supported_features & (1 << HFP_HFSF_VOICE_RECOGNITION_TEXT)){
239356f1adacSMilanka Ringwald sdp_features |= 1 << 7;
2394ef3ae4ebSMilanka Ringwald }
2395ef3ae4ebSMilanka Ringwald
2396aa10b9cbSMatthias Ringwald // codecs
2397aa10b9cbSMatthias Ringwald if ((supported_features & (1 << HFP_HFSF_CODEC_NEGOTIATION)) != 0){
2398aa10b9cbSMatthias Ringwald uint8_t i;
2399aa10b9cbSMatthias Ringwald for (i=0;i<codecs_nr;i++){
2400aa10b9cbSMatthias Ringwald switch (codecs[i]){
2401aa10b9cbSMatthias Ringwald case HFP_CODEC_MSBC:
2402aa10b9cbSMatthias Ringwald sdp_features |= 1 << 5;
2403aa10b9cbSMatthias Ringwald break;
2404aa10b9cbSMatthias Ringwald case HFP_CODEC_LC3_SWB:
2405aa10b9cbSMatthias Ringwald sdp_features |= 1 << 8;
2406aa10b9cbSMatthias Ringwald break;
240775389f80SMatthias Ringwald default:
240875389f80SMatthias Ringwald break;
2409aa10b9cbSMatthias Ringwald }
2410aa10b9cbSMatthias Ringwald }
2411aa10b9cbSMatthias Ringwald }
2412aa10b9cbSMatthias Ringwald
2413aa10b9cbSMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SUPPORTED_FEATURES);
241476cc1527SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, sdp_features);
241576cc1527SMatthias Ringwald }
241676cc1527SMatthias Ringwald
2417aa10b9cbSMatthias Ringwald // @deprecated, call new API
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)2418aa10b9cbSMatthias 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){
2419aa10b9cbSMatthias Ringwald uint8_t codecs_nr;
2420aa10b9cbSMatthias Ringwald const uint8_t * codecs;
2421aa10b9cbSMatthias Ringwald const uint8_t wide_band_codecs[] = { HFP_CODEC_MSBC };
2422aa10b9cbSMatthias Ringwald if (wide_band_speech == 0){
2423aa10b9cbSMatthias Ringwald codecs_nr = 0;
2424aa10b9cbSMatthias Ringwald codecs = NULL;
2425aa10b9cbSMatthias Ringwald } else {
2426aa10b9cbSMatthias Ringwald codecs_nr = 1;
2427aa10b9cbSMatthias Ringwald codecs = wide_band_codecs;
2428aa10b9cbSMatthias Ringwald }
2429aa10b9cbSMatthias Ringwald hfp_hf_create_sdp_record_with_codecs(service, service_record_handle, rfcomm_channel_nr, name, supported_features, codecs_nr, codecs);
2430aa10b9cbSMatthias Ringwald }
2431aa10b9cbSMatthias Ringwald
hfp_hf_register_custom_at_command(hfp_custom_at_command_t * custom_at_command)2432077c2d92SMatthias Ringwald void hfp_hf_register_custom_at_command(hfp_custom_at_command_t * custom_at_command){
2433077c2d92SMatthias Ringwald hfp_register_custom_hf_command(custom_at_command);
2434077c2d92SMatthias Ringwald }
2435077c2d92SMatthias Ringwald
hfp_hf_register_packet_handler(btstack_packet_handler_t callback)243676cc1527SMatthias Ringwald void hfp_hf_register_packet_handler(btstack_packet_handler_t callback){
243768466199SMilanka Ringwald btstack_assert(callback != NULL);
243868466199SMilanka Ringwald
243976cc1527SMatthias Ringwald hfp_hf_callback = callback;
244076cc1527SMatthias Ringwald hfp_set_hf_callback(callback);
244176cc1527SMatthias Ringwald }
2442