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