xref: /btstack/src/classic/hfp.c (revision 8901a7c412361ec9d466369333438b4345d35730)
13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald  *
43deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald  * are met:
73deb3ec6SMatthias Ringwald  *
83deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald  *    monetary gain.
193deb3ec6SMatthias Ringwald  *
203deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
233deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
243deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald  *
333deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald  * [email protected]
353deb3ec6SMatthias Ringwald  *
363deb3ec6SMatthias Ringwald  */
373deb3ec6SMatthias Ringwald 
383deb3ec6SMatthias Ringwald 
397907f069SMatthias Ringwald #include "btstack_config.h"
403deb3ec6SMatthias Ringwald 
413deb3ec6SMatthias Ringwald #include <stdint.h>
423deb3ec6SMatthias Ringwald #include <stdio.h>
433deb3ec6SMatthias Ringwald #include <stdlib.h>
443deb3ec6SMatthias Ringwald #include <string.h>
453deb3ec6SMatthias Ringwald #include <inttypes.h>
463deb3ec6SMatthias Ringwald 
47023f2764SMatthias Ringwald #include "btstack_debug.h"
4859c6af15SMatthias Ringwald #include "btstack_event.h"
4959c6af15SMatthias Ringwald #include "btstack_memory.h"
5059c6af15SMatthias Ringwald #include "btstack_run_loop.h"
5159c6af15SMatthias Ringwald #include "classic/core.h"
52efda0b48SMatthias Ringwald #include "classic/sdp_client_rfcomm.h"
53746ccb7eSMatthias Ringwald #include "classic/sdp_server.h"
54023f2764SMatthias Ringwald #include "classic/sdp_util.h"
5559c6af15SMatthias Ringwald #include "hci.h"
5659c6af15SMatthias Ringwald #include "hci_cmd.h"
5759c6af15SMatthias Ringwald #include "hci_dump.h"
5859c6af15SMatthias Ringwald #include "l2cap.h"
593deb3ec6SMatthias Ringwald 
603deb3ec6SMatthias Ringwald #define HFP_HF_FEATURES_SIZE 10
613deb3ec6SMatthias Ringwald #define HFP_AG_FEATURES_SIZE 12
623deb3ec6SMatthias Ringwald 
633deb3ec6SMatthias Ringwald 
643deb3ec6SMatthias Ringwald static const char * hfp_hf_features[] = {
653deb3ec6SMatthias Ringwald     "EC and/or NR function",
663deb3ec6SMatthias Ringwald     "Three-way calling",
673deb3ec6SMatthias Ringwald     "CLI presentation capability",
683deb3ec6SMatthias Ringwald     "Voice recognition activation",
693deb3ec6SMatthias Ringwald     "Remote volume control",
703deb3ec6SMatthias Ringwald 
713deb3ec6SMatthias Ringwald     "Enhanced call status",
723deb3ec6SMatthias Ringwald     "Enhanced call control",
733deb3ec6SMatthias Ringwald 
743deb3ec6SMatthias Ringwald     "Codec negotiation",
753deb3ec6SMatthias Ringwald 
763deb3ec6SMatthias Ringwald     "HF Indicators",
773deb3ec6SMatthias Ringwald     "eSCO S4 (and T2) Settings Supported",
783deb3ec6SMatthias Ringwald     "Reserved for future definition"
793deb3ec6SMatthias Ringwald };
803deb3ec6SMatthias Ringwald 
813deb3ec6SMatthias Ringwald static const char * hfp_ag_features[] = {
823deb3ec6SMatthias Ringwald     "Three-way calling",
833deb3ec6SMatthias Ringwald     "EC and/or NR function",
843deb3ec6SMatthias Ringwald     "Voice recognition function",
853deb3ec6SMatthias Ringwald     "In-band ring tone capability",
863deb3ec6SMatthias Ringwald     "Attach a number to a voice tag",
873deb3ec6SMatthias Ringwald     "Ability to reject a call",
883deb3ec6SMatthias Ringwald     "Enhanced call status",
893deb3ec6SMatthias Ringwald     "Enhanced call control",
903deb3ec6SMatthias Ringwald     "Extended Error Result Codes",
913deb3ec6SMatthias Ringwald     "Codec negotiation",
923deb3ec6SMatthias Ringwald     "HF Indicators",
933deb3ec6SMatthias Ringwald     "eSCO S4 (and T2) Settings Supported",
943deb3ec6SMatthias Ringwald     "Reserved for future definition"
953deb3ec6SMatthias Ringwald };
963deb3ec6SMatthias Ringwald 
978f2a52f4SMatthias Ringwald static btstack_linked_list_t hfp_connections = NULL;
98ce263fc8SMatthias Ringwald static void parse_sequence(hfp_connection_t * context);
9913839019SMatthias Ringwald static btstack_packet_handler_t hfp_callback;
100d68dcce1SMatthias Ringwald static btstack_packet_handler_t rfcomm_packet_handler;
101f4000eebSMatthias Ringwald 
102eddcd308SMatthias Ringwald static hfp_connection_t * sco_establishment_active;
103eddcd308SMatthias Ringwald 
10413839019SMatthias Ringwald void hfp_set_callback(btstack_packet_handler_t callback){
105f4000eebSMatthias Ringwald     hfp_callback = callback;
106f4000eebSMatthias Ringwald }
1073deb3ec6SMatthias Ringwald 
1083deb3ec6SMatthias Ringwald const char * hfp_hf_feature(int index){
1093deb3ec6SMatthias Ringwald     if (index > HFP_HF_FEATURES_SIZE){
1103deb3ec6SMatthias Ringwald         return hfp_hf_features[HFP_HF_FEATURES_SIZE];
1113deb3ec6SMatthias Ringwald     }
1123deb3ec6SMatthias Ringwald     return hfp_hf_features[index];
1133deb3ec6SMatthias Ringwald }
1143deb3ec6SMatthias Ringwald 
1153deb3ec6SMatthias Ringwald const char * hfp_ag_feature(int index){
1163deb3ec6SMatthias Ringwald     if (index > HFP_AG_FEATURES_SIZE){
1173deb3ec6SMatthias Ringwald         return hfp_ag_features[HFP_AG_FEATURES_SIZE];
1183deb3ec6SMatthias Ringwald     }
1193deb3ec6SMatthias Ringwald     return hfp_ag_features[index];
1203deb3ec6SMatthias Ringwald }
1213deb3ec6SMatthias Ringwald 
1223deb3ec6SMatthias Ringwald int send_str_over_rfcomm(uint16_t cid, char * command){
1233deb3ec6SMatthias Ringwald     if (!rfcomm_can_send_packet_now(cid)) return 1;
12474386ee0SMatthias Ringwald     log_info("HFP_TX %s", command);
12528190c0bSMatthias Ringwald     int err = rfcomm_send(cid, (uint8_t*) command, strlen(command));
1263deb3ec6SMatthias Ringwald     if (err){
12728190c0bSMatthias Ringwald         log_error("rfcomm_send -> error 0x%02x \n", err);
1283deb3ec6SMatthias Ringwald     }
1293deb3ec6SMatthias Ringwald     return 1;
1303deb3ec6SMatthias Ringwald }
1313deb3ec6SMatthias Ringwald 
1326a7f44bdSMilanka Ringwald int hfp_supports_codec(uint8_t codec, int codecs_nr, uint8_t * codecs){
133df327ff3SMilanka Ringwald     int i;
134df327ff3SMilanka Ringwald     for (i = 0; i < codecs_nr; i++){
135df327ff3SMilanka Ringwald         if (codecs[i] == codec) return 1;
136df327ff3SMilanka Ringwald     }
137df327ff3SMilanka Ringwald     return 0;
138df327ff3SMilanka Ringwald }
139df327ff3SMilanka Ringwald 
1403deb3ec6SMatthias Ringwald #if 0
141a0ffb263SMatthias Ringwald void hfp_set_codec(hfp_connection_t * hfp_connection, uint8_t *packet, uint16_t size){
1423deb3ec6SMatthias Ringwald     // parse available codecs
1433deb3ec6SMatthias Ringwald     int pos = 0;
1443deb3ec6SMatthias Ringwald     int i;
1453deb3ec6SMatthias Ringwald     for (i=0; i<size; i++){
1463deb3ec6SMatthias Ringwald         pos+=8;
147a0ffb263SMatthias Ringwald         if (packet[pos] > hfp_connection->negotiated_codec){
148a0ffb263SMatthias Ringwald             hfp_connection->negotiated_codec = packet[pos];
1493deb3ec6SMatthias Ringwald         }
1503deb3ec6SMatthias Ringwald     }
151a0ffb263SMatthias Ringwald     printf("Negotiated Codec 0x%02x\n", hfp_connection->negotiated_codec);
1523deb3ec6SMatthias Ringwald }
1533deb3ec6SMatthias Ringwald #endif
1543deb3ec6SMatthias Ringwald 
1553deb3ec6SMatthias Ringwald // UTILS
1563deb3ec6SMatthias Ringwald int get_bit(uint16_t bitmap, int position){
1573deb3ec6SMatthias Ringwald     return (bitmap >> position) & 1;
1583deb3ec6SMatthias Ringwald }
1593deb3ec6SMatthias Ringwald 
1603deb3ec6SMatthias Ringwald int store_bit(uint32_t bitmap, int position, uint8_t value){
1613deb3ec6SMatthias Ringwald     if (value){
1623deb3ec6SMatthias Ringwald         bitmap |= 1 << position;
1633deb3ec6SMatthias Ringwald     } else {
1643deb3ec6SMatthias Ringwald         bitmap &= ~ (1 << position);
1653deb3ec6SMatthias Ringwald     }
1663deb3ec6SMatthias Ringwald     return bitmap;
1673deb3ec6SMatthias Ringwald }
1683deb3ec6SMatthias Ringwald 
1693deb3ec6SMatthias Ringwald int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){
1703deb3ec6SMatthias Ringwald     if (buffer_size < values_nr * 3) return 0;
1713deb3ec6SMatthias Ringwald     int i;
1723deb3ec6SMatthias Ringwald     int offset = 0;
1733deb3ec6SMatthias Ringwald     for (i = 0; i < values_nr-1; i++) {
1743deb3ec6SMatthias Ringwald       offset += snprintf(buffer+offset, buffer_size-offset, "%d,", values[i]); // puts string into buffer
1753deb3ec6SMatthias Ringwald     }
1763deb3ec6SMatthias Ringwald     if (i<values_nr){
1773deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", values[i]);
1783deb3ec6SMatthias Ringwald     }
1793deb3ec6SMatthias Ringwald     return offset;
1803deb3ec6SMatthias Ringwald }
1813deb3ec6SMatthias Ringwald 
1823deb3ec6SMatthias Ringwald int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){
1833deb3ec6SMatthias Ringwald     if (buffer_size < values_nr * 3) return 0;
1843deb3ec6SMatthias Ringwald 
1853deb3ec6SMatthias Ringwald     int i;
1863deb3ec6SMatthias Ringwald     int offset = 0;
1873deb3ec6SMatthias Ringwald     for (i = 0; i < values_nr-1; i++) {
1883deb3ec6SMatthias Ringwald       offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer
1893deb3ec6SMatthias Ringwald     }
1903deb3ec6SMatthias Ringwald 
1913deb3ec6SMatthias Ringwald     if (i<values_nr){
1923deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", get_bit(values,i));
1933deb3ec6SMatthias Ringwald     }
1943deb3ec6SMatthias Ringwald     return offset;
1953deb3ec6SMatthias Ringwald }
1963deb3ec6SMatthias Ringwald 
19713839019SMatthias Ringwald void hfp_emit_simple_event(btstack_packet_handler_t callback, uint8_t event_subtype){
198a0ffb263SMatthias Ringwald     if (!callback) return;
199a0ffb263SMatthias Ringwald     uint8_t event[3];
200a0ffb263SMatthias Ringwald     event[0] = HCI_EVENT_HFP_META;
201a0ffb263SMatthias Ringwald     event[1] = sizeof(event) - 2;
202a0ffb263SMatthias Ringwald     event[2] = event_subtype;
20313839019SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
204a0ffb263SMatthias Ringwald }
205a0ffb263SMatthias Ringwald 
2066a7f44bdSMilanka Ringwald void hfp_emit_codec_event(btstack_packet_handler_t callback, uint8_t status, uint8_t codec){
2076a7f44bdSMilanka Ringwald     if (!callback) return;
2086a7f44bdSMilanka Ringwald     uint8_t event[5];
2096a7f44bdSMilanka Ringwald     event[0] = HCI_EVENT_HFP_META;
2106a7f44bdSMilanka Ringwald     event[1] = sizeof(event) - 2;
2116a7f44bdSMilanka Ringwald     event[2] = HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE;
2126a7f44bdSMilanka Ringwald     event[3] = status; // status 0 == OK
2136a7f44bdSMilanka Ringwald     event[4] = codec;
2146a7f44bdSMilanka Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
2156a7f44bdSMilanka Ringwald }
2166a7f44bdSMilanka Ringwald 
21713839019SMatthias Ringwald void hfp_emit_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t value){
2183deb3ec6SMatthias Ringwald     if (!callback) return;
2193deb3ec6SMatthias Ringwald     uint8_t event[4];
2203deb3ec6SMatthias Ringwald     event[0] = HCI_EVENT_HFP_META;
2213deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
2223deb3ec6SMatthias Ringwald     event[2] = event_subtype;
2233deb3ec6SMatthias Ringwald     event[3] = value; // status 0 == OK
22413839019SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
2253deb3ec6SMatthias Ringwald }
2263deb3ec6SMatthias Ringwald 
227*8901a7c4SMatthias Ringwald void hfp_emit_connection_event(btstack_packet_handler_t callback, uint8_t event_subtype, uint8_t status, hci_con_handle_t con_handle, bd_addr_t addr){
228a0653c3bSMilanka Ringwald     if (!callback) return;
229*8901a7c4SMatthias Ringwald     uint8_t event[12];
2306a7f44bdSMilanka Ringwald     int pos = 0;
2316a7f44bdSMilanka Ringwald     event[pos++] = HCI_EVENT_HFP_META;
2326a7f44bdSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
2336a7f44bdSMilanka Ringwald     event[pos++] = event_subtype;
2346a7f44bdSMilanka Ringwald     event[pos++] = status; // status 0 == OK
2356a7f44bdSMilanka Ringwald     little_endian_store_16(event, pos, con_handle);
2366a7f44bdSMilanka Ringwald     pos += 2;
2376a7f44bdSMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
2386a7f44bdSMilanka Ringwald     pos += 6;
23913839019SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
240a0653c3bSMilanka Ringwald }
241a0653c3bSMilanka Ringwald 
24213839019SMatthias Ringwald void hfp_emit_string_event(btstack_packet_handler_t callback, uint8_t event_subtype, const char * value){
243aa4dd815SMatthias Ringwald     if (!callback) return;
244c1797c7dSMatthias Ringwald     uint8_t event[40];
245aa4dd815SMatthias Ringwald     event[0] = HCI_EVENT_HFP_META;
246aa4dd815SMatthias Ringwald     event[1] = sizeof(event) - 2;
247aa4dd815SMatthias Ringwald     event[2] = event_subtype;
248aa4dd815SMatthias Ringwald     int size = (strlen(value) < sizeof(event) - 4) ? strlen(value) : sizeof(event) - 4;
249aa4dd815SMatthias Ringwald     strncpy((char*)&event[3], value, size);
250aa4dd815SMatthias Ringwald     event[3 + size] = 0;
25113839019SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
252aa4dd815SMatthias Ringwald }
253aa4dd815SMatthias Ringwald 
2540cb5b971SMatthias Ringwald btstack_linked_list_t * hfp_get_connections(void){
2558f2a52f4SMatthias Ringwald     return (btstack_linked_list_t *) &hfp_connections;
2563deb3ec6SMatthias Ringwald }
2573deb3ec6SMatthias Ringwald 
2583deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){
259665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
260665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
261665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
262a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
263a0ffb263SMatthias Ringwald         if (hfp_connection->rfcomm_cid == cid){
264a0ffb263SMatthias Ringwald             return hfp_connection;
2653deb3ec6SMatthias Ringwald         }
2663deb3ec6SMatthias Ringwald     }
2673deb3ec6SMatthias Ringwald     return NULL;
2683deb3ec6SMatthias Ringwald }
2693deb3ec6SMatthias Ringwald 
2703deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
271665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
272665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
273665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
274a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
275a0ffb263SMatthias Ringwald         if (memcmp(hfp_connection->remote_addr, bd_addr, 6) == 0) {
276a0ffb263SMatthias Ringwald             return hfp_connection;
2773deb3ec6SMatthias Ringwald         }
2783deb3ec6SMatthias Ringwald     }
2793deb3ec6SMatthias Ringwald     return NULL;
2803deb3ec6SMatthias Ringwald }
2813deb3ec6SMatthias Ringwald 
282aa4dd815SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_sco_handle(uint16_t handle){
283665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
284665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, hfp_get_connections());
285665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
286a0ffb263SMatthias Ringwald         hfp_connection_t * hfp_connection = (hfp_connection_t *)btstack_linked_list_iterator_next(&it);
287a0ffb263SMatthias Ringwald         if (hfp_connection->sco_handle == handle){
288a0ffb263SMatthias Ringwald             return hfp_connection;
2893deb3ec6SMatthias Ringwald         }
2903deb3ec6SMatthias Ringwald     }
2913deb3ec6SMatthias Ringwald     return NULL;
2923deb3ec6SMatthias Ringwald }
2933deb3ec6SMatthias Ringwald 
294a0ffb263SMatthias Ringwald void hfp_reset_context_flags(hfp_connection_t * hfp_connection){
295a0ffb263SMatthias Ringwald     if (!hfp_connection) return;
296a0ffb263SMatthias Ringwald     hfp_connection->ok_pending = 0;
297a0ffb263SMatthias Ringwald     hfp_connection->send_error = 0;
2983deb3ec6SMatthias Ringwald 
299a0ffb263SMatthias Ringwald     hfp_connection->keep_byte = 0;
3003deb3ec6SMatthias Ringwald 
301a0ffb263SMatthias Ringwald     hfp_connection->change_status_update_for_individual_ag_indicators = 0;
302a0ffb263SMatthias Ringwald     hfp_connection->operator_name_changed = 0;
3033deb3ec6SMatthias Ringwald 
304a0ffb263SMatthias Ringwald     hfp_connection->enable_extended_audio_gateway_error_report = 0;
305a0ffb263SMatthias Ringwald     hfp_connection->extended_audio_gateway_error = 0;
3063deb3ec6SMatthias Ringwald 
307a0ffb263SMatthias Ringwald     // establish codecs hfp_connection
308a0ffb263SMatthias Ringwald     hfp_connection->suggested_codec = 0;
3096a7f44bdSMilanka Ringwald     hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
310a0ffb263SMatthias Ringwald     hfp_connection->codec_confirmed = 0;
3113deb3ec6SMatthias Ringwald 
312a0ffb263SMatthias Ringwald     hfp_connection->establish_audio_connection = 0;
313a0ffb263SMatthias Ringwald     hfp_connection->call_waiting_notification_enabled = 0;
314a0ffb263SMatthias Ringwald     hfp_connection->command = HFP_CMD_NONE;
315a0ffb263SMatthias Ringwald     hfp_connection->enable_status_update_for_ag_indicators = 0xFF;
3163deb3ec6SMatthias Ringwald }
3173deb3ec6SMatthias Ringwald 
318fffdd288SMatthias Ringwald static hfp_connection_t * create_hfp_connection_context(void){
319a0ffb263SMatthias Ringwald     hfp_connection_t * hfp_connection = btstack_memory_hfp_connection_get();
320a0ffb263SMatthias Ringwald     if (!hfp_connection) return NULL;
3213deb3ec6SMatthias Ringwald     // init state
322a0ffb263SMatthias Ringwald     memset(hfp_connection,0, sizeof(hfp_connection_t));
3233deb3ec6SMatthias Ringwald 
324a0ffb263SMatthias Ringwald     hfp_connection->state = HFP_IDLE;
325a0ffb263SMatthias Ringwald     hfp_connection->call_state = HFP_CALL_IDLE;
326a0ffb263SMatthias Ringwald     hfp_connection->codecs_state = HFP_CODECS_IDLE;
327aa4dd815SMatthias Ringwald 
328a0ffb263SMatthias Ringwald     hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
329a0ffb263SMatthias Ringwald     hfp_connection->command = HFP_CMD_NONE;
3303deb3ec6SMatthias Ringwald 
331a0ffb263SMatthias Ringwald     hfp_reset_context_flags(hfp_connection);
3323deb3ec6SMatthias Ringwald 
333d63c37a1SMatthias Ringwald     btstack_linked_list_add(&hfp_connections, (btstack_linked_item_t*)hfp_connection);
334a0ffb263SMatthias Ringwald     return hfp_connection;
3353deb3ec6SMatthias Ringwald }
3363deb3ec6SMatthias Ringwald 
337a0ffb263SMatthias Ringwald static void remove_hfp_connection_context(hfp_connection_t * hfp_connection){
338a0ffb263SMatthias Ringwald     btstack_linked_list_remove(&hfp_connections, (btstack_linked_item_t*) hfp_connection);
3393deb3ec6SMatthias Ringwald }
3403deb3ec6SMatthias Ringwald 
3413deb3ec6SMatthias Ringwald static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
342a0ffb263SMatthias Ringwald     hfp_connection_t * hfp_connection = get_hfp_connection_context_for_bd_addr(bd_addr);
343a0ffb263SMatthias Ringwald     if (hfp_connection) return  hfp_connection;
344a0ffb263SMatthias Ringwald     hfp_connection = create_hfp_connection_context();
345a0ffb263SMatthias Ringwald     memcpy(hfp_connection->remote_addr, bd_addr, 6);
346a0ffb263SMatthias Ringwald     return hfp_connection;
3473deb3ec6SMatthias Ringwald }
3483deb3ec6SMatthias Ringwald 
349aa4dd815SMatthias Ringwald /* @param network.
350aa4dd815SMatthias Ringwald  * 0 == no ability to reject a call.
351aa4dd815SMatthias Ringwald  * 1 == ability to reject a call.
352aa4dd815SMatthias Ringwald  */
3533deb3ec6SMatthias Ringwald 
3543deb3ec6SMatthias Ringwald /* @param suported_features
3553deb3ec6SMatthias Ringwald  * HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
3563deb3ec6SMatthias Ringwald  * HF bit 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
3573deb3ec6SMatthias Ringwald  * HF bit 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
3583deb3ec6SMatthias Ringwald  * HF bit 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
3593deb3ec6SMatthias Ringwald  * HF bit 4: Remote volume control (yes/no, 1 = yes, 0 = no)
3603deb3ec6SMatthias Ringwald  * HF bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
3613deb3ec6SMatthias Ringwald  */
3623deb3ec6SMatthias Ringwald  /* Bit position:
3633deb3ec6SMatthias Ringwald  * AG bit 0: Three-way calling (yes/no, 1 = yes, 0 = no)
3643deb3ec6SMatthias Ringwald  * AG bit 1: EC and/or NR function (yes/no, 1 = yes, 0 = no)
3653deb3ec6SMatthias Ringwald  * AG bit 2: Voice recognition function (yes/no, 1 = yes, 0 = no)
3663deb3ec6SMatthias Ringwald  * AG bit 3: In-band ring tone capability (yes/no, 1 = yes, 0 = no)
3673deb3ec6SMatthias Ringwald  * AG bit 4: Attach a phone number to a voice tag (yes/no, 1 = yes, 0 = no)
3683deb3ec6SMatthias Ringwald  * AG bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
3693deb3ec6SMatthias Ringwald  */
3703deb3ec6SMatthias Ringwald 
3719b1c3b4dSMatthias Ringwald void hfp_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t service_uuid, int rfcomm_channel_nr, const char * name){
3723deb3ec6SMatthias Ringwald     uint8_t* attribute;
3733deb3ec6SMatthias Ringwald     de_create_sequence(service);
3743deb3ec6SMatthias Ringwald 
3753deb3ec6SMatthias Ringwald     // 0x0000 "Service Record Handle"
3763deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
3779b1c3b4dSMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
3783deb3ec6SMatthias Ringwald 
3793deb3ec6SMatthias Ringwald     // 0x0001 "Service Class ID List"
3803deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
3813deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
3823deb3ec6SMatthias Ringwald     {
3833deb3ec6SMatthias Ringwald         //  "UUID for Service"
3843deb3ec6SMatthias Ringwald         de_add_number(attribute, DE_UUID, DE_SIZE_16, service_uuid);
3853deb3ec6SMatthias Ringwald         de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio);
3863deb3ec6SMatthias Ringwald     }
3873deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
3883deb3ec6SMatthias Ringwald 
3893deb3ec6SMatthias Ringwald     // 0x0004 "Protocol Descriptor List"
3903deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
3913deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
3923deb3ec6SMatthias Ringwald     {
3933deb3ec6SMatthias Ringwald         uint8_t* l2cpProtocol = de_push_sequence(attribute);
3943deb3ec6SMatthias Ringwald         {
3953deb3ec6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
3963deb3ec6SMatthias Ringwald         }
3973deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, l2cpProtocol);
3983deb3ec6SMatthias Ringwald 
3993deb3ec6SMatthias Ringwald         uint8_t* rfcomm = de_push_sequence(attribute);
4003deb3ec6SMatthias Ringwald         {
4013deb3ec6SMatthias Ringwald             de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol);  // rfcomm_service
4023deb3ec6SMatthias Ringwald             de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  rfcomm_channel_nr);  // rfcomm channel
4033deb3ec6SMatthias Ringwald         }
4043deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, rfcomm);
4053deb3ec6SMatthias Ringwald     }
4063deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
4073deb3ec6SMatthias Ringwald 
4083deb3ec6SMatthias Ringwald 
4093deb3ec6SMatthias Ringwald     // 0x0005 "Public Browse Group"
4103deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
4113deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
4123deb3ec6SMatthias Ringwald     {
4133deb3ec6SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
4143deb3ec6SMatthias Ringwald     }
4153deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
4163deb3ec6SMatthias Ringwald 
4173deb3ec6SMatthias Ringwald     // 0x0009 "Bluetooth Profile Descriptor List"
4183deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
4193deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
4203deb3ec6SMatthias Ringwald     {
4213deb3ec6SMatthias Ringwald         uint8_t *sppProfile = de_push_sequence(attribute);
4223deb3ec6SMatthias Ringwald         {
4233deb3ec6SMatthias Ringwald             de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, SDP_Handsfree);
4243deb3ec6SMatthias Ringwald             de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7
4253deb3ec6SMatthias Ringwald         }
4263deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, sppProfile);
4273deb3ec6SMatthias Ringwald     }
4283deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
4293deb3ec6SMatthias Ringwald 
4303deb3ec6SMatthias Ringwald     // 0x0100 "Service Name"
4313deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
4323deb3ec6SMatthias Ringwald     de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
4333deb3ec6SMatthias Ringwald }
4343deb3ec6SMatthias Ringwald 
4353deb3ec6SMatthias Ringwald static hfp_connection_t * connection_doing_sdp_query = NULL;
436a8747467SMatthias Ringwald 
4376c927b22SMatthias Ringwald static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
438a0ffb263SMatthias Ringwald     hfp_connection_t * hfp_connection = connection_doing_sdp_query;
4393deb3ec6SMatthias Ringwald 
440d63c37a1SMatthias Ringwald     if ( hfp_connection->state != HFP_W4_SDP_QUERY_COMPLETE) return;
4413deb3ec6SMatthias Ringwald 
4420e2df43fSMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
4435611a760SMatthias Ringwald         case SDP_EVENT_QUERY_RFCOMM_SERVICE:
444a0ffb263SMatthias Ringwald             if (!hfp_connection) {
44572b50801SMatthias Ringwald                 log_error("handle_query_rfcomm_event alloc connection for RFCOMM port %u failed", sdp_event_query_rfcomm_service_get_rfcomm_channel(packet));
4463deb3ec6SMatthias Ringwald                 return;
4473deb3ec6SMatthias Ringwald             }
448a0ffb263SMatthias Ringwald             hfp_connection->rfcomm_channel_nr = sdp_event_query_rfcomm_service_get_rfcomm_channel(packet);
4493deb3ec6SMatthias Ringwald             break;
4505611a760SMatthias Ringwald         case SDP_EVENT_QUERY_COMPLETE:
4513deb3ec6SMatthias Ringwald             connection_doing_sdp_query = NULL;
452a0ffb263SMatthias Ringwald             if (hfp_connection->rfcomm_channel_nr > 0){
453a0ffb263SMatthias Ringwald                 hfp_connection->state = HFP_W4_RFCOMM_CONNECTED;
454a0ffb263SMatthias Ringwald                 log_info("HFP: SDP_EVENT_QUERY_COMPLETE context %p, addr %s, state %d", hfp_connection, bd_addr_to_str( hfp_connection->remote_addr),  hfp_connection->state);
455d68dcce1SMatthias Ringwald                 rfcomm_create_channel(rfcomm_packet_handler, hfp_connection->remote_addr, hfp_connection->rfcomm_channel_nr, NULL);
4563deb3ec6SMatthias Ringwald                 break;
4573deb3ec6SMatthias Ringwald             }
45872b50801SMatthias Ringwald             log_info("rfcomm service not found, status %u.", sdp_event_query_complete_get_status(packet));
4593deb3ec6SMatthias Ringwald             break;
4603deb3ec6SMatthias Ringwald         default:
4613deb3ec6SMatthias Ringwald             break;
4623deb3ec6SMatthias Ringwald     }
4633deb3ec6SMatthias Ringwald }
4643deb3ec6SMatthias Ringwald 
465eddcd308SMatthias Ringwald static void hfp_handle_failed_sco_connection(uint8_t status){
466eddcd308SMatthias Ringwald 
467eddcd308SMatthias Ringwald     if (!sco_establishment_active){
468eddcd308SMatthias Ringwald         log_error("(e)SCO Connection failed but not started by us");
469eddcd308SMatthias Ringwald         return;
470eddcd308SMatthias Ringwald     }
4716c5b2002SMatthias Ringwald     log_error("(e)SCO Connection failed status 0x%02x", status);
472eddcd308SMatthias Ringwald 
473eddcd308SMatthias Ringwald     // invalid params / unspecified error
474eddcd308SMatthias Ringwald     if (status != 0x11 && status != 0x1f) return;
475eddcd308SMatthias Ringwald 
476eddcd308SMatthias Ringwald      switch (sco_establishment_active->link_setting){
477eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_D0:
478eddcd308SMatthias Ringwald             return; // no other option left
479eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_D1:
480eddcd308SMatthias Ringwald             sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D0;
481eddcd308SMatthias Ringwald             break;
482eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_S1:
483eddcd308SMatthias Ringwald             sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D1;
484eddcd308SMatthias Ringwald             break;
485eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_S2:
486eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_S3:
487eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_S4:
488eddcd308SMatthias Ringwald             sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S1;
489eddcd308SMatthias Ringwald             break;
490eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_T1:
491eddcd308SMatthias Ringwald         case HFP_LINK_SETTINGS_T2:
492eddcd308SMatthias Ringwald             sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S3;
493eddcd308SMatthias Ringwald             break;
494eddcd308SMatthias Ringwald     }
495eddcd308SMatthias Ringwald     sco_establishment_active->establish_audio_connection = 1;
496eddcd308SMatthias Ringwald     sco_establishment_active = 0;
497eddcd308SMatthias Ringwald }
498eddcd308SMatthias Ringwald 
499eddcd308SMatthias Ringwald 
500e30a6a47SMatthias Ringwald void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
5013deb3ec6SMatthias Ringwald     bd_addr_t event_addr;
5023deb3ec6SMatthias Ringwald     uint16_t rfcomm_cid, handle;
503a0ffb263SMatthias Ringwald     hfp_connection_t * hfp_connection = NULL;
504674515e8SMatthias Ringwald     uint8_t status;
5053deb3ec6SMatthias Ringwald 
506eddcd308SMatthias Ringwald     log_info("AG packet_handler type %u, event type %x, size %u", packet_type, hci_event_packet_get_type(packet), size);
507aa4dd815SMatthias Ringwald 
5080e2df43fSMatthias Ringwald     switch (hci_event_packet_get_type(packet)) {
5093deb3ec6SMatthias Ringwald 
5103deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_INCOMING_CONNECTION:
5113deb3ec6SMatthias Ringwald             // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
512caa82391SMilanka Ringwald             rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr);
513d63c37a1SMatthias Ringwald             hfp_connection = provide_hfp_connection_context_for_bd_addr(event_addr);
514d63c37a1SMatthias Ringwald             if (!hfp_connection || hfp_connection->state != HFP_IDLE) return;
5153deb3ec6SMatthias Ringwald 
516caa82391SMilanka Ringwald             hfp_connection->rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
517d63c37a1SMatthias Ringwald             hfp_connection->state = HFP_W4_RFCOMM_CONNECTED;
518674515e8SMatthias Ringwald             // printf("RFCOMM channel %u requested for %s\n", hfp_connection->rfcomm_cid, bd_addr_to_str(hfp_connection->remote_addr));
519d63c37a1SMatthias Ringwald             rfcomm_accept_connection(hfp_connection->rfcomm_cid);
5203deb3ec6SMatthias Ringwald             break;
5213deb3ec6SMatthias Ringwald 
522f8f6a918SMatthias Ringwald         case RFCOMM_EVENT_CHANNEL_OPENED:
5233deb3ec6SMatthias Ringwald             // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
524aa4dd815SMatthias Ringwald 
525674515e8SMatthias Ringwald             rfcomm_event_channel_opened_get_bd_addr(packet, event_addr);
526674515e8SMatthias Ringwald             status = rfcomm_event_channel_opened_get_status(packet);
527674515e8SMatthias Ringwald 
528d63c37a1SMatthias Ringwald             hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr);
529d63c37a1SMatthias Ringwald             if (!hfp_connection || hfp_connection->state != HFP_W4_RFCOMM_CONNECTED) return;
5303deb3ec6SMatthias Ringwald 
531674515e8SMatthias Ringwald             if (status) {
532*8901a7c4SMatthias Ringwald                 hfp_emit_connection_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, status, rfcomm_event_channel_opened_get_con_handle(packet), event_addr);
533d63c37a1SMatthias Ringwald                 remove_hfp_connection_context(hfp_connection);
5343deb3ec6SMatthias Ringwald             } else {
535caa82391SMilanka Ringwald                 hfp_connection->acl_handle = rfcomm_event_channel_opened_get_con_handle(packet);
536caa82391SMilanka Ringwald                 hfp_connection->rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
5376a7f44bdSMilanka Ringwald                 bd_addr_copy(hfp_connection->remote_addr, event_addr);
538674515e8SMatthias Ringwald                 // uint16_t mtu = rfcomm_event_channel_opened_get_max_frame_size(packet);
539674515e8SMatthias Ringwald                 // printf("RFCOMM channel open succeeded. hfp_connection %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", hfp_connection, hfp_connection->rfcomm_cid, mtu);
5403deb3ec6SMatthias Ringwald 
541d63c37a1SMatthias Ringwald                 switch (hfp_connection->state){
5423deb3ec6SMatthias Ringwald                     case HFP_W4_RFCOMM_CONNECTED:
543d63c37a1SMatthias Ringwald                         hfp_connection->state = HFP_EXCHANGE_SUPPORTED_FEATURES;
5443deb3ec6SMatthias Ringwald                         break;
5453deb3ec6SMatthias Ringwald                     case HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
546d63c37a1SMatthias Ringwald                         hfp_connection->state = HFP_W2_DISCONNECT_RFCOMM;
547674515e8SMatthias Ringwald                         // printf("Shutting down RFCOMM.\n");
5483deb3ec6SMatthias Ringwald                         break;
5493deb3ec6SMatthias Ringwald                     default:
5503deb3ec6SMatthias Ringwald                         break;
5513deb3ec6SMatthias Ringwald                 }
552bb6944afSMatthias Ringwald                 rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
5533deb3ec6SMatthias Ringwald             }
5543deb3ec6SMatthias Ringwald             break;
5553deb3ec6SMatthias Ringwald 
556eddcd308SMatthias Ringwald         case HCI_EVENT_COMMAND_STATUS:
557eddcd308SMatthias Ringwald             if (hci_event_command_status_get_command_opcode(packet) == hci_setup_synchronous_connection.opcode) {
558be2a1a78SMatthias Ringwald                 status = hci_event_command_status_get_status(packet);
5596c5b2002SMatthias Ringwald                 if (status) {
560eddcd308SMatthias Ringwald                     hfp_handle_failed_sco_connection(hci_event_command_status_get_status(packet));
561eddcd308SMatthias Ringwald                }
5626c5b2002SMatthias Ringwald             }
563eddcd308SMatthias Ringwald             break;
564eddcd308SMatthias Ringwald 
5653deb3ec6SMatthias Ringwald         case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
566ce263fc8SMatthias Ringwald 
567724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[5], event_addr);
5683deb3ec6SMatthias Ringwald             int index = 2;
569ba92fcf6SMatthias Ringwald             status = packet[index++];
570aa4dd815SMatthias Ringwald 
571aa4dd815SMatthias Ringwald             if (status != 0){
572eddcd308SMatthias Ringwald                 hfp_handle_failed_sco_connection(status);
573aa4dd815SMatthias Ringwald                 break;
574aa4dd815SMatthias Ringwald             }
575aa4dd815SMatthias Ringwald 
576f8fbdce0SMatthias Ringwald             uint16_t sco_handle = little_endian_read_16(packet, index);
5773deb3ec6SMatthias Ringwald             index+=2;
578aa4dd815SMatthias Ringwald 
579724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[index], event_addr);
5803deb3ec6SMatthias Ringwald             index+=6;
581aa4dd815SMatthias Ringwald 
5823deb3ec6SMatthias Ringwald             uint8_t link_type = packet[index++];
5833deb3ec6SMatthias Ringwald             uint8_t transmission_interval = packet[index++];  // measured in slots
5843deb3ec6SMatthias Ringwald             uint8_t retransmission_interval = packet[index++];// measured in slots
585f8fbdce0SMatthias Ringwald             uint16_t rx_packet_length = little_endian_read_16(packet, index); // measured in bytes
5863deb3ec6SMatthias Ringwald             index+=2;
587f8fbdce0SMatthias Ringwald             uint16_t tx_packet_length = little_endian_read_16(packet, index); // measured in bytes
5883deb3ec6SMatthias Ringwald             index+=2;
5893deb3ec6SMatthias Ringwald             uint8_t air_mode = packet[index];
5903deb3ec6SMatthias Ringwald 
5913deb3ec6SMatthias Ringwald             switch (link_type){
5923deb3ec6SMatthias Ringwald                 case 0x00:
593aa4dd815SMatthias Ringwald                     log_info("SCO Connection established.");
5943deb3ec6SMatthias Ringwald                     if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
5953deb3ec6SMatthias Ringwald                     if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
5963deb3ec6SMatthias Ringwald                     if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
5973deb3ec6SMatthias Ringwald                     if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
5983deb3ec6SMatthias Ringwald                     break;
5993deb3ec6SMatthias Ringwald                 case 0x02:
600aa4dd815SMatthias Ringwald                     log_info("eSCO Connection established. \n");
6013deb3ec6SMatthias Ringwald                     break;
6023deb3ec6SMatthias Ringwald                 default:
6033deb3ec6SMatthias Ringwald                     log_error("(e)SCO reserved link_type 0x%2x", link_type);
6043deb3ec6SMatthias Ringwald                     break;
6053deb3ec6SMatthias Ringwald             }
6063deb3ec6SMatthias Ringwald             log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, "
607aa4dd815SMatthias Ringwald                  " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)\n", sco_handle,
608aa4dd815SMatthias Ringwald                  bd_addr_to_str(event_addr), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);
6093deb3ec6SMatthias Ringwald 
610d63c37a1SMatthias Ringwald             hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr);
6113deb3ec6SMatthias Ringwald 
612d63c37a1SMatthias Ringwald             if (!hfp_connection) {
613d63c37a1SMatthias Ringwald                 log_error("SCO link created, hfp_connection for address %s not found.", bd_addr_to_str(event_addr));
6143deb3ec6SMatthias Ringwald                 break;
6153deb3ec6SMatthias Ringwald             }
6163deb3ec6SMatthias Ringwald 
617d63c37a1SMatthias Ringwald             if (hfp_connection->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
618aa4dd815SMatthias Ringwald                 log_info("SCO about to disconnect: HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN");
619d63c37a1SMatthias Ringwald                 hfp_connection->state = HFP_W2_DISCONNECT_SCO;
620aa4dd815SMatthias Ringwald                 break;
621aa4dd815SMatthias Ringwald             }
622d63c37a1SMatthias Ringwald             hfp_connection->sco_handle = sco_handle;
623d63c37a1SMatthias Ringwald             hfp_connection->establish_audio_connection = 0;
624d63c37a1SMatthias Ringwald             hfp_connection->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
625*8901a7c4SMatthias Ringwald             hfp_emit_connection_event(hfp_callback, HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED, packet[2], sco_handle, event_addr);
6263deb3ec6SMatthias Ringwald             break;
6273deb3ec6SMatthias Ringwald         }
6283deb3ec6SMatthias Ringwald 
6293deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_CHANNEL_CLOSED:
630f8fbdce0SMatthias Ringwald             rfcomm_cid = little_endian_read_16(packet,2);
631d63c37a1SMatthias Ringwald             hfp_connection = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
632d63c37a1SMatthias Ringwald             if (!hfp_connection) break;
633d63c37a1SMatthias Ringwald             if (hfp_connection->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
634d63c37a1SMatthias Ringwald                 hfp_connection->state = HFP_IDLE;
635d63c37a1SMatthias Ringwald                 hfp_establish_service_level_connection(hfp_connection->remote_addr, hfp_connection->service_uuid);
6363deb3ec6SMatthias Ringwald                 break;
6373deb3ec6SMatthias Ringwald             }
6383deb3ec6SMatthias Ringwald 
639f4000eebSMatthias Ringwald             hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0);
640d63c37a1SMatthias Ringwald             remove_hfp_connection_context(hfp_connection);
6413deb3ec6SMatthias Ringwald             break;
6423deb3ec6SMatthias Ringwald 
6433deb3ec6SMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
644f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet,3);
645d63c37a1SMatthias Ringwald             hfp_connection = get_hfp_connection_context_for_sco_handle(handle);
646aa4dd815SMatthias Ringwald 
647d63c37a1SMatthias Ringwald             if (!hfp_connection) break;
648aa4dd815SMatthias Ringwald 
649d63c37a1SMatthias Ringwald             if (hfp_connection->state != HFP_W4_SCO_DISCONNECTED){
650aa4dd815SMatthias Ringwald                 log_info("Received gap disconnect in wrong hfp state");
651aa4dd815SMatthias Ringwald             }
652d63c37a1SMatthias Ringwald             log_info("Check SCO handle: incoming 0x%02x, hfp_connection 0x%02x\n", handle, hfp_connection->sco_handle);
653aa4dd815SMatthias Ringwald 
654d63c37a1SMatthias Ringwald             if (handle == hfp_connection->sco_handle){
655aa4dd815SMatthias Ringwald                 log_info("SCO disconnected, w2 disconnect RFCOMM\n");
656d63c37a1SMatthias Ringwald                 hfp_connection->sco_handle = 0;
657d63c37a1SMatthias Ringwald                 hfp_connection->release_audio_connection = 0;
658d63c37a1SMatthias Ringwald                 hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
659f4000eebSMatthias Ringwald                 hfp_emit_event(hfp_callback, HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED, 0);
6603deb3ec6SMatthias Ringwald                 break;
6613deb3ec6SMatthias Ringwald             }
6623deb3ec6SMatthias Ringwald             break;
6633deb3ec6SMatthias Ringwald 
664fc64f94aSMatthias Ringwald         default:
6653deb3ec6SMatthias Ringwald             break;
6663deb3ec6SMatthias Ringwald     }
6673deb3ec6SMatthias Ringwald }
6683deb3ec6SMatthias Ringwald 
669aa4dd815SMatthias Ringwald // translates command string into hfp_command_t CMD
670aa4dd815SMatthias Ringwald static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){
671aa4dd815SMatthias Ringwald     int offset = isHandsFree ? 0 : 2;
6723deb3ec6SMatthias Ringwald 
673ce263fc8SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_LIST_CURRENT_CALLS, strlen(HFP_LIST_CURRENT_CALLS)) == 0){
674ce263fc8SMatthias Ringwald         return HFP_CMD_LIST_CURRENT_CALLS;
675ce263fc8SMatthias Ringwald     }
676ce263fc8SMatthias Ringwald 
677ce263fc8SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_SUBSCRIBER_NUMBER_INFORMATION, strlen(HFP_SUBSCRIBER_NUMBER_INFORMATION)) == 0){
678ce263fc8SMatthias Ringwald         return HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION;
679ce263fc8SMatthias Ringwald     }
680ce263fc8SMatthias Ringwald 
681aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_PHONE_NUMBER_FOR_VOICE_TAG, strlen(HFP_PHONE_NUMBER_FOR_VOICE_TAG)) == 0){
682ce263fc8SMatthias Ringwald         if (isHandsFree) return HFP_CMD_AG_SENT_PHONE_NUMBER;
683aa4dd815SMatthias Ringwald         return HFP_CMD_HF_REQUEST_PHONE_NUMBER;
6843deb3ec6SMatthias Ringwald     }
6853deb3ec6SMatthias Ringwald 
686aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_TRANSMIT_DTMF_CODES, strlen(HFP_TRANSMIT_DTMF_CODES)) == 0){
687aa4dd815SMatthias Ringwald         return HFP_CMD_TRANSMIT_DTMF_CODES;
6883deb3ec6SMatthias Ringwald     }
6893deb3ec6SMatthias Ringwald 
690aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_SET_MICROPHONE_GAIN, strlen(HFP_SET_MICROPHONE_GAIN)) == 0){
691aa4dd815SMatthias Ringwald         return HFP_CMD_SET_MICROPHONE_GAIN;
6923deb3ec6SMatthias Ringwald     }
6933deb3ec6SMatthias Ringwald 
694aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_SET_SPEAKER_GAIN, strlen(HFP_SET_SPEAKER_GAIN)) == 0){
695aa4dd815SMatthias Ringwald         return HFP_CMD_SET_SPEAKER_GAIN;
6963deb3ec6SMatthias Ringwald     }
6973deb3ec6SMatthias Ringwald 
698aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_ACTIVATE_VOICE_RECOGNITION, strlen(HFP_ACTIVATE_VOICE_RECOGNITION)) == 0){
699aa4dd815SMatthias Ringwald         if (isHandsFree) return HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION;
700aa4dd815SMatthias Ringwald         return HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION;
7013deb3ec6SMatthias Ringwald     }
7023deb3ec6SMatthias Ringwald 
703aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_TURN_OFF_EC_AND_NR, strlen(HFP_TURN_OFF_EC_AND_NR)) == 0){
704aa4dd815SMatthias Ringwald         return HFP_CMD_TURN_OFF_EC_AND_NR;
7053deb3ec6SMatthias Ringwald     }
7063deb3ec6SMatthias Ringwald 
707aa4dd815SMatthias Ringwald     if (strncmp(line_buffer, HFP_CALL_ANSWERED, strlen(HFP_CALL_ANSWERED)) == 0){
708aa4dd815SMatthias Ringwald         return HFP_CMD_CALL_ANSWERED;
7093deb3ec6SMatthias Ringwald     }
7103deb3ec6SMatthias Ringwald 
711aa4dd815SMatthias Ringwald     if (strncmp(line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
712aa4dd815SMatthias Ringwald         return HFP_CMD_CALL_PHONE_NUMBER;
7133deb3ec6SMatthias Ringwald     }
7143deb3ec6SMatthias Ringwald 
715ce263fc8SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_REDIAL_LAST_NUMBER, strlen(HFP_REDIAL_LAST_NUMBER)) == 0){
716aa4dd815SMatthias Ringwald         return HFP_CMD_REDIAL_LAST_NUMBER;
7173deb3ec6SMatthias Ringwald     }
7183deb3ec6SMatthias Ringwald 
719aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_CHANGE_IN_BAND_RING_TONE_SETTING, strlen(HFP_CHANGE_IN_BAND_RING_TONE_SETTING)) == 0){
720aa4dd815SMatthias Ringwald         return HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING;
721aa4dd815SMatthias Ringwald     }
722aa4dd815SMatthias Ringwald 
723aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_HANG_UP_CALL, strlen(HFP_HANG_UP_CALL)) == 0){
724aa4dd815SMatthias Ringwald         return HFP_CMD_HANG_UP_CALL;
725aa4dd815SMatthias Ringwald     }
726aa4dd815SMatthias Ringwald 
727aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){
728aa4dd815SMatthias Ringwald         return HFP_CMD_ERROR;
729aa4dd815SMatthias Ringwald     }
730aa4dd815SMatthias Ringwald 
731ce263fc8SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_RING, strlen(HFP_RING)) == 0){
732ce263fc8SMatthias Ringwald         return HFP_CMD_RING;
733ce263fc8SMatthias Ringwald     }
734ce263fc8SMatthias Ringwald 
735aa4dd815SMatthias Ringwald     if (isHandsFree && strncmp(line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){
736aa4dd815SMatthias Ringwald         return HFP_CMD_OK;
737aa4dd815SMatthias Ringwald     }
738aa4dd815SMatthias Ringwald 
739aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){
740aa4dd815SMatthias Ringwald         return HFP_CMD_SUPPORTED_FEATURES;
741aa4dd815SMatthias Ringwald     }
742aa4dd815SMatthias Ringwald 
743ce263fc8SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_TRANSFER_HF_INDICATOR_STATUS, strlen(HFP_TRANSFER_HF_INDICATOR_STATUS)) == 0){
744ce263fc8SMatthias Ringwald         return HFP_CMD_HF_INDICATOR_STATUS;
745ce263fc8SMatthias Ringwald     }
746ce263fc8SMatthias Ringwald 
747ce263fc8SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_RESPONSE_AND_HOLD, strlen(HFP_RESPONSE_AND_HOLD)) == 0){
748ce263fc8SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_RESPONSE_AND_HOLD)+offset, "?", 1) == 0){
749ce263fc8SMatthias Ringwald             return HFP_CMD_RESPONSE_AND_HOLD_QUERY;
750ce263fc8SMatthias Ringwald         }
751ce263fc8SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_RESPONSE_AND_HOLD)+offset, "=", 1) == 0){
752ce263fc8SMatthias Ringwald             return HFP_CMD_RESPONSE_AND_HOLD_COMMAND;
753ce263fc8SMatthias Ringwald         }
754667ec068SMatthias Ringwald         return HFP_CMD_RESPONSE_AND_HOLD_STATUS;
755ce263fc8SMatthias Ringwald     }
756ce263fc8SMatthias Ringwald 
757aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
758aa4dd815SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){
759aa4dd815SMatthias Ringwald             return HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
760aa4dd815SMatthias Ringwald         }
761aa4dd815SMatthias Ringwald 
762aa4dd815SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_INDICATOR)+offset, "=?", 2) == 0){
763aa4dd815SMatthias Ringwald             return HFP_CMD_RETRIEVE_AG_INDICATORS;
764aa4dd815SMatthias Ringwald         }
765aa4dd815SMatthias Ringwald     }
766aa4dd815SMatthias Ringwald 
767aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
768aa4dd815SMatthias Ringwald         return HFP_CMD_AVAILABLE_CODECS;
769aa4dd815SMatthias Ringwald     }
770aa4dd815SMatthias Ringwald 
771aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
772aa4dd815SMatthias Ringwald         return HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
773aa4dd815SMatthias Ringwald     }
774aa4dd815SMatthias Ringwald 
775aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_ENABLE_CLIP, strlen(HFP_ENABLE_CLIP)) == 0){
776a0ffb263SMatthias Ringwald         if (isHandsFree) return HFP_CMD_AG_SENT_CLIP_INFORMATION;
777aa4dd815SMatthias Ringwald         return HFP_CMD_ENABLE_CLIP;
778aa4dd815SMatthias Ringwald     }
779aa4dd815SMatthias Ringwald 
780aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_ENABLE_CALL_WAITING_NOTIFICATION, strlen(HFP_ENABLE_CALL_WAITING_NOTIFICATION)) == 0){
781a0ffb263SMatthias Ringwald         if (isHandsFree) return HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE;
782aa4dd815SMatthias Ringwald         return HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION;
783aa4dd815SMatthias Ringwald     }
784aa4dd815SMatthias Ringwald 
785aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
786aa4dd815SMatthias Ringwald 
787aa4dd815SMatthias Ringwald         if (isHandsFree) return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
788aa4dd815SMatthias Ringwald 
789aa4dd815SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)+offset, "=?", 2) == 0){
790aa4dd815SMatthias Ringwald             return HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
791aa4dd815SMatthias Ringwald         }
792667ec068SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)+offset, "=", 1) == 0){
793aa4dd815SMatthias Ringwald             return HFP_CMD_CALL_HOLD;
794aa4dd815SMatthias Ringwald         }
795aa4dd815SMatthias Ringwald 
796aa4dd815SMatthias Ringwald         return HFP_CMD_UNKNOWN;
797aa4dd815SMatthias Ringwald     }
798aa4dd815SMatthias Ringwald 
799aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
800667ec068SMatthias Ringwald         if (isHandsFree) {
801667ec068SMatthias Ringwald             return HFP_CMD_SET_GENERIC_STATUS_INDICATOR_STATUS;
802667ec068SMatthias Ringwald         }
803aa4dd815SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=?", 2) == 0){
804aa4dd815SMatthias Ringwald             return HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
805aa4dd815SMatthias Ringwald         }
806aa4dd815SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){
807aa4dd815SMatthias Ringwald             return HFP_CMD_LIST_GENERIC_STATUS_INDICATORS;
808aa4dd815SMatthias Ringwald         }
809aa4dd815SMatthias Ringwald         return HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
810aa4dd815SMatthias Ringwald     }
811aa4dd815SMatthias Ringwald 
812aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
813aa4dd815SMatthias Ringwald         return HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE;
8143deb3ec6SMatthias Ringwald     }
8153deb3ec6SMatthias Ringwald 
8163deb3ec6SMatthias Ringwald 
817aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_QUERY_OPERATOR_SELECTION, strlen(HFP_QUERY_OPERATOR_SELECTION)) == 0){
818aa4dd815SMatthias Ringwald         if (strncmp(line_buffer+strlen(HFP_QUERY_OPERATOR_SELECTION)+offset, "=", 1) == 0){
819aa4dd815SMatthias Ringwald             return HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT;
8203deb3ec6SMatthias Ringwald         }
821aa4dd815SMatthias Ringwald         return HFP_CMD_QUERY_OPERATOR_SELECTION_NAME;
8223deb3ec6SMatthias Ringwald     }
8233deb3ec6SMatthias Ringwald 
824aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_TRANSFER_AG_INDICATOR_STATUS)) == 0){
825aa4dd815SMatthias Ringwald         return HFP_CMD_TRANSFER_AG_INDICATOR_STATUS;
8263deb3ec6SMatthias Ringwald     }
8273deb3ec6SMatthias Ringwald 
828aa4dd815SMatthias Ringwald     if (isHandsFree && strncmp(line_buffer+offset, HFP_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
829aa4dd815SMatthias Ringwald         return HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR;
8303deb3ec6SMatthias Ringwald     }
8313deb3ec6SMatthias Ringwald 
832aa4dd815SMatthias Ringwald     if (!isHandsFree && strncmp(line_buffer+offset, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
833aa4dd815SMatthias Ringwald         return HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR;
8343deb3ec6SMatthias Ringwald     }
8353deb3ec6SMatthias Ringwald 
836aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){
837aa4dd815SMatthias Ringwald         return HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
838aa4dd815SMatthias Ringwald     }
839aa4dd815SMatthias Ringwald 
840aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){
8413deb3ec6SMatthias Ringwald         if (isHandsFree){
842aa4dd815SMatthias Ringwald             return HFP_CMD_AG_SUGGESTED_CODEC;
8433deb3ec6SMatthias Ringwald         } else {
844aa4dd815SMatthias Ringwald             return HFP_CMD_HF_CONFIRMED_CODEC;
8453deb3ec6SMatthias Ringwald         }
8463deb3ec6SMatthias Ringwald     }
8473deb3ec6SMatthias Ringwald 
848aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, "AT+", 3) == 0){
849667ec068SMatthias Ringwald         log_info("process unknown HF command %s \n", line_buffer);
850aa4dd815SMatthias Ringwald         return HFP_CMD_UNKNOWN;
8513deb3ec6SMatthias Ringwald     }
8523deb3ec6SMatthias Ringwald 
853aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, "+", 1) == 0){
854667ec068SMatthias Ringwald         log_info(" process unknown AG command %s \n", line_buffer);
855aa4dd815SMatthias Ringwald         return HFP_CMD_UNKNOWN;
856aa4dd815SMatthias Ringwald     }
8573deb3ec6SMatthias Ringwald 
858aa4dd815SMatthias Ringwald     if (strncmp(line_buffer+offset, "NOP", 3) == 0){
859aa4dd815SMatthias Ringwald         return HFP_CMD_NONE;
860aa4dd815SMatthias Ringwald     }
861aa4dd815SMatthias Ringwald 
862aa4dd815SMatthias Ringwald     return HFP_CMD_NONE;
8633deb3ec6SMatthias Ringwald }
8643deb3ec6SMatthias Ringwald 
865a0ffb263SMatthias Ringwald static void hfp_parser_store_byte(hfp_connection_t * hfp_connection, uint8_t byte){
866ce263fc8SMatthias Ringwald     // printf("hfp_parser_store_byte %c at pos %u\n", (char) byte, context->line_size);
8673deb3ec6SMatthias Ringwald     // TODO: add limit
868a0ffb263SMatthias Ringwald     hfp_connection->line_buffer[hfp_connection->line_size++] = byte;
869a0ffb263SMatthias Ringwald     hfp_connection->line_buffer[hfp_connection->line_size] = 0;
8703deb3ec6SMatthias Ringwald }
871a0ffb263SMatthias Ringwald static int hfp_parser_is_buffer_empty(hfp_connection_t * hfp_connection){
872a0ffb263SMatthias Ringwald     return hfp_connection->line_size == 0;
8733deb3ec6SMatthias Ringwald }
8743deb3ec6SMatthias Ringwald 
8753deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){
8763deb3ec6SMatthias Ringwald     return byte == '\n' || byte == '\r';
8773deb3ec6SMatthias Ringwald }
8783deb3ec6SMatthias Ringwald 
8793deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_header(uint8_t byte){
8803deb3ec6SMatthias Ringwald     return hfp_parser_is_end_of_line(byte) || byte == ':' || byte == '?';
8813deb3ec6SMatthias Ringwald }
8823deb3ec6SMatthias Ringwald 
883a0ffb263SMatthias Ringwald static int hfp_parser_found_separator(hfp_connection_t * hfp_connection, uint8_t byte){
884a0ffb263SMatthias Ringwald     if (hfp_connection->keep_byte == 1) return 1;
8853deb3ec6SMatthias Ringwald 
8863deb3ec6SMatthias Ringwald     int found_separator =   byte == ',' || byte == '\n'|| byte == '\r'||
8873deb3ec6SMatthias Ringwald                             byte == ')' || byte == '(' || byte == ':' ||
8883deb3ec6SMatthias Ringwald                             byte == '-' || byte == '"' ||  byte == '?'|| byte == '=';
8893deb3ec6SMatthias Ringwald     return found_separator;
8903deb3ec6SMatthias Ringwald }
8913deb3ec6SMatthias Ringwald 
892a0ffb263SMatthias Ringwald static void hfp_parser_next_state(hfp_connection_t * hfp_connection, uint8_t byte){
893a0ffb263SMatthias Ringwald     hfp_connection->line_size = 0;
8943deb3ec6SMatthias Ringwald     if (hfp_parser_is_end_of_line(byte)){
895a0ffb263SMatthias Ringwald         hfp_connection->parser_item_index = 0;
896a0ffb263SMatthias Ringwald         hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
8973deb3ec6SMatthias Ringwald         return;
8983deb3ec6SMatthias Ringwald     }
899a0ffb263SMatthias Ringwald     switch (hfp_connection->parser_state){
9003deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_HEADER:
901a0ffb263SMatthias Ringwald             hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
902a0ffb263SMatthias Ringwald             if (hfp_connection->keep_byte == 1){
903a0ffb263SMatthias Ringwald                 hfp_parser_store_byte(hfp_connection, byte);
904a0ffb263SMatthias Ringwald                 hfp_connection->keep_byte = 0;
9053deb3ec6SMatthias Ringwald             }
9063deb3ec6SMatthias Ringwald             break;
9073deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_SEQUENCE:
908a0ffb263SMatthias Ringwald             switch (hfp_connection->command){
909ce263fc8SMatthias Ringwald                 case HFP_CMD_AG_SENT_PHONE_NUMBER:
910a0ffb263SMatthias Ringwald                 case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
911a0ffb263SMatthias Ringwald                 case HFP_CMD_AG_SENT_CLIP_INFORMATION:
9123deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
913aa4dd815SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
914aa4dd815SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
915aa4dd815SMatthias Ringwald                 case HFP_CMD_RETRIEVE_AG_INDICATORS:
916aa4dd815SMatthias Ringwald                 case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
917ce263fc8SMatthias Ringwald                 case HFP_CMD_HF_INDICATOR_STATUS:
918a0ffb263SMatthias Ringwald                     hfp_connection->parser_state = HFP_PARSER_SECOND_ITEM;
9193deb3ec6SMatthias Ringwald                     break;
9203deb3ec6SMatthias Ringwald                 default:
9213deb3ec6SMatthias Ringwald                     break;
9223deb3ec6SMatthias Ringwald             }
9233deb3ec6SMatthias Ringwald             break;
9243deb3ec6SMatthias Ringwald         case HFP_PARSER_SECOND_ITEM:
925a0ffb263SMatthias Ringwald             hfp_connection->parser_state = HFP_PARSER_THIRD_ITEM;
9263deb3ec6SMatthias Ringwald             break;
9273deb3ec6SMatthias Ringwald         case HFP_PARSER_THIRD_ITEM:
928a0ffb263SMatthias Ringwald             if (hfp_connection->command == HFP_CMD_RETRIEVE_AG_INDICATORS){
929a0ffb263SMatthias Ringwald                 hfp_connection->parser_state = HFP_PARSER_CMD_SEQUENCE;
9303deb3ec6SMatthias Ringwald                 break;
9313deb3ec6SMatthias Ringwald             }
932a0ffb263SMatthias Ringwald             hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
9333deb3ec6SMatthias Ringwald             break;
9343deb3ec6SMatthias Ringwald     }
9353deb3ec6SMatthias Ringwald }
9363deb3ec6SMatthias Ringwald 
937a0ffb263SMatthias Ringwald void hfp_parse(hfp_connection_t * hfp_connection, uint8_t byte, int isHandsFree){
938aa4dd815SMatthias Ringwald     // handle ATD<dial_string>;
939a0ffb263SMatthias Ringwald     if (strncmp((const char*)hfp_connection->line_buffer, HFP_CALL_PHONE_NUMBER, strlen(HFP_CALL_PHONE_NUMBER)) == 0){
940aa4dd815SMatthias Ringwald         // check for end-of-line or ';'
941aa4dd815SMatthias Ringwald         if (byte == ';' || hfp_parser_is_end_of_line(byte)){
942a0ffb263SMatthias Ringwald             hfp_connection->line_buffer[hfp_connection->line_size] = 0;
943a0ffb263SMatthias Ringwald             hfp_connection->line_size = 0;
944a0ffb263SMatthias Ringwald             hfp_connection->command = HFP_CMD_CALL_PHONE_NUMBER;
945aa4dd815SMatthias Ringwald         } else {
946a0ffb263SMatthias Ringwald             hfp_connection->line_buffer[hfp_connection->line_size++] = byte;
947aa4dd815SMatthias Ringwald         }
948aa4dd815SMatthias Ringwald         return;
949aa4dd815SMatthias Ringwald     }
950aa4dd815SMatthias Ringwald 
9513deb3ec6SMatthias Ringwald     // TODO: handle space inside word
952a0ffb263SMatthias Ringwald     if (byte == ' ' && hfp_connection->parser_state > HFP_PARSER_CMD_HEADER) return;
9533deb3ec6SMatthias Ringwald 
954a0ffb263SMatthias Ringwald     if (byte == ',' && hfp_connection->command == HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE){
955a0ffb263SMatthias Ringwald         if (hfp_connection->line_size == 0){
956a0ffb263SMatthias Ringwald             hfp_connection->line_buffer[0] = 0;
957a0ffb263SMatthias Ringwald             hfp_connection->ignore_value = 1;
958a0ffb263SMatthias Ringwald             parse_sequence(hfp_connection);
959ce263fc8SMatthias Ringwald             return;
960ce263fc8SMatthias Ringwald         }
961ce263fc8SMatthias Ringwald     }
962ce263fc8SMatthias Ringwald 
963a0ffb263SMatthias Ringwald     if (!hfp_parser_found_separator(hfp_connection, byte)){
964a0ffb263SMatthias Ringwald         hfp_parser_store_byte(hfp_connection, byte);
9653deb3ec6SMatthias Ringwald         return;
9663deb3ec6SMatthias Ringwald     }
967ce263fc8SMatthias Ringwald 
9683deb3ec6SMatthias Ringwald     if (hfp_parser_is_end_of_line(byte)) {
969a0ffb263SMatthias Ringwald         if (hfp_parser_is_buffer_empty(hfp_connection)){
970a0ffb263SMatthias Ringwald             hfp_connection->parser_state = HFP_PARSER_CMD_HEADER;
9713deb3ec6SMatthias Ringwald         }
9723deb3ec6SMatthias Ringwald     }
973a0ffb263SMatthias Ringwald     if (hfp_parser_is_buffer_empty(hfp_connection)) return;
9743deb3ec6SMatthias Ringwald 
975a0ffb263SMatthias Ringwald     switch (hfp_connection->parser_state){
9763deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_HEADER: // header
9773deb3ec6SMatthias Ringwald             if (byte == '='){
978a0ffb263SMatthias Ringwald                 hfp_connection->keep_byte = 1;
979a0ffb263SMatthias Ringwald                 hfp_parser_store_byte(hfp_connection, byte);
9803deb3ec6SMatthias Ringwald                 return;
9813deb3ec6SMatthias Ringwald             }
9823deb3ec6SMatthias Ringwald 
9833deb3ec6SMatthias Ringwald             if (byte == '?'){
984a0ffb263SMatthias Ringwald                 hfp_connection->keep_byte = 0;
985a0ffb263SMatthias Ringwald                 hfp_parser_store_byte(hfp_connection, byte);
9863deb3ec6SMatthias Ringwald                 return;
9873deb3ec6SMatthias Ringwald             }
988ce263fc8SMatthias Ringwald 
989ce263fc8SMatthias Ringwald             if (byte == ','){
990a0ffb263SMatthias Ringwald                 hfp_connection->resolve_byte = 1;
991ce263fc8SMatthias Ringwald             }
992ce263fc8SMatthias Ringwald 
993a0ffb263SMatthias Ringwald             // printf(" parse header 2 %s, keep separator $ %d\n", hfp_connection->line_buffer, hfp_connection->keep_byte);
994a0ffb263SMatthias Ringwald             if (hfp_parser_is_end_of_header(byte) || hfp_connection->keep_byte == 1){
995a0ffb263SMatthias Ringwald                 // printf(" parse header 3 %s, keep separator $ %d\n", hfp_connection->line_buffer, hfp_connection->keep_byte);
996a0ffb263SMatthias Ringwald                 char * line_buffer = (char *)hfp_connection->line_buffer;
997a0ffb263SMatthias Ringwald                 hfp_connection->command = parse_command(line_buffer, isHandsFree);
998aa4dd815SMatthias Ringwald 
999a0ffb263SMatthias Ringwald                 /* resolve command name according to hfp_connection */
1000a0ffb263SMatthias Ringwald                 if (hfp_connection->command == HFP_CMD_UNKNOWN){
1001a0ffb263SMatthias Ringwald                     switch(hfp_connection->state){
1002aa4dd815SMatthias Ringwald                         case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
1003a0ffb263SMatthias Ringwald                             hfp_connection->command = HFP_CMD_LIST_GENERIC_STATUS_INDICATORS;
1004aa4dd815SMatthias Ringwald                             break;
1005aa4dd815SMatthias Ringwald                         case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
1006a0ffb263SMatthias Ringwald                             hfp_connection->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS;
1007aa4dd815SMatthias Ringwald                             break;
1008aa4dd815SMatthias Ringwald                         case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
1009a0ffb263SMatthias Ringwald                             hfp_connection->command = HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE;
1010aa4dd815SMatthias Ringwald                             break;
1011aa4dd815SMatthias Ringwald                         case HFP_W4_RETRIEVE_INDICATORS_STATUS:
1012a0ffb263SMatthias Ringwald                             hfp_connection->command = HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS;
1013aa4dd815SMatthias Ringwald                             break;
1014aa4dd815SMatthias Ringwald                         case HFP_W4_RETRIEVE_INDICATORS:
1015a0ffb263SMatthias Ringwald                             hfp_connection->send_ag_indicators_segment = 0;
1016a0ffb263SMatthias Ringwald                             hfp_connection->command = HFP_CMD_RETRIEVE_AG_INDICATORS;
1017aa4dd815SMatthias Ringwald                             break;
1018aa4dd815SMatthias Ringwald                         default:
1019aa4dd815SMatthias Ringwald                             break;
1020aa4dd815SMatthias Ringwald                     }
1021aa4dd815SMatthias Ringwald                 }
10223deb3ec6SMatthias Ringwald             }
10233deb3ec6SMatthias Ringwald             break;
10243deb3ec6SMatthias Ringwald 
1025ce263fc8SMatthias Ringwald         case HFP_PARSER_CMD_SEQUENCE:
1026a0ffb263SMatthias Ringwald             parse_sequence(hfp_connection);
1027ce263fc8SMatthias Ringwald             break;
1028ce263fc8SMatthias Ringwald         case HFP_PARSER_SECOND_ITEM:
1029a0ffb263SMatthias Ringwald             switch (hfp_connection->command){
1030ce263fc8SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
1031a0ffb263SMatthias Ringwald                     log_info("format %s, ", hfp_connection->line_buffer);
1032a0ffb263SMatthias Ringwald                     hfp_connection->network_operator.format =  atoi((char *)&hfp_connection->line_buffer[0]);
1033ce263fc8SMatthias Ringwald                     break;
1034ce263fc8SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
1035a0ffb263SMatthias Ringwald                     log_info("format %s \n", hfp_connection->line_buffer);
1036a0ffb263SMatthias Ringwald                     hfp_connection->network_operator.format =  atoi((char *)&hfp_connection->line_buffer[0]);
1037ce263fc8SMatthias Ringwald                     break;
1038ce263fc8SMatthias Ringwald                 case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
1039ce263fc8SMatthias Ringwald                 case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
1040ce263fc8SMatthias Ringwald                 case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
1041a0ffb263SMatthias Ringwald                     hfp_connection->generic_status_indicators[hfp_connection->parser_item_index].state = (uint8_t)atoi((char*)hfp_connection->line_buffer);
1042ce263fc8SMatthias Ringwald                     break;
1043ce263fc8SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
1044a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators[hfp_connection->parser_item_index].status = (uint8_t)atoi((char*)hfp_connection->line_buffer);
1045a0ffb263SMatthias Ringwald                     log_info("%d \n", hfp_connection->ag_indicators[hfp_connection->parser_item_index].status);
1046a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators[hfp_connection->parser_item_index].status_changed = 1;
1047ce263fc8SMatthias Ringwald                     break;
1048ce263fc8SMatthias Ringwald                 case HFP_CMD_RETRIEVE_AG_INDICATORS:
1049a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators[hfp_connection->parser_item_index].min_range = atoi((char *)hfp_connection->line_buffer);
1050a0ffb263SMatthias Ringwald                     log_info("%s, ", hfp_connection->line_buffer);
1051ce263fc8SMatthias Ringwald                     break;
1052ce263fc8SMatthias Ringwald                 case HFP_CMD_AG_SENT_PHONE_NUMBER:
1053a0ffb263SMatthias Ringwald                 case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
1054a0ffb263SMatthias Ringwald                 case HFP_CMD_AG_SENT_CLIP_INFORMATION:
1055a0ffb263SMatthias Ringwald                     hfp_connection->bnip_type = (uint8_t)atoi((char*)hfp_connection->line_buffer);
1056ce263fc8SMatthias Ringwald                     break;
1057ce263fc8SMatthias Ringwald                 default:
1058ce263fc8SMatthias Ringwald                     break;
1059ce263fc8SMatthias Ringwald             }
1060ce263fc8SMatthias Ringwald             break;
1061ce263fc8SMatthias Ringwald 
1062ce263fc8SMatthias Ringwald         case HFP_PARSER_THIRD_ITEM:
1063a0ffb263SMatthias Ringwald              switch (hfp_connection->command){
1064ce263fc8SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
1065a0ffb263SMatthias Ringwald                     strcpy(hfp_connection->network_operator.name, (char *)hfp_connection->line_buffer);
1066a0ffb263SMatthias Ringwald                     log_info("name %s\n", hfp_connection->line_buffer);
1067ce263fc8SMatthias Ringwald                     break;
1068ce263fc8SMatthias Ringwald                 case HFP_CMD_RETRIEVE_AG_INDICATORS:
1069a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators[hfp_connection->parser_item_index].max_range = atoi((char *)hfp_connection->line_buffer);
1070a0ffb263SMatthias Ringwald                     hfp_connection->parser_item_index++;
1071a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators_nr = hfp_connection->parser_item_index;
1072a0ffb263SMatthias Ringwald                     log_info("%s)\n", hfp_connection->line_buffer);
1073ce263fc8SMatthias Ringwald                     break;
1074ce263fc8SMatthias Ringwald                 default:
1075ce263fc8SMatthias Ringwald                     break;
1076ce263fc8SMatthias Ringwald             }
1077ce263fc8SMatthias Ringwald             break;
1078ce263fc8SMatthias Ringwald     }
1079a0ffb263SMatthias Ringwald     hfp_parser_next_state(hfp_connection, byte);
1080ce263fc8SMatthias Ringwald 
1081a0ffb263SMatthias Ringwald     if (hfp_connection->resolve_byte && hfp_connection->command == HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE){
1082a0ffb263SMatthias Ringwald         hfp_connection->resolve_byte = 0;
1083a0ffb263SMatthias Ringwald         hfp_connection->ignore_value = 1;
1084a0ffb263SMatthias Ringwald         parse_sequence(hfp_connection);
1085a0ffb263SMatthias Ringwald         hfp_connection->line_buffer[0] = 0;
1086a0ffb263SMatthias Ringwald         hfp_connection->line_size = 0;
1087ce263fc8SMatthias Ringwald     }
1088ce263fc8SMatthias Ringwald }
1089ce263fc8SMatthias Ringwald 
1090a0ffb263SMatthias Ringwald static void parse_sequence(hfp_connection_t * hfp_connection){
1091ce263fc8SMatthias Ringwald     int value;
1092a0ffb263SMatthias Ringwald     switch (hfp_connection->command){
1093667ec068SMatthias Ringwald         case HFP_CMD_SET_GENERIC_STATUS_INDICATOR_STATUS:
1094a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1095667ec068SMatthias Ringwald             int i;
1096a0ffb263SMatthias Ringwald             switch (hfp_connection->parser_item_index){
1097667ec068SMatthias Ringwald                 case 0:
1098a0ffb263SMatthias Ringwald                     for (i=0;i<hfp_connection->generic_status_indicators_nr;i++){
1099a0ffb263SMatthias Ringwald                         if (hfp_connection->generic_status_indicators[i].uuid == value){
1100a0ffb263SMatthias Ringwald                             hfp_connection->parser_indicator_index = i;
1101667ec068SMatthias Ringwald                             break;
1102667ec068SMatthias Ringwald                         }
1103667ec068SMatthias Ringwald                     }
1104667ec068SMatthias Ringwald                     break;
1105667ec068SMatthias Ringwald                 case 1:
1106a0ffb263SMatthias Ringwald                     if (hfp_connection->parser_indicator_index <0) break;
1107a0ffb263SMatthias Ringwald                     hfp_connection->generic_status_indicators[hfp_connection->parser_indicator_index].state = value;
1108667ec068SMatthias Ringwald                     log_info("HFP_CMD_SET_GENERIC_STATUS_INDICATOR_STATUS set indicator at index %u, to %u\n",
1109a0ffb263SMatthias Ringwald                      hfp_connection->parser_item_index, value);
1110667ec068SMatthias Ringwald                     break;
1111667ec068SMatthias Ringwald                 default:
1112667ec068SMatthias Ringwald                     break;
1113667ec068SMatthias Ringwald             }
1114a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
1115667ec068SMatthias Ringwald             break;
1116667ec068SMatthias Ringwald 
1117667ec068SMatthias Ringwald         case HFP_CMD_GET_SUBSCRIBER_NUMBER_INFORMATION:
1118a0ffb263SMatthias Ringwald             switch(hfp_connection->parser_item_index){
1119667ec068SMatthias Ringwald                 case 0:
1120a0ffb263SMatthias Ringwald                     strncpy(hfp_connection->bnip_number, (char *)hfp_connection->line_buffer, sizeof(hfp_connection->bnip_number));
1121a0ffb263SMatthias Ringwald                     hfp_connection->bnip_number[sizeof(hfp_connection->bnip_number)-1] = 0;
1122667ec068SMatthias Ringwald                     break;
1123667ec068SMatthias Ringwald                 case 1:
1124a0ffb263SMatthias Ringwald                     value = atoi((char *)&hfp_connection->line_buffer[0]);
1125a0ffb263SMatthias Ringwald                     hfp_connection->bnip_type = value;
1126667ec068SMatthias Ringwald                     break;
1127667ec068SMatthias Ringwald                 default:
1128667ec068SMatthias Ringwald                     break;
1129667ec068SMatthias Ringwald             }
1130a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
1131667ec068SMatthias Ringwald             break;
1132667ec068SMatthias Ringwald         case HFP_CMD_LIST_CURRENT_CALLS:
1133a0ffb263SMatthias Ringwald             switch(hfp_connection->parser_item_index){
1134667ec068SMatthias Ringwald                 case 0:
1135a0ffb263SMatthias Ringwald                     value = atoi((char *)&hfp_connection->line_buffer[0]);
1136a0ffb263SMatthias Ringwald                     hfp_connection->clcc_idx = value;
1137667ec068SMatthias Ringwald                     break;
1138667ec068SMatthias Ringwald                 case 1:
1139a0ffb263SMatthias Ringwald                     value = atoi((char *)&hfp_connection->line_buffer[0]);
1140a0ffb263SMatthias Ringwald                     hfp_connection->clcc_dir = value;
1141667ec068SMatthias Ringwald                     break;
1142667ec068SMatthias Ringwald                 case 2:
1143a0ffb263SMatthias Ringwald                     value = atoi((char *)&hfp_connection->line_buffer[0]);
1144a0ffb263SMatthias Ringwald                     hfp_connection->clcc_status = value;
1145667ec068SMatthias Ringwald                     break;
1146667ec068SMatthias Ringwald                 case 3:
1147a0ffb263SMatthias Ringwald                     value = atoi((char *)&hfp_connection->line_buffer[0]);
1148a0ffb263SMatthias Ringwald                     hfp_connection->clcc_mpty = value;
1149667ec068SMatthias Ringwald                     break;
1150667ec068SMatthias Ringwald                 case 4:
1151a0ffb263SMatthias Ringwald                     strncpy(hfp_connection->bnip_number, (char *)hfp_connection->line_buffer, sizeof(hfp_connection->bnip_number));
1152a0ffb263SMatthias Ringwald                     hfp_connection->bnip_number[sizeof(hfp_connection->bnip_number)-1] = 0;
1153667ec068SMatthias Ringwald                     break;
1154667ec068SMatthias Ringwald                 case 5:
1155a0ffb263SMatthias Ringwald                     value = atoi((char *)&hfp_connection->line_buffer[0]);
1156a0ffb263SMatthias Ringwald                     hfp_connection->bnip_type = value;
1157667ec068SMatthias Ringwald                     break;
1158667ec068SMatthias Ringwald                 default:
1159667ec068SMatthias Ringwald                     break;
1160667ec068SMatthias Ringwald             }
1161a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
1162667ec068SMatthias Ringwald             break;
1163aa4dd815SMatthias Ringwald         case HFP_CMD_SET_MICROPHONE_GAIN:
1164a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1165a0ffb263SMatthias Ringwald             hfp_connection->microphone_gain = value;
1166aa4dd815SMatthias Ringwald             log_info("hfp parse HFP_CMD_SET_MICROPHONE_GAIN %d\n", value);
1167aa4dd815SMatthias Ringwald             break;
1168aa4dd815SMatthias Ringwald         case HFP_CMD_SET_SPEAKER_GAIN:
1169a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1170a0ffb263SMatthias Ringwald             hfp_connection->speaker_gain = value;
1171aa4dd815SMatthias Ringwald             log_info("hfp parse HFP_CMD_SET_SPEAKER_GAIN %d\n", value);
1172aa4dd815SMatthias Ringwald             break;
1173aa4dd815SMatthias Ringwald         case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
1174a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1175a0ffb263SMatthias Ringwald             hfp_connection->ag_activate_voice_recognition = value;
1176aa4dd815SMatthias Ringwald             log_info("hfp parse HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION %d\n", value);
1177aa4dd815SMatthias Ringwald             break;
1178aa4dd815SMatthias Ringwald         case HFP_CMD_TURN_OFF_EC_AND_NR:
1179a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1180a0ffb263SMatthias Ringwald             hfp_connection->ag_echo_and_noise_reduction = value;
1181aa4dd815SMatthias Ringwald             log_info("hfp parse HFP_CMD_TURN_OFF_EC_AND_NR %d\n", value);
1182aa4dd815SMatthias Ringwald             break;
1183aa4dd815SMatthias Ringwald         case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
1184a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1185a0ffb263SMatthias Ringwald             hfp_connection->remote_supported_features = store_bit(hfp_connection->remote_supported_features, HFP_AGSF_IN_BAND_RING_TONE, value);
1186aa4dd815SMatthias Ringwald             log_info("hfp parse HFP_CHANGE_IN_BAND_RING_TONE_SETTING %d\n", value);
1187aa4dd815SMatthias Ringwald             break;
11883deb3ec6SMatthias Ringwald         case HFP_CMD_HF_CONFIRMED_CODEC:
1189a0ffb263SMatthias Ringwald             hfp_connection->codec_confirmed = atoi((char*)hfp_connection->line_buffer);
1190a0ffb263SMatthias Ringwald             log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", hfp_connection->codec_confirmed);
11913deb3ec6SMatthias Ringwald             break;
11923deb3ec6SMatthias Ringwald         case HFP_CMD_AG_SUGGESTED_CODEC:
1193a0ffb263SMatthias Ringwald             hfp_connection->suggested_codec = atoi((char*)hfp_connection->line_buffer);
1194a0ffb263SMatthias Ringwald             log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", hfp_connection->suggested_codec);
11953deb3ec6SMatthias Ringwald             break;
11963deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORTED_FEATURES:
1197a0ffb263SMatthias Ringwald             hfp_connection->remote_supported_features = atoi((char*)hfp_connection->line_buffer);
1198a0ffb263SMatthias Ringwald             log_info("Parsed supported feature %d\n", hfp_connection->remote_supported_features);
11993deb3ec6SMatthias Ringwald             break;
12003deb3ec6SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
1201a0ffb263SMatthias Ringwald             log_info("Parsed codec %s\n", hfp_connection->line_buffer);
1202a0ffb263SMatthias Ringwald             hfp_connection->remote_codecs[hfp_connection->parser_item_index] = (uint16_t)atoi((char*)hfp_connection->line_buffer);
1203a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
1204a0ffb263SMatthias Ringwald             hfp_connection->remote_codecs_nr = hfp_connection->parser_item_index;
12053deb3ec6SMatthias Ringwald             break;
1206aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_AG_INDICATORS:
1207a0ffb263SMatthias Ringwald             strcpy((char *)hfp_connection->ag_indicators[hfp_connection->parser_item_index].name,  (char *)hfp_connection->line_buffer);
1208a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators[hfp_connection->parser_item_index].index = hfp_connection->parser_item_index+1;
1209a0ffb263SMatthias Ringwald             log_info("Indicator %d: %s (", hfp_connection->ag_indicators_nr+1, hfp_connection->line_buffer);
1210aa4dd815SMatthias Ringwald             break;
1211aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
1212a0ffb263SMatthias Ringwald             log_info("Parsed Indicator %d with status: %s\n", hfp_connection->parser_item_index+1, hfp_connection->line_buffer);
1213a0ffb263SMatthias Ringwald             hfp_connection->ag_indicators[hfp_connection->parser_item_index].status = atoi((char *) hfp_connection->line_buffer);
1214a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
12153deb3ec6SMatthias Ringwald             break;
12163deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
1217a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
1218a0ffb263SMatthias Ringwald             if (hfp_connection->parser_item_index != 4) break;
1219a0ffb263SMatthias Ringwald             log_info("Parsed Enable indicators: %s\n", hfp_connection->line_buffer);
1220a0ffb263SMatthias Ringwald             value = atoi((char *)&hfp_connection->line_buffer[0]);
1221a0ffb263SMatthias Ringwald             hfp_connection->enable_status_update_for_ag_indicators = (uint8_t) value;
12223deb3ec6SMatthias Ringwald             break;
12233deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
1224a0ffb263SMatthias Ringwald             log_info("Parsed Support call hold: %s\n", hfp_connection->line_buffer);
1225a0ffb263SMatthias Ringwald             if (hfp_connection->line_size > 2 ) break;
1226a0ffb263SMatthias Ringwald             strcpy((char *)hfp_connection->remote_call_services[hfp_connection->remote_call_services_nr].name,  (char *)hfp_connection->line_buffer);
1227a0ffb263SMatthias Ringwald             hfp_connection->remote_call_services_nr++;
12283deb3ec6SMatthias Ringwald             break;
1229aa4dd815SMatthias Ringwald         case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
1230aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
1231a0ffb263SMatthias Ringwald             log_info("Parsed Generic status indicator: %s\n", hfp_connection->line_buffer);
1232a0ffb263SMatthias Ringwald             hfp_connection->generic_status_indicators[hfp_connection->parser_item_index].uuid = (uint16_t)atoi((char*)hfp_connection->line_buffer);
1233a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
1234a0ffb263SMatthias Ringwald             hfp_connection->generic_status_indicators_nr = hfp_connection->parser_item_index;
12353deb3ec6SMatthias Ringwald             break;
1236aa4dd815SMatthias Ringwald         case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
12373deb3ec6SMatthias Ringwald             // HF parses inital AG gen. ind. state
1238a0ffb263SMatthias Ringwald             log_info("Parsed List generic status indicator %s state: ", hfp_connection->line_buffer);
1239a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index = (uint8_t)atoi((char*)hfp_connection->line_buffer);
12403deb3ec6SMatthias Ringwald             break;
1241ce263fc8SMatthias Ringwald         case HFP_CMD_HF_INDICATOR_STATUS:
1242a0ffb263SMatthias Ringwald             hfp_connection->parser_indicator_index = (uint8_t)atoi((char*)hfp_connection->line_buffer);
1243a0ffb263SMatthias Ringwald             log_info("Parsed HF indicator index %u", hfp_connection->parser_indicator_index);
1244ce263fc8SMatthias Ringwald             break;
12453deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
12463deb3ec6SMatthias Ringwald             // AG parses new gen. ind. state
1247a0ffb263SMatthias Ringwald             if (hfp_connection->ignore_value){
1248a0ffb263SMatthias Ringwald                 hfp_connection->ignore_value = 0;
1249a0ffb263SMatthias Ringwald                 log_info("Parsed Enable AG indicator pos %u('%s') - unchanged (stays %u)\n", hfp_connection->parser_item_index,
1250a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators[hfp_connection->parser_item_index].name, hfp_connection->ag_indicators[hfp_connection->parser_item_index].enabled);
1251ce263fc8SMatthias Ringwald             }
1252a0ffb263SMatthias Ringwald             else if (hfp_connection->ag_indicators[hfp_connection->parser_item_index].mandatory){
1253ce263fc8SMatthias Ringwald                 log_info("Parsed Enable AG indicator pos %u('%s') - ignore (mandatory)\n",
1254a0ffb263SMatthias Ringwald                     hfp_connection->parser_item_index, hfp_connection->ag_indicators[hfp_connection->parser_item_index].name);
1255ce263fc8SMatthias Ringwald             } else {
1256a0ffb263SMatthias Ringwald                 value = atoi((char *)&hfp_connection->line_buffer[0]);
1257a0ffb263SMatthias Ringwald                 hfp_connection->ag_indicators[hfp_connection->parser_item_index].enabled = value;
1258a0ffb263SMatthias Ringwald                 log_info("Parsed Enable AG indicator pos %u('%s'): %u\n", hfp_connection->parser_item_index,
1259a0ffb263SMatthias Ringwald                     hfp_connection->ag_indicators[hfp_connection->parser_item_index].name, value);
12603deb3ec6SMatthias Ringwald             }
1261a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index++;
12623deb3ec6SMatthias Ringwald             break;
12633deb3ec6SMatthias Ringwald         case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
12643deb3ec6SMatthias Ringwald             // indicators are indexed starting with 1
1265a0ffb263SMatthias Ringwald             hfp_connection->parser_item_index = atoi((char *)&hfp_connection->line_buffer[0]) - 1;
1266a0ffb263SMatthias Ringwald             log_info("Parsed status of the AG indicator %d, status ", hfp_connection->parser_item_index);
12673deb3ec6SMatthias Ringwald             break;
1268aa4dd815SMatthias Ringwald         case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME:
1269a0ffb263SMatthias Ringwald             hfp_connection->network_operator.mode = atoi((char *)&hfp_connection->line_buffer[0]);
1270a0ffb263SMatthias Ringwald             log_info("Parsed network operator mode: %d, ", hfp_connection->network_operator.mode);
1271aa4dd815SMatthias Ringwald             break;
1272aa4dd815SMatthias Ringwald         case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT:
1273a0ffb263SMatthias Ringwald             if (hfp_connection->line_buffer[0] == '3'){
1274a0ffb263SMatthias Ringwald                 log_info("Parsed Set network operator format : %s, ", hfp_connection->line_buffer);
12753deb3ec6SMatthias Ringwald                 break;
12763deb3ec6SMatthias Ringwald             }
12773deb3ec6SMatthias Ringwald             // TODO emit ERROR, wrong format
1278a0ffb263SMatthias Ringwald             log_info("ERROR Set network operator format: index %s not supported\n", hfp_connection->line_buffer);
12793deb3ec6SMatthias Ringwald             break;
12803deb3ec6SMatthias Ringwald         case HFP_CMD_ERROR:
12813deb3ec6SMatthias Ringwald             break;
12823deb3ec6SMatthias Ringwald         case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR:
1283a0ffb263SMatthias Ringwald             hfp_connection->extended_audio_gateway_error = 1;
1284a0ffb263SMatthias Ringwald             hfp_connection->extended_audio_gateway_error_value = (uint8_t)atoi((char*)hfp_connection->line_buffer);
12853deb3ec6SMatthias Ringwald             break;
12863deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
1287a0ffb263SMatthias Ringwald             hfp_connection->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)hfp_connection->line_buffer);
1288a0ffb263SMatthias Ringwald             hfp_connection->ok_pending = 1;
1289a0ffb263SMatthias Ringwald             hfp_connection->extended_audio_gateway_error = 0;
12903deb3ec6SMatthias Ringwald             break;
1291ce263fc8SMatthias Ringwald         case HFP_CMD_AG_SENT_PHONE_NUMBER:
1292a0ffb263SMatthias Ringwald         case HFP_CMD_AG_SENT_CALL_WAITING_NOTIFICATION_UPDATE:
1293a0ffb263SMatthias Ringwald         case HFP_CMD_AG_SENT_CLIP_INFORMATION:
1294a0ffb263SMatthias Ringwald             strncpy(hfp_connection->bnip_number, (char *)hfp_connection->line_buffer, sizeof(hfp_connection->bnip_number));
1295a0ffb263SMatthias Ringwald             hfp_connection->bnip_number[sizeof(hfp_connection->bnip_number)-1] = 0;
12963deb3ec6SMatthias Ringwald             break;
12973deb3ec6SMatthias Ringwald         default:
12983deb3ec6SMatthias Ringwald             break;
12993deb3ec6SMatthias Ringwald     }
13003deb3ec6SMatthias Ringwald }
13013deb3ec6SMatthias Ringwald 
13023deb3ec6SMatthias Ringwald void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid){
1303a0ffb263SMatthias Ringwald     hfp_connection_t * hfp_connection = provide_hfp_connection_context_for_bd_addr(bd_addr);
1304a0ffb263SMatthias Ringwald     log_info("hfp_connect %s, hfp_connection %p", bd_addr_to_str(bd_addr), hfp_connection);
13053deb3ec6SMatthias Ringwald 
1306a0ffb263SMatthias Ringwald     if (!hfp_connection) {
13073deb3ec6SMatthias Ringwald         log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
13083deb3ec6SMatthias Ringwald         return;
13093deb3ec6SMatthias Ringwald     }
1310aa4dd815SMatthias Ringwald 
1311a0ffb263SMatthias Ringwald     switch (hfp_connection->state){
13123deb3ec6SMatthias Ringwald         case HFP_W2_DISCONNECT_RFCOMM:
1313a0ffb263SMatthias Ringwald             hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
13143deb3ec6SMatthias Ringwald             return;
13153deb3ec6SMatthias Ringwald         case HFP_W4_RFCOMM_DISCONNECTED:
1316a0ffb263SMatthias Ringwald             hfp_connection->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART;
13173deb3ec6SMatthias Ringwald             return;
13183deb3ec6SMatthias Ringwald         case HFP_IDLE:
1319a0ffb263SMatthias Ringwald             memcpy(hfp_connection->remote_addr, bd_addr, 6);
1320d63c37a1SMatthias Ringwald             hfp_connection->state = HFP_W4_SDP_QUERY_COMPLETE;
1321a0ffb263SMatthias Ringwald             connection_doing_sdp_query = hfp_connection;
1322a0ffb263SMatthias Ringwald             hfp_connection->service_uuid = service_uuid;
13237fbb5f59SMatthias Ringwald             sdp_client_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, hfp_connection->remote_addr, service_uuid);
13243deb3ec6SMatthias Ringwald             break;
13253deb3ec6SMatthias Ringwald         default:
13263deb3ec6SMatthias Ringwald             break;
13273deb3ec6SMatthias Ringwald     }
13283deb3ec6SMatthias Ringwald }
13293deb3ec6SMatthias Ringwald 
1330a0ffb263SMatthias Ringwald void hfp_release_service_level_connection(hfp_connection_t * hfp_connection){
1331a0ffb263SMatthias Ringwald     if (!hfp_connection) return;
1332a0ffb263SMatthias Ringwald     hfp_release_audio_connection(hfp_connection);
13333deb3ec6SMatthias Ringwald 
1334a0ffb263SMatthias Ringwald     if (hfp_connection->state < HFP_W4_RFCOMM_CONNECTED){
1335a0ffb263SMatthias Ringwald         hfp_connection->state = HFP_IDLE;
13363deb3ec6SMatthias Ringwald         return;
13373deb3ec6SMatthias Ringwald     }
13383deb3ec6SMatthias Ringwald 
1339a0ffb263SMatthias Ringwald     if (hfp_connection->state == HFP_W4_RFCOMM_CONNECTED){
1340a0ffb263SMatthias Ringwald         hfp_connection->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
13413deb3ec6SMatthias Ringwald         return;
13423deb3ec6SMatthias Ringwald     }
13433deb3ec6SMatthias Ringwald 
1344a0ffb263SMatthias Ringwald     if (hfp_connection->state < HFP_W4_SCO_CONNECTED){
1345a0ffb263SMatthias Ringwald         hfp_connection->state = HFP_W2_DISCONNECT_RFCOMM;
13463deb3ec6SMatthias Ringwald         return;
13473deb3ec6SMatthias Ringwald     }
13483deb3ec6SMatthias Ringwald 
1349a0ffb263SMatthias Ringwald     if (hfp_connection->state < HFP_W4_SCO_DISCONNECTED){
1350a0ffb263SMatthias Ringwald         hfp_connection->state = HFP_W2_DISCONNECT_SCO;
13513deb3ec6SMatthias Ringwald         return;
13523deb3ec6SMatthias Ringwald     }
13533deb3ec6SMatthias Ringwald 
13543deb3ec6SMatthias Ringwald     return;
13553deb3ec6SMatthias Ringwald }
13563deb3ec6SMatthias Ringwald 
1357a0ffb263SMatthias Ringwald void hfp_release_audio_connection(hfp_connection_t * hfp_connection){
1358a0ffb263SMatthias Ringwald     if (!hfp_connection) return;
1359a0ffb263SMatthias Ringwald     if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO) return;
1360a0ffb263SMatthias Ringwald     hfp_connection->release_audio_connection = 1;
13613deb3ec6SMatthias Ringwald }
13623deb3ec6SMatthias Ringwald 
1363ce263fc8SMatthias Ringwald static const struct link_settings {
1364ce263fc8SMatthias Ringwald     const uint16_t max_latency;
1365ce263fc8SMatthias Ringwald     const uint8_t  retransmission_effort;
1366ce263fc8SMatthias Ringwald     const uint16_t packet_types;
1367ce263fc8SMatthias Ringwald } hfp_link_settings [] = {
1368ce263fc8SMatthias Ringwald     { 0xffff, 0xff, 0x03c1 }, // HFP_LINK_SETTINGS_D0,   HV1
1369ce263fc8SMatthias Ringwald     { 0xffff, 0xff, 0x03c4 }, // HFP_LINK_SETTINGS_D1,   HV3
1370ce263fc8SMatthias Ringwald     { 0x0007, 0x01, 0x03c8 }, // HFP_LINK_SETTINGS_S1,   EV3
1371ce263fc8SMatthias Ringwald     { 0x0007, 0x01, 0x0380 }, // HFP_LINK_SETTINGS_S2, 2-EV3
1372ce263fc8SMatthias Ringwald     { 0x000a, 0x01, 0x0380 }, // HFP_LINK_SETTINGS_S3, 2-EV3
1373ce263fc8SMatthias Ringwald     { 0x000c, 0x02, 0x0380 }, // HFP_LINK_SETTINGS_S4, 2-EV3
1374ce263fc8SMatthias Ringwald     { 0x0008, 0x02, 0x03c8 }, // HFP_LINK_SETTINGS_T1,   EV3
1375ce263fc8SMatthias Ringwald     { 0x000d, 0x02, 0x0380 }  // HFP_LINK_SETTINGS_T2, 2-EV3
1376ce263fc8SMatthias Ringwald };
13773deb3ec6SMatthias Ringwald 
1378eddcd308SMatthias Ringwald void hfp_setup_synchronous_connection(hfp_connection_t * hfp_connection){
1379ce263fc8SMatthias Ringwald     // all packet types, fixed bandwidth
1380eddcd308SMatthias Ringwald     int setting = hfp_connection->link_setting;
1381ce263fc8SMatthias Ringwald     log_info("hfp_setup_synchronous_connection using setting nr %u", setting);
1382eddcd308SMatthias Ringwald     sco_establishment_active = hfp_connection;
1383d2c1d59aSMatthias Ringwald     uint16_t sco_voice_setting = hci_get_sco_voice_setting();
1384d2c1d59aSMatthias Ringwald     if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){
1385d2c1d59aSMatthias Ringwald         sco_voice_setting = 0x0003; // Transparent data
1386d2c1d59aSMatthias Ringwald     }
1387eddcd308SMatthias Ringwald     hci_send_cmd(&hci_setup_synchronous_connection, hfp_connection->acl_handle, 8000, 8000, hfp_link_settings[setting].max_latency,
1388d2c1d59aSMatthias Ringwald         sco_voice_setting, hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380
1389ce263fc8SMatthias Ringwald }
1390d68dcce1SMatthias Ringwald 
1391d68dcce1SMatthias Ringwald void hfp_set_packet_handler_for_rfcomm_connections(btstack_packet_handler_t handler){
1392d68dcce1SMatthias Ringwald     rfcomm_packet_handler = handler;
1393d68dcce1SMatthias Ringwald }
1394d68dcce1SMatthias Ringwald 
1395