xref: /btstack/src/classic/hfp_ag.c (revision 45796ff1c6be75ebedee55d6ee108137ec440a44)
13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald  *
43deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald  * are met:
73deb3ec6SMatthias Ringwald  *
83deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald  *    monetary gain.
193deb3ec6SMatthias Ringwald  *
203deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
233deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
243deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald  *
333deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald  * [email protected]
353deb3ec6SMatthias Ringwald  *
363deb3ec6SMatthias Ringwald  */
37ab2c6ae4SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hfp_ag.c"
393deb3ec6SMatthias Ringwald 
403deb3ec6SMatthias Ringwald // *****************************************************************************
413deb3ec6SMatthias Ringwald //
4266a048abSMatthias Ringwald // HFP Audio Gateway (AG) unit
433deb3ec6SMatthias Ringwald //
443deb3ec6SMatthias Ringwald // *****************************************************************************
453deb3ec6SMatthias Ringwald 
467907f069SMatthias Ringwald #include "btstack_config.h"
473deb3ec6SMatthias Ringwald 
483deb3ec6SMatthias Ringwald #include <stdint.h>
493deb3ec6SMatthias Ringwald #include <string.h>
503deb3ec6SMatthias Ringwald 
5156042629SMatthias Ringwald #include "hci_cmd.h"
5282636622SMatthias Ringwald #include "btstack_run_loop.h"
533deb3ec6SMatthias Ringwald 
54235946f1SMatthias Ringwald #include "bluetooth_sdp.h"
553deb3ec6SMatthias Ringwald #include "hci.h"
563deb3ec6SMatthias Ringwald #include "btstack_memory.h"
573deb3ec6SMatthias Ringwald #include "hci_dump.h"
583deb3ec6SMatthias Ringwald #include "l2cap.h"
5916ece135SMatthias Ringwald #include "btstack_debug.h"
60e30a6a47SMatthias Ringwald #include "btstack_event.h"
6159c6af15SMatthias Ringwald #include "classic/core.h"
623edc84c5SMatthias Ringwald #include "classic/hfp.h"
633edc84c5SMatthias Ringwald #include "classic/hfp_ag.h"
64023f2764SMatthias Ringwald #include "classic/hfp_gsm_model.h"
65efda0b48SMatthias Ringwald #include "classic/sdp_client_rfcomm.h"
66023f2764SMatthias Ringwald #include "classic/sdp_server.h"
67023f2764SMatthias Ringwald #include "classic/sdp_util.h"
683deb3ec6SMatthias Ringwald 
69c5b64319SMatthias Ringwald // private prototypes
70f0aeb307SMatthias Ringwald static void hfp_ag_run_for_context(hfp_connection_t *hfp_connection);
71adaba9f3SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * hfp_connection);
72adaba9f3SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * hfp_connection);
73c5b64319SMatthias Ringwald 
74c5b64319SMatthias Ringwald // public prototypes
7535833313SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void);
7635833313SMatthias Ringwald int get_hfp_generic_status_indicators_nr(void);
77c5b64319SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
78c5b64319SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr);
79c5b64319SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context);
80c5b64319SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context);
81c5b64319SMatthias Ringwald 
8227950165SMatthias Ringwald 
8320b2edb6SMatthias Ringwald // const
843deb3ec6SMatthias Ringwald static const char default_hfp_ag_service_name[] = "Voice gateway";
85aa4dd815SMatthias Ringwald 
8620b2edb6SMatthias Ringwald // globals
8720b2edb6SMatthias Ringwald static btstack_packet_callback_registration_t hfp_ag_hci_event_callback_registration;
88aa4dd815SMatthias Ringwald 
8920b2edb6SMatthias Ringwald static uint16_t hfp_supported_features;
9020b2edb6SMatthias Ringwald 
9120b2edb6SMatthias Ringwald static uint8_t hfp_codecs_nr;
923deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS];
933deb3ec6SMatthias Ringwald 
9420b2edb6SMatthias Ringwald static int  hfp_ag_indicators_nr;
9525789943SMilanka Ringwald static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_INDICATORS];
963deb3ec6SMatthias Ringwald 
9720b2edb6SMatthias Ringwald static int hfp_generic_status_indicators_nr;
9825789943SMilanka Ringwald static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_INDICATORS];
99a0ffb263SMatthias Ringwald 
10020b2edb6SMatthias Ringwald static int  hfp_ag_call_hold_services_nr;
1013deb3ec6SMatthias Ringwald static char *hfp_ag_call_hold_services[6];
102ca59be51SMatthias Ringwald static btstack_packet_handler_t hfp_ag_callback;
1033deb3ec6SMatthias Ringwald 
104ce263fc8SMatthias Ringwald static hfp_response_and_hold_state_t hfp_ag_response_and_hold_state;
10520b2edb6SMatthias Ringwald static int hfp_ag_response_and_hold_active;
106aa4dd815SMatthias Ringwald 
10720b2edb6SMatthias Ringwald // Subscriber information entries
10820b2edb6SMatthias Ringwald static hfp_phone_number_t * subscriber_numbers;
10920b2edb6SMatthias Ringwald static int subscriber_numbers_count;
110ce263fc8SMatthias Ringwald 
11120b2edb6SMatthias Ringwald // code
112a0ffb263SMatthias Ringwald static int hfp_ag_get_ag_indicators_nr(hfp_connection_t * hfp_connection){
113a0ffb263SMatthias Ringwald     if (hfp_connection->ag_indicators_nr != hfp_ag_indicators_nr){
114a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_nr = hfp_ag_indicators_nr;
1156535961aSMatthias Ringwald         (void)memcpy(hfp_connection->ag_indicators, hfp_ag_indicators,
1166535961aSMatthias Ringwald                      hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
1173deb3ec6SMatthias Ringwald     }
118a0ffb263SMatthias Ringwald     return hfp_connection->ag_indicators_nr;
119a0ffb263SMatthias Ringwald }
120a0ffb263SMatthias Ringwald 
121a0ffb263SMatthias Ringwald hfp_ag_indicator_t * hfp_ag_get_ag_indicators(hfp_connection_t * hfp_connection){
122a0ffb263SMatthias Ringwald     // TODO: save only value, and value changed in the hfp_connection?
123a0ffb263SMatthias Ringwald     if (hfp_connection->ag_indicators_nr != hfp_ag_indicators_nr){
124a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_nr = hfp_ag_indicators_nr;
1256535961aSMatthias Ringwald         (void)memcpy(hfp_connection->ag_indicators, hfp_ag_indicators,
1266535961aSMatthias Ringwald                      hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
127a0ffb263SMatthias Ringwald     }
128a0ffb263SMatthias Ringwald     return (hfp_ag_indicator_t *)&(hfp_connection->ag_indicators);
1293deb3ec6SMatthias Ringwald }
1303deb3ec6SMatthias Ringwald 
131aa4dd815SMatthias Ringwald static hfp_ag_indicator_t * get_ag_indicator_for_name(const char * name){
132aa4dd815SMatthias Ringwald     int i;
133aa4dd815SMatthias Ringwald     for (i = 0; i < hfp_ag_indicators_nr; i++){
134aa4dd815SMatthias Ringwald         if (strcmp(hfp_ag_indicators[i].name, name) == 0){
135aa4dd815SMatthias Ringwald             return &hfp_ag_indicators[i];
136aa4dd815SMatthias Ringwald         }
137aa4dd815SMatthias Ringwald     }
138aa4dd815SMatthias Ringwald     return NULL;
139aa4dd815SMatthias Ringwald }
140aa4dd815SMatthias Ringwald 
141aa4dd815SMatthias Ringwald static int get_ag_indicator_index_for_name(const char * name){
142aa4dd815SMatthias Ringwald     int i;
143aa4dd815SMatthias Ringwald     for (i = 0; i < hfp_ag_indicators_nr; i++){
144aa4dd815SMatthias Ringwald         if (strcmp(hfp_ag_indicators[i].name, name) == 0){
145aa4dd815SMatthias Ringwald             return i;
146aa4dd815SMatthias Ringwald         }
147aa4dd815SMatthias Ringwald     }
148aa4dd815SMatthias Ringwald     return -1;
149aa4dd815SMatthias Ringwald }
150aa4dd815SMatthias Ringwald 
1519c9c64c1SMatthias Ringwald static hfp_connection_t * get_hfp_ag_connection_context_for_acl_handle(uint16_t handle){
1529c9c64c1SMatthias Ringwald     btstack_linked_list_iterator_t it;
1539c9c64c1SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1549c9c64c1SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1559c9c64c1SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
1569c9c64c1SMatthias Ringwald         if (hfp_connection->acl_handle != handle)      continue;
1579c9c64c1SMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1589c9c64c1SMatthias Ringwald         return hfp_connection;
1599c9c64c1SMatthias Ringwald     }
1609c9c64c1SMatthias Ringwald     return NULL;
1619c9c64c1SMatthias Ringwald }
1623deb3ec6SMatthias Ringwald 
1630cb5b971SMatthias Ringwald static int use_in_band_tone(void){
164aa4dd815SMatthias Ringwald     return get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE);
1653deb3ec6SMatthias Ringwald }
1663deb3ec6SMatthias Ringwald 
167a0ffb263SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * hfp_connection){
168a0ffb263SMatthias Ringwald     int hf = get_bit(hfp_connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
1693deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
1703deb3ec6SMatthias Ringwald     return hf && ag;
1713deb3ec6SMatthias Ringwald }
1723deb3ec6SMatthias Ringwald 
173a0ffb263SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * hfp_connection){
174a0ffb263SMatthias Ringwald     int hf = get_bit(hfp_connection->remote_supported_features, HFP_HFSF_THREE_WAY_CALLING);
1753deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_THREE_WAY_CALLING);
1763deb3ec6SMatthias Ringwald     return hf && ag;
1773deb3ec6SMatthias Ringwald }
1783deb3ec6SMatthias Ringwald 
179a0ffb263SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * hfp_connection){
180a0ffb263SMatthias Ringwald     int hf = get_bit(hfp_connection->remote_supported_features, HFP_HFSF_HF_INDICATORS);
1813deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_HF_INDICATORS);
1823deb3ec6SMatthias Ringwald     return hf && ag;
1833deb3ec6SMatthias Ringwald }
1843deb3ec6SMatthias Ringwald 
18576cc1527SMatthias Ringwald /* unsolicited responses */
186aa4dd815SMatthias Ringwald 
187485ac19eSMilanka Ringwald static int hfp_ag_send_change_in_band_ring_tone_setting_cmd(uint16_t cid){
188aa4dd815SMatthias Ringwald     char buffer[20];
189ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: %d\r\n",
190ff7d6aeaSMatthias Ringwald              HFP_CHANGE_IN_BAND_RING_TONE_SETTING, use_in_band_tone());
191ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
192aa4dd815SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
1933deb3ec6SMatthias Ringwald }
1943deb3ec6SMatthias Ringwald 
1953deb3ec6SMatthias Ringwald static int hfp_ag_exchange_supported_features_cmd(uint16_t cid){
1963deb3ec6SMatthias Ringwald     char buffer[40];
197ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s:%d\r\n\r\nOK\r\n",
198ff7d6aeaSMatthias Ringwald              HFP_SUPPORTED_FEATURES, hfp_supported_features);
199ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
2003deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
2013deb3ec6SMatthias Ringwald }
2023deb3ec6SMatthias Ringwald 
203485ac19eSMilanka Ringwald static int hfp_ag_send_ok(uint16_t cid){
2043deb3ec6SMatthias Ringwald     char buffer[10];
205ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\nOK\r\n");
206ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
2073deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
2083deb3ec6SMatthias Ringwald }
2093deb3ec6SMatthias Ringwald 
210485ac19eSMilanka Ringwald static int hfp_ag_send_ring(uint16_t cid){
211aa4dd815SMatthias Ringwald     return send_str_over_rfcomm(cid, (char *) "\r\nRING\r\n");
212aa4dd815SMatthias Ringwald }
213aa4dd815SMatthias Ringwald 
214245852b7SMilanka Ringwald static int hfp_ag_send_no_carrier(uint16_t cid){
215245852b7SMilanka Ringwald     char buffer[15];
216245852b7SMilanka Ringwald     snprintf(buffer, sizeof(buffer), "\r\nNO CARRIER\r\n");
217245852b7SMilanka Ringwald     buffer[sizeof(buffer) - 1] = 0;
218245852b7SMilanka Ringwald     return send_str_over_rfcomm(cid, buffer);
219245852b7SMilanka Ringwald }
220245852b7SMilanka Ringwald 
221aa4dd815SMatthias Ringwald static int hfp_ag_send_clip(uint16_t cid){
222aa4dd815SMatthias Ringwald     char buffer[50];
223ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: \"%s\",%u\r\n", HFP_ENABLE_CLIP,
224ff7d6aeaSMatthias Ringwald              hfp_gsm_clip_number(), hfp_gsm_clip_type());
225ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
226aa4dd815SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
227aa4dd815SMatthias Ringwald }
228aa4dd815SMatthias Ringwald 
229ce263fc8SMatthias Ringwald static int hfp_send_subscriber_number_cmd(uint16_t cid, uint8_t type, const char * number){
230ce263fc8SMatthias Ringwald     char buffer[50];
231ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: ,\"%s\",%u, , \r\n",
232ff7d6aeaSMatthias Ringwald              HFP_SUBSCRIBER_NUMBER_INFORMATION, number, type);
233ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
234ce263fc8SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
235ce263fc8SMatthias Ringwald }
236ce263fc8SMatthias Ringwald 
237c1797c7dSMatthias Ringwald static int hfp_ag_send_phone_number_for_voice_tag_cmd(uint16_t cid){
238aa4dd815SMatthias Ringwald     char buffer[50];
239ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: %s\r\n",
240ff7d6aeaSMatthias Ringwald              HFP_PHONE_NUMBER_FOR_VOICE_TAG, hfp_gsm_clip_number());
241ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
242aa4dd815SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
243aa4dd815SMatthias Ringwald }
244aa4dd815SMatthias Ringwald 
245aa4dd815SMatthias Ringwald static int hfp_ag_send_call_waiting_notification(uint16_t cid){
246aa4dd815SMatthias Ringwald     char buffer[50];
247ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: \"%s\",%u\r\n",
248ff7d6aeaSMatthias Ringwald              HFP_ENABLE_CALL_WAITING_NOTIFICATION, hfp_gsm_clip_number(),
249ff7d6aeaSMatthias Ringwald              hfp_gsm_clip_type());
250ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
251aa4dd815SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
252aa4dd815SMatthias Ringwald }
253aa4dd815SMatthias Ringwald 
254485ac19eSMilanka Ringwald static int hfp_ag_send_error(uint16_t cid){
2553deb3ec6SMatthias Ringwald     char buffer[10];
256ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\nERROR\r\n");
257ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
2583deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
2593deb3ec6SMatthias Ringwald }
2603deb3ec6SMatthias Ringwald 
261485ac19eSMilanka Ringwald static int hfp_ag_send_report_extended_audio_gateway_error(uint16_t cid, uint8_t error){
2623deb3ec6SMatthias Ringwald     char buffer[20];
263ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s=%d\r\n",
264ff7d6aeaSMatthias Ringwald              HFP_EXTENDED_AUDIO_GATEWAY_ERROR, error);
265ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
2663deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
2673deb3ec6SMatthias Ringwald }
2683deb3ec6SMatthias Ringwald 
269ad902e3dSMatthias Ringwald // get size for indicator string
270a0ffb263SMatthias Ringwald static int hfp_ag_indicators_string_size(hfp_connection_t * hfp_connection, int i){
271ad902e3dSMatthias Ringwald     // template: ("$NAME",($MIN,$MAX))
27245718b6fSMatthias Ringwald     return 8 + (int) strlen(hfp_ag_get_ag_indicators(hfp_connection)[i].name)
273a0ffb263SMatthias Ringwald          + string_len_for_uint32(hfp_ag_get_ag_indicators(hfp_connection)[i].min_range)
274a0ffb263SMatthias Ringwald          + string_len_for_uint32(hfp_ag_get_ag_indicators(hfp_connection)[i].min_range);
275ad902e3dSMatthias Ringwald }
276ad902e3dSMatthias Ringwald 
277ad902e3dSMatthias Ringwald // store indicator
2781167ff83SMatthias Ringwald static void hfp_ag_indicators_string_store(hfp_connection_t * hfp_connection, int i, uint8_t * buffer, uint16_t buffer_size){
2791167ff83SMatthias Ringwald     snprintf((char *)buffer, buffer_size, "(\"%s\",(%d,%d)),",
280a0ffb263SMatthias Ringwald              hfp_ag_get_ag_indicators(hfp_connection)[i].name,
281a0ffb263SMatthias Ringwald              hfp_ag_get_ag_indicators(hfp_connection)[i].min_range,
282a0ffb263SMatthias Ringwald              hfp_ag_get_ag_indicators(hfp_connection)[i].max_range);
2831167ff83SMatthias Ringwald     ((char *)buffer)[buffer_size - 1] = 0;
2843deb3ec6SMatthias Ringwald }
285ad902e3dSMatthias Ringwald 
286ad902e3dSMatthias Ringwald // structure: header [indicator [comma indicator]] footer
287a0ffb263SMatthias Ringwald static int hfp_ag_indicators_cmd_generator_num_segments(hfp_connection_t * hfp_connection){
288a0ffb263SMatthias Ringwald     int num_indicators = hfp_ag_get_ag_indicators_nr(hfp_connection);
289ad902e3dSMatthias Ringwald     if (!num_indicators) return 2;
290c1ab6cc1SMatthias Ringwald     return 3 + ((num_indicators-1) * 2);
2913deb3ec6SMatthias Ringwald }
292ad902e3dSMatthias Ringwald 
293ad902e3dSMatthias Ringwald // get size of individual segment for hfp_ag_retrieve_indicators_cmd
294a0ffb263SMatthias Ringwald static int hfp_ag_indicators_cmd_generator_get_segment_len(hfp_connection_t * hfp_connection, int index){
295ad902e3dSMatthias Ringwald     if (index == 0) {
296ad902e3dSMatthias Ringwald         return strlen(HFP_INDICATOR) + 3;   // "\n\r%s:""
297ad902e3dSMatthias Ringwald     }
298ad902e3dSMatthias Ringwald     index--;
299a0ffb263SMatthias Ringwald     int num_indicators = hfp_ag_get_ag_indicators_nr(hfp_connection);
300ad902e3dSMatthias Ringwald     int indicator_index = index >> 1;
301ad902e3dSMatthias Ringwald     if ((index & 1) == 0){
302a0ffb263SMatthias Ringwald         return hfp_ag_indicators_string_size(hfp_connection, indicator_index);
303ad902e3dSMatthias Ringwald     }
304c1ab6cc1SMatthias Ringwald     if (indicator_index == (num_indicators - 1)){
305ad902e3dSMatthias Ringwald         return 8; // "\r\n\r\nOK\r\n"
306ad902e3dSMatthias Ringwald     }
307ad902e3dSMatthias Ringwald     return 1; // comma
308ad902e3dSMatthias Ringwald }
309ad902e3dSMatthias Ringwald 
3101167ff83SMatthias Ringwald static void hfp_ag_indicators_cmd_generator_store_segment(hfp_connection_t * hfp_connection, int index, uint8_t * buffer, uint16_t buffer_size){
311ad902e3dSMatthias Ringwald     if (index == 0){
312ad902e3dSMatthias Ringwald         *buffer++ = '\r';
31374386ee0SMatthias Ringwald         *buffer++ = '\n';
314ad902e3dSMatthias Ringwald         int len = strlen(HFP_INDICATOR);
3156535961aSMatthias Ringwald         (void)memcpy(buffer, HFP_INDICATOR, len);
316ad902e3dSMatthias Ringwald         buffer += len;
317ad902e3dSMatthias Ringwald         *buffer++ = ':';
318ad902e3dSMatthias Ringwald         return;
319ad902e3dSMatthias Ringwald     }
320ad902e3dSMatthias Ringwald     index--;
321a0ffb263SMatthias Ringwald     int num_indicators = hfp_ag_get_ag_indicators_nr(hfp_connection);
322ad902e3dSMatthias Ringwald     int indicator_index = index >> 1;
323ad902e3dSMatthias Ringwald     if ((index & 1) == 0){
3241167ff83SMatthias Ringwald         hfp_ag_indicators_string_store(hfp_connection, indicator_index, buffer, buffer_size);
325ad902e3dSMatthias Ringwald         return;
326ad902e3dSMatthias Ringwald     }
327c1ab6cc1SMatthias Ringwald     if (indicator_index == (num_indicators-1)){
3286535961aSMatthias Ringwald         (void)memcpy(buffer, "\r\n\r\nOK\r\n", 8);
329ad902e3dSMatthias Ringwald         return;
330ad902e3dSMatthias Ringwald     }
331ad902e3dSMatthias Ringwald     *buffer = ',';
3323deb3ec6SMatthias Ringwald }
3333deb3ec6SMatthias Ringwald 
3343deb3ec6SMatthias Ringwald static int hfp_hf_indicators_join(char * buffer, int buffer_size){
335c1ab6cc1SMatthias Ringwald     if (buffer_size < (hfp_ag_indicators_nr * 3)) return 0;
3363deb3ec6SMatthias Ringwald     int i;
3373deb3ec6SMatthias Ringwald     int offset = 0;
338c1ab6cc1SMatthias Ringwald     for (i = 0; i < (hfp_generic_status_indicators_nr-1); i++) {
339a0ffb263SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_generic_status_indicators[i].uuid);
3403deb3ec6SMatthias Ringwald     }
341a0ffb263SMatthias Ringwald     if (i < hfp_generic_status_indicators_nr){
342ae46d666SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_generic_status_indicators[i].uuid);
3433deb3ec6SMatthias Ringwald     }
3443deb3ec6SMatthias Ringwald     return offset;
3453deb3ec6SMatthias Ringwald }
3463deb3ec6SMatthias Ringwald 
3473deb3ec6SMatthias Ringwald static int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){
348c1ab6cc1SMatthias Ringwald     if (buffer_size < (hfp_generic_status_indicators_nr * 3)) return 0;
3493deb3ec6SMatthias Ringwald     int i;
3503deb3ec6SMatthias Ringwald     int offset = 0;
351a0ffb263SMatthias Ringwald     for (i = 0; i < hfp_generic_status_indicators_nr; i++) {
352a0ffb263SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "\r\n%s:%d,%d\r\n", HFP_GENERIC_STATUS_INDICATOR, hfp_generic_status_indicators[i].uuid, hfp_generic_status_indicators[i].state);
3533deb3ec6SMatthias Ringwald     }
3543deb3ec6SMatthias Ringwald     return offset;
3553deb3ec6SMatthias Ringwald }
3563deb3ec6SMatthias Ringwald 
3573deb3ec6SMatthias Ringwald static int hfp_ag_indicators_status_join(char * buffer, int buffer_size){
358c1ab6cc1SMatthias Ringwald     if (buffer_size < (hfp_ag_indicators_nr * 3)) return 0;
3593deb3ec6SMatthias Ringwald     int i;
3603deb3ec6SMatthias Ringwald     int offset = 0;
361c1ab6cc1SMatthias Ringwald     for (i = 0; i < (hfp_ag_indicators_nr-1); i++) {
3623deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status);
3633deb3ec6SMatthias Ringwald     }
3643deb3ec6SMatthias Ringwald     if (i<hfp_ag_indicators_nr){
3653deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status);
3663deb3ec6SMatthias Ringwald     }
3673deb3ec6SMatthias Ringwald     return offset;
3683deb3ec6SMatthias Ringwald }
3693deb3ec6SMatthias Ringwald 
3703deb3ec6SMatthias Ringwald static int hfp_ag_call_services_join(char * buffer, int buffer_size){
371c1ab6cc1SMatthias Ringwald     if (buffer_size < (hfp_ag_call_hold_services_nr * 3)) return 0;
3723deb3ec6SMatthias Ringwald     int i;
3733deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, buffer_size, "(");
374c1ab6cc1SMatthias Ringwald     for (i = 0; i < (hfp_ag_call_hold_services_nr-1); i++) {
3753deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]);
3763deb3ec6SMatthias Ringwald     }
3773deb3ec6SMatthias Ringwald     if (i<hfp_ag_call_hold_services_nr){
3783deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%s)", hfp_ag_call_hold_services[i]);
3793deb3ec6SMatthias Ringwald     }
3803deb3ec6SMatthias Ringwald     return offset;
3813deb3ec6SMatthias Ringwald }
3823deb3ec6SMatthias Ringwald 
383485ac19eSMilanka Ringwald static int hfp_ag_send_cmd_via_generator(uint16_t cid, hfp_connection_t * hfp_connection,
384ad902e3dSMatthias Ringwald     int start_segment, int num_segments,
385a0ffb263SMatthias Ringwald     int (*get_segment_len)(hfp_connection_t * hfp_connection, int segment),
3861167ff83SMatthias Ringwald     void (*store_segment) (hfp_connection_t * hfp_connection, int segment, uint8_t * buffer, uint16_t buffer_size)){
3873deb3ec6SMatthias Ringwald 
388ad902e3dSMatthias Ringwald     // assumes: can send now == true
389ad902e3dSMatthias Ringwald     // assumes: num segments > 0
390aba39421SMatthias Ringwald     // assumes: individual segments are smaller than MTU
391ad902e3dSMatthias Ringwald     rfcomm_reserve_packet_buffer();
392ad902e3dSMatthias Ringwald     int mtu = rfcomm_get_max_frame_size(cid);
393ad902e3dSMatthias Ringwald     uint8_t * data = rfcomm_get_outgoing_buffer();
394ad902e3dSMatthias Ringwald     int offset = 0;
395ad902e3dSMatthias Ringwald     int segment = start_segment;
396ad902e3dSMatthias Ringwald     while (segment < num_segments){
397a0ffb263SMatthias Ringwald         int segment_len = get_segment_len(hfp_connection, segment);
3981167ff83SMatthias Ringwald         if ((offset + segment_len + 1) > mtu) break;
3991167ff83SMatthias Ringwald         // append segment. As it appends a '\0', we provide a buffer one byte larger
4001167ff83SMatthias Ringwald         store_segment(hfp_connection, segment, data+offset, segment_len + 1);
401ad902e3dSMatthias Ringwald         offset += segment_len;
402ad902e3dSMatthias Ringwald         segment++;
403ad902e3dSMatthias Ringwald     }
404ad902e3dSMatthias Ringwald     rfcomm_send_prepared(cid, offset);
405f20dd2aeSBjoern Hartmann #ifdef ENABLE_HFP_AT_MESSAGES
406f20dd2aeSBjoern Hartmann     hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_SENT, (char *) data);
407f20dd2aeSBjoern Hartmann #endif
408ad902e3dSMatthias Ringwald     return segment;
409ad902e3dSMatthias Ringwald }
4103deb3ec6SMatthias Ringwald 
411ad902e3dSMatthias Ringwald // returns next segment to store
412485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_indicators_cmd_via_generator(uint16_t cid, hfp_connection_t * hfp_connection, int start_segment){
413a0ffb263SMatthias Ringwald     int num_segments = hfp_ag_indicators_cmd_generator_num_segments(hfp_connection);
414485ac19eSMilanka Ringwald     return hfp_ag_send_cmd_via_generator(cid, hfp_connection, start_segment, num_segments,
415894d499cSMatthias Ringwald                                          hfp_ag_indicators_cmd_generator_get_segment_len,
416894d499cSMatthias Ringwald                                          hfp_ag_indicators_cmd_generator_store_segment);
4173deb3ec6SMatthias Ringwald }
4183deb3ec6SMatthias Ringwald 
419485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_indicators_status_cmd(uint16_t cid){
4203deb3ec6SMatthias Ringwald     char buffer[40];
42189425bfcSMilanka Ringwald     const int size = sizeof(buffer);
42289425bfcSMilanka Ringwald     int offset = snprintf(buffer, size, "\r\n%s:", HFP_INDICATOR);
42389425bfcSMilanka Ringwald     offset += hfp_ag_indicators_status_join(buffer+offset, size-offset-9);
42489425bfcSMilanka Ringwald     offset += snprintf(buffer+offset, size-offset, "\r\n\r\nOK\r\n");
4253deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
4263deb3ec6SMatthias Ringwald }
4273deb3ec6SMatthias Ringwald 
428485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_can_hold_call_cmd(uint16_t cid){
429ad902e3dSMatthias Ringwald     char buffer[40];
43089425bfcSMilanka Ringwald     const int size = sizeof(buffer);
43189425bfcSMilanka Ringwald     int offset = snprintf(buffer, size, "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
43289425bfcSMilanka Ringwald     offset += hfp_ag_call_services_join(buffer+offset, size-offset-9);
43389425bfcSMilanka Ringwald     offset += snprintf(buffer+offset, size-offset, "\r\n\r\nOK\r\n");
4343deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
4353deb3ec6SMatthias Ringwald }
4363deb3ec6SMatthias Ringwald 
4373deb3ec6SMatthias Ringwald 
438485ac19eSMilanka Ringwald static int hfp_ag_send_list_supported_generic_status_indicators_cmd(uint16_t cid){
439485ac19eSMilanka Ringwald     return hfp_ag_send_ok(cid);
4403deb3ec6SMatthias Ringwald }
4413deb3ec6SMatthias Ringwald 
442485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){
4433deb3ec6SMatthias Ringwald     char buffer[40];
44489425bfcSMilanka Ringwald     const int size = sizeof(buffer);
44589425bfcSMilanka Ringwald     int offset = snprintf(buffer, size, "\r\n%s:(", HFP_GENERIC_STATUS_INDICATOR);
44689425bfcSMilanka Ringwald     offset += hfp_hf_indicators_join(buffer+offset, size-offset-10);
44789425bfcSMilanka Ringwald     offset += snprintf(buffer+offset, size-offset, ")\r\n\r\nOK\r\n");
4483deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
4493deb3ec6SMatthias Ringwald }
4503deb3ec6SMatthias Ringwald 
451485ac19eSMilanka Ringwald static int hfp_ag_send_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t cid){
4523deb3ec6SMatthias Ringwald     char buffer[40];
4531cc1d9e9SMilanka Ringwald     int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer) - 7);
4541cc1d9e9SMilanka Ringwald     snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
4553deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
4563deb3ec6SMatthias Ringwald }
4573deb3ec6SMatthias Ringwald 
458485ac19eSMilanka Ringwald static int hfp_ag_send_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t * indicator){
4593deb3ec6SMatthias Ringwald     char buffer[20];
460ff7d6aeaSMatthias Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s:%d,%d\r\n",
461ff7d6aeaSMatthias Ringwald              HFP_TRANSFER_AG_INDICATOR_STATUS, indicator->index,
462ff7d6aeaSMatthias Ringwald              indicator->status);
463ff7d6aeaSMatthias Ringwald     buffer[sizeof(buffer) - 1] = 0;
4643deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
4653deb3ec6SMatthias Ringwald }
4663deb3ec6SMatthias Ringwald 
467485ac19eSMilanka Ringwald static int hfp_ag_send_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){
4685e71456cSMilanka Ringwald     char buffer[41];
4693deb3ec6SMatthias Ringwald     if (strlen(op.name) == 0){
47089425bfcSMilanka Ringwald         snprintf(buffer, sizeof(buffer), "\r\n%s:%d,,\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode);
4713deb3ec6SMatthias Ringwald     } else {
47289425bfcSMilanka Ringwald         int offset = snprintf(buffer,  sizeof(buffer), "\r\n%s:%d,%d,", HFP_QUERY_OPERATOR_SELECTION, op.mode, op.format);
4735e71456cSMilanka Ringwald         offset += snprintf(buffer+offset, 16, "%s", op.name);
47489425bfcSMilanka Ringwald         snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
4753deb3ec6SMatthias Ringwald     }
4763deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
4773deb3ec6SMatthias Ringwald }
4783deb3ec6SMatthias Ringwald 
479a04aecb1SMilanka Ringwald static inline int hfp_ag_send_cmd_with_space_and_int(uint16_t cid, const char * cmd, uint8_t value){
480a04aecb1SMilanka Ringwald     char buffer[30];
481a04aecb1SMilanka Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: %d\r\n", cmd, value);
482a04aecb1SMilanka Ringwald     return send_str_over_rfcomm(cid, buffer);
483a04aecb1SMilanka Ringwald }
484a04aecb1SMilanka Ringwald 
485a04aecb1SMilanka Ringwald 
4861cc1d9e9SMilanka Ringwald static inline int hfp_ag_send_cmd_with_int(uint16_t cid, const char * cmd, uint8_t value){
4871cc1d9e9SMilanka Ringwald     char buffer[30];
48889425bfcSMilanka Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s:%d\r\n", cmd, value);
4891cc1d9e9SMilanka Ringwald     return send_str_over_rfcomm(cid, buffer);
4901cc1d9e9SMilanka Ringwald }
4913deb3ec6SMatthias Ringwald 
492485ac19eSMilanka Ringwald static int hfp_ag_send_suggest_codec_cmd(uint16_t cid, uint8_t codec){
4931cc1d9e9SMilanka Ringwald     return hfp_ag_send_cmd_with_int(cid, HFP_CONFIRM_COMMON_CODEC, codec);
4943deb3ec6SMatthias Ringwald }
4953deb3ec6SMatthias Ringwald 
496485ac19eSMilanka Ringwald static int hfp_ag_send_activate_voice_recognition_cmd(uint16_t cid, uint8_t activate_voice_recognition){
497a04aecb1SMilanka Ringwald     return hfp_ag_send_cmd_with_space_and_int(cid, HFP_ACTIVATE_VOICE_RECOGNITION, activate_voice_recognition);
498aa4dd815SMatthias Ringwald }
499aa4dd815SMatthias Ringwald 
500485ac19eSMilanka Ringwald static int hfp_ag_send_set_speaker_gain_cmd(uint16_t cid, uint8_t gain){
5011cc1d9e9SMilanka Ringwald     return hfp_ag_send_cmd_with_int(cid, HFP_SET_SPEAKER_GAIN, gain);
502aa4dd815SMatthias Ringwald }
503aa4dd815SMatthias Ringwald 
504485ac19eSMilanka Ringwald static int hfp_ag_send_set_microphone_gain_cmd(uint16_t cid, uint8_t gain){
5051cc1d9e9SMilanka Ringwald     return hfp_ag_send_cmd_with_int(cid, HFP_SET_MICROPHONE_GAIN, gain);
506aa4dd815SMatthias Ringwald }
507aa4dd815SMatthias Ringwald 
508485ac19eSMilanka Ringwald static int hfp_ag_send_set_response_and_hold(uint16_t cid, int state){
50966191aa0SMilanka Ringwald     return hfp_ag_send_cmd_with_space_and_int(cid, HFP_RESPONSE_AND_HOLD, state);
510ce263fc8SMatthias Ringwald }
511ce263fc8SMatthias Ringwald 
512*45796ff1SMilanka Ringwald static int hfp_ag_send_enhanced_voice_recognition_cmd(uint16_t cid, uint8_t status, uint8_t state){
513*45796ff1SMilanka Ringwald     char buffer[30];
514*45796ff1SMilanka Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: %d,%d\r\n", HFP_ACTIVATE_VOICE_RECOGNITION, status, state);
515*45796ff1SMilanka Ringwald     return send_str_over_rfcomm(cid, buffer);
516*45796ff1SMilanka Ringwald }
517*45796ff1SMilanka Ringwald 
518*45796ff1SMilanka Ringwald static int hfp_ag_send_enhanced_voice_recognition_msg_cmd(hfp_connection_t *hfp_connection){
519*45796ff1SMilanka Ringwald     char buffer[100];
520*45796ff1SMilanka Ringwald     snprintf(buffer, sizeof(buffer), "\r\n%s: 1,%d,%X,%d,%d,\"%s\"\r\n", HFP_ACTIVATE_VOICE_RECOGNITION,
521*45796ff1SMilanka Ringwald         hfp_connection->ag_vra_state,
522*45796ff1SMilanka Ringwald         hfp_connection->ag_msg.text_id,
523*45796ff1SMilanka Ringwald         hfp_connection->ag_msg.text_type,
524*45796ff1SMilanka Ringwald         hfp_connection->ag_msg.text_operation,
525*45796ff1SMilanka Ringwald         hfp_connection->ag_msg.text);
526*45796ff1SMilanka Ringwald     return send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
527*45796ff1SMilanka Ringwald }
528*45796ff1SMilanka Ringwald 
529a0ffb263SMatthias Ringwald static uint8_t hfp_ag_suggest_codec(hfp_connection_t *hfp_connection){
530bc1b1537SMilanka Ringwald     if (hfp_connection->sco_for_msbc_failed) return HFP_CODEC_CVSD;
531bc1b1537SMilanka Ringwald 
5326a7f44bdSMilanka Ringwald     if (hfp_supports_codec(HFP_CODEC_MSBC, hfp_codecs_nr, hfp_codecs)){
5336a7f44bdSMilanka Ringwald         if (hfp_supports_codec(HFP_CODEC_MSBC, hfp_connection->remote_codecs_nr, hfp_connection->remote_codecs)){
534df327ff3SMilanka Ringwald             return HFP_CODEC_MSBC;
5353deb3ec6SMatthias Ringwald         }
5363deb3ec6SMatthias Ringwald     }
537df327ff3SMilanka Ringwald     return HFP_CODEC_CVSD;
5383deb3ec6SMatthias Ringwald }
5393deb3ec6SMatthias Ringwald 
54076cc1527SMatthias Ringwald /* state machines */
54176cc1527SMatthias Ringwald 
542afac2a04SMilanka Ringwald static uint8_t hfp_ag_esco_s4_supported(hfp_connection_t * hfp_connection){
543afac2a04SMilanka Ringwald     return (hfp_connection->remote_supported_features & (1<<HFP_HFSF_ESCO_S4)) &&  (hfp_supported_features  & (1<<HFP_AGSF_ESCO_S4));
5447522e673SMatthias Ringwald }
5457522e673SMatthias Ringwald 
546a0ffb263SMatthias Ringwald static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
547aa4dd815SMatthias Ringwald     /* events ( == commands):
548aa4dd815SMatthias Ringwald         HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs
549aa4dd815SMatthias Ringwald         HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
550aa4dd815SMatthias Ringwald             hf_trigger_codec_connection_setup == received BCC
551aa4dd815SMatthias Ringwald             ag_trigger_codec_connection_setup == received from AG to send BCS
552aa4dd815SMatthias Ringwald         HFP_CMD_HF_CONFIRMED_CODEC == received AT+BCS
553aa4dd815SMatthias Ringwald     */
554a0ffb263SMatthias Ringwald     switch (hfp_connection->codecs_state){
5553e3b9207SMilanka Ringwald         case HFP_CODECS_EXCHANGED:
5563e3b9207SMilanka Ringwald             if (hfp_connection->command == HFP_CMD_AVAILABLE_CODECS){
5573e3b9207SMilanka Ringwald                 hfp_ag_send_ok(hfp_connection->rfcomm_cid);
5583e3b9207SMilanka Ringwald                 return 1;
5593e3b9207SMilanka Ringwald             }
5603e3b9207SMilanka Ringwald             break;
5613e3b9207SMilanka Ringwald 
562aa4dd815SMatthias Ringwald         case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE:
563a0ffb263SMatthias Ringwald             hfp_connection->command = HFP_CMD_AG_SEND_COMMON_CODEC;
564aa4dd815SMatthias Ringwald             break;
565aa4dd815SMatthias Ringwald         case HFP_CODECS_AG_RESEND_COMMON_CODEC:
566a0ffb263SMatthias Ringwald             hfp_connection->command = HFP_CMD_AG_SEND_COMMON_CODEC;
567aa4dd815SMatthias Ringwald             break;
568aa4dd815SMatthias Ringwald         default:
569aa4dd815SMatthias Ringwald             break;
570aa4dd815SMatthias Ringwald     }
571aa4dd815SMatthias Ringwald 
572a0ffb263SMatthias Ringwald     switch (hfp_connection->command){
573aa4dd815SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
574a0ffb263SMatthias Ringwald             if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){
575a0ffb263SMatthias Ringwald                 hfp_connection->codecs_state = HFP_CODECS_RECEIVED_LIST;
576485ac19eSMilanka Ringwald                 hfp_ag_send_ok(hfp_connection->rfcomm_cid);
577aa4dd815SMatthias Ringwald                 return 1;
578aa4dd815SMatthias Ringwald             }
579aa4dd815SMatthias Ringwald 
580a0ffb263SMatthias Ringwald             switch (hfp_connection->codecs_state){
581aa4dd815SMatthias Ringwald                 case HFP_CODECS_AG_SENT_COMMON_CODEC:
582a0ffb263SMatthias Ringwald                     hfp_connection->codecs_state = HFP_CODECS_AG_RESEND_COMMON_CODEC;
583aa4dd815SMatthias Ringwald                     break;
584aa4dd815SMatthias Ringwald                 default:
585aa4dd815SMatthias Ringwald                     break;
586aa4dd815SMatthias Ringwald             }
587485ac19eSMilanka Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
588aa4dd815SMatthias Ringwald             return 1;
589aa4dd815SMatthias Ringwald 
590aa4dd815SMatthias Ringwald         case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
591a0ffb263SMatthias Ringwald             hfp_connection->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE;
59240e8d6c5SMatthias Ringwald             hfp_connection->establish_audio_connection = 1;
593485ac19eSMilanka Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
594aa4dd815SMatthias Ringwald             return 1;
595aa4dd815SMatthias Ringwald 
596aa4dd815SMatthias Ringwald         case HFP_CMD_AG_SEND_COMMON_CODEC:
597a0ffb263SMatthias Ringwald             hfp_connection->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC;
598a0ffb263SMatthias Ringwald             hfp_connection->suggested_codec = hfp_ag_suggest_codec(hfp_connection);
599485ac19eSMilanka Ringwald             hfp_ag_send_suggest_codec_cmd(hfp_connection->rfcomm_cid, hfp_connection->suggested_codec);
600aa4dd815SMatthias Ringwald             return 1;
601aa4dd815SMatthias Ringwald 
602aa4dd815SMatthias Ringwald         case HFP_CMD_HF_CONFIRMED_CODEC:
603a0ffb263SMatthias Ringwald             if (hfp_connection->codec_confirmed != hfp_connection->suggested_codec){
604a0ffb263SMatthias Ringwald                 hfp_connection->codecs_state = HFP_CODECS_ERROR;
605485ac19eSMilanka Ringwald                 hfp_ag_send_error(hfp_connection->rfcomm_cid);
606aa4dd815SMatthias Ringwald                 return 1;
607aa4dd815SMatthias Ringwald             }
608a0ffb263SMatthias Ringwald             hfp_connection->negotiated_codec = hfp_connection->codec_confirmed;
609a0ffb263SMatthias Ringwald             hfp_connection->codecs_state = HFP_CODECS_EXCHANGED;
610c1ab6cc1SMatthias Ringwald             log_info("hfp: codec confirmed: %s", (hfp_connection->negotiated_codec == HFP_CODEC_MSBC) ? "mSBC" : "CVSD");
611485ac19eSMilanka Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
6127522e673SMatthias Ringwald             // now, pick link settings
613afac2a04SMilanka Ringwald             hfp_init_link_settings(hfp_connection, hfp_ag_esco_s4_supported(hfp_connection));
6143721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP
6153721a235SMatthias Ringwald             hfp_cc256x_prepare_for_sco(hfp_connection);
6163721a235SMatthias Ringwald #endif
617aa4dd815SMatthias Ringwald             return 1;
618aa4dd815SMatthias Ringwald         default:
619aa4dd815SMatthias Ringwald             break;
620aa4dd815SMatthias Ringwald     }
621aa4dd815SMatthias Ringwald     return 0;
622aa4dd815SMatthias Ringwald }
623aa4dd815SMatthias Ringwald 
624a0ffb263SMatthias Ringwald static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
625a0ffb263SMatthias Ringwald     hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
626ca59be51SMatthias Ringwald     hfp_emit_slc_connection_event(hfp_connection, 0, hfp_connection->acl_handle, hfp_connection->remote_addr);
627aa4dd815SMatthias Ringwald 
628a0ffb263SMatthias Ringwald     // if active call exist, set per-hfp_connection state active, too (when audio is on)
629d0c20769SMatthias Ringwald     if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
630a0ffb263SMatthias Ringwald         hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE;
631aa4dd815SMatthias Ringwald     }
632ce263fc8SMatthias Ringwald     // if AG is ringing, also start ringing on the HF
633c1ab6cc1SMatthias Ringwald     if ((hfp_gsm_call_status() == HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) &&
634505f1c30SMatthias Ringwald         (hfp_gsm_callsetup_status() == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS)){
635a0ffb263SMatthias Ringwald         hfp_ag_hf_start_ringing(hfp_connection);
636ce263fc8SMatthias Ringwald     }
637aa4dd815SMatthias Ringwald }
6383deb3ec6SMatthias Ringwald 
639a0ffb263SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * hfp_connection){
640c79b4cabSMatthias Ringwald     // log_info("hfp_ag_run_for_context_service_level_connection state %u, command %u", hfp_connection->state, hfp_connection->command);
641a0ffb263SMatthias Ringwald     if (hfp_connection->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
642c04cf7ffSMilanka Ringwald     int sent = 0;
643a0ffb263SMatthias Ringwald     switch(hfp_connection->command){
6443deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORTED_FEATURES:
645a0ffb263SMatthias Ringwald             switch(hfp_connection->state){
6463deb3ec6SMatthias Ringwald                 case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
647aa4dd815SMatthias Ringwald                 case HFP_EXCHANGE_SUPPORTED_FEATURES:
648d715cf51SMatthias Ringwald                     hfp_hf_drop_mSBC_if_eSCO_not_supported(hfp_codecs, &hfp_codecs_nr);
649a0ffb263SMatthias Ringwald                     if (has_codec_negotiation_feature(hfp_connection)){
650a0ffb263SMatthias Ringwald                         hfp_connection->state = HFP_W4_NOTIFY_ON_CODECS;
651aa4dd815SMatthias Ringwald                     } else {
652a0ffb263SMatthias Ringwald                         hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS;
653aa4dd815SMatthias Ringwald                     }
654a0ffb263SMatthias Ringwald                     hfp_ag_exchange_supported_features_cmd(hfp_connection->rfcomm_cid);
655aa4dd815SMatthias Ringwald                     return 1;
6563deb3ec6SMatthias Ringwald                 default:
6573deb3ec6SMatthias Ringwald                     break;
6583deb3ec6SMatthias Ringwald             }
6593deb3ec6SMatthias Ringwald             break;
6603deb3ec6SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
661c04cf7ffSMilanka Ringwald             sent = codecs_exchange_state_machine(hfp_connection);
662a0ffb263SMatthias Ringwald             if (hfp_connection->codecs_state == HFP_CODECS_RECEIVED_LIST){
663a0ffb263SMatthias Ringwald                 hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS;
6643deb3ec6SMatthias Ringwald             }
665c04cf7ffSMilanka Ringwald             return sent;
666aa4dd815SMatthias Ringwald 
667aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_AG_INDICATORS:
668a0ffb263SMatthias Ringwald             if (hfp_connection->state == HFP_W4_RETRIEVE_INDICATORS) {
669473ac565SMatthias Ringwald                 // HF requested AG Indicators and we did expect it
67084a0c24eSMatthias Ringwald                 hfp_connection->send_ag_indicators_segment = 0;
671473ac565SMatthias Ringwald                 hfp_connection->state = HFP_RETRIEVE_INDICATORS;
672473ac565SMatthias Ringwald                 // continue below in state switch
673ad902e3dSMatthias Ringwald             }
674ad902e3dSMatthias Ringwald             break;
675aa4dd815SMatthias Ringwald 
676aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
677a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break;
678a0ffb263SMatthias Ringwald             hfp_connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
679485ac19eSMilanka Ringwald             hfp_ag_send_retrieve_indicators_status_cmd(hfp_connection->rfcomm_cid);
680aa4dd815SMatthias Ringwald             return 1;
681aa4dd815SMatthias Ringwald 
6823deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
683a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE) break;
684a0ffb263SMatthias Ringwald             if (has_call_waiting_and_3way_calling_feature(hfp_connection)){
685a0ffb263SMatthias Ringwald                 hfp_connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
686a0ffb263SMatthias Ringwald             } else if (has_hf_indicators_feature(hfp_connection)){
687a0ffb263SMatthias Ringwald                 hfp_connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
688aa4dd815SMatthias Ringwald             } else {
689a0ffb263SMatthias Ringwald                 hfp_ag_slc_established(hfp_connection);
6903deb3ec6SMatthias Ringwald             }
6918a46ec40SMatthias Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
692aa4dd815SMatthias Ringwald             return 1;
6933deb3ec6SMatthias Ringwald 
694aa4dd815SMatthias Ringwald         case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
695a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break;
696a0ffb263SMatthias Ringwald             if (has_hf_indicators_feature(hfp_connection)){
697a0ffb263SMatthias Ringwald                 hfp_connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
698aa4dd815SMatthias Ringwald             }
699485ac19eSMilanka Ringwald             hfp_ag_send_retrieve_can_hold_call_cmd(hfp_connection->rfcomm_cid);
700a0ffb263SMatthias Ringwald             if (!has_hf_indicators_feature(hfp_connection)){
701a0ffb263SMatthias Ringwald                 hfp_ag_slc_established(hfp_connection);
702ce263fc8SMatthias Ringwald             }
703aa4dd815SMatthias Ringwald             return 1;
704aa4dd815SMatthias Ringwald 
705aa4dd815SMatthias Ringwald         case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
706a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_W4_LIST_GENERIC_STATUS_INDICATORS) break;
707a0ffb263SMatthias Ringwald             hfp_connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
708485ac19eSMilanka Ringwald             hfp_ag_send_list_supported_generic_status_indicators_cmd(hfp_connection->rfcomm_cid);
709aa4dd815SMatthias Ringwald             return 1;
710aa4dd815SMatthias Ringwald 
711aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
712a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS) break;
713a0ffb263SMatthias Ringwald             hfp_connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
714485ac19eSMilanka Ringwald             hfp_ag_send_retrieve_supported_generic_status_indicators_cmd(hfp_connection->rfcomm_cid);
715aa4dd815SMatthias Ringwald             return 1;
716aa4dd815SMatthias Ringwald 
717aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
718a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS) break;
719a0ffb263SMatthias Ringwald             hfp_ag_slc_established(hfp_connection);
720485ac19eSMilanka Ringwald             hfp_ag_send_retrieve_initital_supported_generic_status_indicators_cmd(hfp_connection->rfcomm_cid);
721aa4dd815SMatthias Ringwald             return 1;
7223deb3ec6SMatthias Ringwald         default:
7233deb3ec6SMatthias Ringwald             break;
7243deb3ec6SMatthias Ringwald     }
725473ac565SMatthias Ringwald 
726473ac565SMatthias Ringwald     switch (hfp_connection->state){
727473ac565SMatthias Ringwald         case HFP_RETRIEVE_INDICATORS: {
728485ac19eSMilanka Ringwald             int next_segment = hfp_ag_send_retrieve_indicators_cmd_via_generator(hfp_connection->rfcomm_cid, hfp_connection, hfp_connection->send_ag_indicators_segment);
729473ac565SMatthias Ringwald             int num_segments = hfp_ag_indicators_cmd_generator_num_segments(hfp_connection);
730473ac565SMatthias Ringwald             log_info("HFP_CMD_RETRIEVE_AG_INDICATORS next segment %u, num_segments %u", next_segment, num_segments);
731473ac565SMatthias Ringwald             if (next_segment < num_segments){
732473ac565SMatthias Ringwald                 // prepare sending of next segment
733473ac565SMatthias Ringwald                 hfp_connection->send_ag_indicators_segment = next_segment;
734473ac565SMatthias Ringwald                 log_info("HFP_CMD_RETRIEVE_AG_INDICATORS more. command %u, next seg %u", hfp_connection->command, next_segment);
735473ac565SMatthias Ringwald             } else {
736473ac565SMatthias Ringwald                 // done, go to next state
737473ac565SMatthias Ringwald                 hfp_connection->send_ag_indicators_segment = 0;
738473ac565SMatthias Ringwald                 hfp_connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
739473ac565SMatthias Ringwald             }
740473ac565SMatthias Ringwald             return 1;
741473ac565SMatthias Ringwald         }
742473ac565SMatthias Ringwald         default:
743473ac565SMatthias Ringwald             break;
744473ac565SMatthias Ringwald     }
745c04cf7ffSMilanka Ringwald     return 0;
7463deb3ec6SMatthias Ringwald }
7473deb3ec6SMatthias Ringwald 
748a0ffb263SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){
749c04cf7ffSMilanka Ringwald     int sent = codecs_exchange_state_machine(hfp_connection);
750c04cf7ffSMilanka Ringwald     if (sent) return 1;
751aa4dd815SMatthias Ringwald 
752a0ffb263SMatthias Ringwald     switch(hfp_connection->command){
753aa4dd815SMatthias Ringwald         case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
754485ac19eSMilanka Ringwald             hfp_ag_send_activate_voice_recognition_cmd(hfp_connection->rfcomm_cid, hfp_connection->ag_activate_voice_recognition);
75505ce4bb6SMilanka Ringwald             if (hfp_connection->ag_activate_voice_recognition > 0){
75605ce4bb6SMilanka Ringwald                 hfp_ag_setup_audio_connection(hfp_connection);
75705ce4bb6SMilanka Ringwald             } else {
75805ce4bb6SMilanka Ringwald                 hfp_release_audio_connection(hfp_connection);
75905ce4bb6SMilanka Ringwald             }
760aa4dd815SMatthias Ringwald             return 1;
761*45796ff1SMilanka Ringwald 
762*45796ff1SMilanka Ringwald         case HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION:
763*45796ff1SMilanka Ringwald             switch (hfp_connection->ag_vra_status){
764*45796ff1SMilanka Ringwald                 case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED:
765*45796ff1SMilanka Ringwald                     hfp_connection->ag_vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
766*45796ff1SMilanka Ringwald                     hfp_ag_send_enhanced_voice_recognition_cmd(hfp_connection->rfcomm_cid, 1, hfp_connection->ag_vra_state);
767*45796ff1SMilanka Ringwald                     hfp_ag_setup_audio_connection(hfp_connection);
768*45796ff1SMilanka Ringwald                     break;
769*45796ff1SMilanka Ringwald                 case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS:
770*45796ff1SMilanka Ringwald                     hfp_connection->ag_vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
771*45796ff1SMilanka Ringwald                     hfp_ag_send_enhanced_voice_recognition_cmd(hfp_connection->rfcomm_cid, 1, hfp_connection->ag_vra_state);
772*45796ff1SMilanka Ringwald                     break;
773*45796ff1SMilanka Ringwald                 case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF:
774*45796ff1SMilanka Ringwald                     hfp_connection->ag_vra_status = HFP_VRA_VOICE_RECOGNITION_OFF;
775*45796ff1SMilanka Ringwald                     hfp_ag_send_enhanced_voice_recognition_cmd(hfp_connection->rfcomm_cid, 0, hfp_connection->ag_vra_state);
776*45796ff1SMilanka Ringwald                     hfp_release_audio_connection(hfp_connection);
777*45796ff1SMilanka Ringwald                     break;
778*45796ff1SMilanka Ringwald                 case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_MSG:
779*45796ff1SMilanka Ringwald                     hfp_connection->ag_vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
780*45796ff1SMilanka Ringwald                     hfp_ag_send_enhanced_voice_recognition_msg_cmd(hfp_connection);
781*45796ff1SMilanka Ringwald                     break;
782*45796ff1SMilanka Ringwald                 default:
783*45796ff1SMilanka Ringwald                     return 0;
784*45796ff1SMilanka Ringwald             }
785*45796ff1SMilanka Ringwald             return 1;
786*45796ff1SMilanka Ringwald 
787aa4dd815SMatthias Ringwald         case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
788*45796ff1SMilanka Ringwald 
789aa4dd815SMatthias Ringwald             if (get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)){
790485ac19eSMilanka Ringwald                 hfp_ag_send_ok(hfp_connection->rfcomm_cid);
791aa4dd815SMatthias Ringwald             } else {
792*45796ff1SMilanka Ringwald                 switch (hfp_connection->ag_vra_status){
793*45796ff1SMilanka Ringwald                     case HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED:
794*45796ff1SMilanka Ringwald                         hfp_ag_send_ok(hfp_connection->rfcomm_cid);
795*45796ff1SMilanka Ringwald                         break;
796*45796ff1SMilanka Ringwald                     default:
797485ac19eSMilanka Ringwald                         hfp_ag_send_error(hfp_connection->rfcomm_cid);
798*45796ff1SMilanka Ringwald                         break;
799*45796ff1SMilanka Ringwald                 }
800aa4dd815SMatthias Ringwald             }
801aa4dd815SMatthias Ringwald             return 1;
802aa4dd815SMatthias Ringwald         case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
803485ac19eSMilanka Ringwald             hfp_ag_send_change_in_band_ring_tone_setting_cmd(hfp_connection->rfcomm_cid);
804aa4dd815SMatthias Ringwald             return 1;
805aa4dd815SMatthias Ringwald         case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
806485ac19eSMilanka Ringwald             hfp_ag_send_report_network_operator_name_cmd(hfp_connection->rfcomm_cid, hfp_connection->network_operator);
807aa4dd815SMatthias Ringwald             return 1;
808aa4dd815SMatthias Ringwald         case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
809a0ffb263SMatthias Ringwald             if (hfp_connection->network_operator.format != 0){
810485ac19eSMilanka Ringwald                 hfp_ag_send_error(hfp_connection->rfcomm_cid);
811aa4dd815SMatthias Ringwald             } else {
812485ac19eSMilanka Ringwald                 hfp_ag_send_ok(hfp_connection->rfcomm_cid);
8133deb3ec6SMatthias Ringwald             }
814aa4dd815SMatthias Ringwald             return 1;
815aa4dd815SMatthias Ringwald         case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
816485ac19eSMilanka Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
817aa4dd815SMatthias Ringwald             return 1;
8183deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
819a0ffb263SMatthias Ringwald             if (hfp_connection->extended_audio_gateway_error){
820a0ffb263SMatthias Ringwald                 hfp_connection->extended_audio_gateway_error = 0;
821485ac19eSMilanka Ringwald                 hfp_ag_send_report_extended_audio_gateway_error(hfp_connection->rfcomm_cid, hfp_connection->extended_audio_gateway_error_value);
822aa4dd815SMatthias Ringwald                 return 1;
8233deb3ec6SMatthias Ringwald             }
824202c8a4cSMatthias Ringwald             break;
8253deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
826485ac19eSMilanka Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
827ce263fc8SMatthias Ringwald             return 1;
8283deb3ec6SMatthias Ringwald         default:
8293deb3ec6SMatthias Ringwald             break;
8303deb3ec6SMatthias Ringwald     }
831aa4dd815SMatthias Ringwald     return 0;
8323deb3ec6SMatthias Ringwald }
8333deb3ec6SMatthias Ringwald 
834a0ffb263SMatthias Ringwald static int hfp_ag_run_for_audio_connection(hfp_connection_t * hfp_connection){
835505f1c30SMatthias Ringwald     if ((hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) ||
836505f1c30SMatthias Ringwald         (hfp_connection->state > HFP_W2_DISCONNECT_SCO)) return 0;
8373deb3ec6SMatthias Ringwald 
838a0ffb263SMatthias Ringwald     if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return 0;
839aa4dd815SMatthias Ringwald 
84029cddf58SMatthias Ringwald     // accept incoming audio connection (codec negotiation is not used)
84129cddf58SMatthias Ringwald     if (hfp_connection->accept_sco){
84229cddf58SMatthias Ringwald         // notify about codec selection if not done already
84329cddf58SMatthias Ringwald         if (hfp_connection->negotiated_codec == 0){
84429cddf58SMatthias Ringwald             hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
84529cddf58SMatthias Ringwald         }
84629cddf58SMatthias Ringwald         //
84729cddf58SMatthias Ringwald         bool incoming_eSCO = hfp_connection->accept_sco == 2;
84829cddf58SMatthias Ringwald         hfp_connection->accept_sco = 0;
84929cddf58SMatthias Ringwald         hfp_connection->state = HFP_W4_SCO_CONNECTED;
85029cddf58SMatthias Ringwald         hfp_accept_synchronous_connection(hfp_connection, incoming_eSCO);
85129cddf58SMatthias Ringwald         return 1;
85229cddf58SMatthias Ringwald     }
85329cddf58SMatthias Ringwald 
854aa4dd815SMatthias Ringwald     // run codecs exchange
855c04cf7ffSMilanka Ringwald     int sent = codecs_exchange_state_machine(hfp_connection);
856c04cf7ffSMilanka Ringwald     if (sent) return 1;
857aa4dd815SMatthias Ringwald 
858c04cf7ffSMilanka Ringwald     if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return 0;
859a0ffb263SMatthias Ringwald     if (hfp_connection->establish_audio_connection){
860a0ffb263SMatthias Ringwald         hfp_connection->state = HFP_W4_SCO_CONNECTED;
861a0ffb263SMatthias Ringwald         hfp_connection->establish_audio_connection = 0;
862eddcd308SMatthias Ringwald         hfp_setup_synchronous_connection(hfp_connection);
863aa4dd815SMatthias Ringwald         return 1;
864aa4dd815SMatthias Ringwald     }
865aa4dd815SMatthias Ringwald     return 0;
866aa4dd815SMatthias Ringwald }
867aa4dd815SMatthias Ringwald 
868ec820d77SMatthias Ringwald static hfp_connection_t * hfp_ag_context_for_timer(btstack_timer_source_t * ts){
869665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
870665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
871aa4dd815SMatthias Ringwald 
872665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
873a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
874a0ffb263SMatthias Ringwald         if ( & hfp_connection->hfp_timeout == ts) {
875a0ffb263SMatthias Ringwald             return hfp_connection;
876aa4dd815SMatthias Ringwald         }
877aa4dd815SMatthias Ringwald     }
878aa4dd815SMatthias Ringwald     return NULL;
879aa4dd815SMatthias Ringwald }
880aa4dd815SMatthias Ringwald 
881ec820d77SMatthias Ringwald static void hfp_timeout_handler(btstack_timer_source_t * timer){
882d63c37a1SMatthias Ringwald     hfp_connection_t * hfp_connection = hfp_ag_context_for_timer(timer);
883d63c37a1SMatthias Ringwald     if (!hfp_connection) return;
884aa4dd815SMatthias Ringwald 
885d63c37a1SMatthias Ringwald     log_info("HFP start ring timeout, con handle 0x%02x", hfp_connection->acl_handle);
886a0ffb263SMatthias Ringwald     hfp_connection->ag_ring = 1;
887a0ffb263SMatthias Ringwald     hfp_connection->ag_send_clip = hfp_gsm_clip_type() && hfp_connection->clip_enabled;
888aa4dd815SMatthias Ringwald 
889a0ffb263SMatthias Ringwald     btstack_run_loop_set_timer(& hfp_connection->hfp_timeout, 2000); // 2 seconds timeout
890a0ffb263SMatthias Ringwald     btstack_run_loop_add_timer(& hfp_connection->hfp_timeout);
891aa4dd815SMatthias Ringwald 
892f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
893aa4dd815SMatthias Ringwald }
894aa4dd815SMatthias Ringwald 
895a0ffb263SMatthias Ringwald static void hfp_timeout_start(hfp_connection_t * hfp_connection){
896a0ffb263SMatthias Ringwald     btstack_run_loop_remove_timer(& hfp_connection->hfp_timeout);
897a0ffb263SMatthias Ringwald     btstack_run_loop_set_timer_handler(& hfp_connection->hfp_timeout, hfp_timeout_handler);
898a0ffb263SMatthias Ringwald     btstack_run_loop_set_timer(& hfp_connection->hfp_timeout, 2000); // 2 seconds timeout
899a0ffb263SMatthias Ringwald     btstack_run_loop_add_timer(& hfp_connection->hfp_timeout);
900aa4dd815SMatthias Ringwald }
901aa4dd815SMatthias Ringwald 
902a0ffb263SMatthias Ringwald static void hfp_timeout_stop(hfp_connection_t * hfp_connection){
903a0ffb263SMatthias Ringwald     log_info("HFP stop ring timeout, con handle 0x%02x", hfp_connection->acl_handle);
904a0ffb263SMatthias Ringwald     btstack_run_loop_remove_timer(& hfp_connection->hfp_timeout);
905aa4dd815SMatthias Ringwald }
906aa4dd815SMatthias Ringwald 
907056efd45SMatthias Ringwald static void hfp_ag_set_callsetup_indicator(void){
908056efd45SMatthias Ringwald     hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callsetup");
909056efd45SMatthias Ringwald     if (!indicator){
910056efd45SMatthias Ringwald         log_error("hfp_ag_set_callsetup_indicator: callsetup indicator is missing");
911056efd45SMatthias Ringwald         return;
912056efd45SMatthias Ringwald     };
913056efd45SMatthias Ringwald     indicator->status = hfp_gsm_callsetup_status();
914056efd45SMatthias Ringwald }
915056efd45SMatthias Ringwald 
916056efd45SMatthias Ringwald static void hfp_ag_set_callheld_indicator(void){
917056efd45SMatthias Ringwald     hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callheld");
918056efd45SMatthias Ringwald     if (!indicator){
919056efd45SMatthias Ringwald         log_error("hfp_ag_set_callheld_state: callheld indicator is missing");
920056efd45SMatthias Ringwald         return;
921056efd45SMatthias Ringwald     };
922056efd45SMatthias Ringwald     indicator->status = hfp_gsm_callheld_status();
923056efd45SMatthias Ringwald }
924056efd45SMatthias Ringwald 
925aa4dd815SMatthias Ringwald //
926aa4dd815SMatthias Ringwald // transitition implementations for hfp_ag_call_state_machine
927aa4dd815SMatthias Ringwald //
928aa4dd815SMatthias Ringwald 
929a0ffb263SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * hfp_connection){
930aa4dd815SMatthias Ringwald     if (use_in_band_tone()){
931a0ffb263SMatthias Ringwald         hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING;
932d97d752dSMilanka Ringwald         hfp_ag_establish_audio_connection(hfp_connection->acl_handle);
933aa4dd815SMatthias Ringwald     } else {
934a0ffb263SMatthias Ringwald         hfp_timeout_start(hfp_connection);
935a0ffb263SMatthias Ringwald         hfp_connection->ag_ring = 1;
936a0ffb263SMatthias Ringwald         hfp_connection->ag_send_clip = hfp_gsm_clip_type() && hfp_connection->clip_enabled;
937a0ffb263SMatthias Ringwald         hfp_connection->call_state = HFP_CALL_RINGING;
938ca59be51SMatthias Ringwald         hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_START_RINGINIG);
939aa4dd815SMatthias Ringwald     }
940aa4dd815SMatthias Ringwald }
941aa4dd815SMatthias Ringwald 
942a0ffb263SMatthias Ringwald static void hfp_ag_hf_stop_ringing(hfp_connection_t * hfp_connection){
943a0ffb263SMatthias Ringwald     hfp_connection->ag_ring = 0;
944a0ffb263SMatthias Ringwald     hfp_connection->ag_send_clip = 0;
945a0ffb263SMatthias Ringwald     hfp_timeout_stop(hfp_connection);
946ca59be51SMatthias Ringwald     hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_STOP_RINGINIG);
947aa4dd815SMatthias Ringwald }
948aa4dd815SMatthias Ringwald 
949aa4dd815SMatthias Ringwald static void hfp_ag_trigger_incoming_call(void){
950aa4dd815SMatthias Ringwald     int indicator_index = get_ag_indicator_index_for_name("callsetup");
951aa4dd815SMatthias Ringwald     if (indicator_index < 0) return;
952aa4dd815SMatthias Ringwald 
953665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
954665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
955665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
956a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
95766c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
958a0ffb263SMatthias Ringwald         hfp_ag_establish_service_level_connection(hfp_connection->remote_addr);
959a0ffb263SMatthias Ringwald         if (hfp_connection->call_state == HFP_CALL_IDLE){
960a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1);
961d63c37a1SMatthias Ringwald             hfp_ag_hf_start_ringing(hfp_connection);
962aa4dd815SMatthias Ringwald         }
963a0ffb263SMatthias Ringwald         if (hfp_connection->call_state == HFP_CALL_ACTIVE){
964a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_W2_SEND_CALL_WAITING;
965aa4dd815SMatthias Ringwald         }
966f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
967aa4dd815SMatthias Ringwald     }
968aa4dd815SMatthias Ringwald }
969aa4dd815SMatthias Ringwald 
970fe899794SMatthias Ringwald static void hfp_ag_trigger_outgoing_call(void){
971fe899794SMatthias Ringwald     btstack_linked_list_iterator_t it;
972fe899794SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
973fe899794SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
974fe899794SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
975fe899794SMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
976fe899794SMatthias Ringwald         hfp_ag_establish_service_level_connection(hfp_connection->remote_addr);
977fe899794SMatthias Ringwald         if (hfp_connection->call_state == HFP_CALL_IDLE){
978fe899794SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_OUTGOING_INITIATED;
979fe899794SMatthias Ringwald         }
980fe899794SMatthias Ringwald     }
981fe899794SMatthias Ringwald }
9825a7033e2SMatthias Ringwald 
9835a7033e2SMatthias Ringwald static void hfp_ag_handle_outgoing_call_accepted(hfp_connection_t * hfp_connection){
9845a7033e2SMatthias Ringwald     hfp_connection->call_state = HFP_CALL_OUTGOING_DIALING;
9855a7033e2SMatthias Ringwald 
9865a7033e2SMatthias Ringwald     // trigger callsetup to be
9875a7033e2SMatthias Ringwald     int put_call_on_hold = hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT;
9885a7033e2SMatthias Ringwald     hfp_gsm_handler(HFP_AG_OUTGOING_CALL_ACCEPTED, 0, 0, NULL);
9895a7033e2SMatthias Ringwald 
9905a7033e2SMatthias Ringwald     int indicator_index ;
9915a7033e2SMatthias Ringwald 
9925a7033e2SMatthias Ringwald     hfp_ag_set_callsetup_indicator();
9935a7033e2SMatthias Ringwald     indicator_index = get_ag_indicator_index_for_name("callsetup");
9945a7033e2SMatthias Ringwald     hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1);
9955a7033e2SMatthias Ringwald 
9965a7033e2SMatthias Ringwald     // put current call on hold if active
9975a7033e2SMatthias Ringwald     if (put_call_on_hold){
9985a7033e2SMatthias Ringwald         log_info("AG putting current call on hold for new outgoing call");
9995a7033e2SMatthias Ringwald         hfp_ag_set_callheld_indicator();
10005a7033e2SMatthias Ringwald         indicator_index = get_ag_indicator_index_for_name("callheld");
10015a7033e2SMatthias Ringwald         hfp_ag_send_transfer_ag_indicators_status_cmd(hfp_connection->rfcomm_cid, &hfp_ag_indicators[indicator_index]);
10025a7033e2SMatthias Ringwald     }
10035a7033e2SMatthias Ringwald 
10045a7033e2SMatthias Ringwald     // start audio if needed
10055a7033e2SMatthias Ringwald     hfp_ag_establish_audio_connection(hfp_connection->acl_handle);
10065a7033e2SMatthias Ringwald }
1007fe899794SMatthias Ringwald 
10084a2e058fSMatthias Ringwald static void hfp_ag_transfer_indicator(const char * name){
10094a2e058fSMatthias Ringwald     int indicator_index = get_ag_indicator_index_for_name(name);
1010aa4dd815SMatthias Ringwald     if (indicator_index < 0) return;
1011aa4dd815SMatthias Ringwald 
1012665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1013665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1014665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1015a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
101666c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1017a0ffb263SMatthias Ringwald         hfp_ag_establish_service_level_connection(hfp_connection->remote_addr);
1018a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1);
1019f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
1020aa4dd815SMatthias Ringwald     }
1021aa4dd815SMatthias Ringwald }
1022aa4dd815SMatthias Ringwald 
10234a2e058fSMatthias Ringwald static void hfp_ag_transfer_callsetup_state(void){
10244a2e058fSMatthias Ringwald     hfp_ag_transfer_indicator("callsetup");
10254a2e058fSMatthias Ringwald }
10264a2e058fSMatthias Ringwald 
1027aa4dd815SMatthias Ringwald static void hfp_ag_transfer_call_state(void){
10284a2e058fSMatthias Ringwald     hfp_ag_transfer_indicator("call");
1029aa4dd815SMatthias Ringwald }
1030aa4dd815SMatthias Ringwald 
1031aa4dd815SMatthias Ringwald static void hfp_ag_transfer_callheld_state(void){
10324a2e058fSMatthias Ringwald     hfp_ag_transfer_indicator("callheld");
1033aa4dd815SMatthias Ringwald }
1034aa4dd815SMatthias Ringwald 
1035aa4dd815SMatthias Ringwald static void hfp_ag_hf_accept_call(hfp_connection_t * source){
1036aa4dd815SMatthias Ringwald     int call_indicator_index = get_ag_indicator_index_for_name("call");
1037aa4dd815SMatthias Ringwald     int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup");
1038aa4dd815SMatthias Ringwald 
1039665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1040665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1041665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1042a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
104366c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1044505f1c30SMatthias Ringwald         if ((hfp_connection->call_state != HFP_CALL_RINGING) &&
1045505f1c30SMatthias Ringwald             (hfp_connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING)) continue;
1046aa4dd815SMatthias Ringwald 
1047a0ffb263SMatthias Ringwald         hfp_ag_hf_stop_ringing(hfp_connection);
1048a0ffb263SMatthias Ringwald         if (hfp_connection == source){
1049aa4dd815SMatthias Ringwald 
1050aa4dd815SMatthias Ringwald             if (use_in_band_tone()){
1051a0ffb263SMatthias Ringwald                 hfp_connection->call_state = HFP_CALL_ACTIVE;
1052aa4dd815SMatthias Ringwald             } else {
1053a0ffb263SMatthias Ringwald                 hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE;
1054d97d752dSMilanka Ringwald                 hfp_ag_establish_audio_connection(hfp_connection->acl_handle);
1055aa4dd815SMatthias Ringwald             }
1056aa4dd815SMatthias Ringwald 
1057a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
1058a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
1059aa4dd815SMatthias Ringwald 
1060aa4dd815SMatthias Ringwald         } else {
1061a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_IDLE;
1062aa4dd815SMatthias Ringwald         }
1063f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
1064aa4dd815SMatthias Ringwald     }
1065aa4dd815SMatthias Ringwald }
1066aa4dd815SMatthias Ringwald 
1067aa4dd815SMatthias Ringwald static void hfp_ag_ag_accept_call(void){
1068aa4dd815SMatthias Ringwald     int call_indicator_index = get_ag_indicator_index_for_name("call");
1069aa4dd815SMatthias Ringwald     int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup");
1070aa4dd815SMatthias Ringwald 
1071665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1072665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1073665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1074a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
107566c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1076a0ffb263SMatthias Ringwald         if (hfp_connection->call_state != HFP_CALL_RINGING) continue;
1077aa4dd815SMatthias Ringwald 
1078a0ffb263SMatthias Ringwald         hfp_ag_hf_stop_ringing(hfp_connection);
1079a0ffb263SMatthias Ringwald         hfp_connection->call_state = HFP_CALL_TRIGGER_AUDIO_CONNECTION;
1080aa4dd815SMatthias Ringwald 
1081a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
1082a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
1083aa4dd815SMatthias Ringwald 
1084f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
1085aa4dd815SMatthias Ringwald         break;  // only single
1086aa4dd815SMatthias Ringwald     }
1087aa4dd815SMatthias Ringwald }
1088aa4dd815SMatthias Ringwald 
1089aa4dd815SMatthias Ringwald static void hfp_ag_trigger_reject_call(void){
1090aa4dd815SMatthias Ringwald     int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup");
1091665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1092665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1093665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1094665d90f2SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
109566c5995fSMatthias Ringwald         if (connection->local_role != HFP_ROLE_AG) continue;
1096505f1c30SMatthias Ringwald         if ((connection->call_state != HFP_CALL_RINGING) &&
1097505f1c30SMatthias Ringwald             (connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING)) continue;
1098aa4dd815SMatthias Ringwald         hfp_ag_hf_stop_ringing(connection);
1099aa4dd815SMatthias Ringwald         connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
1100aa4dd815SMatthias Ringwald         connection->call_state = HFP_CALL_IDLE;
1101f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(connection);
1102aa4dd815SMatthias Ringwald     }
1103aa4dd815SMatthias Ringwald }
1104aa4dd815SMatthias Ringwald 
1105aa4dd815SMatthias Ringwald static void hfp_ag_trigger_terminate_call(void){
1106aa4dd815SMatthias Ringwald     int call_indicator_index = get_ag_indicator_index_for_name("call");
1107aa4dd815SMatthias Ringwald 
1108665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1109665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1110665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1111a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
111266c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1113d63c37a1SMatthias Ringwald         hfp_ag_establish_service_level_connection(hfp_connection->remote_addr);
1114a0ffb263SMatthias Ringwald         if (hfp_connection->call_state == HFP_CALL_IDLE) continue;
1115a0ffb263SMatthias Ringwald         hfp_connection->call_state = HFP_CALL_IDLE;
1116a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
11176d78145cSMatthias Ringwald         if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED){
1118a0ffb263SMatthias Ringwald             hfp_connection->release_audio_connection = 1;
11196d78145cSMatthias Ringwald         }
1120f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
1121aa4dd815SMatthias Ringwald     }
11227d81706fSMatthias Ringwald     hfp_emit_simple_event(NULL, HFP_SUBEVENT_CALL_TERMINATED);
1123aa4dd815SMatthias Ringwald }
1124aa4dd815SMatthias Ringwald 
11250cb5b971SMatthias Ringwald static void hfp_ag_set_call_indicator(void){
1126aa4dd815SMatthias Ringwald     hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call");
1127aa4dd815SMatthias Ringwald     if (!indicator){
1128aa4dd815SMatthias Ringwald         log_error("hfp_ag_set_call_state: call indicator is missing");
112945718b6fSMatthias Ringwald         return;
1130aa4dd815SMatthias Ringwald     };
1131d210d9c4SMatthias Ringwald     indicator->status = hfp_gsm_call_status();
1132aa4dd815SMatthias Ringwald }
1133aa4dd815SMatthias Ringwald 
1134aa4dd815SMatthias Ringwald static void hfp_ag_stop_ringing(void){
1135665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1136665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1137665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1138a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
113966c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1140505f1c30SMatthias Ringwald         if ((hfp_connection->call_state != HFP_CALL_RINGING) &&
1141505f1c30SMatthias Ringwald             (hfp_connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING)) continue;
1142a0ffb263SMatthias Ringwald         hfp_ag_hf_stop_ringing(hfp_connection);
1143aa4dd815SMatthias Ringwald     }
1144aa4dd815SMatthias Ringwald }
1145aa4dd815SMatthias Ringwald 
1146aa4dd815SMatthias Ringwald static hfp_connection_t * hfp_ag_connection_for_call_state(hfp_call_state_t call_state){
1147665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1148665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1149665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1150a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
115166c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1152a0ffb263SMatthias Ringwald         if (hfp_connection->call_state == call_state) return hfp_connection;
1153aa4dd815SMatthias Ringwald     }
1154aa4dd815SMatthias Ringwald     return NULL;
1155aa4dd815SMatthias Ringwald }
1156aa4dd815SMatthias Ringwald 
1157a5bdcda8SMatthias Ringwald static void hfp_ag_send_response_and_hold_state(hfp_response_and_hold_state_t state){
1158665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1159665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
1160665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1161a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
116266c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
1163a0ffb263SMatthias Ringwald         hfp_connection->send_response_and_hold_status = state + 1;
1164ce263fc8SMatthias Ringwald     }
1165ce263fc8SMatthias Ringwald }
1166ce263fc8SMatthias Ringwald 
1167a0ffb263SMatthias Ringwald static int call_setup_state_machine(hfp_connection_t * hfp_connection){
1168aa4dd815SMatthias Ringwald     int indicator_index;
1169a0ffb263SMatthias Ringwald     switch (hfp_connection->call_state){
1170aa4dd815SMatthias Ringwald         case HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING:
1171a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0;
1172a0ffb263SMatthias Ringwald             // we got event: audio hfp_connection established
1173a0ffb263SMatthias Ringwald             hfp_timeout_start(hfp_connection);
1174a0ffb263SMatthias Ringwald             hfp_connection->ag_ring = 1;
1175a0ffb263SMatthias Ringwald             hfp_connection->ag_send_clip = hfp_gsm_clip_type() && hfp_connection->clip_enabled;
1176a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_RINGING;
1177ca59be51SMatthias Ringwald             hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_START_RINGINIG);
1178aa4dd815SMatthias Ringwald             break;
1179aa4dd815SMatthias Ringwald         case HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE:
1180a0ffb263SMatthias Ringwald             if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0;
1181a0ffb263SMatthias Ringwald             // we got event: audio hfp_connection established
1182a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_ACTIVE;
1183aa4dd815SMatthias Ringwald             break;
1184aa4dd815SMatthias Ringwald         case HFP_CALL_W2_SEND_CALL_WAITING:
1185a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_W4_CHLD;
1186a0ffb263SMatthias Ringwald             hfp_ag_send_call_waiting_notification(hfp_connection->rfcomm_cid);
1187aa4dd815SMatthias Ringwald             indicator_index = get_ag_indicator_index_for_name("callsetup");
1188a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1);
1189aa4dd815SMatthias Ringwald             break;
1190aa4dd815SMatthias Ringwald         default:
1191aa4dd815SMatthias Ringwald             break;
1192aa4dd815SMatthias Ringwald     }
1193aa4dd815SMatthias Ringwald     return 0;
1194aa4dd815SMatthias Ringwald }
119539426febSMatthias Ringwald 
119639426febSMatthias Ringwald // functions extracted from hfp_ag_call_sm below
11979f9621cfSMatthias Ringwald static void hfp_ag_handle_reject_outgoing_call(void){
119839426febSMatthias Ringwald     hfp_connection_t * hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED);
119939426febSMatthias Ringwald     if (!hfp_connection){
120039426febSMatthias Ringwald         log_info("hfp_ag_call_sm: did not find outgoing hfp_connection in initiated state");
120139426febSMatthias Ringwald         return;
120239426febSMatthias Ringwald     }
120339426febSMatthias Ringwald 
1204f8737b81SMatthias Ringwald     hfp_gsm_handler(HFP_AG_OUTGOING_CALL_REJECTED, 0, 0, NULL);
120539426febSMatthias Ringwald     hfp_connection->call_state = HFP_CALL_IDLE;
120639426febSMatthias Ringwald     hfp_connection->send_error = 1;
120739426febSMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
120839426febSMatthias Ringwald }
120939426febSMatthias Ringwald 
1210a0ffb263SMatthias Ringwald // hfp_connection is used to identify originating HF
1211a0ffb263SMatthias Ringwald static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * hfp_connection){
1212d210d9c4SMatthias Ringwald     int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup");
1213d210d9c4SMatthias Ringwald     int callheld_indicator_index = get_ag_indicator_index_for_name("callheld");
1214d210d9c4SMatthias Ringwald     int call_indicator_index = get_ag_indicator_index_for_name("call");
121574386ee0SMatthias Ringwald 
1216aa4dd815SMatthias Ringwald     switch (event){
1217aa4dd815SMatthias Ringwald         case HFP_AG_INCOMING_CALL:
1218d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1219aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1220d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
122112cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS:
1222f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_INCOMING_CALL, 0, 0, NULL);
1223d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1224aa4dd815SMatthias Ringwald                             hfp_ag_trigger_incoming_call();
122560ebb071SMilanka Ringwald                             log_info("AG rings");
1226aa4dd815SMatthias Ringwald                             break;
1227aa4dd815SMatthias Ringwald                         default:
12283deb3ec6SMatthias Ringwald                             break;
12293deb3ec6SMatthias Ringwald                     }
12303deb3ec6SMatthias Ringwald                     break;
1231aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
1232d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
123312cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS:
1234f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_INCOMING_CALL, 0, 0, NULL);
1235d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1236aa4dd815SMatthias Ringwald                             hfp_ag_trigger_incoming_call();
123760ebb071SMilanka Ringwald                             log_info("AG call waiting");
1238aa4dd815SMatthias Ringwald                             break;
1239aa4dd815SMatthias Ringwald                         default:
12403deb3ec6SMatthias Ringwald                             break;
12413deb3ec6SMatthias Ringwald                     }
12423deb3ec6SMatthias Ringwald                     break;
12437bbeb3adSMilanka Ringwald                 default:
12447bbeb3adSMilanka Ringwald                     break;
1245aa4dd815SMatthias Ringwald             }
1246aa4dd815SMatthias Ringwald             break;
1247aa4dd815SMatthias Ringwald         case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
1248d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1249aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1250d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
125112cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1252f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, 0, 0, NULL);
1253d210d9c4SMatthias Ringwald                             hfp_ag_set_call_indicator();
1254d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1255aa4dd815SMatthias Ringwald                             hfp_ag_ag_accept_call();
125660ebb071SMilanka Ringwald                             log_info("AG answers call, accept call by GSM");
1257aa4dd815SMatthias Ringwald                             break;
1258aa4dd815SMatthias Ringwald                         default:
12593deb3ec6SMatthias Ringwald                             break;
12603deb3ec6SMatthias Ringwald                     }
1261aa4dd815SMatthias Ringwald                     break;
1262aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
1263d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
1264aa4dd815SMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
126560ebb071SMilanka Ringwald                             log_info("AG: current call is placed on hold, incoming call gets active");
1266f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, 0, 0, NULL);
1267d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1268d0c20769SMatthias Ringwald                             hfp_ag_set_callheld_indicator();
1269ce263fc8SMatthias Ringwald                             hfp_ag_transfer_callsetup_state();
1270ce263fc8SMatthias Ringwald                             hfp_ag_transfer_callheld_state();
1271aa4dd815SMatthias Ringwald                             break;
1272aa4dd815SMatthias Ringwald                         default:
1273aa4dd815SMatthias Ringwald                             break;
1274aa4dd815SMatthias Ringwald                     }
1275aa4dd815SMatthias Ringwald                     break;
12767bbeb3adSMilanka Ringwald                 default:
12777bbeb3adSMilanka Ringwald                     break;
1278aa4dd815SMatthias Ringwald             }
1279aa4dd815SMatthias Ringwald             break;
1280ce263fc8SMatthias Ringwald 
1281ce263fc8SMatthias Ringwald         case HFP_AG_HELD_CALL_JOINED_BY_AG:
1282d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1283ce263fc8SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
1284d0c20769SMatthias Ringwald                     switch (hfp_gsm_callheld_status()){
1285ce263fc8SMatthias Ringwald                         case HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED:
128660ebb071SMilanka Ringwald                             log_info("AG: joining held call with active call");
1287f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_HELD_CALL_JOINED_BY_AG, 0, 0, NULL);
1288d0c20769SMatthias Ringwald                             hfp_ag_set_callheld_indicator();
1289ce263fc8SMatthias Ringwald                             hfp_ag_transfer_callheld_state();
1290ca59be51SMatthias Ringwald                             hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CONFERENCE_CALL);
1291ce263fc8SMatthias Ringwald                             break;
1292ce263fc8SMatthias Ringwald                         default:
1293ce263fc8SMatthias Ringwald                             break;
1294ce263fc8SMatthias Ringwald                     }
1295ce263fc8SMatthias Ringwald                     break;
1296ce263fc8SMatthias Ringwald                 default:
1297ce263fc8SMatthias Ringwald                     break;
1298ce263fc8SMatthias Ringwald             }
1299ce263fc8SMatthias Ringwald             break;
1300ce263fc8SMatthias Ringwald 
1301aa4dd815SMatthias Ringwald         case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
1302d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1303aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1304d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
130512cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1306f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, 0, 0, NULL);
1307d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1308d210d9c4SMatthias Ringwald                             hfp_ag_set_call_indicator();
1309a0ffb263SMatthias Ringwald                             hfp_ag_hf_accept_call(hfp_connection);
13106323f788SMatthias Ringwald                             hfp_connection->ok_pending = 1;
131160ebb071SMilanka Ringwald                             log_info("HF answers call, accept call by GSM");
1312ca59be51SMatthias Ringwald                             hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_ANSWERED);
1313aa4dd815SMatthias Ringwald                             break;
1314aa4dd815SMatthias Ringwald                         default:
1315aa4dd815SMatthias Ringwald                             break;
1316aa4dd815SMatthias Ringwald                     }
13173deb3ec6SMatthias Ringwald                     break;
13183deb3ec6SMatthias Ringwald                 default:
13193deb3ec6SMatthias Ringwald                     break;
13203deb3ec6SMatthias Ringwald             }
13213deb3ec6SMatthias Ringwald             break;
13223deb3ec6SMatthias Ringwald 
1323ce263fc8SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG:
1324d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1325ce263fc8SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1326d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
132712cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1328f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG, 0, 0, NULL);
1329ce263fc8SMatthias Ringwald                             hfp_ag_response_and_hold_active = 1;
1330ce263fc8SMatthias Ringwald                             hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD;
1331a5bdcda8SMatthias Ringwald                             hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
1332ce263fc8SMatthias Ringwald                             // as with regualr call
1333d210d9c4SMatthias Ringwald                             hfp_ag_set_call_indicator();
1334d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1335ce263fc8SMatthias Ringwald                             hfp_ag_ag_accept_call();
133660ebb071SMilanka Ringwald                             log_info("AG response and hold - hold by AG");
1337ce263fc8SMatthias Ringwald                             break;
1338ce263fc8SMatthias Ringwald                         default:
1339ce263fc8SMatthias Ringwald                             break;
1340ce263fc8SMatthias Ringwald                     }
1341ce263fc8SMatthias Ringwald                     break;
1342ce263fc8SMatthias Ringwald                 default:
1343ce263fc8SMatthias Ringwald                     break;
1344ce263fc8SMatthias Ringwald             }
1345ce263fc8SMatthias Ringwald             break;
1346ce263fc8SMatthias Ringwald 
1347ce263fc8SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF:
1348d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1349ce263fc8SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1350d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
135112cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1352f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, 0, 0, NULL);
1353ce263fc8SMatthias Ringwald                             hfp_ag_response_and_hold_active = 1;
1354ce263fc8SMatthias Ringwald                             hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD;
1355a5bdcda8SMatthias Ringwald                             hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
1356ce263fc8SMatthias Ringwald                             // as with regualr call
1357d210d9c4SMatthias Ringwald                             hfp_ag_set_call_indicator();
1358d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1359a0ffb263SMatthias Ringwald                             hfp_ag_hf_accept_call(hfp_connection);
136060ebb071SMilanka Ringwald                             log_info("AG response and hold - hold by HF");
1361ce263fc8SMatthias Ringwald                             break;
1362ce263fc8SMatthias Ringwald                         default:
1363ce263fc8SMatthias Ringwald                             break;
1364ce263fc8SMatthias Ringwald                     }
1365ce263fc8SMatthias Ringwald                     break;
1366ce263fc8SMatthias Ringwald                 default:
1367ce263fc8SMatthias Ringwald                     break;
1368ce263fc8SMatthias Ringwald             }
1369ce263fc8SMatthias Ringwald             break;
1370ce263fc8SMatthias Ringwald 
1371ce263fc8SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG:
1372ce263fc8SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
1373ce263fc8SMatthias Ringwald             if (!hfp_ag_response_and_hold_active) break;
1374ce263fc8SMatthias Ringwald             if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break;
1375f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG, 0, 0, NULL);
1376a5bdcda8SMatthias Ringwald             hfp_ag_response_and_hold_active = 0;
1377ce263fc8SMatthias Ringwald             hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED;
1378a5bdcda8SMatthias Ringwald             hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
137960ebb071SMilanka Ringwald             log_info("Held Call accepted and active");
1380ce263fc8SMatthias Ringwald             break;
1381ce263fc8SMatthias Ringwald 
1382ce263fc8SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
1383ce263fc8SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF:
1384ce263fc8SMatthias Ringwald             if (!hfp_ag_response_and_hold_active) break;
1385ce263fc8SMatthias Ringwald             if (hfp_ag_response_and_hold_state != HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD) break;
1386f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, 0, 0, NULL);
1387a5bdcda8SMatthias Ringwald             hfp_ag_response_and_hold_active = 0;
1388ce263fc8SMatthias Ringwald             hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED;
1389a5bdcda8SMatthias Ringwald             hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
1390ce263fc8SMatthias Ringwald             // from terminate by ag
1391d210d9c4SMatthias Ringwald             hfp_ag_set_call_indicator();
1392ce263fc8SMatthias Ringwald             hfp_ag_trigger_terminate_call();
1393ce263fc8SMatthias Ringwald             break;
1394ce263fc8SMatthias Ringwald 
1395aa4dd815SMatthias Ringwald         case HFP_AG_TERMINATE_CALL_BY_HF:
1396d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1397aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1398d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
139912cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1400f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_HF, 0, 0, NULL);
1401d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1402aa4dd815SMatthias Ringwald                             hfp_ag_transfer_callsetup_state();
1403aa4dd815SMatthias Ringwald                             hfp_ag_trigger_reject_call();
140460ebb071SMilanka Ringwald                             log_info("HF Rejected Incoming call, AG terminate call");
1405aa4dd815SMatthias Ringwald                             break;
1406aa4dd815SMatthias Ringwald                         case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE:
140712cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE:
1408f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_HF, 0, 0, NULL);
1409d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1410aa4dd815SMatthias Ringwald                             hfp_ag_transfer_callsetup_state();
141160ebb071SMilanka Ringwald                             log_info("AG terminate outgoing call process");
1412202c8a4cSMatthias Ringwald                             break;
1413aa4dd815SMatthias Ringwald                         default:
1414aa4dd815SMatthias Ringwald                             break;
1415aa4dd815SMatthias Ringwald                     }
1416aa4dd815SMatthias Ringwald                     break;
141712cbbeeeSMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
1418f8737b81SMatthias Ringwald                     hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_HF, 0, 0, NULL);
14191ec112deSMatthias Ringwald                     hfp_ag_set_callsetup_indicator();
1420d210d9c4SMatthias Ringwald                     hfp_ag_set_call_indicator();
14211ec112deSMatthias Ringwald                     hfp_ag_trigger_terminate_call();
142260ebb071SMilanka Ringwald                     log_info("AG terminate call");
1423aa4dd815SMatthias Ringwald                     break;
14247bbeb3adSMilanka Ringwald                 default:
14257bbeb3adSMilanka Ringwald                     break;
1426aa4dd815SMatthias Ringwald             }
14270c1b8529SMatthias Ringwald             hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CALL_TERMINATED);
1428aa4dd815SMatthias Ringwald             break;
14293deb3ec6SMatthias Ringwald 
1430aa4dd815SMatthias Ringwald         case HFP_AG_TERMINATE_CALL_BY_AG:
1431d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1432aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1433d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
143412cbbeeeSMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1435f8737b81SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_AG, 0, 0, NULL);
1436d0c20769SMatthias Ringwald                             hfp_ag_set_callsetup_indicator();
1437aa4dd815SMatthias Ringwald                             hfp_ag_trigger_reject_call();
143860ebb071SMilanka Ringwald                             log_info("AG Rejected Incoming call, AG terminate call");
1439aa4dd815SMatthias Ringwald                             break;
1440aa4dd815SMatthias Ringwald                         default:
1441aa4dd815SMatthias Ringwald                             break;
14423deb3ec6SMatthias Ringwald                     }
1443202c8a4cSMatthias Ringwald                     break;
144412cbbeeeSMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
1445f8737b81SMatthias Ringwald                     hfp_gsm_handler(HFP_AG_TERMINATE_CALL_BY_AG, 0, 0, NULL);
1446d0c20769SMatthias Ringwald                     hfp_ag_set_callsetup_indicator();
1447d210d9c4SMatthias Ringwald                     hfp_ag_set_call_indicator();
1448aa4dd815SMatthias Ringwald                     hfp_ag_trigger_terminate_call();
144960ebb071SMilanka Ringwald                     log_info("AG terminate call");
1450aa4dd815SMatthias Ringwald                     break;
1451aa4dd815SMatthias Ringwald                 default:
14523deb3ec6SMatthias Ringwald                     break;
14533deb3ec6SMatthias Ringwald             }
14543deb3ec6SMatthias Ringwald             break;
1455aa4dd815SMatthias Ringwald         case HFP_AG_CALL_DROPPED:
1456d0c20769SMatthias Ringwald             switch (hfp_gsm_call_status()){
1457aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1458d0c20769SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()){
1459aa4dd815SMatthias Ringwald                         case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS:
1460aa4dd815SMatthias Ringwald                             hfp_ag_stop_ringing();
146160ebb071SMilanka Ringwald                             log_info("Incoming call interrupted");
1462aa4dd815SMatthias Ringwald                             break;
1463aa4dd815SMatthias Ringwald                         case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE:
1464aa4dd815SMatthias Ringwald                         case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE:
146560ebb071SMilanka Ringwald                             log_info("Outgoing call interrupted\n");
146660ebb071SMilanka Ringwald                             log_info("AG notify call dropped\n");
1467aa4dd815SMatthias Ringwald                             break;
1468aa4dd815SMatthias Ringwald                         default:
14693deb3ec6SMatthias Ringwald                             break;
14703deb3ec6SMatthias Ringwald                     }
1471f8737b81SMatthias Ringwald                     hfp_gsm_handler(HFP_AG_CALL_DROPPED, 0, 0, NULL);
1472d0c20769SMatthias Ringwald                     hfp_ag_set_callsetup_indicator();
1473aa4dd815SMatthias Ringwald                     hfp_ag_transfer_callsetup_state();
147410c236bfSMatthias Ringwald                     hfp_ag_trigger_terminate_call();
1475aa4dd815SMatthias Ringwald                     break;
1476aa4dd815SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
1477ce263fc8SMatthias Ringwald                     if (hfp_ag_response_and_hold_active) {
1478f8737b81SMatthias Ringwald                         hfp_gsm_handler(HFP_AG_CALL_DROPPED, 0, 0, NULL);
1479ce263fc8SMatthias Ringwald                         hfp_ag_response_and_hold_state = HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED;
1480a5bdcda8SMatthias Ringwald                         hfp_ag_send_response_and_hold_state(hfp_ag_response_and_hold_state);
1481ce263fc8SMatthias Ringwald                     }
1482f8737b81SMatthias Ringwald                     hfp_gsm_handler(HFP_AG_CALL_DROPPED, 0, 0, NULL);
1483d0c20769SMatthias Ringwald                     hfp_ag_set_callsetup_indicator();
1484d210d9c4SMatthias Ringwald                     hfp_ag_set_call_indicator();
1485aa4dd815SMatthias Ringwald                     hfp_ag_trigger_terminate_call();
148660ebb071SMilanka Ringwald                     log_info("AG notify call dropped");
1487aa4dd815SMatthias Ringwald                     break;
1488aa4dd815SMatthias Ringwald                 default:
1489aa4dd815SMatthias Ringwald                     break;
1490aa4dd815SMatthias Ringwald             }
1491aa4dd815SMatthias Ringwald             break;
1492aa4dd815SMatthias Ringwald 
14939ff73f41SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_INITIATED_BY_HF:
1494d210d9c4SMatthias Ringwald             // directly reject call if number of free slots is exceeded
1495d210d9c4SMatthias Ringwald             if (!hfp_gsm_call_possible()){
1496a0ffb263SMatthias Ringwald                 hfp_connection->send_error = 1;
1497f0aeb307SMatthias Ringwald                 hfp_ag_run_for_context(hfp_connection);
1498d210d9c4SMatthias Ringwald                 break;
1499d210d9c4SMatthias Ringwald             }
1500fe899794SMatthias Ringwald 
1501fe899794SMatthias Ringwald             // note: number not used currently
15029ff73f41SMatthias Ringwald             hfp_gsm_handler(HFP_AG_OUTGOING_CALL_INITIATED_BY_HF, 0, 0, (const char *) &hfp_connection->line_buffer[3]);
15039cae807eSMatthias Ringwald 
1504a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_OUTGOING_INITIATED;
150574386ee0SMatthias Ringwald 
1506ca59be51SMatthias Ringwald             hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, (const char *) &hfp_connection->line_buffer[3]);
1507aa4dd815SMatthias Ringwald             break;
1508aa4dd815SMatthias Ringwald 
1509fe899794SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_INITIATED_BY_AG:
1510fe899794SMatthias Ringwald             // directly reject call if number of free slots is exceeded
1511fe899794SMatthias Ringwald             if (!hfp_gsm_call_possible()) {
1512fe899794SMatthias Ringwald                 // TODO: no error for user
1513fe899794SMatthias Ringwald                 break;
1514fe899794SMatthias Ringwald             }
1515fe899794SMatthias Ringwald             switch (hfp_gsm_call_status()) {
1516fe899794SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
1517fe899794SMatthias Ringwald                     switch (hfp_gsm_callsetup_status()) {
1518fe899794SMatthias Ringwald                         case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS:
1519fe899794SMatthias Ringwald                             // note: number not used currently
1520fe899794SMatthias Ringwald                             hfp_gsm_handler(HFP_AG_OUTGOING_CALL_INITIATED_BY_AG, 0, 0, "1234567");
1521fe899794SMatthias Ringwald                             // init call state for all connections
1522fe899794SMatthias Ringwald                             hfp_ag_trigger_outgoing_call();
1523fe899794SMatthias Ringwald                             // get first one and accept call
1524fe899794SMatthias Ringwald                             hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED);
1525fe899794SMatthias Ringwald                             if (hfp_connection) {
1526fe899794SMatthias Ringwald                                 hfp_ag_handle_outgoing_call_accepted(hfp_connection);
1527fe899794SMatthias Ringwald                             }
1528fe899794SMatthias Ringwald                             break;
1529fe899794SMatthias Ringwald                         default:
1530fe899794SMatthias Ringwald                             // TODO: no error for user
1531fe899794SMatthias Ringwald                             break;
1532fe899794SMatthias Ringwald                     }
1533fe899794SMatthias Ringwald                     break;
1534fe899794SMatthias Ringwald                 default:
1535fe899794SMatthias Ringwald                     // TODO: no error for user
1536fe899794SMatthias Ringwald                     break;
1537fe899794SMatthias Ringwald             }
1538fe899794SMatthias Ringwald             break;
15399cae807eSMatthias Ringwald         case HFP_AG_OUTGOING_REDIAL_INITIATED:{
1540d210d9c4SMatthias Ringwald             // directly reject call if number of free slots is exceeded
1541d210d9c4SMatthias Ringwald             if (!hfp_gsm_call_possible()){
1542a0ffb263SMatthias Ringwald                 hfp_connection->send_error = 1;
1543f0aeb307SMatthias Ringwald                 hfp_ag_run_for_context(hfp_connection);
1544d210d9c4SMatthias Ringwald                 break;
1545d210d9c4SMatthias Ringwald             }
1546d210d9c4SMatthias Ringwald 
1547f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_OUTGOING_REDIAL_INITIATED, 0, 0, NULL);
1548a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_OUTGOING_INITIATED;
154974386ee0SMatthias Ringwald 
155060ebb071SMilanka Ringwald             log_info("Redial last number");
15519cae807eSMatthias Ringwald             char * last_dialed_number = hfp_gsm_last_dialed_number();
1552aa4dd815SMatthias Ringwald 
15539cae807eSMatthias Ringwald             if (strlen(last_dialed_number) > 0){
155460ebb071SMilanka Ringwald                 log_info("Last number exists: accept call");
1555ca59be51SMatthias Ringwald                 hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, last_dialed_number);
15569cae807eSMatthias Ringwald             } else {
155760ebb071SMilanka Ringwald                 log_info("log_infoLast number missing: reject call");
15589f9621cfSMatthias Ringwald                 hfp_ag_handle_reject_outgoing_call();
15599cae807eSMatthias Ringwald             }
15609cae807eSMatthias Ringwald             break;
15619cae807eSMatthias Ringwald         }
1562aa4dd815SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_REJECTED:
15639f9621cfSMatthias Ringwald             hfp_ag_handle_reject_outgoing_call();
1564aa4dd815SMatthias Ringwald             break;
1565aa4dd815SMatthias Ringwald 
1566d210d9c4SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_ACCEPTED:{
1567a0ffb263SMatthias Ringwald             hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED);
1568a0ffb263SMatthias Ringwald             if (!hfp_connection){
1569a0ffb263SMatthias Ringwald                 log_info("hfp_ag_call_sm: did not find outgoing hfp_connection in initiated state");
1570aa4dd815SMatthias Ringwald                 break;
1571aa4dd815SMatthias Ringwald             }
1572aa4dd815SMatthias Ringwald 
1573a0ffb263SMatthias Ringwald             hfp_connection->ok_pending = 1;
15745a7033e2SMatthias Ringwald             hfp_ag_handle_outgoing_call_accepted(hfp_connection);
1575aa4dd815SMatthias Ringwald             break;
1576d210d9c4SMatthias Ringwald         }
1577aa4dd815SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_RINGING:
1578a0ffb263SMatthias Ringwald             hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING);
1579a0ffb263SMatthias Ringwald             if (!hfp_connection){
1580a0ffb263SMatthias Ringwald                 log_info("hfp_ag_call_sm: did not find outgoing hfp_connection in dialing state");
1581aa4dd815SMatthias Ringwald                 break;
1582aa4dd815SMatthias Ringwald             }
1583d210d9c4SMatthias Ringwald 
1584f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_OUTGOING_CALL_RINGING, 0, 0, NULL);
1585a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_OUTGOING_RINGING;
1586d0c20769SMatthias Ringwald             hfp_ag_set_callsetup_indicator();
1587aa4dd815SMatthias Ringwald             hfp_ag_transfer_callsetup_state();
1588aa4dd815SMatthias Ringwald             break;
1589aa4dd815SMatthias Ringwald 
1590d210d9c4SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_ESTABLISHED:{
1591aa4dd815SMatthias Ringwald             // get outgoing call
1592a0ffb263SMatthias Ringwald             hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING);
1593a0ffb263SMatthias Ringwald             if (!hfp_connection){
1594a0ffb263SMatthias Ringwald                 hfp_connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING);
1595aa4dd815SMatthias Ringwald             }
1596a0ffb263SMatthias Ringwald             if (!hfp_connection){
1597a0ffb263SMatthias Ringwald                 log_info("hfp_ag_call_sm: did not find outgoing hfp_connection");
1598aa4dd815SMatthias Ringwald                 break;
1599aa4dd815SMatthias Ringwald             }
1600d210d9c4SMatthias Ringwald 
1601d0c20769SMatthias Ringwald             int CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS = hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS;
1602f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_OUTGOING_CALL_ESTABLISHED, 0, 0, NULL);
1603a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_ACTIVE;
1604d0c20769SMatthias Ringwald             hfp_ag_set_callsetup_indicator();
1605d210d9c4SMatthias Ringwald             hfp_ag_set_call_indicator();
1606aa4dd815SMatthias Ringwald             hfp_ag_transfer_call_state();
1607aa4dd815SMatthias Ringwald             hfp_ag_transfer_callsetup_state();
1608d210d9c4SMatthias Ringwald             if (CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS){
1609d0c20769SMatthias Ringwald                 hfp_ag_set_callheld_indicator();
1610aa4dd815SMatthias Ringwald                 hfp_ag_transfer_callheld_state();
16113deb3ec6SMatthias Ringwald             }
16123deb3ec6SMatthias Ringwald             break;
1613d210d9c4SMatthias Ringwald         }
1614d210d9c4SMatthias Ringwald 
161512cbbeeeSMatthias Ringwald         case HFP_AG_CALL_HOLD_USER_BUSY:
1616f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_CALL_HOLD_USER_BUSY, 0, 0, NULL);
1617d0c20769SMatthias Ringwald             hfp_ag_set_callsetup_indicator();
1618a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
1619a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_ACTIVE;
162060ebb071SMilanka Ringwald             log_info("AG: Call Waiting, User Busy");
1621d210d9c4SMatthias Ringwald             break;
1622d210d9c4SMatthias Ringwald 
1623d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
1624d0c20769SMatthias Ringwald             int call_setup_in_progress = hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
1625d0c20769SMatthias Ringwald             int call_held = hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD;
1626d210d9c4SMatthias Ringwald 
1627d210d9c4SMatthias Ringwald             // Releases all active calls (if any exist) and accepts the other (held or waiting) call.
1628d0c20769SMatthias Ringwald             if (call_held || call_setup_in_progress){
1629f8737b81SMatthias Ringwald                 hfp_gsm_handler(HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection->call_index,
1630f8737b81SMatthias Ringwald                                 0, NULL);
1631d0c20769SMatthias Ringwald 
1632d0c20769SMatthias Ringwald             }
1633d0c20769SMatthias Ringwald 
1634d210d9c4SMatthias Ringwald             if (call_setup_in_progress){
163560ebb071SMilanka Ringwald                 log_info("AG: Call Dropped, Accept new call");
1636d0c20769SMatthias Ringwald                 hfp_ag_set_callsetup_indicator();
1637a0ffb263SMatthias Ringwald                 hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
1638d210d9c4SMatthias Ringwald             } else {
163960ebb071SMilanka Ringwald                 log_info("AG: Call Dropped, Resume held call");
1640d210d9c4SMatthias Ringwald             }
1641d210d9c4SMatthias Ringwald             if (call_held){
1642d0c20769SMatthias Ringwald                 hfp_ag_set_callheld_indicator();
1643a0ffb263SMatthias Ringwald                 hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
1644d210d9c4SMatthias Ringwald             }
1645d0c20769SMatthias Ringwald 
1646a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_ACTIVE;
1647d210d9c4SMatthias Ringwald             break;
1648d210d9c4SMatthias Ringwald         }
1649d0c20769SMatthias Ringwald 
1650d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
1651d210d9c4SMatthias Ringwald             // Places all active calls (if any exist) on hold and accepts the other (held or waiting) call.
1652d210d9c4SMatthias Ringwald             // only update if callsetup changed
1653d0c20769SMatthias Ringwald             int call_setup_in_progress = hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
1654f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection->call_index, 0,
1655f8737b81SMatthias Ringwald                             NULL);
1656d0c20769SMatthias Ringwald 
1657d210d9c4SMatthias Ringwald             if (call_setup_in_progress){
165860ebb071SMilanka Ringwald                 log_info("AG: Call on Hold, Accept new call");
1659d0c20769SMatthias Ringwald                 hfp_ag_set_callsetup_indicator();
1660a0ffb263SMatthias Ringwald                 hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1);
1661d210d9c4SMatthias Ringwald             } else {
166260ebb071SMilanka Ringwald                 log_info("AG: Swap calls");
1663d210d9c4SMatthias Ringwald             }
1664d0c20769SMatthias Ringwald 
1665d0c20769SMatthias Ringwald             hfp_ag_set_callheld_indicator();
1666d0c20769SMatthias Ringwald             // hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED);
1667a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
1668a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_ACTIVE;
1669d210d9c4SMatthias Ringwald             break;
1670d210d9c4SMatthias Ringwald         }
1671d0c20769SMatthias Ringwald 
1672d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_ADD_HELD_CALL:
1673d210d9c4SMatthias Ringwald             // Adds a held call to the conversation.
1674d0c20769SMatthias Ringwald             if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
167560ebb071SMilanka Ringwald                 log_info("AG: Join 3-way-call");
1676f8737b81SMatthias Ringwald                 hfp_gsm_handler(HFP_AG_CALL_HOLD_ADD_HELD_CALL, 0, 0, NULL);
1677d0c20769SMatthias Ringwald                 hfp_ag_set_callheld_indicator();
1678a0ffb263SMatthias Ringwald                 hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
1679ca59be51SMatthias Ringwald                 hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_CONFERENCE_CALL);
1680d210d9c4SMatthias Ringwald             }
1681a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_ACTIVE;
1682d210d9c4SMatthias Ringwald             break;
1683d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS:
1684d210d9c4SMatthias Ringwald             // Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)
1685f8737b81SMatthias Ringwald             hfp_gsm_handler(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS, 0, 0, NULL);
168660ebb071SMilanka Ringwald             log_info("AG: Transfer call -> Connect two calls and disconnect");
1687d210d9c4SMatthias Ringwald             hfp_ag_set_call_indicator();
1688d0c20769SMatthias Ringwald             hfp_ag_set_callheld_indicator();
1689a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, call_indicator_index, 1);
1690a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, callheld_indicator_index, 1);
1691a0ffb263SMatthias Ringwald             hfp_connection->call_state = HFP_CALL_IDLE;
1692d210d9c4SMatthias Ringwald             break;
1693ce263fc8SMatthias Ringwald 
16943deb3ec6SMatthias Ringwald         default:
16953deb3ec6SMatthias Ringwald             break;
16963deb3ec6SMatthias Ringwald     }
1697d210d9c4SMatthias Ringwald 
1698d0c20769SMatthias Ringwald 
16993deb3ec6SMatthias Ringwald }
17003deb3ec6SMatthias Ringwald 
17019cae807eSMatthias Ringwald 
1702a0ffb263SMatthias Ringwald static void hfp_ag_send_call_status(hfp_connection_t * hfp_connection, int call_index){
17039cae807eSMatthias Ringwald     hfp_gsm_call_t * active_call = hfp_gsm_call(call_index);
17049cae807eSMatthias Ringwald     if (!active_call) return;
17059cae807eSMatthias Ringwald 
17069cae807eSMatthias Ringwald     int idx = active_call->index;
17079cae807eSMatthias Ringwald     hfp_enhanced_call_dir_t dir = active_call->direction;
17089cae807eSMatthias Ringwald     hfp_enhanced_call_status_t status = active_call->enhanced_status;
17099cae807eSMatthias Ringwald     hfp_enhanced_call_mode_t mode = active_call->mode;
17109cae807eSMatthias Ringwald     hfp_enhanced_call_mpty_t mpty = active_call->mpty;
17119cae807eSMatthias Ringwald     uint8_t type = active_call->clip_type;
17129cae807eSMatthias Ringwald     char * number = active_call->clip_number;
17139cae807eSMatthias Ringwald 
17149cae807eSMatthias Ringwald     char buffer[100];
17159cae807eSMatthias Ringwald     // TODO: check length of a buffer, to fit the MTU
17169cae807eSMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s: %d,%d,%d,%d,%d", HFP_LIST_CURRENT_CALLS, idx, dir, status, mode, mpty);
17179cae807eSMatthias Ringwald     if (number){
17181cc1d9e9SMilanka Ringwald         offset += snprintf(buffer+offset, sizeof(buffer)-offset-3, ", \"%s\",%u", number, type);
17199cae807eSMatthias Ringwald     }
17209cae807eSMatthias Ringwald     snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n");
172160ebb071SMilanka Ringwald     log_info("hfp_ag_send_current_call_status 000 index %d, dir %d, status %d, mode %d, mpty %d, type %d, number %s", idx, dir, status,
17229cae807eSMatthias Ringwald        mode, mpty, type, number);
1723a0ffb263SMatthias Ringwald     send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
17249cae807eSMatthias Ringwald }
17259cae807eSMatthias Ringwald 
1726473ac565SMatthias Ringwald 
1727febc14f5SMatthias Ringwald // sends pending command, returns if command was sent
1728febc14f5SMatthias Ringwald static int hfp_ag_send_commands(hfp_connection_t *hfp_connection){
172922387625SMatthias Ringwald 
1730a0ffb263SMatthias Ringwald     if (hfp_connection->send_status_of_current_calls){
1731a0ffb263SMatthias Ringwald         hfp_connection->ok_pending = 0;
1732a0ffb263SMatthias Ringwald         if (hfp_connection->next_call_index < hfp_gsm_get_number_of_calls()){
1733a0ffb263SMatthias Ringwald             hfp_connection->next_call_index++;
1734a0ffb263SMatthias Ringwald             hfp_ag_send_call_status(hfp_connection, hfp_connection->next_call_index);
1735febc14f5SMatthias Ringwald             return 1;
17369cae807eSMatthias Ringwald         } else {
1737febc14f5SMatthias Ringwald             // TODO: this code should be removed. check a) before setting send_status_of_current_calls, or b) right before hfp_ag_send_call_status above
1738a0ffb263SMatthias Ringwald             hfp_connection->next_call_index = 0;
1739a0ffb263SMatthias Ringwald             hfp_connection->ok_pending = 1;
1740a0ffb263SMatthias Ringwald             hfp_connection->send_status_of_current_calls = 0;
17419cae807eSMatthias Ringwald         }
1742ce263fc8SMatthias Ringwald     }
1743ce263fc8SMatthias Ringwald 
1744a0ffb263SMatthias Ringwald     if (hfp_connection->ag_notify_incoming_call_waiting){
1745a0ffb263SMatthias Ringwald         hfp_connection->ag_notify_incoming_call_waiting = 0;
1746a0ffb263SMatthias Ringwald         hfp_ag_send_call_waiting_notification(hfp_connection->rfcomm_cid);
1747febc14f5SMatthias Ringwald         return 1;
1748aa4dd815SMatthias Ringwald     }
1749aa4dd815SMatthias Ringwald 
1750a0ffb263SMatthias Ringwald     if (hfp_connection->command == HFP_CMD_UNKNOWN){
1751a0ffb263SMatthias Ringwald         hfp_connection->ok_pending = 0;
1752a0ffb263SMatthias Ringwald         hfp_connection->send_error = 0;
1753a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1754485ac19eSMilanka Ringwald         hfp_ag_send_error(hfp_connection->rfcomm_cid);
1755febc14f5SMatthias Ringwald         return 1;
1756a0ffb263SMatthias Ringwald     }
1757a0ffb263SMatthias Ringwald 
1758a0ffb263SMatthias Ringwald     if (hfp_connection->send_error){
1759a0ffb263SMatthias Ringwald         hfp_connection->send_error = 0;
1760a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1761485ac19eSMilanka Ringwald         hfp_ag_send_error(hfp_connection->rfcomm_cid);
1762febc14f5SMatthias Ringwald         return 1;
1763aa4dd815SMatthias Ringwald     }
1764aa4dd815SMatthias Ringwald 
1765ce263fc8SMatthias Ringwald     // note: before update AG indicators and ok_pending
1766a0ffb263SMatthias Ringwald     if (hfp_connection->send_response_and_hold_status){
1767a0ffb263SMatthias Ringwald         int status = hfp_connection->send_response_and_hold_status - 1;
1768a0ffb263SMatthias Ringwald         hfp_connection->send_response_and_hold_status = 0;
1769485ac19eSMilanka Ringwald         hfp_ag_send_set_response_and_hold(hfp_connection->rfcomm_cid, status);
1770febc14f5SMatthias Ringwald         return 1;
1771ce263fc8SMatthias Ringwald     }
1772ce263fc8SMatthias Ringwald 
1773a0ffb263SMatthias Ringwald     if (hfp_connection->ok_pending){
1774a0ffb263SMatthias Ringwald         hfp_connection->ok_pending = 0;
1775a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1776485ac19eSMilanka Ringwald         hfp_ag_send_ok(hfp_connection->rfcomm_cid);
1777febc14f5SMatthias Ringwald         return 1;
1778ce263fc8SMatthias Ringwald     }
1779ce263fc8SMatthias Ringwald 
1780aa4dd815SMatthias Ringwald     // update AG indicators
1781a0ffb263SMatthias Ringwald     if (hfp_connection->ag_indicators_status_update_bitmap){
1782aa4dd815SMatthias Ringwald         int i;
1783a0ffb263SMatthias Ringwald         for (i=0;i<hfp_connection->ag_indicators_nr;i++){
1784a0ffb263SMatthias Ringwald             if (get_bit(hfp_connection->ag_indicators_status_update_bitmap, i)){
1785a0ffb263SMatthias Ringwald                 hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, i, 0);
1786a0ffb263SMatthias Ringwald                 if (!hfp_connection->enable_status_update_for_ag_indicators) {
1787ce263fc8SMatthias Ringwald                     log_info("+CMER:3,0,0,0 - not sending update for '%s'", hfp_ag_indicators[i].name);
1788ce263fc8SMatthias Ringwald                     break;
1789ce263fc8SMatthias Ringwald                 }
1790485ac19eSMilanka Ringwald                 hfp_ag_send_transfer_ag_indicators_status_cmd(hfp_connection->rfcomm_cid, &hfp_ag_indicators[i]);
1791febc14f5SMatthias Ringwald                 return 1;
1792aa4dd815SMatthias Ringwald             }
1793aa4dd815SMatthias Ringwald         }
1794aa4dd815SMatthias Ringwald     }
1795aa4dd815SMatthias Ringwald 
1796245852b7SMilanka Ringwald     if (hfp_connection->ag_send_no_carrier){
1797245852b7SMilanka Ringwald         hfp_connection->ag_send_no_carrier = false;
1798245852b7SMilanka Ringwald         hfp_ag_send_no_carrier(hfp_connection->rfcomm_cid);
1799245852b7SMilanka Ringwald         return 1;
1800245852b7SMilanka Ringwald     }
1801245852b7SMilanka Ringwald 
1802a0ffb263SMatthias Ringwald     if (hfp_connection->ag_ring){
1803a0ffb263SMatthias Ringwald         hfp_connection->ag_ring = 0;
1804a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1805485ac19eSMilanka Ringwald         hfp_ag_send_ring(hfp_connection->rfcomm_cid);
1806febc14f5SMatthias Ringwald         return 1;
1807aa4dd815SMatthias Ringwald     }
1808aa4dd815SMatthias Ringwald 
1809a0ffb263SMatthias Ringwald     if (hfp_connection->ag_send_clip){
1810a0ffb263SMatthias Ringwald         hfp_connection->ag_send_clip = 0;
1811a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1812a0ffb263SMatthias Ringwald         hfp_ag_send_clip(hfp_connection->rfcomm_cid);
1813febc14f5SMatthias Ringwald         return 1;
1814aa4dd815SMatthias Ringwald     }
1815aa4dd815SMatthias Ringwald 
1816a0ffb263SMatthias Ringwald     if (hfp_connection->send_phone_number_for_voice_tag){
1817a0ffb263SMatthias Ringwald         hfp_connection->send_phone_number_for_voice_tag = 0;
1818a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1819a0ffb263SMatthias Ringwald         hfp_connection->ok_pending = 1;
1820a0ffb263SMatthias Ringwald         hfp_ag_send_phone_number_for_voice_tag_cmd(hfp_connection->rfcomm_cid);
1821febc14f5SMatthias Ringwald         return 1;
1822aa4dd815SMatthias Ringwald     }
1823aa4dd815SMatthias Ringwald 
1824a0ffb263SMatthias Ringwald     if (hfp_connection->send_subscriber_number){
1825a0ffb263SMatthias Ringwald         if (hfp_connection->next_subscriber_number_to_send < subscriber_numbers_count){
1826a0ffb263SMatthias Ringwald             hfp_phone_number_t phone = subscriber_numbers[hfp_connection->next_subscriber_number_to_send++];
1827a0ffb263SMatthias Ringwald             hfp_send_subscriber_number_cmd(hfp_connection->rfcomm_cid, phone.type, phone.number);
1828ce263fc8SMatthias Ringwald         } else {
1829a0ffb263SMatthias Ringwald             hfp_connection->send_subscriber_number = 0;
1830a0ffb263SMatthias Ringwald             hfp_connection->next_subscriber_number_to_send = 0;
1831485ac19eSMilanka Ringwald             hfp_ag_send_ok(hfp_connection->rfcomm_cid);
1832ce263fc8SMatthias Ringwald         }
1833a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1834febc14f5SMatthias Ringwald         return 1;
1835ce263fc8SMatthias Ringwald     }
1836ce263fc8SMatthias Ringwald 
1837a0ffb263SMatthias Ringwald     if (hfp_connection->send_microphone_gain){
1838a0ffb263SMatthias Ringwald         hfp_connection->send_microphone_gain = 0;
1839a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1840485ac19eSMilanka Ringwald         hfp_ag_send_set_microphone_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->microphone_gain);
1841febc14f5SMatthias Ringwald         return 1;
1842aa4dd815SMatthias Ringwald     }
1843aa4dd815SMatthias Ringwald 
1844a0ffb263SMatthias Ringwald     if (hfp_connection->send_speaker_gain){
1845a0ffb263SMatthias Ringwald         hfp_connection->send_speaker_gain = 0;
1846a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1847485ac19eSMilanka Ringwald         hfp_ag_send_set_speaker_gain_cmd(hfp_connection->rfcomm_cid, hfp_connection->speaker_gain);
1848febc14f5SMatthias Ringwald         return 1;
18493deb3ec6SMatthias Ringwald     }
18503deb3ec6SMatthias Ringwald 
1851a0ffb263SMatthias Ringwald     if (hfp_connection->send_ag_status_indicators){
1852a0ffb263SMatthias Ringwald         hfp_connection->send_ag_status_indicators = 0;
1853485ac19eSMilanka Ringwald         hfp_ag_send_retrieve_indicators_status_cmd(hfp_connection->rfcomm_cid);
1854febc14f5SMatthias Ringwald         return 1;
1855febc14f5SMatthias Ringwald     }
1856febc14f5SMatthias Ringwald 
1857febc14f5SMatthias Ringwald     return 0;
1858febc14f5SMatthias Ringwald }
1859febc14f5SMatthias Ringwald 
1860febc14f5SMatthias Ringwald static void hfp_ag_run_for_context(hfp_connection_t *hfp_connection){
1861febc14f5SMatthias Ringwald 
186276cc1527SMatthias Ringwald 	btstack_assert(hfp_connection != NULL);
186376cc1527SMatthias Ringwald 	btstack_assert(hfp_connection->local_role == HFP_ROLE_AG);
1864febc14f5SMatthias Ringwald 
186576cc1527SMatthias Ringwald 	// during SDP query, RFCOMM CID is not set
186676cc1527SMatthias Ringwald 	if (hfp_connection->rfcomm_cid == 0) return;
1867ce263fc8SMatthias Ringwald 
18683721a235SMatthias Ringwald     // assert command could be sent
18693721a235SMatthias Ringwald     if (hci_can_send_command_packet_now() == 0) return;
18703721a235SMatthias Ringwald 
1871f9f3ba28SMilanka Ringwald     if ((hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) && hfp_connection->release_audio_connection){
1872f9f3ba28SMilanka Ringwald         hfp_connection->state = HFP_W4_SCO_DISCONNECTED;
1873f9f3ba28SMilanka Ringwald         hfp_connection->release_audio_connection = 0;
1874f9f3ba28SMilanka Ringwald         gap_disconnect(hfp_connection->sco_handle);
1875f9f3ba28SMilanka Ringwald         return;
1876f9f3ba28SMilanka Ringwald     }
1877f9f3ba28SMilanka Ringwald 
18783721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP
18793721a235SMatthias Ringwald     // WBS Disassociate
18803721a235SMatthias Ringwald     if (hfp_connection->cc256x_send_wbs_disassociate){
18813721a235SMatthias Ringwald         hfp_connection->cc256x_send_wbs_disassociate = false;
18823721a235SMatthias Ringwald         hci_send_cmd(&hci_ti_wbs_disassociate);
18833721a235SMatthias Ringwald         return;
18843721a235SMatthias Ringwald     }
18853721a235SMatthias Ringwald     // Write Codec Config
18863721a235SMatthias Ringwald     if (hfp_connection->cc256x_send_write_codec_config){
18873721a235SMatthias Ringwald         hfp_connection->cc256x_send_write_codec_config = false;
18883721a235SMatthias Ringwald         hfp_cc256x_write_codec_config(hfp_connection);
18893721a235SMatthias Ringwald         return;
18903721a235SMatthias Ringwald     }
18913721a235SMatthias Ringwald     // WBS Associate
18923721a235SMatthias Ringwald     if (hfp_connection->cc256x_send_wbs_associate){
18933721a235SMatthias Ringwald         hfp_connection->cc256x_send_wbs_associate = false;
18943721a235SMatthias Ringwald         hci_send_cmd(&hci_ti_wbs_associate, hfp_connection->acl_handle);
18953721a235SMatthias Ringwald         return;
18963721a235SMatthias Ringwald     }
18973721a235SMatthias Ringwald #endif
1898689d4323SMatthias Ringwald #ifdef ENABLE_BCM_PCM_WBS
1899689d4323SMatthias Ringwald     // Enable WBS
1900689d4323SMatthias Ringwald     if (hfp_connection->bcm_send_enable_wbs){
1901689d4323SMatthias Ringwald         hfp_connection->bcm_send_enable_wbs = false;
1902689d4323SMatthias Ringwald         hci_send_cmd(&hci_bcm_enable_wbs, 1, 2);
1903689d4323SMatthias Ringwald         return;
1904689d4323SMatthias Ringwald     }
1905689d4323SMatthias Ringwald     // Write I2S/PCM params
1906689d4323SMatthias Ringwald     if (hfp_connection->bcm_send_write_i2spcm_interface_param){
1907689d4323SMatthias Ringwald         hfp_connection->bcm_send_write_i2spcm_interface_param = false;
1908689d4323SMatthias Ringwald         hfp_bcm_write_i2spcm_interface_param(hfp_connection);
1909689d4323SMatthias Ringwald         return;
1910689d4323SMatthias Ringwald     }
1911689d4323SMatthias Ringwald     // Disable WBS
1912689d4323SMatthias Ringwald     if (hfp_connection->bcm_send_disable_wbs){
1913689d4323SMatthias Ringwald         hfp_connection->bcm_send_disable_wbs = false;
1914689d4323SMatthias Ringwald         hci_send_cmd(&hci_bcm_enable_wbs, 0, 2);
1915689d4323SMatthias Ringwald         return;
1916689d4323SMatthias Ringwald     }
1917689d4323SMatthias Ringwald #endif
191848e6eeeeSMatthias Ringwald #if defined (ENABLE_CC256X_ASSISTED_HFP) || defined (ENABLE_BCM_PCM_WBS)
191948e6eeeeSMatthias Ringwald     if (hfp_connection->state == HFP_W4_WBS_SHUTDOWN){
192048e6eeeeSMatthias Ringwald         hfp_finalize_connection_context(hfp_connection);
192148e6eeeeSMatthias Ringwald         return;
192248e6eeeeSMatthias Ringwald     }
192348e6eeeeSMatthias Ringwald #endif
19243721a235SMatthias Ringwald 
1925febc14f5SMatthias Ringwald     if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) {
1926febc14f5SMatthias Ringwald         log_info("hfp_ag_run_for_context: request can send for 0x%02x", hfp_connection->rfcomm_cid);
1927febc14f5SMatthias Ringwald         rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
1928febc14f5SMatthias Ringwald         return;
1929febc14f5SMatthias Ringwald     }
1930febc14f5SMatthias Ringwald 
1931febc14f5SMatthias Ringwald     int cmd_sent = hfp_ag_send_commands(hfp_connection);
1932febc14f5SMatthias Ringwald 
1933febc14f5SMatthias Ringwald     if (!cmd_sent){
1934febc14f5SMatthias Ringwald         cmd_sent = hfp_ag_run_for_context_service_level_connection(hfp_connection);
1935febc14f5SMatthias Ringwald     }
1936febc14f5SMatthias Ringwald 
1937c04cf7ffSMilanka Ringwald     if (!cmd_sent){
1938c04cf7ffSMilanka Ringwald         cmd_sent = hfp_ag_run_for_context_service_level_connection_queries(hfp_connection);
19393deb3ec6SMatthias Ringwald     }
19403deb3ec6SMatthias Ringwald 
1941c04cf7ffSMilanka Ringwald     if (!cmd_sent){
1942c04cf7ffSMilanka Ringwald         cmd_sent = call_setup_state_machine(hfp_connection);
1943aa4dd815SMatthias Ringwald     }
1944aa4dd815SMatthias Ringwald 
1945b956fff3SMatthias Ringwald     // trigger codec exchange (must be before hfp_ag_run_for_audio_connection)
1946d0a0eceeSMatthias Ringwald     if (!cmd_sent && (hfp_connection->command == HFP_CMD_NONE) && hfp_connection->trigger_codec_exchange){
1947d0a0eceeSMatthias Ringwald         switch (hfp_connection->codecs_state){
1948d0a0eceeSMatthias Ringwald             case HFP_CODECS_IDLE:
1949d0a0eceeSMatthias Ringwald             case HFP_CODECS_RECEIVED_LIST:
1950d0a0eceeSMatthias Ringwald             case HFP_CODECS_AG_RESEND_COMMON_CODEC:
1951d0a0eceeSMatthias Ringwald             case HFP_CODECS_ERROR:
1952d0a0eceeSMatthias Ringwald                 hfp_connection->trigger_codec_exchange = 0;
1953d0a0eceeSMatthias Ringwald                 hfp_connection->command = HFP_CMD_AG_SEND_COMMON_CODEC;
19543deb3ec6SMatthias Ringwald                 break;
19553deb3ec6SMatthias Ringwald             default:
19563deb3ec6SMatthias Ringwald                 break;
19573deb3ec6SMatthias Ringwald         }
19583deb3ec6SMatthias Ringwald     }
1959c04cf7ffSMilanka Ringwald 
1960b956fff3SMatthias Ringwald     if (!cmd_sent){
1961b956fff3SMatthias Ringwald         cmd_sent = hfp_ag_run_for_audio_connection(hfp_connection);
1962b956fff3SMatthias Ringwald     }
1963b956fff3SMatthias Ringwald 
1964b956fff3SMatthias Ringwald 
1965d0a0eceeSMatthias Ringwald     // disconnect
1966d0a0eceeSMatthias Ringwald     if (!cmd_sent && (hfp_connection->command == HFP_CMD_NONE) && (hfp_connection->state == HFP_W2_DISCONNECT_RFCOMM)){
1967d0a0eceeSMatthias Ringwald         hfp_connection->state = HFP_W4_RFCOMM_DISCONNECTED;
1968d0a0eceeSMatthias Ringwald         rfcomm_disconnect(hfp_connection->rfcomm_cid);
1969d0a0eceeSMatthias Ringwald     }
1970d0a0eceeSMatthias Ringwald 
1971c04cf7ffSMilanka Ringwald     if (cmd_sent){
1972a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_NONE;
1973473ac565SMatthias Ringwald         rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
1974473ac565SMatthias Ringwald     }
19753deb3ec6SMatthias Ringwald }
1976d68dcce1SMatthias Ringwald 
1977e0d09929SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){
1978c1ab6cc1SMatthias Ringwald     return (byte == '\n') || (byte == '\r');
1979e0d09929SMatthias Ringwald }
1980e0d09929SMatthias Ringwald 
1981e9c22d4eSMatthias Ringwald static void hfp_ag_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
19828a46ec40SMatthias Ringwald     UNUSED(packet_type);    // ok: only called with RFCOMM_DATA_PACKET
19838a46ec40SMatthias Ringwald 
19848a46ec40SMatthias Ringwald     // assertion: size >= 1 as rfcomm.c does not deliver empty packets
19858a46ec40SMatthias Ringwald     if (size < 1) return;
19869ec2630cSMatthias Ringwald 
1987a0ffb263SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_connection_context_for_rfcomm_cid(channel);
1988a0ffb263SMatthias Ringwald     if (!hfp_connection) return;
19891e35c04dSMatthias Ringwald 
1990186dd3d2SMatthias Ringwald     hfp_log_rfcomm_message("HFP_AG_RX", packet, size);
1991e43d1938SMatthias Ringwald #ifdef ENABLE_HFP_AT_MESSAGES
1992e43d1938SMatthias Ringwald     hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_RECEIVED, (char *) packet);
1993e43d1938SMatthias Ringwald #endif
19941e35c04dSMatthias Ringwald 
19958a46ec40SMatthias Ringwald     // process messages byte-wise
19963deb3ec6SMatthias Ringwald     int pos;
19973deb3ec6SMatthias Ringwald     for (pos = 0; pos < size ; pos++){
1998a0ffb263SMatthias Ringwald         hfp_parse(hfp_connection, packet[pos], 0);
1999186dd3d2SMatthias Ringwald 
2000e0d09929SMatthias Ringwald         // parse until end of line
2001e0d09929SMatthias Ringwald         if (!hfp_parser_is_end_of_line(packet[pos])) continue;
2002e0d09929SMatthias Ringwald 
2003186dd3d2SMatthias Ringwald         hfp_generic_status_indicator_t * indicator;
2004a0ffb263SMatthias Ringwald         switch(hfp_connection->command){
2005*45796ff1SMilanka Ringwald             case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
2006*45796ff1SMilanka Ringwald                 if (hfp_connection->ag_activate_voice_recognition == 0){
2007*45796ff1SMilanka Ringwald                     hfp_release_audio_connection(hfp_connection);
2008*45796ff1SMilanka Ringwald                 }
2009*45796ff1SMilanka Ringwald                 break;
2010ce263fc8SMatthias Ringwald             case HFP_CMD_RESPONSE_AND_HOLD_QUERY:
2011ce263fc8SMatthias Ringwald                 if (hfp_ag_response_and_hold_active){
2012a0ffb263SMatthias Ringwald                     hfp_connection->send_response_and_hold_status = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD + 1;
2013ce263fc8SMatthias Ringwald                 }
2014a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2015ce263fc8SMatthias Ringwald                 break;
2016ce263fc8SMatthias Ringwald             case HFP_CMD_RESPONSE_AND_HOLD_COMMAND:
20170222a807SMatthias Ringwald                 switch(hfp_connection->ag_response_and_hold_action){
2018ce263fc8SMatthias Ringwald                     case HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD:
2019a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF, hfp_connection);
2020ce263fc8SMatthias Ringwald                         break;
2021ce263fc8SMatthias Ringwald                     case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_ACCEPTED:
2022a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF, hfp_connection);
2023ce263fc8SMatthias Ringwald                         break;
2024ce263fc8SMatthias Ringwald                     case HFP_RESPONSE_AND_HOLD_HELD_INCOMING_REJECTED:
2025a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF, hfp_connection);
2026ce263fc8SMatthias Ringwald                         break;
2027ce263fc8SMatthias Ringwald                     default:
2028ce263fc8SMatthias Ringwald                         break;
2029ce263fc8SMatthias Ringwald                 }
2030a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2031ce263fc8SMatthias Ringwald                 break;
2032ce263fc8SMatthias Ringwald             case HFP_CMD_HF_INDICATOR_STATUS:
2033a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
20340b6ea433SMilanka Ringwald                 if (hfp_connection->parser_indicator_index < hfp_generic_status_indicators_nr){
20350b6ea433SMilanka Ringwald                     indicator = &hfp_generic_status_indicators[hfp_connection->parser_indicator_index];
20360b6ea433SMilanka Ringwald                 } else {
2037a0ffb263SMatthias Ringwald                     hfp_connection->send_error = 1;
2038ce263fc8SMatthias Ringwald                     break;
2039ce263fc8SMatthias Ringwald                 }
2040ce263fc8SMatthias Ringwald                 switch (indicator->uuid){
2041ce263fc8SMatthias Ringwald                     case 1: // enhanced security
20420222a807SMatthias Ringwald                         if (hfp_connection->parser_indicator_value > 1) {
2043a0ffb263SMatthias Ringwald                             hfp_connection->send_error = 1;
2044ce263fc8SMatthias Ringwald                             return;
2045ce263fc8SMatthias Ringwald                         }
2046e883851fSMatthias Ringwald                         log_info("HF Indicator 'enhanced security' set to %u", (unsigned int) hfp_connection->parser_indicator_value);
2047ce263fc8SMatthias Ringwald                         break;
2048ce263fc8SMatthias Ringwald                     case 2: // battery level
20490222a807SMatthias Ringwald                         if (hfp_connection->parser_indicator_value > 100){
2050a0ffb263SMatthias Ringwald                             hfp_connection->send_error = 1;
2051ce263fc8SMatthias Ringwald                             return;
2052ce263fc8SMatthias Ringwald                         }
2053e883851fSMatthias Ringwald                         log_info("HF Indicator 'battery' set to %u", (unsigned int) hfp_connection->parser_indicator_value);
2054ce263fc8SMatthias Ringwald                         break;
2055ce263fc8SMatthias Ringwald                     default:
2056e883851fSMatthias Ringwald                         log_info("HF Indicator unknown set to %u", (unsigned int) hfp_connection->parser_indicator_value);
2057ce263fc8SMatthias Ringwald                         break;
2058ce263fc8SMatthias Ringwald                 }
2059a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2060ce263fc8SMatthias Ringwald                 break;
2061ce263fc8SMatthias Ringwald             case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
2062ce263fc8SMatthias Ringwald                 // expected by SLC state machine
2063a0ffb263SMatthias Ringwald                 if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break;
2064a0ffb263SMatthias Ringwald                 hfp_connection->send_ag_indicators_segment = 0;
2065a0ffb263SMatthias Ringwald                 hfp_connection->send_ag_status_indicators = 1;
2066ce263fc8SMatthias Ringwald                 break;
2067ce263fc8SMatthias Ringwald             case HFP_CMD_LIST_CURRENT_CALLS:
2068a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2069a0ffb263SMatthias Ringwald                 hfp_connection->next_call_index = 0;
2070a0ffb263SMatthias Ringwald                 hfp_connection->send_status_of_current_calls = 1;
2071ce263fc8SMatthias Ringwald                 break;
2072ce263fc8SMatthias Ringwald             case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION:
2073ce263fc8SMatthias Ringwald                 if (subscriber_numbers_count == 0){
2074485ac19eSMilanka Ringwald                     hfp_ag_send_ok(hfp_connection->rfcomm_cid);
2075ce263fc8SMatthias Ringwald                     break;
2076ce263fc8SMatthias Ringwald                 }
2077a0ffb263SMatthias Ringwald                 hfp_connection->next_subscriber_number_to_send = 0;
2078a0ffb263SMatthias Ringwald                 hfp_connection->send_subscriber_number = 1;
2079ce263fc8SMatthias Ringwald                 break;
2080c1797c7dSMatthias Ringwald             case HFP_CMD_TRANSMIT_DTMF_CODES:
20810222a807SMatthias Ringwald             {
2082a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
20830222a807SMatthias Ringwald                 char buffer[2];
20840222a807SMatthias Ringwald                 buffer[0] = (char) hfp_connection->ag_dtmf_code;
20850222a807SMatthias Ringwald                 buffer[1] = 0;
20860222a807SMatthias Ringwald                 hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_TRANSMIT_DTMF_CODES, buffer);
2087c1797c7dSMatthias Ringwald                 break;
20880222a807SMatthias Ringwald             }
2089aa4dd815SMatthias Ringwald             case HFP_CMD_HF_REQUEST_PHONE_NUMBER:
2090a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2091ca59be51SMatthias Ringwald                 hfp_emit_simple_event(hfp_connection, HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG);
2092aa4dd815SMatthias Ringwald                 break;
2093aa4dd815SMatthias Ringwald             case HFP_CMD_TURN_OFF_EC_AND_NR:
2094a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2095aa4dd815SMatthias Ringwald                 if (get_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION)){
2096a0ffb263SMatthias Ringwald                     hfp_connection->ok_pending = 1;
2097a0ffb263SMatthias Ringwald                     hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION, hfp_connection->ag_echo_and_noise_reduction);
209860ebb071SMilanka Ringwald                     log_info("AG: EC/NR = %u", hfp_connection->ag_echo_and_noise_reduction);
2099aa4dd815SMatthias Ringwald                 } else {
2100a0ffb263SMatthias Ringwald                     hfp_connection->send_error = 1;
2101aa4dd815SMatthias Ringwald                 }
2102aa4dd815SMatthias Ringwald                 break;
2103aa4dd815SMatthias Ringwald             case HFP_CMD_CALL_ANSWERED:
2104a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
210560ebb071SMilanka Ringwald                 log_info("HFP: ATA");
2106a0ffb263SMatthias Ringwald                 hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, hfp_connection);
2107aa4dd815SMatthias Ringwald                 break;
2108aa4dd815SMatthias Ringwald             case HFP_CMD_HANG_UP_CALL:
2109a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2110a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2111a0ffb263SMatthias Ringwald                 hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_HF, hfp_connection);
2112aa4dd815SMatthias Ringwald                 break;
2113aa4dd815SMatthias Ringwald             case HFP_CMD_CALL_HOLD: {
2114a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2115a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2116d0c20769SMatthias Ringwald 
21170222a807SMatthias Ringwald                 switch (hfp_connection->ag_call_hold_action){
21180222a807SMatthias Ringwald                     case 0:
2119d0c20769SMatthias Ringwald                         // Releases all held calls or sets User Determined User Busy (UDUB) for a waiting call.
2120a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_CALL_HOLD_USER_BUSY, hfp_connection);
2121aa4dd815SMatthias Ringwald                         break;
21220222a807SMatthias Ringwald                     case 1:
2123d0c20769SMatthias Ringwald                         // Releases all active calls (if any exist) and accepts the other (held or waiting) call.
2124d0c20769SMatthias Ringwald                         // Where both a held and a waiting call exist, the above procedures shall apply to the
2125d0c20769SMatthias Ringwald                         // waiting call (i.e., not to the held call) in conflicting situation.
2126a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection);
2127aa4dd815SMatthias Ringwald                         break;
21280222a807SMatthias Ringwald                     case 2:
2129d0c20769SMatthias Ringwald                         // Places all active calls (if any exist) on hold and accepts the other (held or waiting) call.
2130d0c20769SMatthias Ringwald                         // Where both a held and a waiting call exist, the above procedures shall apply to the
2131d0c20769SMatthias Ringwald                         // waiting call (i.e., not to the held call) in conflicting situation.
2132a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL, hfp_connection);
2133aa4dd815SMatthias Ringwald                         break;
21340222a807SMatthias Ringwald                     case 3:
2135d0c20769SMatthias Ringwald                         // Adds a held call to the conversation.
2136a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_CALL_HOLD_ADD_HELD_CALL, hfp_connection);
2137aa4dd815SMatthias Ringwald                         break;
21380222a807SMatthias Ringwald                     case 4:
2139d0c20769SMatthias Ringwald                         // Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer).
2140a0ffb263SMatthias Ringwald                         hfp_ag_call_sm(HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS, hfp_connection);
2141aa4dd815SMatthias Ringwald                         break;
2142aa4dd815SMatthias Ringwald                     default:
2143aa4dd815SMatthias Ringwald                         break;
2144aa4dd815SMatthias Ringwald                 }
21450222a807SMatthias Ringwald 				hfp_connection->call_index = 0;
214635e92150SMatthias Ringwald                 break;
2147aa4dd815SMatthias Ringwald             }
2148aa4dd815SMatthias Ringwald             case HFP_CMD_CALL_PHONE_NUMBER:
2149a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
21509ff73f41SMatthias Ringwald                 hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_INITIATED_BY_HF, hfp_connection);
2151aa4dd815SMatthias Ringwald                 break;
2152aa4dd815SMatthias Ringwald             case HFP_CMD_REDIAL_LAST_NUMBER:
2153a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2154a0ffb263SMatthias Ringwald                 hfp_ag_call_sm(HFP_AG_OUTGOING_REDIAL_INITIATED, hfp_connection);
2155aa4dd815SMatthias Ringwald                 break;
2156aa4dd815SMatthias Ringwald             case HFP_CMD_ENABLE_CLIP:
2157a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2158a0ffb263SMatthias Ringwald                 log_info("hfp: clip set, now: %u", hfp_connection->clip_enabled);
2159a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2160aa4dd815SMatthias Ringwald                 break;
2161aa4dd815SMatthias Ringwald             case HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION:
2162a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2163a0ffb263SMatthias Ringwald                 log_info("hfp: call waiting notification set, now: %u", hfp_connection->call_waiting_notification_enabled);
2164a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
2165aa4dd815SMatthias Ringwald                 break;
2166aa4dd815SMatthias Ringwald             case HFP_CMD_SET_SPEAKER_GAIN:
2167a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2168a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
216960ebb071SMilanka Ringwald                 log_info("HF speaker gain = %u", hfp_connection->speaker_gain);
21703db60f78SBjoern Hartmann                 hfp_emit_event(hfp_connection, HFP_SUBEVENT_SPEAKER_VOLUME, hfp_connection->speaker_gain);
2171aa4dd815SMatthias Ringwald                 break;
2172aa4dd815SMatthias Ringwald             case HFP_CMD_SET_MICROPHONE_GAIN:
2173a0ffb263SMatthias Ringwald                 hfp_connection->command = HFP_CMD_NONE;
2174a0ffb263SMatthias Ringwald                 hfp_connection->ok_pending = 1;
217560ebb071SMilanka Ringwald                 log_info("HF microphone gain = %u", hfp_connection->microphone_gain);
21762abbd98dSMatthias Ringwald                 hfp_emit_event(hfp_connection, HFP_SUBEVENT_MICROPHONE_VOLUME, hfp_connection->microphone_gain);
2177aa4dd815SMatthias Ringwald                 break;
2178aa4dd815SMatthias Ringwald             default:
2179aa4dd815SMatthias Ringwald                 break;
21803deb3ec6SMatthias Ringwald         }
21813deb3ec6SMatthias Ringwald     }
21820cef86faSMatthias Ringwald }
21833deb3ec6SMatthias Ringwald 
21841c6a0fc0SMatthias Ringwald static void hfp_ag_run(void){
2185d63c37a1SMatthias Ringwald     btstack_linked_list_iterator_t it;
2186d63c37a1SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
2187d63c37a1SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2188d63c37a1SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
218922387625SMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
2190f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
21913deb3ec6SMatthias Ringwald     }
21923deb3ec6SMatthias Ringwald }
21933deb3ec6SMatthias Ringwald 
21941c6a0fc0SMatthias Ringwald static void hfp_ag_rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
21953deb3ec6SMatthias Ringwald     switch (packet_type){
21963deb3ec6SMatthias Ringwald         case RFCOMM_DATA_PACKET:
2197e9c22d4eSMatthias Ringwald             hfp_ag_handle_rfcomm_data(packet_type, channel, packet, size);
21983deb3ec6SMatthias Ringwald             break;
21993deb3ec6SMatthias Ringwald         case HCI_EVENT_PACKET:
2200e30a6a47SMatthias Ringwald             if (packet[0] == RFCOMM_EVENT_CAN_SEND_NOW){
2201e30a6a47SMatthias Ringwald                 uint16_t rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet);
2202f0aeb307SMatthias Ringwald                 hfp_ag_run_for_context(get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid));
2203e30a6a47SMatthias Ringwald                 return;
2204e30a6a47SMatthias Ringwald             }
220527950165SMatthias Ringwald             hfp_handle_rfcomm_event(packet_type, channel, packet, size, HFP_ROLE_AG);
2206aa4dd815SMatthias Ringwald             break;
22073deb3ec6SMatthias Ringwald         default:
22083deb3ec6SMatthias Ringwald             break;
22093deb3ec6SMatthias Ringwald     }
22103deb3ec6SMatthias Ringwald 
22111c6a0fc0SMatthias Ringwald     hfp_ag_run();
22123deb3ec6SMatthias Ringwald }
22133deb3ec6SMatthias Ringwald 
22141c6a0fc0SMatthias Ringwald static void hfp_ag_hci_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
2215405014fbSMatthias Ringwald     hfp_handle_hci_event(packet_type, channel, packet, size, HFP_ROLE_AG);
22161c6a0fc0SMatthias Ringwald     hfp_ag_run();
2217405014fbSMatthias Ringwald }
2218405014fbSMatthias Ringwald 
22197ca89cabSMatthias Ringwald void hfp_ag_init_codecs(int codecs_nr, const uint8_t * codecs){
22203deb3ec6SMatthias Ringwald     if (codecs_nr > HFP_MAX_NUM_CODECS){
22213deb3ec6SMatthias Ringwald         log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
22223deb3ec6SMatthias Ringwald         return;
22233deb3ec6SMatthias Ringwald     }
22243deb3ec6SMatthias Ringwald     int i;
2225a0ffb263SMatthias Ringwald     hfp_codecs_nr = codecs_nr;
22263deb3ec6SMatthias Ringwald     for (i=0; i < codecs_nr; i++){
22273deb3ec6SMatthias Ringwald         hfp_codecs[i] = codecs[i];
22283deb3ec6SMatthias Ringwald     }
2229a0ffb263SMatthias Ringwald }
22303deb3ec6SMatthias Ringwald 
2231a0ffb263SMatthias Ringwald void hfp_ag_init_supported_features(uint32_t supported_features){
2232a0ffb263SMatthias Ringwald     hfp_supported_features = supported_features;
2233a0ffb263SMatthias Ringwald }
22343deb3ec6SMatthias Ringwald 
22357ca89cabSMatthias Ringwald void hfp_ag_init_ag_indicators(int ag_indicators_nr, const hfp_ag_indicator_t * ag_indicators){
2236a0ffb263SMatthias Ringwald     hfp_ag_indicators_nr = ag_indicators_nr;
22376535961aSMatthias Ringwald     (void)memcpy(hfp_ag_indicators, ag_indicators,
22386535961aSMatthias Ringwald                  ag_indicators_nr * sizeof(hfp_ag_indicator_t));
2239a0ffb263SMatthias Ringwald }
22403deb3ec6SMatthias Ringwald 
22417ca89cabSMatthias Ringwald void hfp_ag_init_hf_indicators(int hf_indicators_nr, const hfp_generic_status_indicator_t * hf_indicators){
224225789943SMilanka Ringwald     if (hf_indicators_nr > HFP_MAX_NUM_INDICATORS) return;
2243a0ffb263SMatthias Ringwald     hfp_generic_status_indicators_nr = hf_indicators_nr;
22446535961aSMatthias Ringwald     (void)memcpy(hfp_generic_status_indicators, hf_indicators,
22456535961aSMatthias Ringwald                  hf_indicators_nr * sizeof(hfp_generic_status_indicator_t));
2246a0ffb263SMatthias Ringwald }
2247a0ffb263SMatthias Ringwald 
2248a0ffb263SMatthias Ringwald void hfp_ag_init_call_hold_services(int call_hold_services_nr, const char * call_hold_services[]){
22493deb3ec6SMatthias Ringwald     hfp_ag_call_hold_services_nr = call_hold_services_nr;
22506535961aSMatthias Ringwald     (void)memcpy(hfp_ag_call_hold_services, call_hold_services,
22516535961aSMatthias Ringwald                  call_hold_services_nr * sizeof(char *));
2252a0ffb263SMatthias Ringwald }
2253a0ffb263SMatthias Ringwald 
2254a0ffb263SMatthias Ringwald 
2255a0ffb263SMatthias Ringwald void hfp_ag_init(uint16_t rfcomm_channel_nr){
225627950165SMatthias Ringwald 
2257520c92d5SMatthias Ringwald     hfp_init();
225820b2edb6SMatthias Ringwald     hfp_ag_call_hold_services_nr = 0;
225920b2edb6SMatthias Ringwald     hfp_ag_response_and_hold_active = 0;
226020b2edb6SMatthias Ringwald     hfp_ag_indicators_nr = 0;
226120b2edb6SMatthias Ringwald     hfp_codecs_nr = 0;
226220b2edb6SMatthias Ringwald     hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES;
226320b2edb6SMatthias Ringwald     subscriber_numbers = NULL;
226420b2edb6SMatthias Ringwald     subscriber_numbers_count = 0;
2265d63c37a1SMatthias Ringwald 
22661c6a0fc0SMatthias Ringwald     hfp_ag_hci_event_callback_registration.callback = &hfp_ag_hci_event_packet_handler;
22671c6a0fc0SMatthias Ringwald     hci_add_event_handler(&hfp_ag_hci_event_callback_registration);
226827950165SMatthias Ringwald 
22691c6a0fc0SMatthias Ringwald     rfcomm_register_service(&hfp_ag_rfcomm_packet_handler, rfcomm_channel_nr, 0xffff);
227027950165SMatthias Ringwald 
227127950165SMatthias Ringwald     // used to set packet handler for outgoing rfcomm connections - could be handled by emitting an event to us
22721c6a0fc0SMatthias Ringwald     hfp_set_ag_rfcomm_packet_handler(&hfp_ag_rfcomm_packet_handler);
2273aa4dd815SMatthias Ringwald 
2274d210d9c4SMatthias Ringwald     hfp_gsm_init();
22753deb3ec6SMatthias Ringwald }
22763deb3ec6SMatthias Ringwald 
227720b2edb6SMatthias Ringwald void hfp_ag_deinit(void){
227820b2edb6SMatthias Ringwald     hfp_deinit();
227920b2edb6SMatthias Ringwald     hfp_gsm_deinit();
228020b2edb6SMatthias Ringwald     (void) memset(&hfp_ag_hci_event_callback_registration, 0, sizeof(btstack_packet_callback_registration_t));
228120b2edb6SMatthias Ringwald     (void) memset(&hfp_ag_callback, 0, sizeof(btstack_packet_handler_t));
228220b2edb6SMatthias Ringwald     (void) memset(&hfp_ag_call_hold_services, 0, sizeof(hfp_ag_call_hold_services));
228320b2edb6SMatthias Ringwald     (void) memset(&hfp_ag_response_and_hold_state, 0, sizeof(hfp_response_and_hold_state_t));
228420b2edb6SMatthias Ringwald }
228520b2edb6SMatthias Ringwald 
22863deb3ec6SMatthias Ringwald void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){
2287323d3000SMatthias Ringwald     hfp_establish_service_level_connection(bd_addr, BLUETOOTH_SERVICE_CLASS_HANDSFREE, HFP_ROLE_AG);
22883deb3ec6SMatthias Ringwald }
22893deb3ec6SMatthias Ringwald 
2290d97d752dSMilanka Ringwald void hfp_ag_release_service_level_connection(hci_con_handle_t acl_handle){
22919c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2292a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2293a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2294a33eb0c4SMilanka Ringwald         return;
2295a33eb0c4SMilanka Ringwald     }
2296a0ffb263SMatthias Ringwald     hfp_release_service_level_connection(hfp_connection);
2297f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
22983deb3ec6SMatthias Ringwald }
22993deb3ec6SMatthias Ringwald 
2300d97d752dSMilanka Ringwald void hfp_ag_report_extended_audio_gateway_error_result_code(hci_con_handle_t acl_handle, hfp_cme_error_t error){
23019c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2302a0ffb263SMatthias Ringwald     if (!hfp_connection){
2303a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
23043deb3ec6SMatthias Ringwald         return;
23053deb3ec6SMatthias Ringwald     }
2306a0ffb263SMatthias Ringwald     hfp_connection->extended_audio_gateway_error = 0;
2307a0ffb263SMatthias Ringwald     if (!hfp_connection->enable_extended_audio_gateway_error_report){
23083deb3ec6SMatthias Ringwald         return;
23093deb3ec6SMatthias Ringwald     }
2310a0ffb263SMatthias Ringwald     hfp_connection->extended_audio_gateway_error = error;
2311f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
23123deb3ec6SMatthias Ringwald }
23133deb3ec6SMatthias Ringwald 
2314a0ffb263SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * hfp_connection){
23152ee45eb2SMilanka Ringwald     log_info("hfp_ag_setup_audio_connection state %u", hfp_connection->state);
2316a0ffb263SMatthias Ringwald     if (hfp_connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return;
2317a0ffb263SMatthias Ringwald     if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO) return;
23183deb3ec6SMatthias Ringwald 
2319a0ffb263SMatthias Ringwald     hfp_connection->establish_audio_connection = 1;
2320a0ffb263SMatthias Ringwald     if (!has_codec_negotiation_feature(hfp_connection)){
2321d6ff09e1SMatthias Ringwald         log_info("hfp_ag_establish_audio_connection - no codec negotiation feature, using CVSD");
2322d6ff09e1SMatthias Ringwald         hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
2323a0ffb263SMatthias Ringwald         hfp_connection->codecs_state = HFP_CODECS_EXCHANGED;
23247522e673SMatthias Ringwald         // now, pick link settings
2325afac2a04SMilanka Ringwald         hfp_init_link_settings(hfp_connection, hfp_ag_esco_s4_supported(hfp_connection));
23263721a235SMatthias Ringwald #ifdef ENABLE_CC256X_ASSISTED_HFP
23273721a235SMatthias Ringwald         hfp_cc256x_prepare_for_sco(hfp_connection);
23283721a235SMatthias Ringwald #endif
23292ee45eb2SMilanka Ringwald         return;
23303deb3ec6SMatthias Ringwald     }
2331aa4dd815SMatthias Ringwald 
2332411a9776SMilanka Ringwald     uint8_t i;
2333411a9776SMilanka Ringwald     bool codec_was_in_use = false;
2334411a9776SMilanka Ringwald     bool better_codec_can_be_used = false;
2335411a9776SMilanka Ringwald 
2336411a9776SMilanka Ringwald     for (i = 0; i<hfp_connection->remote_codecs_nr; i++){
2337411a9776SMilanka Ringwald         if (hfp_connection->negotiated_codec == hfp_connection->remote_codecs[i]){
2338411a9776SMilanka Ringwald             codec_was_in_use = true;
2339411a9776SMilanka Ringwald         } else if (hfp_connection->negotiated_codec < hfp_connection->remote_codecs[i]){
2340411a9776SMilanka Ringwald             better_codec_can_be_used = true;
2341411a9776SMilanka Ringwald         }
2342411a9776SMilanka Ringwald     }
2343411a9776SMilanka Ringwald 
2344411a9776SMilanka Ringwald     if (!codec_was_in_use || better_codec_can_be_used){
23452ee45eb2SMilanka Ringwald         hfp_connection->trigger_codec_exchange = 1;
2346411a9776SMilanka Ringwald         hfp_connection->codecs_state = HFP_CODECS_IDLE;
2347411a9776SMilanka Ringwald     }
2348aa4dd815SMatthias Ringwald }
2349aa4dd815SMatthias Ringwald 
2350d97d752dSMilanka Ringwald void hfp_ag_establish_audio_connection(hci_con_handle_t acl_handle){
23519c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2352a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2353a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2354a33eb0c4SMilanka Ringwald         return;
2355a33eb0c4SMilanka Ringwald     }
2356411a9776SMilanka Ringwald 
2357a0ffb263SMatthias Ringwald     hfp_connection->establish_audio_connection = 0;
2358a0ffb263SMatthias Ringwald     hfp_ag_setup_audio_connection(hfp_connection);
2359f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
23603deb3ec6SMatthias Ringwald }
23613deb3ec6SMatthias Ringwald 
2362d97d752dSMilanka Ringwald void hfp_ag_release_audio_connection(hci_con_handle_t acl_handle){
23639c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2364a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2365a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2366a33eb0c4SMilanka Ringwald         return;
2367a33eb0c4SMilanka Ringwald     }
2368a0ffb263SMatthias Ringwald     hfp_release_audio_connection(hfp_connection);
2369f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
23703deb3ec6SMatthias Ringwald }
2371aa4dd815SMatthias Ringwald 
2372aa4dd815SMatthias Ringwald /**
2373aa4dd815SMatthias Ringwald  * @brief Enable in-band ring tone
2374aa4dd815SMatthias Ringwald  */
2375aa4dd815SMatthias Ringwald void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone){
2376aa4dd815SMatthias Ringwald     if (get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE) == use_in_band_ring_tone){
2377aa4dd815SMatthias Ringwald         return;
2378aa4dd815SMatthias Ringwald     }
2379aa4dd815SMatthias Ringwald     hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE, use_in_band_ring_tone);
2380aa4dd815SMatthias Ringwald 
2381665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
2382665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
2383665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2384a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
238566c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
2386a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING;
2387f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
2388aa4dd815SMatthias Ringwald     }
2389aa4dd815SMatthias Ringwald }
2390aa4dd815SMatthias Ringwald 
2391aa4dd815SMatthias Ringwald /**
2392aa4dd815SMatthias Ringwald  * @brief Called from GSM
2393aa4dd815SMatthias Ringwald  */
2394aa4dd815SMatthias Ringwald void hfp_ag_incoming_call(void){
2395aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_INCOMING_CALL, NULL);
2396aa4dd815SMatthias Ringwald }
2397aa4dd815SMatthias Ringwald 
2398fe899794SMatthias Ringwald void hfp_ag_outgoing_call_initiated(const char * number) {
2399c5753b03SMatthias Ringwald     UNUSED(number);
2400fe899794SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_INITIATED_BY_AG, NULL);
2401fe899794SMatthias Ringwald }
2402fe899794SMatthias Ringwald 
2403aa4dd815SMatthias Ringwald /**
2404aa4dd815SMatthias Ringwald  * @brief number is stored.
2405aa4dd815SMatthias Ringwald  */
2406aa4dd815SMatthias Ringwald void hfp_ag_set_clip(uint8_t type, const char * number){
2407f8737b81SMatthias Ringwald     hfp_gsm_handler(HFP_AG_SET_CLIP, 0, type, number);
2408aa4dd815SMatthias Ringwald }
2409aa4dd815SMatthias Ringwald 
2410aa4dd815SMatthias Ringwald void hfp_ag_call_dropped(void){
2411aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL);
2412aa4dd815SMatthias Ringwald }
2413aa4dd815SMatthias Ringwald 
2414aa4dd815SMatthias Ringwald // call from AG UI
2415aa4dd815SMatthias Ringwald void hfp_ag_answer_incoming_call(void){
2416aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, NULL);
2417aa4dd815SMatthias Ringwald }
2418aa4dd815SMatthias Ringwald 
2419ce263fc8SMatthias Ringwald void hfp_ag_join_held_call(void){
2420ce263fc8SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_HELD_CALL_JOINED_BY_AG, NULL);
2421ce263fc8SMatthias Ringwald }
2422ce263fc8SMatthias Ringwald 
2423aa4dd815SMatthias Ringwald void hfp_ag_terminate_call(void){
2424aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_AG, NULL);
2425aa4dd815SMatthias Ringwald }
2426aa4dd815SMatthias Ringwald 
2427aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_ringing(void){
2428aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_RINGING, NULL);
2429aa4dd815SMatthias Ringwald }
2430aa4dd815SMatthias Ringwald 
2431aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_established(void){
2432aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ESTABLISHED, NULL);
2433aa4dd815SMatthias Ringwald }
2434aa4dd815SMatthias Ringwald 
2435aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_rejected(void){
2436aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_REJECTED, NULL);
2437aa4dd815SMatthias Ringwald }
2438aa4dd815SMatthias Ringwald 
2439aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_accepted(void){
2440aa4dd815SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ACCEPTED, NULL);
2441aa4dd815SMatthias Ringwald }
2442ce263fc8SMatthias Ringwald 
2443ce263fc8SMatthias Ringwald void hfp_ag_hold_incoming_call(void){
2444ce263fc8SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG, NULL);
2445ce263fc8SMatthias Ringwald }
2446ce263fc8SMatthias Ringwald 
2447ce263fc8SMatthias Ringwald void hfp_ag_accept_held_incoming_call(void) {
2448ce263fc8SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG, NULL);
2449ce263fc8SMatthias Ringwald }
2450ce263fc8SMatthias Ringwald 
2451ce263fc8SMatthias Ringwald void hfp_ag_reject_held_incoming_call(void){
2452ce263fc8SMatthias Ringwald     hfp_ag_call_sm(HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG, NULL);
2453ce263fc8SMatthias Ringwald }
2454ce263fc8SMatthias Ringwald 
2455aa4dd815SMatthias Ringwald static void hfp_ag_set_ag_indicator(const char * name, int value){
2456aa4dd815SMatthias Ringwald     int indicator_index = get_ag_indicator_index_for_name(name);
2457aa4dd815SMatthias Ringwald     if (indicator_index < 0) return;
2458aa4dd815SMatthias Ringwald     hfp_ag_indicators[indicator_index].status = value;
2459aa4dd815SMatthias Ringwald 
2460665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
2461665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
2462665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2463a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
246466c5995fSMatthias Ringwald         if (hfp_connection->local_role != HFP_ROLE_AG) continue;
2465a0ffb263SMatthias Ringwald         if (!hfp_connection->ag_indicators[indicator_index].enabled) {
2466245852b7SMilanka Ringwald             log_info("Requested AG indicator '%s' update to %u, but it is not enabled", hfp_ag_indicators[indicator_index].name, value);
2467ce263fc8SMatthias Ringwald             continue;
2468ce263fc8SMatthias Ringwald         }
2469245852b7SMilanka Ringwald         log_info("AG indicator '%s' changed to %u, request transfer status", hfp_ag_indicators[indicator_index].name, value);
2470a0ffb263SMatthias Ringwald         hfp_connection->ag_indicators_status_update_bitmap = store_bit(hfp_connection->ag_indicators_status_update_bitmap, indicator_index, 1);
2471f0aeb307SMatthias Ringwald         hfp_ag_run_for_context(hfp_connection);
2472aa4dd815SMatthias Ringwald     }
2473aa4dd815SMatthias Ringwald }
2474aa4dd815SMatthias Ringwald 
2475aa4dd815SMatthias Ringwald void hfp_ag_set_registration_status(int status){
2476245852b7SMilanka Ringwald     if ( (status == 0) && (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT)){
2477245852b7SMilanka Ringwald 
2478245852b7SMilanka Ringwald         // if network goes away wihle a call is active:
2479245852b7SMilanka Ringwald         // - the  call gets dropped
2480245852b7SMilanka Ringwald         // - we send NO CARRIER
2481245852b7SMilanka Ringwald         // NOTE: the CALL=0 has to be sent before NO CARRIER
2482245852b7SMilanka Ringwald 
2483245852b7SMilanka Ringwald         hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL);
2484245852b7SMilanka Ringwald 
2485245852b7SMilanka Ringwald         btstack_linked_list_iterator_t it;
2486245852b7SMilanka Ringwald         btstack_linked_list_iterator_init(&it, hfp_get_connections());
2487245852b7SMilanka Ringwald         while (btstack_linked_list_iterator_has_next(&it)){
2488245852b7SMilanka Ringwald             hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
2489245852b7SMilanka Ringwald             hfp_connection->ag_send_no_carrier = true;
2490245852b7SMilanka Ringwald         }
2491245852b7SMilanka Ringwald     }
2492aa4dd815SMatthias Ringwald     hfp_ag_set_ag_indicator("service", status);
2493aa4dd815SMatthias Ringwald }
2494aa4dd815SMatthias Ringwald 
2495aa4dd815SMatthias Ringwald void hfp_ag_set_signal_strength(int strength){
2496aa4dd815SMatthias Ringwald     hfp_ag_set_ag_indicator("signal", strength);
2497aa4dd815SMatthias Ringwald }
2498aa4dd815SMatthias Ringwald 
2499aa4dd815SMatthias Ringwald void hfp_ag_set_roaming_status(int status){
2500aa4dd815SMatthias Ringwald     hfp_ag_set_ag_indicator("roam", status);
2501aa4dd815SMatthias Ringwald }
2502aa4dd815SMatthias Ringwald 
2503aa4dd815SMatthias Ringwald void hfp_ag_set_battery_level(int level){
2504aa4dd815SMatthias Ringwald     hfp_ag_set_ag_indicator("battchg", level);
2505aa4dd815SMatthias Ringwald }
2506aa4dd815SMatthias Ringwald 
2507d97d752dSMilanka Ringwald void hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle, int activate){
2508aa4dd815SMatthias Ringwald     if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
25099c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2510a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2511a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2512a33eb0c4SMilanka Ringwald         return;
2513a33eb0c4SMilanka Ringwald     }
2514aa4dd815SMatthias Ringwald 
2515a0ffb263SMatthias Ringwald     if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) {
251660ebb071SMilanka Ringwald         log_info("AG cannot acivate voice recognition - not supported by HF");
2517aa4dd815SMatthias Ringwald         return;
2518aa4dd815SMatthias Ringwald     }
2519aa4dd815SMatthias Ringwald 
2520a0ffb263SMatthias Ringwald     hfp_connection->ag_activate_voice_recognition = activate;
2521a0ffb263SMatthias Ringwald     hfp_connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION;
2522f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
2523aa4dd815SMatthias Ringwald }
2524aa4dd815SMatthias Ringwald 
2525*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_activate(hci_con_handle_t acl_handle){
2526*45796ff1SMilanka Ringwald     if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
2527*45796ff1SMilanka Ringwald 
2528*45796ff1SMilanka Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2529*45796ff1SMilanka Ringwald     if (!hfp_connection){
2530*45796ff1SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2531*45796ff1SMilanka Ringwald         return;
2532*45796ff1SMilanka Ringwald     }
2533*45796ff1SMilanka Ringwald     if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
2534*45796ff1SMilanka Ringwald 
2535*45796ff1SMilanka Ringwald     hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
2536*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY;
2537*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
2538*45796ff1SMilanka Ringwald     hfp_ag_run_for_context(hfp_connection);
2539*45796ff1SMilanka Ringwald }
2540*45796ff1SMilanka Ringwald 
2541*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_deactivate(hci_con_handle_t acl_handle){
2542*45796ff1SMilanka Ringwald     if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
2543*45796ff1SMilanka Ringwald 
2544*45796ff1SMilanka Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2545*45796ff1SMilanka Ringwald     if (!hfp_connection){
2546*45796ff1SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2547*45796ff1SMilanka Ringwald         return;
2548*45796ff1SMilanka Ringwald     }
2549*45796ff1SMilanka Ringwald     if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
2550*45796ff1SMilanka Ringwald 
2551*45796ff1SMilanka Ringwald     hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
2552*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY;
2553*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF;
2554*45796ff1SMilanka Ringwald     hfp_ag_run_for_context(hfp_connection);
2555*45796ff1SMilanka Ringwald }
2556*45796ff1SMilanka Ringwald 
2557*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_status(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state){
2558*45796ff1SMilanka Ringwald     if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
2559*45796ff1SMilanka Ringwald 
2560*45796ff1SMilanka Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2561*45796ff1SMilanka Ringwald     if (!hfp_connection){
2562*45796ff1SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2563*45796ff1SMilanka Ringwald         return;
2564*45796ff1SMilanka Ringwald     }
2565*45796ff1SMilanka Ringwald     if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
2566*45796ff1SMilanka Ringwald 
2567*45796ff1SMilanka Ringwald     hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
2568*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_state = state;
2569*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS;
2570*45796ff1SMilanka Ringwald     hfp_ag_run_for_context(hfp_connection);
2571*45796ff1SMilanka Ringwald }
2572*45796ff1SMilanka Ringwald 
2573*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_starting_sound(hci_con_handle_t acl_handle){
2574*45796ff1SMilanka Ringwald     hfp_ag_enhanced_voice_recognition_status(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_SENDING_AUDIO_TO_HF);
2575*45796ff1SMilanka Ringwald }
2576*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_ready_for_input(hci_con_handle_t acl_handle){
2577*45796ff1SMilanka Ringwald     hfp_ag_enhanced_voice_recognition_status(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT);
2578*45796ff1SMilanka Ringwald }
2579*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_processing_input(hci_con_handle_t acl_handle){
2580*45796ff1SMilanka Ringwald     hfp_ag_enhanced_voice_recognition_status(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT);
2581*45796ff1SMilanka Ringwald }
2582*45796ff1SMilanka Ringwald 
2583*45796ff1SMilanka Ringwald void hfp_ag_enhanced_voice_recognition_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg){
2584*45796ff1SMilanka Ringwald     if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
2585*45796ff1SMilanka Ringwald 
2586*45796ff1SMilanka Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2587*45796ff1SMilanka Ringwald     if (!hfp_connection){
2588*45796ff1SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2589*45796ff1SMilanka Ringwald         return;
2590*45796ff1SMilanka Ringwald     }
2591*45796ff1SMilanka Ringwald     if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
2592*45796ff1SMilanka Ringwald 
2593*45796ff1SMilanka Ringwald     hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
2594*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_state = state;
2595*45796ff1SMilanka Ringwald     hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_MSG;
2596*45796ff1SMilanka Ringwald     hfp_connection->ag_msg = msg;
2597*45796ff1SMilanka Ringwald     hfp_ag_run_for_context(hfp_connection);
2598*45796ff1SMilanka Ringwald }
2599*45796ff1SMilanka Ringwald 
2600d97d752dSMilanka Ringwald void hfp_ag_set_microphone_gain(hci_con_handle_t acl_handle, int gain){
26019c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2602a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2603a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2604a33eb0c4SMilanka Ringwald         return;
2605a33eb0c4SMilanka Ringwald     }
2606a0ffb263SMatthias Ringwald     if (hfp_connection->microphone_gain != gain){
2607a0ffb263SMatthias Ringwald         hfp_connection->command = HFP_CMD_SET_MICROPHONE_GAIN;
2608a0ffb263SMatthias Ringwald         hfp_connection->microphone_gain = gain;
2609a0ffb263SMatthias Ringwald         hfp_connection->send_microphone_gain = 1;
2610aa4dd815SMatthias Ringwald     }
2611f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
2612aa4dd815SMatthias Ringwald }
2613aa4dd815SMatthias Ringwald 
2614d97d752dSMilanka Ringwald void hfp_ag_set_speaker_gain(hci_con_handle_t acl_handle, int gain){
26159c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2616a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2617a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2618a33eb0c4SMilanka Ringwald         return;
2619a33eb0c4SMilanka Ringwald     }
2620a0ffb263SMatthias Ringwald     if (hfp_connection->speaker_gain != gain){
2621a0ffb263SMatthias Ringwald         hfp_connection->speaker_gain = gain;
2622a0ffb263SMatthias Ringwald         hfp_connection->send_speaker_gain = 1;
2623aa4dd815SMatthias Ringwald     }
2624f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
2625aa4dd815SMatthias Ringwald }
2626aa4dd815SMatthias Ringwald 
2627d97d752dSMilanka Ringwald void hfp_ag_send_phone_number_for_voice_tag(hci_con_handle_t acl_handle, const char * number){
26289c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2629a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2630a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2631a33eb0c4SMilanka Ringwald         return;
2632a33eb0c4SMilanka Ringwald     }
2633aa4dd815SMatthias Ringwald     hfp_ag_set_clip(0, number);
2634a0ffb263SMatthias Ringwald     hfp_connection->send_phone_number_for_voice_tag = 1;
2635aa4dd815SMatthias Ringwald }
2636aa4dd815SMatthias Ringwald 
2637d97d752dSMilanka Ringwald void hfp_ag_reject_phone_number_for_voice_tag(hci_con_handle_t acl_handle){
26389c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2639a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2640a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2641a33eb0c4SMilanka Ringwald         return;
2642a33eb0c4SMilanka Ringwald     }
2643a0ffb263SMatthias Ringwald     hfp_connection->send_error = 1;
2644aa4dd815SMatthias Ringwald }
2645aa4dd815SMatthias Ringwald 
2646d97d752dSMilanka Ringwald void hfp_ag_send_dtmf_code_done(hci_con_handle_t acl_handle){
26479c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2648a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2649a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2650a33eb0c4SMilanka Ringwald         return;
2651a33eb0c4SMilanka Ringwald     }
2652a0ffb263SMatthias Ringwald     hfp_connection->ok_pending = 1;
2653c1797c7dSMatthias Ringwald }
2654aa4dd815SMatthias Ringwald 
2655ce263fc8SMatthias Ringwald void hfp_ag_set_subcriber_number_information(hfp_phone_number_t * numbers, int numbers_count){
2656ce263fc8SMatthias Ringwald     subscriber_numbers = numbers;
2657ce263fc8SMatthias Ringwald     subscriber_numbers_count = numbers_count;
2658ce263fc8SMatthias Ringwald }
2659ce263fc8SMatthias Ringwald 
26609cae807eSMatthias Ringwald void hfp_ag_clear_last_dialed_number(void){
26619cae807eSMatthias Ringwald     hfp_gsm_clear_last_dialed_number();
2662ce263fc8SMatthias Ringwald }
2663ce263fc8SMatthias Ringwald 
26649de679b7SMilanka Ringwald void hfp_ag_set_last_dialed_number(const char * number){
26659de679b7SMilanka Ringwald     hfp_gsm_set_last_dialed_number(number);
26669de679b7SMilanka Ringwald }
26679de679b7SMilanka Ringwald 
2668d97d752dSMilanka Ringwald void hfp_ag_notify_incoming_call_waiting(hci_con_handle_t acl_handle){
26699c9c64c1SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
2670a33eb0c4SMilanka Ringwald     if (!hfp_connection){
2671a33eb0c4SMilanka Ringwald         log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
2672a33eb0c4SMilanka Ringwald         return;
2673a33eb0c4SMilanka Ringwald     }
2674a0ffb263SMatthias Ringwald     if (!hfp_connection->call_waiting_notification_enabled) return;
2675a0ffb263SMatthias Ringwald 
2676a0ffb263SMatthias Ringwald     hfp_connection->ag_notify_incoming_call_waiting = 1;
2677f0aeb307SMatthias Ringwald     hfp_ag_run_for_context(hfp_connection);
2678a0ffb263SMatthias Ringwald }
2679ce263fc8SMatthias Ringwald 
268076cc1527SMatthias Ringwald void hfp_ag_create_sdp_record(uint8_t * service, uint32_t service_record_handle, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features, int wide_band_speech){
268176cc1527SMatthias Ringwald 	if (!name){
268276cc1527SMatthias Ringwald 		name = default_hfp_ag_service_name;
268376cc1527SMatthias Ringwald 	}
268476cc1527SMatthias Ringwald 	hfp_create_sdp_record(service, service_record_handle, BLUETOOTH_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, rfcomm_channel_nr, name);
268576cc1527SMatthias Ringwald 
268676cc1527SMatthias Ringwald 	/*
268776cc1527SMatthias Ringwald 	 * 0x01 – Ability to reject a call
268876cc1527SMatthias Ringwald 	 * 0x00 – No ability to reject a call
268976cc1527SMatthias Ringwald 	 */
269076cc1527SMatthias Ringwald 	de_add_number(service, DE_UINT, DE_SIZE_16, 0x0301);    // Hands-Free Profile - Network
269176cc1527SMatthias Ringwald 	de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call);
269276cc1527SMatthias Ringwald 
269376cc1527SMatthias Ringwald 	// Construct SupportedFeatures for SDP bitmap:
269476cc1527SMatthias Ringwald 	//
269576cc1527SMatthias Ringwald 	// "The values of the “SupportedFeatures” bitmap given in Table 5.4 shall be the same as the values
269676cc1527SMatthias Ringwald 	//  of the Bits 0 to 4 of the unsolicited result code +BRSF"
269776cc1527SMatthias Ringwald 	//
269876cc1527SMatthias Ringwald 	// Wide band speech (bit 5) requires Codec negotiation
269976cc1527SMatthias Ringwald 	//
270076cc1527SMatthias Ringwald 	uint16_t sdp_features = supported_features & 0x1f;
2701ef3ae4ebSMilanka Ringwald 	if ( (wide_band_speech == 1) && (supported_features & (1 << HFP_AGSF_CODEC_NEGOTIATION))){
270276cc1527SMatthias Ringwald 		sdp_features |= 1 << 5;
270376cc1527SMatthias Ringwald 	}
2704ef3ae4ebSMilanka Ringwald 
2705ef3ae4ebSMilanka Ringwald     if (supported_features & (1 << HFP_AGSF_ENHANCED_VOICE_RECOGNITION_STATUS)){
2706ef3ae4ebSMilanka Ringwald         sdp_features |= 1 << 6;
2707ef3ae4ebSMilanka Ringwald     }
2708ef3ae4ebSMilanka Ringwald 
2709ef3ae4ebSMilanka Ringwald     if (supported_features & (1 << HFP_AGSF_VOICE_RECOGNITION_TEXT)){
2710ef3ae4ebSMilanka Ringwald         sdp_features |= 1 << 7;
2711ef3ae4ebSMilanka Ringwald     }
2712ef3ae4ebSMilanka Ringwald 
271376cc1527SMatthias Ringwald 	de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);    // Hands-Free Profile - SupportedFeatures
271476cc1527SMatthias Ringwald 	de_add_number(service, DE_UINT, DE_SIZE_16, sdp_features);
271576cc1527SMatthias Ringwald }
271676cc1527SMatthias Ringwald 
271776cc1527SMatthias Ringwald void hfp_ag_register_packet_handler(btstack_packet_handler_t callback){
271876cc1527SMatthias Ringwald 	if (callback == NULL){
271976cc1527SMatthias Ringwald 		log_error("hfp_ag_register_packet_handler called with NULL callback");
272076cc1527SMatthias Ringwald 		return;
272176cc1527SMatthias Ringwald 	}
272276cc1527SMatthias Ringwald 	hfp_ag_callback = callback;
272376cc1527SMatthias Ringwald 	hfp_set_ag_callback(callback);
272476cc1527SMatthias Ringwald }
2725