xref: /btstack/src/classic/hfp.c (revision 3edc84c5b6b1e23a3d103fe8ce1f6b5ad1df3498)
13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald  *
43deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald  * are met:
73deb3ec6SMatthias Ringwald  *
83deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald  *    monetary gain.
193deb3ec6SMatthias Ringwald  *
203deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
233deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
243deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald  *
333deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald  * [email protected]
353deb3ec6SMatthias Ringwald  *
363deb3ec6SMatthias Ringwald  */
373deb3ec6SMatthias Ringwald 
383deb3ec6SMatthias Ringwald // *****************************************************************************
393deb3ec6SMatthias Ringwald //
403deb3ec6SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
413deb3ec6SMatthias Ringwald //
423deb3ec6SMatthias Ringwald // *****************************************************************************
433deb3ec6SMatthias Ringwald 
443deb3ec6SMatthias Ringwald #include "btstack-config.h"
453deb3ec6SMatthias Ringwald 
463deb3ec6SMatthias Ringwald #include <stdint.h>
473deb3ec6SMatthias Ringwald #include <stdio.h>
483deb3ec6SMatthias Ringwald #include <stdlib.h>
493deb3ec6SMatthias Ringwald #include <string.h>
503deb3ec6SMatthias Ringwald #include <inttypes.h>
513deb3ec6SMatthias Ringwald 
523deb3ec6SMatthias Ringwald #include "hci_cmds.h"
533deb3ec6SMatthias Ringwald #include "run_loop.h"
543deb3ec6SMatthias Ringwald 
553deb3ec6SMatthias Ringwald #include "hci.h"
563deb3ec6SMatthias Ringwald #include "btstack_memory.h"
573deb3ec6SMatthias Ringwald #include "hci_dump.h"
583deb3ec6SMatthias Ringwald #include "l2cap.h"
59*3edc84c5SMatthias Ringwald #include "classic/sdp_query_rfcomm.h"
60*3edc84c5SMatthias Ringwald #include "classic/sdp.h"
613deb3ec6SMatthias Ringwald #include "debug.h"
623deb3ec6SMatthias Ringwald 
633deb3ec6SMatthias Ringwald #define HFP_HF_FEATURES_SIZE 10
643deb3ec6SMatthias Ringwald #define HFP_AG_FEATURES_SIZE 12
653deb3ec6SMatthias Ringwald 
663deb3ec6SMatthias Ringwald 
673deb3ec6SMatthias Ringwald static const char * hfp_hf_features[] = {
683deb3ec6SMatthias Ringwald     "EC and/or NR function",
693deb3ec6SMatthias Ringwald     "Three-way calling",
703deb3ec6SMatthias Ringwald     "CLI presentation capability",
713deb3ec6SMatthias Ringwald     "Voice recognition activation",
723deb3ec6SMatthias Ringwald     "Remote volume control",
733deb3ec6SMatthias Ringwald 
743deb3ec6SMatthias Ringwald     "Enhanced call status",
753deb3ec6SMatthias Ringwald     "Enhanced call control",
763deb3ec6SMatthias Ringwald 
773deb3ec6SMatthias Ringwald     "Codec negotiation",
783deb3ec6SMatthias Ringwald 
793deb3ec6SMatthias Ringwald     "HF Indicators",
803deb3ec6SMatthias Ringwald     "eSCO S4 (and T2) Settings Supported",
813deb3ec6SMatthias Ringwald     "Reserved for future definition"
823deb3ec6SMatthias Ringwald };
833deb3ec6SMatthias Ringwald 
843deb3ec6SMatthias Ringwald static const char * hfp_ag_features[] = {
853deb3ec6SMatthias Ringwald     "Three-way calling",
863deb3ec6SMatthias Ringwald     "EC and/or NR function",
873deb3ec6SMatthias Ringwald     "Voice recognition function",
883deb3ec6SMatthias Ringwald     "In-band ring tone capability",
893deb3ec6SMatthias Ringwald     "Attach a number to a voice tag",
903deb3ec6SMatthias Ringwald     "Ability to reject a call",
913deb3ec6SMatthias Ringwald     "Enhanced call status",
923deb3ec6SMatthias Ringwald     "Enhanced call control",
933deb3ec6SMatthias Ringwald     "Extended Error Result Codes",
943deb3ec6SMatthias Ringwald     "Codec negotiation",
953deb3ec6SMatthias Ringwald     "HF Indicators",
963deb3ec6SMatthias Ringwald     "eSCO S4 (and T2) Settings Supported",
973deb3ec6SMatthias Ringwald     "Reserved for future definition"
983deb3ec6SMatthias Ringwald };
993deb3ec6SMatthias Ringwald 
1003deb3ec6SMatthias Ringwald static int hfp_generic_status_indicators_nr = 0;
1013deb3ec6SMatthias Ringwald static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_HF_INDICATORS];
1023deb3ec6SMatthias Ringwald 
1033deb3ec6SMatthias Ringwald static linked_list_t hfp_connections = NULL;
1043deb3ec6SMatthias Ringwald 
1053deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void){
1063deb3ec6SMatthias Ringwald     return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators;
1073deb3ec6SMatthias Ringwald }
1083deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr(void){
1093deb3ec6SMatthias Ringwald     return hfp_generic_status_indicators_nr;
1103deb3ec6SMatthias Ringwald }
1113deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr){
1123deb3ec6SMatthias Ringwald     if (indicator_nr > HFP_MAX_NUM_HF_INDICATORS) return;
1133deb3ec6SMatthias Ringwald     hfp_generic_status_indicators_nr = indicator_nr;
1143deb3ec6SMatthias Ringwald     memcpy(hfp_generic_status_indicators, indicators, indicator_nr * sizeof(hfp_generic_status_indicator_t));
1153deb3ec6SMatthias Ringwald }
1163deb3ec6SMatthias Ringwald 
1173deb3ec6SMatthias Ringwald const char * hfp_hf_feature(int index){
1183deb3ec6SMatthias Ringwald     if (index > HFP_HF_FEATURES_SIZE){
1193deb3ec6SMatthias Ringwald         return hfp_hf_features[HFP_HF_FEATURES_SIZE];
1203deb3ec6SMatthias Ringwald     }
1213deb3ec6SMatthias Ringwald     return hfp_hf_features[index];
1223deb3ec6SMatthias Ringwald }
1233deb3ec6SMatthias Ringwald 
1243deb3ec6SMatthias Ringwald const char * hfp_ag_feature(int index){
1253deb3ec6SMatthias Ringwald     if (index > HFP_AG_FEATURES_SIZE){
1263deb3ec6SMatthias Ringwald         return hfp_ag_features[HFP_AG_FEATURES_SIZE];
1273deb3ec6SMatthias Ringwald     }
1283deb3ec6SMatthias Ringwald     return hfp_ag_features[index];
1293deb3ec6SMatthias Ringwald }
1303deb3ec6SMatthias Ringwald 
1313deb3ec6SMatthias Ringwald int send_str_over_rfcomm(uint16_t cid, char * command){
1323deb3ec6SMatthias Ringwald     if (!rfcomm_can_send_packet_now(cid)) return 1;
1333deb3ec6SMatthias Ringwald     int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
1343deb3ec6SMatthias Ringwald     if (err){
1353deb3ec6SMatthias Ringwald         log_error("rfcomm_send_internal -> error 0x%02x \n", err);
1363deb3ec6SMatthias Ringwald     }
1373deb3ec6SMatthias Ringwald     return 1;
1383deb3ec6SMatthias Ringwald }
1393deb3ec6SMatthias Ringwald 
1403deb3ec6SMatthias Ringwald #if 0
1413deb3ec6SMatthias Ringwald void hfp_set_codec(hfp_connection_t * context, 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;
1473deb3ec6SMatthias Ringwald         if (packet[pos] > context->negotiated_codec){
1483deb3ec6SMatthias Ringwald             context->negotiated_codec = packet[pos];
1493deb3ec6SMatthias Ringwald         }
1503deb3ec6SMatthias Ringwald     }
1513deb3ec6SMatthias Ringwald     printf("Negotiated Codec 0x%02x\n", context->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 
1973deb3ec6SMatthias Ringwald void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){
1983deb3ec6SMatthias Ringwald     if (!callback) return;
1993deb3ec6SMatthias Ringwald     uint8_t event[4];
2003deb3ec6SMatthias Ringwald     event[0] = HCI_EVENT_HFP_META;
2013deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
2023deb3ec6SMatthias Ringwald     event[2] = event_subtype;
2033deb3ec6SMatthias Ringwald     event[3] = value; // status 0 == OK
2043deb3ec6SMatthias Ringwald     (*callback)(event, sizeof(event));
2053deb3ec6SMatthias Ringwald }
2063deb3ec6SMatthias Ringwald 
2073deb3ec6SMatthias Ringwald 
2083deb3ec6SMatthias Ringwald linked_list_t * hfp_get_connections(){
2093deb3ec6SMatthias Ringwald     return (linked_list_t *) &hfp_connections;
2103deb3ec6SMatthias Ringwald }
2113deb3ec6SMatthias Ringwald 
2123deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){
2133deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
2143deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
2153deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
2163deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
2173deb3ec6SMatthias Ringwald         if (connection->rfcomm_cid == cid){
2183deb3ec6SMatthias Ringwald             return connection;
2193deb3ec6SMatthias Ringwald         }
2203deb3ec6SMatthias Ringwald     }
2213deb3ec6SMatthias Ringwald     return NULL;
2223deb3ec6SMatthias Ringwald }
2233deb3ec6SMatthias Ringwald 
2243deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
2253deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
2263deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
2273deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
2283deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
2293deb3ec6SMatthias Ringwald         if (memcmp(connection->remote_addr, bd_addr, 6) == 0) {
2303deb3ec6SMatthias Ringwald             return connection;
2313deb3ec6SMatthias Ringwald         }
2323deb3ec6SMatthias Ringwald     }
2333deb3ec6SMatthias Ringwald     return NULL;
2343deb3ec6SMatthias Ringwald }
2353deb3ec6SMatthias Ringwald 
2363deb3ec6SMatthias Ringwald static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){
2373deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
2383deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
2393deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
2403deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
2413deb3ec6SMatthias Ringwald         if (connection->con_handle == handle){
2423deb3ec6SMatthias Ringwald             return connection;
2433deb3ec6SMatthias Ringwald         }
2443deb3ec6SMatthias Ringwald     }
2453deb3ec6SMatthias Ringwald     return NULL;
2463deb3ec6SMatthias Ringwald }
2473deb3ec6SMatthias Ringwald 
2483deb3ec6SMatthias Ringwald void hfp_reset_context_flags(hfp_connection_t * context){
2493deb3ec6SMatthias Ringwald     if (!context) return;
2503deb3ec6SMatthias Ringwald     context->wait_ok = 0;
2513deb3ec6SMatthias Ringwald     context->send_ok = 0;
2523deb3ec6SMatthias Ringwald     context->send_error = 0;
2533deb3ec6SMatthias Ringwald 
2543deb3ec6SMatthias Ringwald     context->keep_separator = 0;
2553deb3ec6SMatthias Ringwald 
2563deb3ec6SMatthias Ringwald     context->retrieve_ag_indicators = 0;        // HFP_CMD_INDICATOR, check if needed
2573deb3ec6SMatthias Ringwald     context->retrieve_ag_indicators_status = 0;
2583deb3ec6SMatthias Ringwald 
2593deb3ec6SMatthias Ringwald     context->list_generic_status_indicators = 0;           // HFP_CMD_LIST_GENERIC_STATUS_INDICATOR
2603deb3ec6SMatthias Ringwald     context->retrieve_generic_status_indicators = 0;       // HFP_CMD_GENERIC_STATUS_INDICATOR
2613deb3ec6SMatthias Ringwald     context->retrieve_generic_status_indicators_state = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR_STATE
2623deb3ec6SMatthias Ringwald 
2633deb3ec6SMatthias Ringwald     context->change_status_update_for_individual_ag_indicators = 0;
2643deb3ec6SMatthias Ringwald 
2653deb3ec6SMatthias Ringwald     context->operator_name_format = 0;
2663deb3ec6SMatthias Ringwald     context->operator_name = 0;
2673deb3ec6SMatthias Ringwald     context->operator_name_changed = 0;
2683deb3ec6SMatthias Ringwald 
2693deb3ec6SMatthias Ringwald     context->enable_extended_audio_gateway_error_report = 0;
2703deb3ec6SMatthias Ringwald     context->extended_audio_gateway_error = 0;
2713deb3ec6SMatthias Ringwald 
2723deb3ec6SMatthias Ringwald     // can come any time (here taken into account only after SLE),
2733deb3ec6SMatthias Ringwald     // if codec negotiation feature is set
2743deb3ec6SMatthias Ringwald     context->notify_ag_on_new_codecs = 0;
2753deb3ec6SMatthias Ringwald 
2763deb3ec6SMatthias Ringwald     // establish codecs connection
2773deb3ec6SMatthias Ringwald     context->ag_trigger_codec_connection_setup = 0;
2783deb3ec6SMatthias Ringwald     context->hf_trigger_codec_connection_setup = 0;
2793deb3ec6SMatthias Ringwald     context->suggested_codec = 0;
2803deb3ec6SMatthias Ringwald     context->negotiated_codec = 0;
2813deb3ec6SMatthias Ringwald     context->codec_confirmed = 0;
2823deb3ec6SMatthias Ringwald 
2833deb3ec6SMatthias Ringwald     context->establish_audio_connection = 0;
2843deb3ec6SMatthias Ringwald }
2853deb3ec6SMatthias Ringwald 
2863deb3ec6SMatthias Ringwald static hfp_connection_t * create_hfp_connection_context(){
2873deb3ec6SMatthias Ringwald     hfp_connection_t * context = btstack_memory_hfp_connection_get();
2883deb3ec6SMatthias Ringwald     if (!context) return NULL;
2893deb3ec6SMatthias Ringwald     // init state
2903deb3ec6SMatthias Ringwald     memset(context,0, sizeof(hfp_connection_t));
2913deb3ec6SMatthias Ringwald 
2923deb3ec6SMatthias Ringwald     context->state = HFP_IDLE;
2933deb3ec6SMatthias Ringwald     context->parser_state = HFP_PARSER_CMD_HEADER;
2943deb3ec6SMatthias Ringwald     context->command = HFP_CMD_NONE;
2953deb3ec6SMatthias Ringwald     context->negotiated_codec = 0;
2963deb3ec6SMatthias Ringwald 
2973deb3ec6SMatthias Ringwald     context->enable_status_update_for_ag_indicators = 0xFF;
2983deb3ec6SMatthias Ringwald 
2993deb3ec6SMatthias Ringwald     context->generic_status_indicators_nr = hfp_generic_status_indicators_nr;
3003deb3ec6SMatthias Ringwald     memcpy(context->generic_status_indicators, hfp_generic_status_indicators, hfp_generic_status_indicators_nr * sizeof(hfp_generic_status_indicator_t));
3013deb3ec6SMatthias Ringwald 
3023deb3ec6SMatthias Ringwald     linked_list_add(&hfp_connections, (linked_item_t*)context);
3033deb3ec6SMatthias Ringwald     return context;
3043deb3ec6SMatthias Ringwald }
3053deb3ec6SMatthias Ringwald 
3063deb3ec6SMatthias Ringwald static void remove_hfp_connection_context(hfp_connection_t * context){
3073deb3ec6SMatthias Ringwald     linked_list_remove(&hfp_connections, (linked_item_t*)context);
3083deb3ec6SMatthias Ringwald }
3093deb3ec6SMatthias Ringwald 
3103deb3ec6SMatthias Ringwald static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){
3113deb3ec6SMatthias Ringwald     hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr);
3123deb3ec6SMatthias Ringwald     if (context) return  context;
3133deb3ec6SMatthias Ringwald     context = create_hfp_connection_context();
3143deb3ec6SMatthias Ringwald     memcpy(context->remote_addr, bd_addr, 6);
3153deb3ec6SMatthias Ringwald     return context;
3163deb3ec6SMatthias Ringwald }
3173deb3ec6SMatthias Ringwald 
3183deb3ec6SMatthias Ringwald 
3193deb3ec6SMatthias Ringwald /* @param suported_features
3203deb3ec6SMatthias Ringwald  * HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no)
3213deb3ec6SMatthias Ringwald  * HF bit 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no)
3223deb3ec6SMatthias Ringwald  * HF bit 2: CLI presentation capability (yes/no, 1 = yes, 0 = no)
3233deb3ec6SMatthias Ringwald  * HF bit 3: Voice recognition activation (yes/no, 1= yes, 0 = no)
3243deb3ec6SMatthias Ringwald  * HF bit 4: Remote volume control (yes/no, 1 = yes, 0 = no)
3253deb3ec6SMatthias Ringwald  * HF bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
3263deb3ec6SMatthias Ringwald  */
3273deb3ec6SMatthias Ringwald  /* Bit position:
3283deb3ec6SMatthias Ringwald  * AG bit 0: Three-way calling (yes/no, 1 = yes, 0 = no)
3293deb3ec6SMatthias Ringwald  * AG bit 1: EC and/or NR function (yes/no, 1 = yes, 0 = no)
3303deb3ec6SMatthias Ringwald  * AG bit 2: Voice recognition function (yes/no, 1 = yes, 0 = no)
3313deb3ec6SMatthias Ringwald  * AG bit 3: In-band ring tone capability (yes/no, 1 = yes, 0 = no)
3323deb3ec6SMatthias Ringwald  * AG bit 4: Attach a phone number to a voice tag (yes/no, 1 = yes, 0 = no)
3333deb3ec6SMatthias Ringwald  * AG bit 5: Wide band speech (yes/no, 1 = yes, 0 = no)
3343deb3ec6SMatthias Ringwald  */
3353deb3ec6SMatthias Ringwald 
3363deb3ec6SMatthias Ringwald 
3373deb3ec6SMatthias Ringwald void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){
3383deb3ec6SMatthias Ringwald     uint8_t* attribute;
3393deb3ec6SMatthias Ringwald     de_create_sequence(service);
3403deb3ec6SMatthias Ringwald 
3413deb3ec6SMatthias Ringwald     // 0x0000 "Service Record Handle"
3423deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
3433deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
3443deb3ec6SMatthias Ringwald 
3453deb3ec6SMatthias Ringwald     // 0x0001 "Service Class ID List"
3463deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
3473deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
3483deb3ec6SMatthias Ringwald     {
3493deb3ec6SMatthias Ringwald         //  "UUID for Service"
3503deb3ec6SMatthias Ringwald         de_add_number(attribute, DE_UUID, DE_SIZE_16, service_uuid);
3513deb3ec6SMatthias Ringwald         de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio);
3523deb3ec6SMatthias Ringwald     }
3533deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
3543deb3ec6SMatthias Ringwald 
3553deb3ec6SMatthias Ringwald     // 0x0004 "Protocol Descriptor List"
3563deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
3573deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
3583deb3ec6SMatthias Ringwald     {
3593deb3ec6SMatthias Ringwald         uint8_t* l2cpProtocol = de_push_sequence(attribute);
3603deb3ec6SMatthias Ringwald         {
3613deb3ec6SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
3623deb3ec6SMatthias Ringwald         }
3633deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, l2cpProtocol);
3643deb3ec6SMatthias Ringwald 
3653deb3ec6SMatthias Ringwald         uint8_t* rfcomm = de_push_sequence(attribute);
3663deb3ec6SMatthias Ringwald         {
3673deb3ec6SMatthias Ringwald             de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol);  // rfcomm_service
3683deb3ec6SMatthias Ringwald             de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  rfcomm_channel_nr);  // rfcomm channel
3693deb3ec6SMatthias Ringwald         }
3703deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, rfcomm);
3713deb3ec6SMatthias Ringwald     }
3723deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
3733deb3ec6SMatthias Ringwald 
3743deb3ec6SMatthias Ringwald 
3753deb3ec6SMatthias Ringwald     // 0x0005 "Public Browse Group"
3763deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
3773deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
3783deb3ec6SMatthias Ringwald     {
3793deb3ec6SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup);
3803deb3ec6SMatthias Ringwald     }
3813deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
3823deb3ec6SMatthias Ringwald 
3833deb3ec6SMatthias Ringwald     // 0x0009 "Bluetooth Profile Descriptor List"
3843deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
3853deb3ec6SMatthias Ringwald     attribute = de_push_sequence(service);
3863deb3ec6SMatthias Ringwald     {
3873deb3ec6SMatthias Ringwald         uint8_t *sppProfile = de_push_sequence(attribute);
3883deb3ec6SMatthias Ringwald         {
3893deb3ec6SMatthias Ringwald             de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, SDP_Handsfree);
3903deb3ec6SMatthias Ringwald             de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7
3913deb3ec6SMatthias Ringwald         }
3923deb3ec6SMatthias Ringwald         de_pop_sequence(attribute, sppProfile);
3933deb3ec6SMatthias Ringwald     }
3943deb3ec6SMatthias Ringwald     de_pop_sequence(service, attribute);
3953deb3ec6SMatthias Ringwald 
3963deb3ec6SMatthias Ringwald     // 0x0100 "Service Name"
3973deb3ec6SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
3983deb3ec6SMatthias Ringwald     de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
3993deb3ec6SMatthias Ringwald 
4003deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
4013deb3ec6SMatthias Ringwald }
4023deb3ec6SMatthias Ringwald 
4033deb3ec6SMatthias Ringwald static hfp_connection_t * connection_doing_sdp_query = NULL;
4043deb3ec6SMatthias Ringwald static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){
4053deb3ec6SMatthias Ringwald     sdp_query_rfcomm_service_event_t * ve;
4063deb3ec6SMatthias Ringwald     sdp_query_complete_event_t * ce;
4073deb3ec6SMatthias Ringwald     hfp_connection_t * connection = connection_doing_sdp_query;
4083deb3ec6SMatthias Ringwald 
4093deb3ec6SMatthias Ringwald     if ( connection->state != HFP_W4_SDP_QUERY_COMPLETE) return;
4103deb3ec6SMatthias Ringwald 
4113deb3ec6SMatthias Ringwald     switch (event->type){
4123deb3ec6SMatthias Ringwald         case SDP_QUERY_RFCOMM_SERVICE:
4133deb3ec6SMatthias Ringwald             ve = (sdp_query_rfcomm_service_event_t*) event;
4143deb3ec6SMatthias Ringwald             if (!connection) {
4153deb3ec6SMatthias Ringwald                 log_error("handle_query_rfcomm_event alloc connection for RFCOMM port %u failed", ve->channel_nr);
4163deb3ec6SMatthias Ringwald                 return;
4173deb3ec6SMatthias Ringwald             }
4183deb3ec6SMatthias Ringwald             connection->rfcomm_channel_nr = ve->channel_nr;
4193deb3ec6SMatthias Ringwald             break;
4203deb3ec6SMatthias Ringwald         case SDP_QUERY_COMPLETE:
4213deb3ec6SMatthias Ringwald             connection_doing_sdp_query = NULL;
4223deb3ec6SMatthias Ringwald             ce = (sdp_query_complete_event_t*) event;
4233deb3ec6SMatthias Ringwald 
4243deb3ec6SMatthias Ringwald             if (connection->rfcomm_channel_nr > 0){
4253deb3ec6SMatthias Ringwald                 connection->state = HFP_W4_RFCOMM_CONNECTED;
4263deb3ec6SMatthias Ringwald                 log_info("HFP: SDP_QUERY_COMPLETE context %p, addr %s, state %d", connection, bd_addr_to_str( connection->remote_addr),  connection->state);
4273deb3ec6SMatthias Ringwald                 rfcomm_create_channel_internal(NULL, connection->remote_addr, connection->rfcomm_channel_nr);
4283deb3ec6SMatthias Ringwald                 break;
4293deb3ec6SMatthias Ringwald             }
4303deb3ec6SMatthias Ringwald             log_info("rfcomm service not found, status %u.", ce->status);
4313deb3ec6SMatthias Ringwald             break;
4323deb3ec6SMatthias Ringwald         default:
4333deb3ec6SMatthias Ringwald             break;
4343deb3ec6SMatthias Ringwald     }
4353deb3ec6SMatthias Ringwald }
4363deb3ec6SMatthias Ringwald 
4373deb3ec6SMatthias Ringwald void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t *packet, uint16_t size){
4383deb3ec6SMatthias Ringwald     bd_addr_t event_addr;
4393deb3ec6SMatthias Ringwald     uint16_t rfcomm_cid, handle;
4403deb3ec6SMatthias Ringwald     hfp_connection_t * context = NULL;
4413deb3ec6SMatthias Ringwald 
4423deb3ec6SMatthias Ringwald     switch (packet[0]) {
4433deb3ec6SMatthias Ringwald         case BTSTACK_EVENT_STATE:
4443deb3ec6SMatthias Ringwald             // bt stack activated, get started
4453deb3ec6SMatthias Ringwald             if (packet[2] == HCI_STATE_WORKING){
4463deb3ec6SMatthias Ringwald                 printf("BTstack activated, get started .\n");
4473deb3ec6SMatthias Ringwald             }
4483deb3ec6SMatthias Ringwald             break;
4493deb3ec6SMatthias Ringwald 
4503deb3ec6SMatthias Ringwald         case HCI_EVENT_PIN_CODE_REQUEST:
4513deb3ec6SMatthias Ringwald             // inform about pin code request
4523deb3ec6SMatthias Ringwald             printf("Pin code request - using '0000'\n\r");
4533deb3ec6SMatthias Ringwald             bt_flip_addr(event_addr, &packet[2]);
4543deb3ec6SMatthias Ringwald             hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
4553deb3ec6SMatthias Ringwald             break;
4563deb3ec6SMatthias Ringwald 
4573deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_INCOMING_CONNECTION:
4583deb3ec6SMatthias Ringwald             // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
4593deb3ec6SMatthias Ringwald             bt_flip_addr(event_addr, &packet[2]);
4603deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_bd_addr(event_addr);
4613deb3ec6SMatthias Ringwald 
4623deb3ec6SMatthias Ringwald             if (!context || context->state != HFP_IDLE) return;
4633deb3ec6SMatthias Ringwald 
4643deb3ec6SMatthias Ringwald             context->rfcomm_cid = READ_BT_16(packet, 9);
4653deb3ec6SMatthias Ringwald             context->state = HFP_W4_RFCOMM_CONNECTED;
4663deb3ec6SMatthias Ringwald             printf("RFCOMM channel %u requested for %s\n", context->rfcomm_cid, bd_addr_to_str(context->remote_addr));
4673deb3ec6SMatthias Ringwald             rfcomm_accept_connection_internal(context->rfcomm_cid);
4683deb3ec6SMatthias Ringwald             break;
4693deb3ec6SMatthias Ringwald 
4703deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
4713deb3ec6SMatthias Ringwald             // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
4723deb3ec6SMatthias Ringwald             printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
4733deb3ec6SMatthias Ringwald             bt_flip_addr(event_addr, &packet[3]);
4743deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_bd_addr(event_addr);
4753deb3ec6SMatthias Ringwald             if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return;
4763deb3ec6SMatthias Ringwald 
4773deb3ec6SMatthias Ringwald             if (packet[2]) {
4783deb3ec6SMatthias Ringwald                 hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, packet[2]);
4793deb3ec6SMatthias Ringwald                 remove_hfp_connection_context(context);
4803deb3ec6SMatthias Ringwald             } else {
4813deb3ec6SMatthias Ringwald                 context->con_handle = READ_BT_16(packet, 9);
4823deb3ec6SMatthias Ringwald                 context->rfcomm_cid = READ_BT_16(packet, 12);
4833deb3ec6SMatthias Ringwald                 uint16_t mtu = READ_BT_16(packet, 14);
4843deb3ec6SMatthias Ringwald                 printf("RFCOMM channel open succeeded. Context %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", context, context->rfcomm_cid, mtu);
4853deb3ec6SMatthias Ringwald 
4863deb3ec6SMatthias Ringwald                 switch (context->state){
4873deb3ec6SMatthias Ringwald                     case HFP_W4_RFCOMM_CONNECTED:
4883deb3ec6SMatthias Ringwald                         context->state = HFP_EXCHANGE_SUPPORTED_FEATURES;
4893deb3ec6SMatthias Ringwald                         break;
4903deb3ec6SMatthias Ringwald                     case HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
4913deb3ec6SMatthias Ringwald                         context->state = HFP_W2_DISCONNECT_RFCOMM;
4923deb3ec6SMatthias Ringwald                         printf("Shutting down RFCOMM.\n");
4933deb3ec6SMatthias Ringwald                         break;
4943deb3ec6SMatthias Ringwald                     default:
4953deb3ec6SMatthias Ringwald                         break;
4963deb3ec6SMatthias Ringwald                 }
4973deb3ec6SMatthias Ringwald             }
4983deb3ec6SMatthias Ringwald             break;
4993deb3ec6SMatthias Ringwald 
5003deb3ec6SMatthias Ringwald         case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
5013deb3ec6SMatthias Ringwald             int index = 2;
5023deb3ec6SMatthias Ringwald             uint8_t status = packet[index++];
5033deb3ec6SMatthias Ringwald             uint16_t sco_handle = READ_BT_16(packet, index);
5043deb3ec6SMatthias Ringwald             index+=2;
5053deb3ec6SMatthias Ringwald             bd_addr_t address;
5063deb3ec6SMatthias Ringwald             memcpy(address, &packet[index], 6);
5073deb3ec6SMatthias Ringwald             index+=6;
5083deb3ec6SMatthias Ringwald             uint8_t link_type = packet[index++];
5093deb3ec6SMatthias Ringwald             uint8_t transmission_interval = packet[index++];  // measured in slots
5103deb3ec6SMatthias Ringwald             uint8_t retransmission_interval = packet[index++];// measured in slots
5113deb3ec6SMatthias Ringwald             uint16_t rx_packet_length = READ_BT_16(packet, index); // measured in bytes
5123deb3ec6SMatthias Ringwald             index+=2;
5133deb3ec6SMatthias Ringwald             uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes
5143deb3ec6SMatthias Ringwald             index+=2;
5153deb3ec6SMatthias Ringwald             uint8_t air_mode = packet[index];
5163deb3ec6SMatthias Ringwald 
5173deb3ec6SMatthias Ringwald             if (status != 0){
5183deb3ec6SMatthias Ringwald                 log_error("(e)SCO Connection is not established, status %u", status);
5193deb3ec6SMatthias Ringwald                 break;
5203deb3ec6SMatthias Ringwald             }
5213deb3ec6SMatthias Ringwald             switch (link_type){
5223deb3ec6SMatthias Ringwald                 case 0x00:
5233deb3ec6SMatthias Ringwald                     printf("SCO Connection established. \n");
5243deb3ec6SMatthias Ringwald                     if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
5253deb3ec6SMatthias Ringwald                     if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
5263deb3ec6SMatthias Ringwald                     if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
5273deb3ec6SMatthias Ringwald                     if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
5283deb3ec6SMatthias Ringwald                     break;
5293deb3ec6SMatthias Ringwald                 case 0x02:
5303deb3ec6SMatthias Ringwald                     printf("eSCO Connection established. \n");
5313deb3ec6SMatthias Ringwald                     break;
5323deb3ec6SMatthias Ringwald                 default:
5333deb3ec6SMatthias Ringwald                     log_error("(e)SCO reserved link_type 0x%2x", link_type);
5343deb3ec6SMatthias Ringwald                     break;
5353deb3ec6SMatthias Ringwald             }
5363deb3ec6SMatthias Ringwald             log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, "
5373deb3ec6SMatthias Ringwald                  " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle,
5383deb3ec6SMatthias Ringwald                  bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);
5393deb3ec6SMatthias Ringwald 
5403deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_bd_addr(address);
5413deb3ec6SMatthias Ringwald 
5423deb3ec6SMatthias Ringwald             if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
5433deb3ec6SMatthias Ringwald                 context->state = HFP_W2_DISCONNECT_SCO;
5443deb3ec6SMatthias Ringwald                 break;
5453deb3ec6SMatthias Ringwald             }
5463deb3ec6SMatthias Ringwald 
5473deb3ec6SMatthias Ringwald             context->sco_handle = sco_handle;
5483deb3ec6SMatthias Ringwald             context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
5493deb3ec6SMatthias Ringwald             hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
5503deb3ec6SMatthias Ringwald             break;
5513deb3ec6SMatthias Ringwald         }
5523deb3ec6SMatthias Ringwald 
5533deb3ec6SMatthias Ringwald         case RFCOMM_EVENT_CHANNEL_CLOSED:
5543deb3ec6SMatthias Ringwald             rfcomm_cid = READ_BT_16(packet,2);
5553deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
5563deb3ec6SMatthias Ringwald             if (!context) break;
5573deb3ec6SMatthias Ringwald             if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
5583deb3ec6SMatthias Ringwald                 context->state = HFP_IDLE;
5593deb3ec6SMatthias Ringwald                 hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
5603deb3ec6SMatthias Ringwald                 break;
5613deb3ec6SMatthias Ringwald             }
5623deb3ec6SMatthias Ringwald 
5633deb3ec6SMatthias Ringwald             hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0);
5643deb3ec6SMatthias Ringwald             remove_hfp_connection_context(context);
5653deb3ec6SMatthias Ringwald             break;
5663deb3ec6SMatthias Ringwald 
5673deb3ec6SMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
5683deb3ec6SMatthias Ringwald             handle = READ_BT_16(packet,3);
5693deb3ec6SMatthias Ringwald             context = get_hfp_connection_context_for_handle(handle);
5703deb3ec6SMatthias Ringwald             if (!context) break;
5713deb3ec6SMatthias Ringwald             if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
5723deb3ec6SMatthias Ringwald                 context->state = HFP_IDLE;
5733deb3ec6SMatthias Ringwald                 hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
5743deb3ec6SMatthias Ringwald                 break;
5753deb3ec6SMatthias Ringwald             }
5763deb3ec6SMatthias Ringwald             hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]);
5773deb3ec6SMatthias Ringwald             remove_hfp_connection_context(context);
5783deb3ec6SMatthias Ringwald             break;
5793deb3ec6SMatthias Ringwald 
5803deb3ec6SMatthias Ringwald         default:
5813deb3ec6SMatthias Ringwald             break;
5823deb3ec6SMatthias Ringwald     }
5833deb3ec6SMatthias Ringwald }
5843deb3ec6SMatthias Ringwald 
5853deb3ec6SMatthias Ringwald // translates command string into hfp_command_t CMD and flags to distinguish between CMD=, CMD?, CMD=?
5863deb3ec6SMatthias Ringwald static void process_command(hfp_connection_t * context){
5873deb3ec6SMatthias Ringwald     if (context->line_size < 2) return;
5883deb3ec6SMatthias Ringwald     // printf("process_command %s\n", context->line_buffer);
5893deb3ec6SMatthias Ringwald     context->command = HFP_CMD_NONE;
5903deb3ec6SMatthias Ringwald     int offset = 0;
5913deb3ec6SMatthias Ringwald     int isHandsFree = 1;
5923deb3ec6SMatthias Ringwald 
5933deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer, "AT", 2) == 0){
5943deb3ec6SMatthias Ringwald         offset = 2;
5953deb3ec6SMatthias Ringwald         isHandsFree = 0;
5963deb3ec6SMatthias Ringwald     }
5973deb3ec6SMatthias Ringwald 
5983deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){
5993deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ERROR;
6003deb3ec6SMatthias Ringwald         return;
6013deb3ec6SMatthias Ringwald     }
6023deb3ec6SMatthias Ringwald 
6033deb3ec6SMatthias Ringwald     if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){
6043deb3ec6SMatthias Ringwald         //printf("parsed HFP_CMD_OK \n");
6053deb3ec6SMatthias Ringwald         context->command = HFP_CMD_OK;
6063deb3ec6SMatthias Ringwald         return;
6073deb3ec6SMatthias Ringwald     }
6083deb3ec6SMatthias Ringwald 
6093deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){
6103deb3ec6SMatthias Ringwald         context->command = HFP_CMD_SUPPORTED_FEATURES;
6113deb3ec6SMatthias Ringwald         return;
6123deb3ec6SMatthias Ringwald     }
6133deb3ec6SMatthias Ringwald 
6143deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){
6153deb3ec6SMatthias Ringwald         //printf("parsed HFP_INDICATOR \n");
6163deb3ec6SMatthias Ringwald         context->command = HFP_CMD_INDICATOR;
6173deb3ec6SMatthias Ringwald         if (isHandsFree) return;
6183deb3ec6SMatthias Ringwald 
6193deb3ec6SMatthias Ringwald         if (strncmp((char *)context->line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){
6203deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators_status = 1;
6213deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators = 0;
6223deb3ec6SMatthias Ringwald         } else {
6233deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators = 1;
6243deb3ec6SMatthias Ringwald             context->retrieve_ag_indicators_status = 0;
6253deb3ec6SMatthias Ringwald         }
6263deb3ec6SMatthias Ringwald         return;
6273deb3ec6SMatthias Ringwald     }
6283deb3ec6SMatthias Ringwald 
6293deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){
6303deb3ec6SMatthias Ringwald         context->command = HFP_CMD_AVAILABLE_CODECS;
6313deb3ec6SMatthias Ringwald         context->notify_ag_on_new_codecs = 1;
6323deb3ec6SMatthias Ringwald         return;
6333deb3ec6SMatthias Ringwald     }
6343deb3ec6SMatthias Ringwald 
6353deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){
6363deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE;
6373deb3ec6SMatthias Ringwald         return;
6383deb3ec6SMatthias Ringwald     }
6393deb3ec6SMatthias Ringwald 
6403deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){
6413deb3ec6SMatthias Ringwald         context->command = HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES;
6423deb3ec6SMatthias Ringwald         return;
6433deb3ec6SMatthias Ringwald     }
6443deb3ec6SMatthias Ringwald 
6453deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){
6463deb3ec6SMatthias Ringwald         context->command = HFP_CMD_GENERIC_STATUS_INDICATOR;
6473deb3ec6SMatthias Ringwald         if (isHandsFree) return;
6483deb3ec6SMatthias Ringwald 
6493deb3ec6SMatthias Ringwald         if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=?", 2) == 0){
6503deb3ec6SMatthias Ringwald             context->list_generic_status_indicators = 0;
6513deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators = 1;
6523deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators_state = 0;
6533deb3ec6SMatthias Ringwald         } else if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){
6543deb3ec6SMatthias Ringwald             context->list_generic_status_indicators = 1;
6553deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators = 0;
6563deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators_state = 0;
6573deb3ec6SMatthias Ringwald         } else {
6583deb3ec6SMatthias Ringwald             context->list_generic_status_indicators = 0;
6593deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators = 0;
6603deb3ec6SMatthias Ringwald             context->retrieve_generic_status_indicators_state = 1;
6613deb3ec6SMatthias Ringwald         }
6623deb3ec6SMatthias Ringwald         return;
6633deb3ec6SMatthias Ringwald     }
6643deb3ec6SMatthias Ringwald 
6653deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS, strlen(HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS)) == 0){
6663deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE;
6673deb3ec6SMatthias Ringwald         return;
6683deb3ec6SMatthias Ringwald     }
6693deb3ec6SMatthias Ringwald 
6703deb3ec6SMatthias Ringwald 
6713deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_QUERY_OPERATOR_SELECTION, strlen(HFP_QUERY_OPERATOR_SELECTION)) == 0){
6723deb3ec6SMatthias Ringwald         context->command = HFP_CMD_QUERY_OPERATOR_SELECTION;
6733deb3ec6SMatthias Ringwald         context->operator_name = 1;
6743deb3ec6SMatthias Ringwald         context->operator_name_format = 0;
6753deb3ec6SMatthias Ringwald         if (isHandsFree) return;
6763deb3ec6SMatthias Ringwald 
6773deb3ec6SMatthias Ringwald         context->operator_name = 0;
6783deb3ec6SMatthias Ringwald         if (strncmp((char *)context->line_buffer+strlen(HFP_QUERY_OPERATOR_SELECTION)+offset, "=", 1) == 0){
6793deb3ec6SMatthias Ringwald             context->operator_name_format = 1;
6803deb3ec6SMatthias Ringwald         }
6813deb3ec6SMatthias Ringwald         return;
6823deb3ec6SMatthias Ringwald     }
6833deb3ec6SMatthias Ringwald 
6843deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_TRANSFER_AG_INDICATOR_STATUS)) == 0){
6853deb3ec6SMatthias Ringwald         context->command = HFP_CMD_TRANSFER_AG_INDICATOR_STATUS;
6863deb3ec6SMatthias Ringwald         return;
6873deb3ec6SMatthias Ringwald     }
6883deb3ec6SMatthias Ringwald 
6893deb3ec6SMatthias Ringwald     if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
6903deb3ec6SMatthias Ringwald         context->command = HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR;
6913deb3ec6SMatthias Ringwald         return;
6923deb3ec6SMatthias Ringwald     }
6933deb3ec6SMatthias Ringwald 
6943deb3ec6SMatthias Ringwald     if (!isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){
6953deb3ec6SMatthias Ringwald         context->command = HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR;
6963deb3ec6SMatthias Ringwald         return;
6973deb3ec6SMatthias Ringwald     }
6983deb3ec6SMatthias Ringwald 
6993deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){
7003deb3ec6SMatthias Ringwald         context->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
7013deb3ec6SMatthias Ringwald         // printf("HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP update command\n");
7023deb3ec6SMatthias Ringwald         if (isHandsFree){
7033deb3ec6SMatthias Ringwald             context->hf_trigger_codec_connection_setup = 1;
7043deb3ec6SMatthias Ringwald             printf("update command: hf_trigger_codec_connection_setup = 1\n");
7053deb3ec6SMatthias Ringwald         } else {
7063deb3ec6SMatthias Ringwald             context->hf_trigger_codec_connection_setup = 1;
7073deb3ec6SMatthias Ringwald             printf("update command: hf_trigger_codec_connection_setup = 1\n");
7083deb3ec6SMatthias Ringwald         }
7093deb3ec6SMatthias Ringwald         return;
7103deb3ec6SMatthias Ringwald     }
7113deb3ec6SMatthias Ringwald 
7123deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){
7133deb3ec6SMatthias Ringwald         if (!isHandsFree){
7143deb3ec6SMatthias Ringwald             context->command = HFP_CMD_HF_CONFIRMED_CODEC;
7153deb3ec6SMatthias Ringwald         } else {
7163deb3ec6SMatthias Ringwald             context->command = HFP_CMD_AG_SUGGESTED_CODEC;
7173deb3ec6SMatthias Ringwald         }
7183deb3ec6SMatthias Ringwald         return;
7193deb3ec6SMatthias Ringwald     }
7203deb3ec6SMatthias Ringwald 
7213deb3ec6SMatthias Ringwald     if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0) return;
7223deb3ec6SMatthias Ringwald 
7233deb3ec6SMatthias Ringwald     printf(" process unknown command 3 %s \n", context->line_buffer);
7243deb3ec6SMatthias Ringwald }
7253deb3ec6SMatthias Ringwald 
7263deb3ec6SMatthias Ringwald #if 0
7273deb3ec6SMatthias Ringwald uint32_t fromBinary(char *s) {
7283deb3ec6SMatthias Ringwald     return (uint32_t) strtol(s, NULL, 2);
7293deb3ec6SMatthias Ringwald }
7303deb3ec6SMatthias Ringwald #endif
7313deb3ec6SMatthias Ringwald 
7323deb3ec6SMatthias Ringwald static void hfp_parser_store_byte(hfp_connection_t * context, uint8_t byte){
7333deb3ec6SMatthias Ringwald     // TODO: add limit
7343deb3ec6SMatthias Ringwald     context->line_buffer[context->line_size++] = byte;
7353deb3ec6SMatthias Ringwald     context->line_buffer[context->line_size] = 0;
7363deb3ec6SMatthias Ringwald }
7373deb3ec6SMatthias Ringwald static int hfp_parser_is_buffer_empty(hfp_connection_t * context){
7383deb3ec6SMatthias Ringwald     return context->line_size == 0;
7393deb3ec6SMatthias Ringwald }
7403deb3ec6SMatthias Ringwald 
7413deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){
7423deb3ec6SMatthias Ringwald     return byte == '\n' || byte == '\r';
7433deb3ec6SMatthias Ringwald }
7443deb3ec6SMatthias Ringwald 
7453deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_header(uint8_t byte){
7463deb3ec6SMatthias Ringwald     return hfp_parser_is_end_of_line(byte) || byte == ':' || byte == '?';
7473deb3ec6SMatthias Ringwald }
7483deb3ec6SMatthias Ringwald 
7493deb3ec6SMatthias Ringwald static int hfp_parser_found_separator(hfp_connection_t * context, uint8_t byte){
7503deb3ec6SMatthias Ringwald     if (context->keep_separator == 1) return 1;
7513deb3ec6SMatthias Ringwald 
7523deb3ec6SMatthias Ringwald     int found_separator =   byte == ',' || byte == '\n'|| byte == '\r'||
7533deb3ec6SMatthias Ringwald                             byte == ')' || byte == '(' || byte == ':' ||
7543deb3ec6SMatthias Ringwald                             byte == '-' || byte == '"' ||  byte == '?'|| byte == '=';
7553deb3ec6SMatthias Ringwald     return found_separator;
7563deb3ec6SMatthias Ringwald }
7573deb3ec6SMatthias Ringwald 
7583deb3ec6SMatthias Ringwald static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){
7593deb3ec6SMatthias Ringwald     context->line_size = 0;
7603deb3ec6SMatthias Ringwald     if (hfp_parser_is_end_of_line(byte)){
7613deb3ec6SMatthias Ringwald         context->parser_item_index = 0;
7623deb3ec6SMatthias Ringwald         context->parser_state = HFP_PARSER_CMD_HEADER;
7633deb3ec6SMatthias Ringwald         return;
7643deb3ec6SMatthias Ringwald     }
7653deb3ec6SMatthias Ringwald     switch (context->parser_state){
7663deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_HEADER:
7673deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_CMD_SEQUENCE;
7683deb3ec6SMatthias Ringwald             if (context->keep_separator == 1){
7693deb3ec6SMatthias Ringwald                 hfp_parser_store_byte(context, byte);
7703deb3ec6SMatthias Ringwald                 context->keep_separator = 0;
7713deb3ec6SMatthias Ringwald             }
7723deb3ec6SMatthias Ringwald             break;
7733deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_SEQUENCE:
7743deb3ec6SMatthias Ringwald             switch (context->command){
7753deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
7763deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
7773deb3ec6SMatthias Ringwald                     context->parser_state = HFP_PARSER_SECOND_ITEM;
7783deb3ec6SMatthias Ringwald                     break;
7793deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
7803deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
7813deb3ec6SMatthias Ringwald                         context->parser_state = HFP_PARSER_SECOND_ITEM;
7823deb3ec6SMatthias Ringwald                         break;
7833deb3ec6SMatthias Ringwald                     }
7843deb3ec6SMatthias Ringwald                     break;
7853deb3ec6SMatthias Ringwald                 case HFP_CMD_GENERIC_STATUS_INDICATOR:
7863deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators_state == 1){
7873deb3ec6SMatthias Ringwald                         context->parser_state = HFP_PARSER_SECOND_ITEM;
7883deb3ec6SMatthias Ringwald                         break;
7893deb3ec6SMatthias Ringwald                     }
7903deb3ec6SMatthias Ringwald                     break;
7913deb3ec6SMatthias Ringwald                 default:
7923deb3ec6SMatthias Ringwald                     break;
7933deb3ec6SMatthias Ringwald             }
7943deb3ec6SMatthias Ringwald             break;
7953deb3ec6SMatthias Ringwald         case HFP_PARSER_SECOND_ITEM:
7963deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_THIRD_ITEM;
7973deb3ec6SMatthias Ringwald             break;
7983deb3ec6SMatthias Ringwald         case HFP_PARSER_THIRD_ITEM:
7993deb3ec6SMatthias Ringwald             if (context->command == HFP_CMD_INDICATOR && context->retrieve_ag_indicators){
8003deb3ec6SMatthias Ringwald                 context->parser_state = HFP_PARSER_CMD_SEQUENCE;
8013deb3ec6SMatthias Ringwald                 break;
8023deb3ec6SMatthias Ringwald             }
8033deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_CMD_HEADER;
8043deb3ec6SMatthias Ringwald             break;
8053deb3ec6SMatthias Ringwald     }
8063deb3ec6SMatthias Ringwald }
8073deb3ec6SMatthias Ringwald 
8083deb3ec6SMatthias Ringwald void hfp_parse(hfp_connection_t * context, uint8_t byte){
8093deb3ec6SMatthias Ringwald     int value;
8103deb3ec6SMatthias Ringwald 
8113deb3ec6SMatthias Ringwald     // TODO: handle space inside word
8123deb3ec6SMatthias Ringwald     if (byte == ' ' && context->parser_state > HFP_PARSER_CMD_HEADER) return;
8133deb3ec6SMatthias Ringwald 
8143deb3ec6SMatthias Ringwald     if (!hfp_parser_found_separator(context, byte)){
8153deb3ec6SMatthias Ringwald         hfp_parser_store_byte(context, byte);
8163deb3ec6SMatthias Ringwald         return;
8173deb3ec6SMatthias Ringwald     }
8183deb3ec6SMatthias Ringwald     if (hfp_parser_is_end_of_line(byte)) {
8193deb3ec6SMatthias Ringwald         if (hfp_parser_is_buffer_empty(context)){
8203deb3ec6SMatthias Ringwald             context->parser_state = HFP_PARSER_CMD_HEADER;
8213deb3ec6SMatthias Ringwald         }
8223deb3ec6SMatthias Ringwald     }
8233deb3ec6SMatthias Ringwald     if (hfp_parser_is_buffer_empty(context)) return;
8243deb3ec6SMatthias Ringwald 
8253deb3ec6SMatthias Ringwald 
8263deb3ec6SMatthias Ringwald     switch (context->parser_state){
8273deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_HEADER: // header
8283deb3ec6SMatthias Ringwald             if (byte == '='){
8293deb3ec6SMatthias Ringwald                 context->keep_separator = 1;
8303deb3ec6SMatthias Ringwald                 hfp_parser_store_byte(context, byte);
8313deb3ec6SMatthias Ringwald                 return;
8323deb3ec6SMatthias Ringwald             }
8333deb3ec6SMatthias Ringwald 
8343deb3ec6SMatthias Ringwald             if (byte == '?'){
8353deb3ec6SMatthias Ringwald                 context->keep_separator = 0;
8363deb3ec6SMatthias Ringwald                 hfp_parser_store_byte(context, byte);
8373deb3ec6SMatthias Ringwald                 return;
8383deb3ec6SMatthias Ringwald             }
8393deb3ec6SMatthias Ringwald             // printf(" parse header 2 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
8403deb3ec6SMatthias Ringwald             if (hfp_parser_is_end_of_header(byte) || context->keep_separator == 1){
8413deb3ec6SMatthias Ringwald                 // printf(" parse header 3 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator);
8423deb3ec6SMatthias Ringwald                 process_command(context);
8433deb3ec6SMatthias Ringwald             }
8443deb3ec6SMatthias Ringwald             break;
8453deb3ec6SMatthias Ringwald 
8463deb3ec6SMatthias Ringwald         case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes
8473deb3ec6SMatthias Ringwald             switch (context->command){
8483deb3ec6SMatthias Ringwald                 case HFP_CMD_HF_CONFIRMED_CODEC:
8493deb3ec6SMatthias Ringwald                     context->codec_confirmed = atoi((char*)context->line_buffer);
8503deb3ec6SMatthias Ringwald                     log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", context->codec_confirmed);
8513deb3ec6SMatthias Ringwald                     break;
8523deb3ec6SMatthias Ringwald                 case HFP_CMD_AG_SUGGESTED_CODEC:
8533deb3ec6SMatthias Ringwald                     context->suggested_codec = atoi((char*)context->line_buffer);
8543deb3ec6SMatthias Ringwald                     log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", context->suggested_codec);
8553deb3ec6SMatthias Ringwald                     break;
8563deb3ec6SMatthias Ringwald                 case HFP_CMD_SUPPORTED_FEATURES:
8573deb3ec6SMatthias Ringwald                     context->remote_supported_features = atoi((char*)context->line_buffer);
8583deb3ec6SMatthias Ringwald                     log_info("Parsed supported feature %d\n", context->remote_supported_features);
8593deb3ec6SMatthias Ringwald                     break;
8603deb3ec6SMatthias Ringwald                 case HFP_CMD_AVAILABLE_CODECS:
8613deb3ec6SMatthias Ringwald                     log_info("Parsed codec %s\n", context->line_buffer);
8623deb3ec6SMatthias Ringwald                     context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer);
8633deb3ec6SMatthias Ringwald                     context->parser_item_index++;
8643deb3ec6SMatthias Ringwald                     context->remote_codecs_nr = context->parser_item_index;
8653deb3ec6SMatthias Ringwald                     break;
8663deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
8673deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
8683deb3ec6SMatthias Ringwald                         strcpy((char *)context->ag_indicators[context->parser_item_index].name,  (char *)context->line_buffer);
8693deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1;
8703deb3ec6SMatthias Ringwald                         log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer);
8713deb3ec6SMatthias Ringwald                     }
8723deb3ec6SMatthias Ringwald 
8733deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators_status == 1){
8743deb3ec6SMatthias Ringwald                         log_info("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer);
8753deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer);
8763deb3ec6SMatthias Ringwald                         context->parser_item_index++;
8773deb3ec6SMatthias Ringwald                         break;
8783deb3ec6SMatthias Ringwald                     }
8793deb3ec6SMatthias Ringwald                     break;
8803deb3ec6SMatthias Ringwald                 case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
8813deb3ec6SMatthias Ringwald                     context->parser_item_index++;
8823deb3ec6SMatthias Ringwald                     if (context->parser_item_index != 4) break;
8833deb3ec6SMatthias Ringwald                     log_info("Parsed Enable indicators: %s\n", context->line_buffer);
8843deb3ec6SMatthias Ringwald                     value = atoi((char *)&context->line_buffer[0]);
8853deb3ec6SMatthias Ringwald                     context->enable_status_update_for_ag_indicators = (uint8_t) value;
8863deb3ec6SMatthias Ringwald                     break;
8873deb3ec6SMatthias Ringwald                 case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
8883deb3ec6SMatthias Ringwald                     log_info("Parsed Support call hold: %s\n", context->line_buffer);
8893deb3ec6SMatthias Ringwald                     if (context->line_size > 2 ) break;
8903deb3ec6SMatthias Ringwald                     strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name,  (char *)context->line_buffer);
8913deb3ec6SMatthias Ringwald                     context->remote_call_services_nr++;
8923deb3ec6SMatthias Ringwald                     break;
8933deb3ec6SMatthias Ringwald                 case HFP_CMD_GENERIC_STATUS_INDICATOR:
8943deb3ec6SMatthias Ringwald                     log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 1 (%d, %d, %d)\n",
8953deb3ec6SMatthias Ringwald                             context->list_generic_status_indicators,
8963deb3ec6SMatthias Ringwald                             context->retrieve_generic_status_indicators,
8973deb3ec6SMatthias Ringwald                             context->retrieve_generic_status_indicators_state);
8983deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators == 1 || context->list_generic_status_indicators == 1){
8993deb3ec6SMatthias Ringwald                         log_info("Parsed Generic status indicator: %s\n", context->line_buffer);
9003deb3ec6SMatthias Ringwald                         context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer);
9013deb3ec6SMatthias Ringwald                         context->parser_item_index++;
9023deb3ec6SMatthias Ringwald                         context->generic_status_indicators_nr = context->parser_item_index;
9033deb3ec6SMatthias Ringwald                         break;
9043deb3ec6SMatthias Ringwald                     }
9053deb3ec6SMatthias Ringwald                     log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 2\n");
9063deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators_state == 1){
9073deb3ec6SMatthias Ringwald                         // HF parses inital AG gen. ind. state
9083deb3ec6SMatthias Ringwald                         log_info("Parsed List generic status indicator %s state: ", context->line_buffer);
9093deb3ec6SMatthias Ringwald                         context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer);
9103deb3ec6SMatthias Ringwald                         break;
9113deb3ec6SMatthias Ringwald                     }
9123deb3ec6SMatthias Ringwald                     break;
9133deb3ec6SMatthias Ringwald 
9143deb3ec6SMatthias Ringwald                 case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:
9153deb3ec6SMatthias Ringwald                     // AG parses new gen. ind. state
9163deb3ec6SMatthias Ringwald                     log_info("Parsed Enable ag indicator state: %s\n", context->line_buffer);
9173deb3ec6SMatthias Ringwald                     value = atoi((char *)&context->line_buffer[0]);
9183deb3ec6SMatthias Ringwald                     if (!context->ag_indicators[context->parser_item_index].mandatory){
9193deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].enabled = value;
9203deb3ec6SMatthias Ringwald                     }
9213deb3ec6SMatthias Ringwald                     context->parser_item_index++;
9223deb3ec6SMatthias Ringwald                     break;
9233deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
9243deb3ec6SMatthias Ringwald                     // indicators are indexed starting with 1
9253deb3ec6SMatthias Ringwald                     context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
9263deb3ec6SMatthias Ringwald                     log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index);
9273deb3ec6SMatthias Ringwald                     break;
9283deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
9293deb3ec6SMatthias Ringwald                     if (context->operator_name_format == 1){
9303deb3ec6SMatthias Ringwald                         if (context->line_buffer[0] == '3'){
9313deb3ec6SMatthias Ringwald                             log_info("Parsed Set network operator format : %s, ", context->line_buffer);
9323deb3ec6SMatthias Ringwald                             break;
9333deb3ec6SMatthias Ringwald                         }
9343deb3ec6SMatthias Ringwald                         // TODO emit ERROR, wrong format
9353deb3ec6SMatthias Ringwald                         log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer);
9363deb3ec6SMatthias Ringwald                         break;
9373deb3ec6SMatthias Ringwald                     }
9383deb3ec6SMatthias Ringwald 
9393deb3ec6SMatthias Ringwald                     if (context->operator_name == 1) {
9403deb3ec6SMatthias Ringwald                         context->network_operator.mode = atoi((char *)&context->line_buffer[0]);
9413deb3ec6SMatthias Ringwald                         log_info("Parsed network operator mode: %d, ", context->network_operator.mode);
9423deb3ec6SMatthias Ringwald                         break;
9433deb3ec6SMatthias Ringwald                     }
9443deb3ec6SMatthias Ringwald                     break;
9453deb3ec6SMatthias Ringwald                 case HFP_CMD_ERROR:
9463deb3ec6SMatthias Ringwald                     break;
9473deb3ec6SMatthias Ringwald                 case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR:
9483deb3ec6SMatthias Ringwald                     context->extended_audio_gateway_error = (uint8_t)atoi((char*)context->line_buffer);
9493deb3ec6SMatthias Ringwald                     break;
9503deb3ec6SMatthias Ringwald                 case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
9513deb3ec6SMatthias Ringwald                     context->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)context->line_buffer);
9523deb3ec6SMatthias Ringwald                     context->send_ok = 1;
9533deb3ec6SMatthias Ringwald                     context->extended_audio_gateway_error = 0;
9543deb3ec6SMatthias Ringwald                     break;
9553deb3ec6SMatthias Ringwald                 default:
9563deb3ec6SMatthias Ringwald                     break;
9573deb3ec6SMatthias Ringwald             }
9583deb3ec6SMatthias Ringwald             break;
9593deb3ec6SMatthias Ringwald 
9603deb3ec6SMatthias Ringwald         case HFP_PARSER_SECOND_ITEM:
9613deb3ec6SMatthias Ringwald             switch (context->command){
9623deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
9633deb3ec6SMatthias Ringwald                     if (context->operator_name_format == 1) {
9643deb3ec6SMatthias Ringwald                         log_info("format %s \n", context->line_buffer);
9653deb3ec6SMatthias Ringwald                         context->network_operator.format =  atoi((char *)&context->line_buffer[0]);
9663deb3ec6SMatthias Ringwald                         break;
9673deb3ec6SMatthias Ringwald                     }
9683deb3ec6SMatthias Ringwald                     if (context->operator_name == 1){
9693deb3ec6SMatthias Ringwald                         log_info("format %s, ", context->line_buffer);
9703deb3ec6SMatthias Ringwald                         context->network_operator.format =  atoi((char *)&context->line_buffer[0]);
9713deb3ec6SMatthias Ringwald                     }
9723deb3ec6SMatthias Ringwald                     break;
9733deb3ec6SMatthias Ringwald                 case HFP_CMD_GENERIC_STATUS_INDICATOR:
9743deb3ec6SMatthias Ringwald                     context->generic_status_indicators[context->parser_item_index].state = (uint8_t)atoi((char*)context->line_buffer);
9753deb3ec6SMatthias Ringwald                     break;
9763deb3ec6SMatthias Ringwald                 case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
9773deb3ec6SMatthias Ringwald                     context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer);
9783deb3ec6SMatthias Ringwald                     context->ag_indicators[context->parser_item_index].status_changed = 1;
9793deb3ec6SMatthias Ringwald                     break;
9803deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
9813deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
9823deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer);
9833deb3ec6SMatthias Ringwald                         log_info("%s, ", context->line_buffer);
9843deb3ec6SMatthias Ringwald                     }
9853deb3ec6SMatthias Ringwald                     break;
9863deb3ec6SMatthias Ringwald                 default:
9873deb3ec6SMatthias Ringwald                     break;
9883deb3ec6SMatthias Ringwald             }
9893deb3ec6SMatthias Ringwald             break;
9903deb3ec6SMatthias Ringwald 
9913deb3ec6SMatthias Ringwald         case HFP_PARSER_THIRD_ITEM:
9923deb3ec6SMatthias Ringwald              switch (context->command){
9933deb3ec6SMatthias Ringwald                 case HFP_CMD_QUERY_OPERATOR_SELECTION:
9943deb3ec6SMatthias Ringwald                     if (context->operator_name == 1){
9953deb3ec6SMatthias Ringwald                         strcpy(context->network_operator.name, (char *)context->line_buffer);
9963deb3ec6SMatthias Ringwald                         log_info("name %s\n", context->line_buffer);
9973deb3ec6SMatthias Ringwald                     }
9983deb3ec6SMatthias Ringwald                     break;
9993deb3ec6SMatthias Ringwald                 case HFP_CMD_INDICATOR:
10003deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 1){
10013deb3ec6SMatthias Ringwald                         context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer);
10023deb3ec6SMatthias Ringwald                         context->parser_item_index++;
10033deb3ec6SMatthias Ringwald                         context->ag_indicators_nr = context->parser_item_index;
10043deb3ec6SMatthias Ringwald                         log_info("%s)\n", context->line_buffer);
10053deb3ec6SMatthias Ringwald                     }
10063deb3ec6SMatthias Ringwald                     break;
10073deb3ec6SMatthias Ringwald                 default:
10083deb3ec6SMatthias Ringwald                     break;
10093deb3ec6SMatthias Ringwald             }
10103deb3ec6SMatthias Ringwald             break;
10113deb3ec6SMatthias Ringwald     }
10123deb3ec6SMatthias Ringwald     hfp_parser_next_state(context, byte);
10133deb3ec6SMatthias Ringwald }
10143deb3ec6SMatthias Ringwald 
10153deb3ec6SMatthias Ringwald void hfp_init(uint16_t rfcomm_channel_nr){
10163deb3ec6SMatthias Ringwald     rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 0xffff);
10173deb3ec6SMatthias Ringwald     sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL);
10183deb3ec6SMatthias Ringwald }
10193deb3ec6SMatthias Ringwald 
10203deb3ec6SMatthias Ringwald void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid){
10213deb3ec6SMatthias Ringwald     hfp_connection_t * context = provide_hfp_connection_context_for_bd_addr(bd_addr);
10223deb3ec6SMatthias Ringwald     log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context);
10233deb3ec6SMatthias Ringwald 
10243deb3ec6SMatthias Ringwald     if (!context) {
10253deb3ec6SMatthias Ringwald         log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr));
10263deb3ec6SMatthias Ringwald         return;
10273deb3ec6SMatthias Ringwald     }
10283deb3ec6SMatthias Ringwald     switch (context->state){
10293deb3ec6SMatthias Ringwald         case HFP_W2_DISCONNECT_RFCOMM:
10303deb3ec6SMatthias Ringwald             context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
10313deb3ec6SMatthias Ringwald             return;
10323deb3ec6SMatthias Ringwald         case HFP_W4_RFCOMM_DISCONNECTED:
10333deb3ec6SMatthias Ringwald             context->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART;
10343deb3ec6SMatthias Ringwald             return;
10353deb3ec6SMatthias Ringwald         case HFP_IDLE:
10363deb3ec6SMatthias Ringwald             memcpy(context->remote_addr, bd_addr, 6);
10373deb3ec6SMatthias Ringwald             context->state = HFP_W4_SDP_QUERY_COMPLETE;
10383deb3ec6SMatthias Ringwald             connection_doing_sdp_query = context;
10393deb3ec6SMatthias Ringwald             context->service_uuid = service_uuid;
10403deb3ec6SMatthias Ringwald             sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid);
10413deb3ec6SMatthias Ringwald             break;
10423deb3ec6SMatthias Ringwald         default:
10433deb3ec6SMatthias Ringwald             break;
10443deb3ec6SMatthias Ringwald     }
10453deb3ec6SMatthias Ringwald }
10463deb3ec6SMatthias Ringwald 
10473deb3ec6SMatthias Ringwald void hfp_release_service_level_connection(hfp_connection_t * context){
10483deb3ec6SMatthias Ringwald     if (!context) return;
10493deb3ec6SMatthias Ringwald 
10503deb3ec6SMatthias Ringwald     if (context->state < HFP_W4_RFCOMM_CONNECTED){
10513deb3ec6SMatthias Ringwald         context->state = HFP_IDLE;
10523deb3ec6SMatthias Ringwald         return;
10533deb3ec6SMatthias Ringwald     }
10543deb3ec6SMatthias Ringwald 
10553deb3ec6SMatthias Ringwald     if (context->state == HFP_W4_RFCOMM_CONNECTED){
10563deb3ec6SMatthias Ringwald         context->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
10573deb3ec6SMatthias Ringwald         return;
10583deb3ec6SMatthias Ringwald     }
10593deb3ec6SMatthias Ringwald 
10603deb3ec6SMatthias Ringwald     if (context->state < HFP_CCE_W4_SCO_CONNECTION_ESTABLISHED){
10613deb3ec6SMatthias Ringwald         context->state = HFP_W2_DISCONNECT_RFCOMM;
10623deb3ec6SMatthias Ringwald         return;
10633deb3ec6SMatthias Ringwald     }
10643deb3ec6SMatthias Ringwald 
10653deb3ec6SMatthias Ringwald     if (context->state < HFP_W4_SCO_DISCONNECTED){
10663deb3ec6SMatthias Ringwald         context->state = HFP_W2_DISCONNECT_SCO;
10673deb3ec6SMatthias Ringwald         return;
10683deb3ec6SMatthias Ringwald     }
10693deb3ec6SMatthias Ringwald 
10703deb3ec6SMatthias Ringwald     return;
10713deb3ec6SMatthias Ringwald }
10723deb3ec6SMatthias Ringwald 
10733deb3ec6SMatthias Ringwald void hfp_release_audio_connection(hfp_connection_t * connection){
10743deb3ec6SMatthias Ringwald     if (!connection) return;
10753deb3ec6SMatthias Ringwald     if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
10763deb3ec6SMatthias Ringwald     connection->release_audio_connection = 1;
10773deb3ec6SMatthias Ringwald }
10783deb3ec6SMatthias Ringwald 
10793deb3ec6SMatthias Ringwald 
1080