1*3deb3ec6SMatthias Ringwald /* 2*3deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*3deb3ec6SMatthias Ringwald * 4*3deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*3deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 6*3deb3ec6SMatthias Ringwald * are met: 7*3deb3ec6SMatthias Ringwald * 8*3deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*3deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*3deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*3deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*3deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*3deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*3deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*3deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 16*3deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*3deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*3deb3ec6SMatthias Ringwald * monetary gain. 19*3deb3ec6SMatthias Ringwald * 20*3deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*3deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*3deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*3deb3ec6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*3deb3ec6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*3deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*3deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*3deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*3deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*3deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*3deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*3deb3ec6SMatthias Ringwald * SUCH DAMAGE. 32*3deb3ec6SMatthias Ringwald * 33*3deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 34*3deb3ec6SMatthias Ringwald * [email protected] 35*3deb3ec6SMatthias Ringwald * 36*3deb3ec6SMatthias Ringwald */ 37*3deb3ec6SMatthias Ringwald 38*3deb3ec6SMatthias Ringwald // ***************************************************************************** 39*3deb3ec6SMatthias Ringwald // 40*3deb3ec6SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!) 41*3deb3ec6SMatthias Ringwald // 42*3deb3ec6SMatthias Ringwald // ***************************************************************************** 43*3deb3ec6SMatthias Ringwald 44*3deb3ec6SMatthias Ringwald #include "btstack-config.h" 45*3deb3ec6SMatthias Ringwald 46*3deb3ec6SMatthias Ringwald #include <stdint.h> 47*3deb3ec6SMatthias Ringwald #include <stdio.h> 48*3deb3ec6SMatthias Ringwald #include <stdlib.h> 49*3deb3ec6SMatthias Ringwald #include <string.h> 50*3deb3ec6SMatthias Ringwald #include <inttypes.h> 51*3deb3ec6SMatthias Ringwald 52*3deb3ec6SMatthias Ringwald #include "hci_cmds.h" 53*3deb3ec6SMatthias Ringwald #include "run_loop.h" 54*3deb3ec6SMatthias Ringwald 55*3deb3ec6SMatthias Ringwald #include "hci.h" 56*3deb3ec6SMatthias Ringwald #include "btstack_memory.h" 57*3deb3ec6SMatthias Ringwald #include "hci_dump.h" 58*3deb3ec6SMatthias Ringwald #include "l2cap.h" 59*3deb3ec6SMatthias Ringwald #include "sdp_query_rfcomm.h" 60*3deb3ec6SMatthias Ringwald #include "sdp.h" 61*3deb3ec6SMatthias Ringwald #include "debug.h" 62*3deb3ec6SMatthias Ringwald 63*3deb3ec6SMatthias Ringwald #define HFP_HF_FEATURES_SIZE 10 64*3deb3ec6SMatthias Ringwald #define HFP_AG_FEATURES_SIZE 12 65*3deb3ec6SMatthias Ringwald 66*3deb3ec6SMatthias Ringwald 67*3deb3ec6SMatthias Ringwald static const char * hfp_hf_features[] = { 68*3deb3ec6SMatthias Ringwald "EC and/or NR function", 69*3deb3ec6SMatthias Ringwald "Three-way calling", 70*3deb3ec6SMatthias Ringwald "CLI presentation capability", 71*3deb3ec6SMatthias Ringwald "Voice recognition activation", 72*3deb3ec6SMatthias Ringwald "Remote volume control", 73*3deb3ec6SMatthias Ringwald 74*3deb3ec6SMatthias Ringwald "Enhanced call status", 75*3deb3ec6SMatthias Ringwald "Enhanced call control", 76*3deb3ec6SMatthias Ringwald 77*3deb3ec6SMatthias Ringwald "Codec negotiation", 78*3deb3ec6SMatthias Ringwald 79*3deb3ec6SMatthias Ringwald "HF Indicators", 80*3deb3ec6SMatthias Ringwald "eSCO S4 (and T2) Settings Supported", 81*3deb3ec6SMatthias Ringwald "Reserved for future definition" 82*3deb3ec6SMatthias Ringwald }; 83*3deb3ec6SMatthias Ringwald 84*3deb3ec6SMatthias Ringwald static const char * hfp_ag_features[] = { 85*3deb3ec6SMatthias Ringwald "Three-way calling", 86*3deb3ec6SMatthias Ringwald "EC and/or NR function", 87*3deb3ec6SMatthias Ringwald "Voice recognition function", 88*3deb3ec6SMatthias Ringwald "In-band ring tone capability", 89*3deb3ec6SMatthias Ringwald "Attach a number to a voice tag", 90*3deb3ec6SMatthias Ringwald "Ability to reject a call", 91*3deb3ec6SMatthias Ringwald "Enhanced call status", 92*3deb3ec6SMatthias Ringwald "Enhanced call control", 93*3deb3ec6SMatthias Ringwald "Extended Error Result Codes", 94*3deb3ec6SMatthias Ringwald "Codec negotiation", 95*3deb3ec6SMatthias Ringwald "HF Indicators", 96*3deb3ec6SMatthias Ringwald "eSCO S4 (and T2) Settings Supported", 97*3deb3ec6SMatthias Ringwald "Reserved for future definition" 98*3deb3ec6SMatthias Ringwald }; 99*3deb3ec6SMatthias Ringwald 100*3deb3ec6SMatthias Ringwald static int hfp_generic_status_indicators_nr = 0; 101*3deb3ec6SMatthias Ringwald static hfp_generic_status_indicator_t hfp_generic_status_indicators[HFP_MAX_NUM_HF_INDICATORS]; 102*3deb3ec6SMatthias Ringwald 103*3deb3ec6SMatthias Ringwald static linked_list_t hfp_connections = NULL; 104*3deb3ec6SMatthias Ringwald 105*3deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(void){ 106*3deb3ec6SMatthias Ringwald return (hfp_generic_status_indicator_t *) &hfp_generic_status_indicators; 107*3deb3ec6SMatthias Ringwald } 108*3deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr(void){ 109*3deb3ec6SMatthias Ringwald return hfp_generic_status_indicators_nr; 110*3deb3ec6SMatthias Ringwald } 111*3deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr){ 112*3deb3ec6SMatthias Ringwald if (indicator_nr > HFP_MAX_NUM_HF_INDICATORS) return; 113*3deb3ec6SMatthias Ringwald hfp_generic_status_indicators_nr = indicator_nr; 114*3deb3ec6SMatthias Ringwald memcpy(hfp_generic_status_indicators, indicators, indicator_nr * sizeof(hfp_generic_status_indicator_t)); 115*3deb3ec6SMatthias Ringwald } 116*3deb3ec6SMatthias Ringwald 117*3deb3ec6SMatthias Ringwald const char * hfp_hf_feature(int index){ 118*3deb3ec6SMatthias Ringwald if (index > HFP_HF_FEATURES_SIZE){ 119*3deb3ec6SMatthias Ringwald return hfp_hf_features[HFP_HF_FEATURES_SIZE]; 120*3deb3ec6SMatthias Ringwald } 121*3deb3ec6SMatthias Ringwald return hfp_hf_features[index]; 122*3deb3ec6SMatthias Ringwald } 123*3deb3ec6SMatthias Ringwald 124*3deb3ec6SMatthias Ringwald const char * hfp_ag_feature(int index){ 125*3deb3ec6SMatthias Ringwald if (index > HFP_AG_FEATURES_SIZE){ 126*3deb3ec6SMatthias Ringwald return hfp_ag_features[HFP_AG_FEATURES_SIZE]; 127*3deb3ec6SMatthias Ringwald } 128*3deb3ec6SMatthias Ringwald return hfp_ag_features[index]; 129*3deb3ec6SMatthias Ringwald } 130*3deb3ec6SMatthias Ringwald 131*3deb3ec6SMatthias Ringwald int send_str_over_rfcomm(uint16_t cid, char * command){ 132*3deb3ec6SMatthias Ringwald if (!rfcomm_can_send_packet_now(cid)) return 1; 133*3deb3ec6SMatthias Ringwald int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command)); 134*3deb3ec6SMatthias Ringwald if (err){ 135*3deb3ec6SMatthias Ringwald log_error("rfcomm_send_internal -> error 0x%02x \n", err); 136*3deb3ec6SMatthias Ringwald } 137*3deb3ec6SMatthias Ringwald return 1; 138*3deb3ec6SMatthias Ringwald } 139*3deb3ec6SMatthias Ringwald 140*3deb3ec6SMatthias Ringwald #if 0 141*3deb3ec6SMatthias Ringwald void hfp_set_codec(hfp_connection_t * context, uint8_t *packet, uint16_t size){ 142*3deb3ec6SMatthias Ringwald // parse available codecs 143*3deb3ec6SMatthias Ringwald int pos = 0; 144*3deb3ec6SMatthias Ringwald int i; 145*3deb3ec6SMatthias Ringwald for (i=0; i<size; i++){ 146*3deb3ec6SMatthias Ringwald pos+=8; 147*3deb3ec6SMatthias Ringwald if (packet[pos] > context->negotiated_codec){ 148*3deb3ec6SMatthias Ringwald context->negotiated_codec = packet[pos]; 149*3deb3ec6SMatthias Ringwald } 150*3deb3ec6SMatthias Ringwald } 151*3deb3ec6SMatthias Ringwald printf("Negotiated Codec 0x%02x\n", context->negotiated_codec); 152*3deb3ec6SMatthias Ringwald } 153*3deb3ec6SMatthias Ringwald #endif 154*3deb3ec6SMatthias Ringwald 155*3deb3ec6SMatthias Ringwald // UTILS 156*3deb3ec6SMatthias Ringwald int get_bit(uint16_t bitmap, int position){ 157*3deb3ec6SMatthias Ringwald return (bitmap >> position) & 1; 158*3deb3ec6SMatthias Ringwald } 159*3deb3ec6SMatthias Ringwald 160*3deb3ec6SMatthias Ringwald int store_bit(uint32_t bitmap, int position, uint8_t value){ 161*3deb3ec6SMatthias Ringwald if (value){ 162*3deb3ec6SMatthias Ringwald bitmap |= 1 << position; 163*3deb3ec6SMatthias Ringwald } else { 164*3deb3ec6SMatthias Ringwald bitmap &= ~ (1 << position); 165*3deb3ec6SMatthias Ringwald } 166*3deb3ec6SMatthias Ringwald return bitmap; 167*3deb3ec6SMatthias Ringwald } 168*3deb3ec6SMatthias Ringwald 169*3deb3ec6SMatthias Ringwald int join(char * buffer, int buffer_size, uint8_t * values, int values_nr){ 170*3deb3ec6SMatthias Ringwald if (buffer_size < values_nr * 3) return 0; 171*3deb3ec6SMatthias Ringwald int i; 172*3deb3ec6SMatthias Ringwald int offset = 0; 173*3deb3ec6SMatthias Ringwald for (i = 0; i < values_nr-1; i++) { 174*3deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", values[i]); // puts string into buffer 175*3deb3ec6SMatthias Ringwald } 176*3deb3ec6SMatthias Ringwald if (i<values_nr){ 177*3deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d", values[i]); 178*3deb3ec6SMatthias Ringwald } 179*3deb3ec6SMatthias Ringwald return offset; 180*3deb3ec6SMatthias Ringwald } 181*3deb3ec6SMatthias Ringwald 182*3deb3ec6SMatthias Ringwald int join_bitmap(char * buffer, int buffer_size, uint32_t values, int values_nr){ 183*3deb3ec6SMatthias Ringwald if (buffer_size < values_nr * 3) return 0; 184*3deb3ec6SMatthias Ringwald 185*3deb3ec6SMatthias Ringwald int i; 186*3deb3ec6SMatthias Ringwald int offset = 0; 187*3deb3ec6SMatthias Ringwald for (i = 0; i < values_nr-1; i++) { 188*3deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_bit(values,i)); // puts string into buffer 189*3deb3ec6SMatthias Ringwald } 190*3deb3ec6SMatthias Ringwald 191*3deb3ec6SMatthias Ringwald if (i<values_nr){ 192*3deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d", get_bit(values,i)); 193*3deb3ec6SMatthias Ringwald } 194*3deb3ec6SMatthias Ringwald return offset; 195*3deb3ec6SMatthias Ringwald } 196*3deb3ec6SMatthias Ringwald 197*3deb3ec6SMatthias Ringwald void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t value){ 198*3deb3ec6SMatthias Ringwald if (!callback) return; 199*3deb3ec6SMatthias Ringwald uint8_t event[4]; 200*3deb3ec6SMatthias Ringwald event[0] = HCI_EVENT_HFP_META; 201*3deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 202*3deb3ec6SMatthias Ringwald event[2] = event_subtype; 203*3deb3ec6SMatthias Ringwald event[3] = value; // status 0 == OK 204*3deb3ec6SMatthias Ringwald (*callback)(event, sizeof(event)); 205*3deb3ec6SMatthias Ringwald } 206*3deb3ec6SMatthias Ringwald 207*3deb3ec6SMatthias Ringwald 208*3deb3ec6SMatthias Ringwald linked_list_t * hfp_get_connections(){ 209*3deb3ec6SMatthias Ringwald return (linked_list_t *) &hfp_connections; 210*3deb3ec6SMatthias Ringwald } 211*3deb3ec6SMatthias Ringwald 212*3deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid){ 213*3deb3ec6SMatthias Ringwald linked_list_iterator_t it; 214*3deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 215*3deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 216*3deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 217*3deb3ec6SMatthias Ringwald if (connection->rfcomm_cid == cid){ 218*3deb3ec6SMatthias Ringwald return connection; 219*3deb3ec6SMatthias Ringwald } 220*3deb3ec6SMatthias Ringwald } 221*3deb3ec6SMatthias Ringwald return NULL; 222*3deb3ec6SMatthias Ringwald } 223*3deb3ec6SMatthias Ringwald 224*3deb3ec6SMatthias Ringwald hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){ 225*3deb3ec6SMatthias Ringwald linked_list_iterator_t it; 226*3deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 227*3deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 228*3deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 229*3deb3ec6SMatthias Ringwald if (memcmp(connection->remote_addr, bd_addr, 6) == 0) { 230*3deb3ec6SMatthias Ringwald return connection; 231*3deb3ec6SMatthias Ringwald } 232*3deb3ec6SMatthias Ringwald } 233*3deb3ec6SMatthias Ringwald return NULL; 234*3deb3ec6SMatthias Ringwald } 235*3deb3ec6SMatthias Ringwald 236*3deb3ec6SMatthias Ringwald static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle){ 237*3deb3ec6SMatthias Ringwald linked_list_iterator_t it; 238*3deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 239*3deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 240*3deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 241*3deb3ec6SMatthias Ringwald if (connection->con_handle == handle){ 242*3deb3ec6SMatthias Ringwald return connection; 243*3deb3ec6SMatthias Ringwald } 244*3deb3ec6SMatthias Ringwald } 245*3deb3ec6SMatthias Ringwald return NULL; 246*3deb3ec6SMatthias Ringwald } 247*3deb3ec6SMatthias Ringwald 248*3deb3ec6SMatthias Ringwald void hfp_reset_context_flags(hfp_connection_t * context){ 249*3deb3ec6SMatthias Ringwald if (!context) return; 250*3deb3ec6SMatthias Ringwald context->wait_ok = 0; 251*3deb3ec6SMatthias Ringwald context->send_ok = 0; 252*3deb3ec6SMatthias Ringwald context->send_error = 0; 253*3deb3ec6SMatthias Ringwald 254*3deb3ec6SMatthias Ringwald context->keep_separator = 0; 255*3deb3ec6SMatthias Ringwald 256*3deb3ec6SMatthias Ringwald context->retrieve_ag_indicators = 0; // HFP_CMD_INDICATOR, check if needed 257*3deb3ec6SMatthias Ringwald context->retrieve_ag_indicators_status = 0; 258*3deb3ec6SMatthias Ringwald 259*3deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 0; // HFP_CMD_LIST_GENERIC_STATUS_INDICATOR 260*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR 261*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR_STATE 262*3deb3ec6SMatthias Ringwald 263*3deb3ec6SMatthias Ringwald context->change_status_update_for_individual_ag_indicators = 0; 264*3deb3ec6SMatthias Ringwald 265*3deb3ec6SMatthias Ringwald context->operator_name_format = 0; 266*3deb3ec6SMatthias Ringwald context->operator_name = 0; 267*3deb3ec6SMatthias Ringwald context->operator_name_changed = 0; 268*3deb3ec6SMatthias Ringwald 269*3deb3ec6SMatthias Ringwald context->enable_extended_audio_gateway_error_report = 0; 270*3deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = 0; 271*3deb3ec6SMatthias Ringwald 272*3deb3ec6SMatthias Ringwald // can come any time (here taken into account only after SLE), 273*3deb3ec6SMatthias Ringwald // if codec negotiation feature is set 274*3deb3ec6SMatthias Ringwald context->notify_ag_on_new_codecs = 0; 275*3deb3ec6SMatthias Ringwald 276*3deb3ec6SMatthias Ringwald // establish codecs connection 277*3deb3ec6SMatthias Ringwald context->ag_trigger_codec_connection_setup = 0; 278*3deb3ec6SMatthias Ringwald context->hf_trigger_codec_connection_setup = 0; 279*3deb3ec6SMatthias Ringwald context->suggested_codec = 0; 280*3deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 281*3deb3ec6SMatthias Ringwald context->codec_confirmed = 0; 282*3deb3ec6SMatthias Ringwald 283*3deb3ec6SMatthias Ringwald context->establish_audio_connection = 0; 284*3deb3ec6SMatthias Ringwald } 285*3deb3ec6SMatthias Ringwald 286*3deb3ec6SMatthias Ringwald static hfp_connection_t * create_hfp_connection_context(){ 287*3deb3ec6SMatthias Ringwald hfp_connection_t * context = btstack_memory_hfp_connection_get(); 288*3deb3ec6SMatthias Ringwald if (!context) return NULL; 289*3deb3ec6SMatthias Ringwald // init state 290*3deb3ec6SMatthias Ringwald memset(context,0, sizeof(hfp_connection_t)); 291*3deb3ec6SMatthias Ringwald 292*3deb3ec6SMatthias Ringwald context->state = HFP_IDLE; 293*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_CMD_HEADER; 294*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 295*3deb3ec6SMatthias Ringwald context->negotiated_codec = 0; 296*3deb3ec6SMatthias Ringwald 297*3deb3ec6SMatthias Ringwald context->enable_status_update_for_ag_indicators = 0xFF; 298*3deb3ec6SMatthias Ringwald 299*3deb3ec6SMatthias Ringwald context->generic_status_indicators_nr = hfp_generic_status_indicators_nr; 300*3deb3ec6SMatthias Ringwald memcpy(context->generic_status_indicators, hfp_generic_status_indicators, hfp_generic_status_indicators_nr * sizeof(hfp_generic_status_indicator_t)); 301*3deb3ec6SMatthias Ringwald 302*3deb3ec6SMatthias Ringwald linked_list_add(&hfp_connections, (linked_item_t*)context); 303*3deb3ec6SMatthias Ringwald return context; 304*3deb3ec6SMatthias Ringwald } 305*3deb3ec6SMatthias Ringwald 306*3deb3ec6SMatthias Ringwald static void remove_hfp_connection_context(hfp_connection_t * context){ 307*3deb3ec6SMatthias Ringwald linked_list_remove(&hfp_connections, (linked_item_t*)context); 308*3deb3ec6SMatthias Ringwald } 309*3deb3ec6SMatthias Ringwald 310*3deb3ec6SMatthias Ringwald static hfp_connection_t * provide_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr){ 311*3deb3ec6SMatthias Ringwald hfp_connection_t * context = get_hfp_connection_context_for_bd_addr(bd_addr); 312*3deb3ec6SMatthias Ringwald if (context) return context; 313*3deb3ec6SMatthias Ringwald context = create_hfp_connection_context(); 314*3deb3ec6SMatthias Ringwald memcpy(context->remote_addr, bd_addr, 6); 315*3deb3ec6SMatthias Ringwald return context; 316*3deb3ec6SMatthias Ringwald } 317*3deb3ec6SMatthias Ringwald 318*3deb3ec6SMatthias Ringwald 319*3deb3ec6SMatthias Ringwald /* @param suported_features 320*3deb3ec6SMatthias Ringwald * HF bit 0: EC and/or NR function (yes/no, 1 = yes, 0 = no) 321*3deb3ec6SMatthias Ringwald * HF bit 1: Call waiting or three-way calling(yes/no, 1 = yes, 0 = no) 322*3deb3ec6SMatthias Ringwald * HF bit 2: CLI presentation capability (yes/no, 1 = yes, 0 = no) 323*3deb3ec6SMatthias Ringwald * HF bit 3: Voice recognition activation (yes/no, 1= yes, 0 = no) 324*3deb3ec6SMatthias Ringwald * HF bit 4: Remote volume control (yes/no, 1 = yes, 0 = no) 325*3deb3ec6SMatthias Ringwald * HF bit 5: Wide band speech (yes/no, 1 = yes, 0 = no) 326*3deb3ec6SMatthias Ringwald */ 327*3deb3ec6SMatthias Ringwald /* Bit position: 328*3deb3ec6SMatthias Ringwald * AG bit 0: Three-way calling (yes/no, 1 = yes, 0 = no) 329*3deb3ec6SMatthias Ringwald * AG bit 1: EC and/or NR function (yes/no, 1 = yes, 0 = no) 330*3deb3ec6SMatthias Ringwald * AG bit 2: Voice recognition function (yes/no, 1 = yes, 0 = no) 331*3deb3ec6SMatthias Ringwald * AG bit 3: In-band ring tone capability (yes/no, 1 = yes, 0 = no) 332*3deb3ec6SMatthias Ringwald * AG bit 4: Attach a phone number to a voice tag (yes/no, 1 = yes, 0 = no) 333*3deb3ec6SMatthias Ringwald * AG bit 5: Wide band speech (yes/no, 1 = yes, 0 = no) 334*3deb3ec6SMatthias Ringwald */ 335*3deb3ec6SMatthias Ringwald 336*3deb3ec6SMatthias Ringwald 337*3deb3ec6SMatthias Ringwald void hfp_create_sdp_record(uint8_t * service, uint16_t service_uuid, int rfcomm_channel_nr, const char * name, uint16_t supported_features){ 338*3deb3ec6SMatthias Ringwald uint8_t* attribute; 339*3deb3ec6SMatthias Ringwald de_create_sequence(service); 340*3deb3ec6SMatthias Ringwald 341*3deb3ec6SMatthias Ringwald // 0x0000 "Service Record Handle" 342*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); 343*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001); 344*3deb3ec6SMatthias Ringwald 345*3deb3ec6SMatthias Ringwald // 0x0001 "Service Class ID List" 346*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); 347*3deb3ec6SMatthias Ringwald attribute = de_push_sequence(service); 348*3deb3ec6SMatthias Ringwald { 349*3deb3ec6SMatthias Ringwald // "UUID for Service" 350*3deb3ec6SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, service_uuid); 351*3deb3ec6SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_GenericAudio); 352*3deb3ec6SMatthias Ringwald } 353*3deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute); 354*3deb3ec6SMatthias Ringwald 355*3deb3ec6SMatthias Ringwald // 0x0004 "Protocol Descriptor List" 356*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList); 357*3deb3ec6SMatthias Ringwald attribute = de_push_sequence(service); 358*3deb3ec6SMatthias Ringwald { 359*3deb3ec6SMatthias Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute); 360*3deb3ec6SMatthias Ringwald { 361*3deb3ec6SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol); 362*3deb3ec6SMatthias Ringwald } 363*3deb3ec6SMatthias Ringwald de_pop_sequence(attribute, l2cpProtocol); 364*3deb3ec6SMatthias Ringwald 365*3deb3ec6SMatthias Ringwald uint8_t* rfcomm = de_push_sequence(attribute); 366*3deb3ec6SMatthias Ringwald { 367*3deb3ec6SMatthias Ringwald de_add_number(rfcomm, DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol); // rfcomm_service 368*3deb3ec6SMatthias Ringwald de_add_number(rfcomm, DE_UINT, DE_SIZE_8, rfcomm_channel_nr); // rfcomm channel 369*3deb3ec6SMatthias Ringwald } 370*3deb3ec6SMatthias Ringwald de_pop_sequence(attribute, rfcomm); 371*3deb3ec6SMatthias Ringwald } 372*3deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute); 373*3deb3ec6SMatthias Ringwald 374*3deb3ec6SMatthias Ringwald 375*3deb3ec6SMatthias Ringwald // 0x0005 "Public Browse Group" 376*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group 377*3deb3ec6SMatthias Ringwald attribute = de_push_sequence(service); 378*3deb3ec6SMatthias Ringwald { 379*3deb3ec6SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup); 380*3deb3ec6SMatthias Ringwald } 381*3deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute); 382*3deb3ec6SMatthias Ringwald 383*3deb3ec6SMatthias Ringwald // 0x0009 "Bluetooth Profile Descriptor List" 384*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList); 385*3deb3ec6SMatthias Ringwald attribute = de_push_sequence(service); 386*3deb3ec6SMatthias Ringwald { 387*3deb3ec6SMatthias Ringwald uint8_t *sppProfile = de_push_sequence(attribute); 388*3deb3ec6SMatthias Ringwald { 389*3deb3ec6SMatthias Ringwald de_add_number(sppProfile, DE_UUID, DE_SIZE_16, SDP_Handsfree); 390*3deb3ec6SMatthias Ringwald de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0107); // Verision 1.7 391*3deb3ec6SMatthias Ringwald } 392*3deb3ec6SMatthias Ringwald de_pop_sequence(attribute, sppProfile); 393*3deb3ec6SMatthias Ringwald } 394*3deb3ec6SMatthias Ringwald de_pop_sequence(service, attribute); 395*3deb3ec6SMatthias Ringwald 396*3deb3ec6SMatthias Ringwald // 0x0100 "Service Name" 397*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 398*3deb3ec6SMatthias Ringwald de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name); 399*3deb3ec6SMatthias Ringwald 400*3deb3ec6SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 401*3deb3ec6SMatthias Ringwald } 402*3deb3ec6SMatthias Ringwald 403*3deb3ec6SMatthias Ringwald static hfp_connection_t * connection_doing_sdp_query = NULL; 404*3deb3ec6SMatthias Ringwald static void handle_query_rfcomm_event(sdp_query_event_t * event, void * context){ 405*3deb3ec6SMatthias Ringwald sdp_query_rfcomm_service_event_t * ve; 406*3deb3ec6SMatthias Ringwald sdp_query_complete_event_t * ce; 407*3deb3ec6SMatthias Ringwald hfp_connection_t * connection = connection_doing_sdp_query; 408*3deb3ec6SMatthias Ringwald 409*3deb3ec6SMatthias Ringwald if ( connection->state != HFP_W4_SDP_QUERY_COMPLETE) return; 410*3deb3ec6SMatthias Ringwald 411*3deb3ec6SMatthias Ringwald switch (event->type){ 412*3deb3ec6SMatthias Ringwald case SDP_QUERY_RFCOMM_SERVICE: 413*3deb3ec6SMatthias Ringwald ve = (sdp_query_rfcomm_service_event_t*) event; 414*3deb3ec6SMatthias Ringwald if (!connection) { 415*3deb3ec6SMatthias Ringwald log_error("handle_query_rfcomm_event alloc connection for RFCOMM port %u failed", ve->channel_nr); 416*3deb3ec6SMatthias Ringwald return; 417*3deb3ec6SMatthias Ringwald } 418*3deb3ec6SMatthias Ringwald connection->rfcomm_channel_nr = ve->channel_nr; 419*3deb3ec6SMatthias Ringwald break; 420*3deb3ec6SMatthias Ringwald case SDP_QUERY_COMPLETE: 421*3deb3ec6SMatthias Ringwald connection_doing_sdp_query = NULL; 422*3deb3ec6SMatthias Ringwald ce = (sdp_query_complete_event_t*) event; 423*3deb3ec6SMatthias Ringwald 424*3deb3ec6SMatthias Ringwald if (connection->rfcomm_channel_nr > 0){ 425*3deb3ec6SMatthias Ringwald connection->state = HFP_W4_RFCOMM_CONNECTED; 426*3deb3ec6SMatthias Ringwald log_info("HFP: SDP_QUERY_COMPLETE context %p, addr %s, state %d", connection, bd_addr_to_str( connection->remote_addr), connection->state); 427*3deb3ec6SMatthias Ringwald rfcomm_create_channel_internal(NULL, connection->remote_addr, connection->rfcomm_channel_nr); 428*3deb3ec6SMatthias Ringwald break; 429*3deb3ec6SMatthias Ringwald } 430*3deb3ec6SMatthias Ringwald log_info("rfcomm service not found, status %u.", ce->status); 431*3deb3ec6SMatthias Ringwald break; 432*3deb3ec6SMatthias Ringwald default: 433*3deb3ec6SMatthias Ringwald break; 434*3deb3ec6SMatthias Ringwald } 435*3deb3ec6SMatthias Ringwald } 436*3deb3ec6SMatthias Ringwald 437*3deb3ec6SMatthias Ringwald void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t *packet, uint16_t size){ 438*3deb3ec6SMatthias Ringwald bd_addr_t event_addr; 439*3deb3ec6SMatthias Ringwald uint16_t rfcomm_cid, handle; 440*3deb3ec6SMatthias Ringwald hfp_connection_t * context = NULL; 441*3deb3ec6SMatthias Ringwald 442*3deb3ec6SMatthias Ringwald switch (packet[0]) { 443*3deb3ec6SMatthias Ringwald case BTSTACK_EVENT_STATE: 444*3deb3ec6SMatthias Ringwald // bt stack activated, get started 445*3deb3ec6SMatthias Ringwald if (packet[2] == HCI_STATE_WORKING){ 446*3deb3ec6SMatthias Ringwald printf("BTstack activated, get started .\n"); 447*3deb3ec6SMatthias Ringwald } 448*3deb3ec6SMatthias Ringwald break; 449*3deb3ec6SMatthias Ringwald 450*3deb3ec6SMatthias Ringwald case HCI_EVENT_PIN_CODE_REQUEST: 451*3deb3ec6SMatthias Ringwald // inform about pin code request 452*3deb3ec6SMatthias Ringwald printf("Pin code request - using '0000'\n\r"); 453*3deb3ec6SMatthias Ringwald bt_flip_addr(event_addr, &packet[2]); 454*3deb3ec6SMatthias Ringwald hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000"); 455*3deb3ec6SMatthias Ringwald break; 456*3deb3ec6SMatthias Ringwald 457*3deb3ec6SMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION: 458*3deb3ec6SMatthias Ringwald // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) 459*3deb3ec6SMatthias Ringwald bt_flip_addr(event_addr, &packet[2]); 460*3deb3ec6SMatthias Ringwald context = get_hfp_connection_context_for_bd_addr(event_addr); 461*3deb3ec6SMatthias Ringwald 462*3deb3ec6SMatthias Ringwald if (!context || context->state != HFP_IDLE) return; 463*3deb3ec6SMatthias Ringwald 464*3deb3ec6SMatthias Ringwald context->rfcomm_cid = READ_BT_16(packet, 9); 465*3deb3ec6SMatthias Ringwald context->state = HFP_W4_RFCOMM_CONNECTED; 466*3deb3ec6SMatthias Ringwald printf("RFCOMM channel %u requested for %s\n", context->rfcomm_cid, bd_addr_to_str(context->remote_addr)); 467*3deb3ec6SMatthias Ringwald rfcomm_accept_connection_internal(context->rfcomm_cid); 468*3deb3ec6SMatthias Ringwald break; 469*3deb3ec6SMatthias Ringwald 470*3deb3ec6SMatthias Ringwald case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE: 471*3deb3ec6SMatthias Ringwald // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16) 472*3deb3ec6SMatthias Ringwald printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]); 473*3deb3ec6SMatthias Ringwald bt_flip_addr(event_addr, &packet[3]); 474*3deb3ec6SMatthias Ringwald context = get_hfp_connection_context_for_bd_addr(event_addr); 475*3deb3ec6SMatthias Ringwald if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return; 476*3deb3ec6SMatthias Ringwald 477*3deb3ec6SMatthias Ringwald if (packet[2]) { 478*3deb3ec6SMatthias Ringwald hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, packet[2]); 479*3deb3ec6SMatthias Ringwald remove_hfp_connection_context(context); 480*3deb3ec6SMatthias Ringwald } else { 481*3deb3ec6SMatthias Ringwald context->con_handle = READ_BT_16(packet, 9); 482*3deb3ec6SMatthias Ringwald context->rfcomm_cid = READ_BT_16(packet, 12); 483*3deb3ec6SMatthias Ringwald uint16_t mtu = READ_BT_16(packet, 14); 484*3deb3ec6SMatthias Ringwald printf("RFCOMM channel open succeeded. Context %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", context, context->rfcomm_cid, mtu); 485*3deb3ec6SMatthias Ringwald 486*3deb3ec6SMatthias Ringwald switch (context->state){ 487*3deb3ec6SMatthias Ringwald case HFP_W4_RFCOMM_CONNECTED: 488*3deb3ec6SMatthias Ringwald context->state = HFP_EXCHANGE_SUPPORTED_FEATURES; 489*3deb3ec6SMatthias Ringwald break; 490*3deb3ec6SMatthias Ringwald case HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN: 491*3deb3ec6SMatthias Ringwald context->state = HFP_W2_DISCONNECT_RFCOMM; 492*3deb3ec6SMatthias Ringwald printf("Shutting down RFCOMM.\n"); 493*3deb3ec6SMatthias Ringwald break; 494*3deb3ec6SMatthias Ringwald default: 495*3deb3ec6SMatthias Ringwald break; 496*3deb3ec6SMatthias Ringwald } 497*3deb3ec6SMatthias Ringwald } 498*3deb3ec6SMatthias Ringwald break; 499*3deb3ec6SMatthias Ringwald 500*3deb3ec6SMatthias Ringwald case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ 501*3deb3ec6SMatthias Ringwald int index = 2; 502*3deb3ec6SMatthias Ringwald uint8_t status = packet[index++]; 503*3deb3ec6SMatthias Ringwald uint16_t sco_handle = READ_BT_16(packet, index); 504*3deb3ec6SMatthias Ringwald index+=2; 505*3deb3ec6SMatthias Ringwald bd_addr_t address; 506*3deb3ec6SMatthias Ringwald memcpy(address, &packet[index], 6); 507*3deb3ec6SMatthias Ringwald index+=6; 508*3deb3ec6SMatthias Ringwald uint8_t link_type = packet[index++]; 509*3deb3ec6SMatthias Ringwald uint8_t transmission_interval = packet[index++]; // measured in slots 510*3deb3ec6SMatthias Ringwald uint8_t retransmission_interval = packet[index++];// measured in slots 511*3deb3ec6SMatthias Ringwald uint16_t rx_packet_length = READ_BT_16(packet, index); // measured in bytes 512*3deb3ec6SMatthias Ringwald index+=2; 513*3deb3ec6SMatthias Ringwald uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes 514*3deb3ec6SMatthias Ringwald index+=2; 515*3deb3ec6SMatthias Ringwald uint8_t air_mode = packet[index]; 516*3deb3ec6SMatthias Ringwald 517*3deb3ec6SMatthias Ringwald if (status != 0){ 518*3deb3ec6SMatthias Ringwald log_error("(e)SCO Connection is not established, status %u", status); 519*3deb3ec6SMatthias Ringwald break; 520*3deb3ec6SMatthias Ringwald } 521*3deb3ec6SMatthias Ringwald switch (link_type){ 522*3deb3ec6SMatthias Ringwald case 0x00: 523*3deb3ec6SMatthias Ringwald printf("SCO Connection established. \n"); 524*3deb3ec6SMatthias Ringwald if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval); 525*3deb3ec6SMatthias Ringwald if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval); 526*3deb3ec6SMatthias Ringwald if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length); 527*3deb3ec6SMatthias Ringwald if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length); 528*3deb3ec6SMatthias Ringwald break; 529*3deb3ec6SMatthias Ringwald case 0x02: 530*3deb3ec6SMatthias Ringwald printf("eSCO Connection established. \n"); 531*3deb3ec6SMatthias Ringwald break; 532*3deb3ec6SMatthias Ringwald default: 533*3deb3ec6SMatthias Ringwald log_error("(e)SCO reserved link_type 0x%2x", link_type); 534*3deb3ec6SMatthias Ringwald break; 535*3deb3ec6SMatthias Ringwald } 536*3deb3ec6SMatthias Ringwald log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, " 537*3deb3ec6SMatthias Ringwald " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle, 538*3deb3ec6SMatthias Ringwald bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); 539*3deb3ec6SMatthias Ringwald 540*3deb3ec6SMatthias Ringwald context = get_hfp_connection_context_for_bd_addr(address); 541*3deb3ec6SMatthias Ringwald 542*3deb3ec6SMatthias Ringwald if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){ 543*3deb3ec6SMatthias Ringwald context->state = HFP_W2_DISCONNECT_SCO; 544*3deb3ec6SMatthias Ringwald break; 545*3deb3ec6SMatthias Ringwald } 546*3deb3ec6SMatthias Ringwald 547*3deb3ec6SMatthias Ringwald context->sco_handle = sco_handle; 548*3deb3ec6SMatthias Ringwald context->state = HFP_AUDIO_CONNECTION_ESTABLISHED; 549*3deb3ec6SMatthias Ringwald hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]); 550*3deb3ec6SMatthias Ringwald break; 551*3deb3ec6SMatthias Ringwald } 552*3deb3ec6SMatthias Ringwald 553*3deb3ec6SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED: 554*3deb3ec6SMatthias Ringwald rfcomm_cid = READ_BT_16(packet,2); 555*3deb3ec6SMatthias Ringwald context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid); 556*3deb3ec6SMatthias Ringwald if (!context) break; 557*3deb3ec6SMatthias Ringwald if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){ 558*3deb3ec6SMatthias Ringwald context->state = HFP_IDLE; 559*3deb3ec6SMatthias Ringwald hfp_establish_service_level_connection(context->remote_addr, context->service_uuid); 560*3deb3ec6SMatthias Ringwald break; 561*3deb3ec6SMatthias Ringwald } 562*3deb3ec6SMatthias Ringwald 563*3deb3ec6SMatthias Ringwald hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0); 564*3deb3ec6SMatthias Ringwald remove_hfp_connection_context(context); 565*3deb3ec6SMatthias Ringwald break; 566*3deb3ec6SMatthias Ringwald 567*3deb3ec6SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 568*3deb3ec6SMatthias Ringwald handle = READ_BT_16(packet,3); 569*3deb3ec6SMatthias Ringwald context = get_hfp_connection_context_for_handle(handle); 570*3deb3ec6SMatthias Ringwald if (!context) break; 571*3deb3ec6SMatthias Ringwald if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){ 572*3deb3ec6SMatthias Ringwald context->state = HFP_IDLE; 573*3deb3ec6SMatthias Ringwald hfp_establish_service_level_connection(context->remote_addr, context->service_uuid); 574*3deb3ec6SMatthias Ringwald break; 575*3deb3ec6SMatthias Ringwald } 576*3deb3ec6SMatthias Ringwald hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]); 577*3deb3ec6SMatthias Ringwald remove_hfp_connection_context(context); 578*3deb3ec6SMatthias Ringwald break; 579*3deb3ec6SMatthias Ringwald 580*3deb3ec6SMatthias Ringwald default: 581*3deb3ec6SMatthias Ringwald break; 582*3deb3ec6SMatthias Ringwald } 583*3deb3ec6SMatthias Ringwald } 584*3deb3ec6SMatthias Ringwald 585*3deb3ec6SMatthias Ringwald // translates command string into hfp_command_t CMD and flags to distinguish between CMD=, CMD?, CMD=? 586*3deb3ec6SMatthias Ringwald static void process_command(hfp_connection_t * context){ 587*3deb3ec6SMatthias Ringwald if (context->line_size < 2) return; 588*3deb3ec6SMatthias Ringwald // printf("process_command %s\n", context->line_buffer); 589*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 590*3deb3ec6SMatthias Ringwald int offset = 0; 591*3deb3ec6SMatthias Ringwald int isHandsFree = 1; 592*3deb3ec6SMatthias Ringwald 593*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer, "AT", 2) == 0){ 594*3deb3ec6SMatthias Ringwald offset = 2; 595*3deb3ec6SMatthias Ringwald isHandsFree = 0; 596*3deb3ec6SMatthias Ringwald } 597*3deb3ec6SMatthias Ringwald 598*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){ 599*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_ERROR; 600*3deb3ec6SMatthias Ringwald return; 601*3deb3ec6SMatthias Ringwald } 602*3deb3ec6SMatthias Ringwald 603*3deb3ec6SMatthias Ringwald if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_OK, strlen(HFP_OK)) == 0){ 604*3deb3ec6SMatthias Ringwald //printf("parsed HFP_CMD_OK \n"); 605*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_OK; 606*3deb3ec6SMatthias Ringwald return; 607*3deb3ec6SMatthias Ringwald } 608*3deb3ec6SMatthias Ringwald 609*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORTED_FEATURES, strlen(HFP_SUPPORTED_FEATURES)) == 0){ 610*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_SUPPORTED_FEATURES; 611*3deb3ec6SMatthias Ringwald return; 612*3deb3ec6SMatthias Ringwald } 613*3deb3ec6SMatthias Ringwald 614*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_INDICATOR, strlen(HFP_INDICATOR)) == 0){ 615*3deb3ec6SMatthias Ringwald //printf("parsed HFP_INDICATOR \n"); 616*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_INDICATOR; 617*3deb3ec6SMatthias Ringwald if (isHandsFree) return; 618*3deb3ec6SMatthias Ringwald 619*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+strlen(HFP_INDICATOR)+offset, "?", 1) == 0){ 620*3deb3ec6SMatthias Ringwald context->retrieve_ag_indicators_status = 1; 621*3deb3ec6SMatthias Ringwald context->retrieve_ag_indicators = 0; 622*3deb3ec6SMatthias Ringwald } else { 623*3deb3ec6SMatthias Ringwald context->retrieve_ag_indicators = 1; 624*3deb3ec6SMatthias Ringwald context->retrieve_ag_indicators_status = 0; 625*3deb3ec6SMatthias Ringwald } 626*3deb3ec6SMatthias Ringwald return; 627*3deb3ec6SMatthias Ringwald } 628*3deb3ec6SMatthias Ringwald 629*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_AVAILABLE_CODECS, strlen(HFP_AVAILABLE_CODECS)) == 0){ 630*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_AVAILABLE_CODECS; 631*3deb3ec6SMatthias Ringwald context->notify_ag_on_new_codecs = 1; 632*3deb3ec6SMatthias Ringwald return; 633*3deb3ec6SMatthias Ringwald } 634*3deb3ec6SMatthias Ringwald 635*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, strlen(HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS)) == 0){ 636*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE; 637*3deb3ec6SMatthias Ringwald return; 638*3deb3ec6SMatthias Ringwald } 639*3deb3ec6SMatthias Ringwald 640*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES, strlen(HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES)) == 0){ 641*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES; 642*3deb3ec6SMatthias Ringwald return; 643*3deb3ec6SMatthias Ringwald } 644*3deb3ec6SMatthias Ringwald 645*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_GENERIC_STATUS_INDICATOR, strlen(HFP_GENERIC_STATUS_INDICATOR)) == 0){ 646*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_GENERIC_STATUS_INDICATOR; 647*3deb3ec6SMatthias Ringwald if (isHandsFree) return; 648*3deb3ec6SMatthias Ringwald 649*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=?", 2) == 0){ 650*3deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 0; 651*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 1; 652*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 0; 653*3deb3ec6SMatthias Ringwald } else if (strncmp((char *)context->line_buffer+strlen(HFP_GENERIC_STATUS_INDICATOR)+offset, "=", 1) == 0){ 654*3deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 1; 655*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; 656*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 0; 657*3deb3ec6SMatthias Ringwald } else { 658*3deb3ec6SMatthias Ringwald context->list_generic_status_indicators = 0; 659*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators = 0; 660*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state = 1; 661*3deb3ec6SMatthias Ringwald } 662*3deb3ec6SMatthias Ringwald return; 663*3deb3ec6SMatthias Ringwald } 664*3deb3ec6SMatthias Ringwald 665*3deb3ec6SMatthias 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){ 666*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE; 667*3deb3ec6SMatthias Ringwald return; 668*3deb3ec6SMatthias Ringwald } 669*3deb3ec6SMatthias Ringwald 670*3deb3ec6SMatthias Ringwald 671*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_QUERY_OPERATOR_SELECTION, strlen(HFP_QUERY_OPERATOR_SELECTION)) == 0){ 672*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_QUERY_OPERATOR_SELECTION; 673*3deb3ec6SMatthias Ringwald context->operator_name = 1; 674*3deb3ec6SMatthias Ringwald context->operator_name_format = 0; 675*3deb3ec6SMatthias Ringwald if (isHandsFree) return; 676*3deb3ec6SMatthias Ringwald 677*3deb3ec6SMatthias Ringwald context->operator_name = 0; 678*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+strlen(HFP_QUERY_OPERATOR_SELECTION)+offset, "=", 1) == 0){ 679*3deb3ec6SMatthias Ringwald context->operator_name_format = 1; 680*3deb3ec6SMatthias Ringwald } 681*3deb3ec6SMatthias Ringwald return; 682*3deb3ec6SMatthias Ringwald } 683*3deb3ec6SMatthias Ringwald 684*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_TRANSFER_AG_INDICATOR_STATUS, strlen(HFP_TRANSFER_AG_INDICATOR_STATUS)) == 0){ 685*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_TRANSFER_AG_INDICATOR_STATUS; 686*3deb3ec6SMatthias Ringwald return; 687*3deb3ec6SMatthias Ringwald } 688*3deb3ec6SMatthias Ringwald 689*3deb3ec6SMatthias Ringwald if (isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){ 690*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR; 691*3deb3ec6SMatthias Ringwald return; 692*3deb3ec6SMatthias Ringwald } 693*3deb3ec6SMatthias Ringwald 694*3deb3ec6SMatthias Ringwald if (!isHandsFree && strncmp((char *)context->line_buffer+offset, HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, strlen(HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR)) == 0){ 695*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR; 696*3deb3ec6SMatthias Ringwald return; 697*3deb3ec6SMatthias Ringwald } 698*3deb3ec6SMatthias Ringwald 699*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){ 700*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP; 701*3deb3ec6SMatthias Ringwald // printf("HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP update command\n"); 702*3deb3ec6SMatthias Ringwald if (isHandsFree){ 703*3deb3ec6SMatthias Ringwald context->hf_trigger_codec_connection_setup = 1; 704*3deb3ec6SMatthias Ringwald printf("update command: hf_trigger_codec_connection_setup = 1\n"); 705*3deb3ec6SMatthias Ringwald } else { 706*3deb3ec6SMatthias Ringwald context->hf_trigger_codec_connection_setup = 1; 707*3deb3ec6SMatthias Ringwald printf("update command: hf_trigger_codec_connection_setup = 1\n"); 708*3deb3ec6SMatthias Ringwald } 709*3deb3ec6SMatthias Ringwald return; 710*3deb3ec6SMatthias Ringwald } 711*3deb3ec6SMatthias Ringwald 712*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){ 713*3deb3ec6SMatthias Ringwald if (!isHandsFree){ 714*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_HF_CONFIRMED_CODEC; 715*3deb3ec6SMatthias Ringwald } else { 716*3deb3ec6SMatthias Ringwald context->command = HFP_CMD_AG_SUGGESTED_CODEC; 717*3deb3ec6SMatthias Ringwald } 718*3deb3ec6SMatthias Ringwald return; 719*3deb3ec6SMatthias Ringwald } 720*3deb3ec6SMatthias Ringwald 721*3deb3ec6SMatthias Ringwald if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0) return; 722*3deb3ec6SMatthias Ringwald 723*3deb3ec6SMatthias Ringwald printf(" process unknown command 3 %s \n", context->line_buffer); 724*3deb3ec6SMatthias Ringwald } 725*3deb3ec6SMatthias Ringwald 726*3deb3ec6SMatthias Ringwald #if 0 727*3deb3ec6SMatthias Ringwald uint32_t fromBinary(char *s) { 728*3deb3ec6SMatthias Ringwald return (uint32_t) strtol(s, NULL, 2); 729*3deb3ec6SMatthias Ringwald } 730*3deb3ec6SMatthias Ringwald #endif 731*3deb3ec6SMatthias Ringwald 732*3deb3ec6SMatthias Ringwald static void hfp_parser_store_byte(hfp_connection_t * context, uint8_t byte){ 733*3deb3ec6SMatthias Ringwald // TODO: add limit 734*3deb3ec6SMatthias Ringwald context->line_buffer[context->line_size++] = byte; 735*3deb3ec6SMatthias Ringwald context->line_buffer[context->line_size] = 0; 736*3deb3ec6SMatthias Ringwald } 737*3deb3ec6SMatthias Ringwald static int hfp_parser_is_buffer_empty(hfp_connection_t * context){ 738*3deb3ec6SMatthias Ringwald return context->line_size == 0; 739*3deb3ec6SMatthias Ringwald } 740*3deb3ec6SMatthias Ringwald 741*3deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_line(uint8_t byte){ 742*3deb3ec6SMatthias Ringwald return byte == '\n' || byte == '\r'; 743*3deb3ec6SMatthias Ringwald } 744*3deb3ec6SMatthias Ringwald 745*3deb3ec6SMatthias Ringwald static int hfp_parser_is_end_of_header(uint8_t byte){ 746*3deb3ec6SMatthias Ringwald return hfp_parser_is_end_of_line(byte) || byte == ':' || byte == '?'; 747*3deb3ec6SMatthias Ringwald } 748*3deb3ec6SMatthias Ringwald 749*3deb3ec6SMatthias Ringwald static int hfp_parser_found_separator(hfp_connection_t * context, uint8_t byte){ 750*3deb3ec6SMatthias Ringwald if (context->keep_separator == 1) return 1; 751*3deb3ec6SMatthias Ringwald 752*3deb3ec6SMatthias Ringwald int found_separator = byte == ',' || byte == '\n'|| byte == '\r'|| 753*3deb3ec6SMatthias Ringwald byte == ')' || byte == '(' || byte == ':' || 754*3deb3ec6SMatthias Ringwald byte == '-' || byte == '"' || byte == '?'|| byte == '='; 755*3deb3ec6SMatthias Ringwald return found_separator; 756*3deb3ec6SMatthias Ringwald } 757*3deb3ec6SMatthias Ringwald 758*3deb3ec6SMatthias Ringwald static void hfp_parser_next_state(hfp_connection_t * context, uint8_t byte){ 759*3deb3ec6SMatthias Ringwald context->line_size = 0; 760*3deb3ec6SMatthias Ringwald if (hfp_parser_is_end_of_line(byte)){ 761*3deb3ec6SMatthias Ringwald context->parser_item_index = 0; 762*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_CMD_HEADER; 763*3deb3ec6SMatthias Ringwald return; 764*3deb3ec6SMatthias Ringwald } 765*3deb3ec6SMatthias Ringwald switch (context->parser_state){ 766*3deb3ec6SMatthias Ringwald case HFP_PARSER_CMD_HEADER: 767*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_CMD_SEQUENCE; 768*3deb3ec6SMatthias Ringwald if (context->keep_separator == 1){ 769*3deb3ec6SMatthias Ringwald hfp_parser_store_byte(context, byte); 770*3deb3ec6SMatthias Ringwald context->keep_separator = 0; 771*3deb3ec6SMatthias Ringwald } 772*3deb3ec6SMatthias Ringwald break; 773*3deb3ec6SMatthias Ringwald case HFP_PARSER_CMD_SEQUENCE: 774*3deb3ec6SMatthias Ringwald switch (context->command){ 775*3deb3ec6SMatthias Ringwald case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: 776*3deb3ec6SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION: 777*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_SECOND_ITEM; 778*3deb3ec6SMatthias Ringwald break; 779*3deb3ec6SMatthias Ringwald case HFP_CMD_INDICATOR: 780*3deb3ec6SMatthias Ringwald if (context->retrieve_ag_indicators == 1){ 781*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_SECOND_ITEM; 782*3deb3ec6SMatthias Ringwald break; 783*3deb3ec6SMatthias Ringwald } 784*3deb3ec6SMatthias Ringwald break; 785*3deb3ec6SMatthias Ringwald case HFP_CMD_GENERIC_STATUS_INDICATOR: 786*3deb3ec6SMatthias Ringwald if (context->retrieve_generic_status_indicators_state == 1){ 787*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_SECOND_ITEM; 788*3deb3ec6SMatthias Ringwald break; 789*3deb3ec6SMatthias Ringwald } 790*3deb3ec6SMatthias Ringwald break; 791*3deb3ec6SMatthias Ringwald default: 792*3deb3ec6SMatthias Ringwald break; 793*3deb3ec6SMatthias Ringwald } 794*3deb3ec6SMatthias Ringwald break; 795*3deb3ec6SMatthias Ringwald case HFP_PARSER_SECOND_ITEM: 796*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_THIRD_ITEM; 797*3deb3ec6SMatthias Ringwald break; 798*3deb3ec6SMatthias Ringwald case HFP_PARSER_THIRD_ITEM: 799*3deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_INDICATOR && context->retrieve_ag_indicators){ 800*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_CMD_SEQUENCE; 801*3deb3ec6SMatthias Ringwald break; 802*3deb3ec6SMatthias Ringwald } 803*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_CMD_HEADER; 804*3deb3ec6SMatthias Ringwald break; 805*3deb3ec6SMatthias Ringwald } 806*3deb3ec6SMatthias Ringwald } 807*3deb3ec6SMatthias Ringwald 808*3deb3ec6SMatthias Ringwald void hfp_parse(hfp_connection_t * context, uint8_t byte){ 809*3deb3ec6SMatthias Ringwald int value; 810*3deb3ec6SMatthias Ringwald 811*3deb3ec6SMatthias Ringwald // TODO: handle space inside word 812*3deb3ec6SMatthias Ringwald if (byte == ' ' && context->parser_state > HFP_PARSER_CMD_HEADER) return; 813*3deb3ec6SMatthias Ringwald 814*3deb3ec6SMatthias Ringwald if (!hfp_parser_found_separator(context, byte)){ 815*3deb3ec6SMatthias Ringwald hfp_parser_store_byte(context, byte); 816*3deb3ec6SMatthias Ringwald return; 817*3deb3ec6SMatthias Ringwald } 818*3deb3ec6SMatthias Ringwald if (hfp_parser_is_end_of_line(byte)) { 819*3deb3ec6SMatthias Ringwald if (hfp_parser_is_buffer_empty(context)){ 820*3deb3ec6SMatthias Ringwald context->parser_state = HFP_PARSER_CMD_HEADER; 821*3deb3ec6SMatthias Ringwald } 822*3deb3ec6SMatthias Ringwald } 823*3deb3ec6SMatthias Ringwald if (hfp_parser_is_buffer_empty(context)) return; 824*3deb3ec6SMatthias Ringwald 825*3deb3ec6SMatthias Ringwald 826*3deb3ec6SMatthias Ringwald switch (context->parser_state){ 827*3deb3ec6SMatthias Ringwald case HFP_PARSER_CMD_HEADER: // header 828*3deb3ec6SMatthias Ringwald if (byte == '='){ 829*3deb3ec6SMatthias Ringwald context->keep_separator = 1; 830*3deb3ec6SMatthias Ringwald hfp_parser_store_byte(context, byte); 831*3deb3ec6SMatthias Ringwald return; 832*3deb3ec6SMatthias Ringwald } 833*3deb3ec6SMatthias Ringwald 834*3deb3ec6SMatthias Ringwald if (byte == '?'){ 835*3deb3ec6SMatthias Ringwald context->keep_separator = 0; 836*3deb3ec6SMatthias Ringwald hfp_parser_store_byte(context, byte); 837*3deb3ec6SMatthias Ringwald return; 838*3deb3ec6SMatthias Ringwald } 839*3deb3ec6SMatthias Ringwald // printf(" parse header 2 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator); 840*3deb3ec6SMatthias Ringwald if (hfp_parser_is_end_of_header(byte) || context->keep_separator == 1){ 841*3deb3ec6SMatthias Ringwald // printf(" parse header 3 %s, keep separator $ %d\n", context->line_buffer, context->keep_separator); 842*3deb3ec6SMatthias Ringwald process_command(context); 843*3deb3ec6SMatthias Ringwald } 844*3deb3ec6SMatthias Ringwald break; 845*3deb3ec6SMatthias Ringwald 846*3deb3ec6SMatthias Ringwald case HFP_PARSER_CMD_SEQUENCE: // parse comma separated sequence, ignore breacktes 847*3deb3ec6SMatthias Ringwald switch (context->command){ 848*3deb3ec6SMatthias Ringwald case HFP_CMD_HF_CONFIRMED_CODEC: 849*3deb3ec6SMatthias Ringwald context->codec_confirmed = atoi((char*)context->line_buffer); 850*3deb3ec6SMatthias Ringwald log_info("hfp parse HFP_CMD_HF_CONFIRMED_CODEC %d\n", context->codec_confirmed); 851*3deb3ec6SMatthias Ringwald break; 852*3deb3ec6SMatthias Ringwald case HFP_CMD_AG_SUGGESTED_CODEC: 853*3deb3ec6SMatthias Ringwald context->suggested_codec = atoi((char*)context->line_buffer); 854*3deb3ec6SMatthias Ringwald log_info("hfp parse HFP_CMD_AG_SUGGESTED_CODEC %d\n", context->suggested_codec); 855*3deb3ec6SMatthias Ringwald break; 856*3deb3ec6SMatthias Ringwald case HFP_CMD_SUPPORTED_FEATURES: 857*3deb3ec6SMatthias Ringwald context->remote_supported_features = atoi((char*)context->line_buffer); 858*3deb3ec6SMatthias Ringwald log_info("Parsed supported feature %d\n", context->remote_supported_features); 859*3deb3ec6SMatthias Ringwald break; 860*3deb3ec6SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 861*3deb3ec6SMatthias Ringwald log_info("Parsed codec %s\n", context->line_buffer); 862*3deb3ec6SMatthias Ringwald context->remote_codecs[context->parser_item_index] = (uint16_t)atoi((char*)context->line_buffer); 863*3deb3ec6SMatthias Ringwald context->parser_item_index++; 864*3deb3ec6SMatthias Ringwald context->remote_codecs_nr = context->parser_item_index; 865*3deb3ec6SMatthias Ringwald break; 866*3deb3ec6SMatthias Ringwald case HFP_CMD_INDICATOR: 867*3deb3ec6SMatthias Ringwald if (context->retrieve_ag_indicators == 1){ 868*3deb3ec6SMatthias Ringwald strcpy((char *)context->ag_indicators[context->parser_item_index].name, (char *)context->line_buffer); 869*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].index = context->parser_item_index+1; 870*3deb3ec6SMatthias Ringwald log_info("Indicator %d: %s (", context->ag_indicators_nr+1, context->line_buffer); 871*3deb3ec6SMatthias Ringwald } 872*3deb3ec6SMatthias Ringwald 873*3deb3ec6SMatthias Ringwald if (context->retrieve_ag_indicators_status == 1){ 874*3deb3ec6SMatthias Ringwald log_info("Parsed Indicator %d with status: %s\n", context->parser_item_index+1, context->line_buffer); 875*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].status = atoi((char *) context->line_buffer); 876*3deb3ec6SMatthias Ringwald context->parser_item_index++; 877*3deb3ec6SMatthias Ringwald break; 878*3deb3ec6SMatthias Ringwald } 879*3deb3ec6SMatthias Ringwald break; 880*3deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 881*3deb3ec6SMatthias Ringwald context->parser_item_index++; 882*3deb3ec6SMatthias Ringwald if (context->parser_item_index != 4) break; 883*3deb3ec6SMatthias Ringwald log_info("Parsed Enable indicators: %s\n", context->line_buffer); 884*3deb3ec6SMatthias Ringwald value = atoi((char *)&context->line_buffer[0]); 885*3deb3ec6SMatthias Ringwald context->enable_status_update_for_ag_indicators = (uint8_t) value; 886*3deb3ec6SMatthias Ringwald break; 887*3deb3ec6SMatthias Ringwald case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: 888*3deb3ec6SMatthias Ringwald log_info("Parsed Support call hold: %s\n", context->line_buffer); 889*3deb3ec6SMatthias Ringwald if (context->line_size > 2 ) break; 890*3deb3ec6SMatthias Ringwald strcpy((char *)context->remote_call_services[context->remote_call_services_nr].name, (char *)context->line_buffer); 891*3deb3ec6SMatthias Ringwald context->remote_call_services_nr++; 892*3deb3ec6SMatthias Ringwald break; 893*3deb3ec6SMatthias Ringwald case HFP_CMD_GENERIC_STATUS_INDICATOR: 894*3deb3ec6SMatthias Ringwald log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 1 (%d, %d, %d)\n", 895*3deb3ec6SMatthias Ringwald context->list_generic_status_indicators, 896*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators, 897*3deb3ec6SMatthias Ringwald context->retrieve_generic_status_indicators_state); 898*3deb3ec6SMatthias Ringwald if (context->retrieve_generic_status_indicators == 1 || context->list_generic_status_indicators == 1){ 899*3deb3ec6SMatthias Ringwald log_info("Parsed Generic status indicator: %s\n", context->line_buffer); 900*3deb3ec6SMatthias Ringwald context->generic_status_indicators[context->parser_item_index].uuid = (uint16_t)atoi((char*)context->line_buffer); 901*3deb3ec6SMatthias Ringwald context->parser_item_index++; 902*3deb3ec6SMatthias Ringwald context->generic_status_indicators_nr = context->parser_item_index; 903*3deb3ec6SMatthias Ringwald break; 904*3deb3ec6SMatthias Ringwald } 905*3deb3ec6SMatthias Ringwald log_info("parser HFP_CMD_GENERIC_STATUS_INDICATOR 2\n"); 906*3deb3ec6SMatthias Ringwald if (context->retrieve_generic_status_indicators_state == 1){ 907*3deb3ec6SMatthias Ringwald // HF parses inital AG gen. ind. state 908*3deb3ec6SMatthias Ringwald log_info("Parsed List generic status indicator %s state: ", context->line_buffer); 909*3deb3ec6SMatthias Ringwald context->parser_item_index = (uint8_t)atoi((char*)context->line_buffer); 910*3deb3ec6SMatthias Ringwald break; 911*3deb3ec6SMatthias Ringwald } 912*3deb3ec6SMatthias Ringwald break; 913*3deb3ec6SMatthias Ringwald 914*3deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE: 915*3deb3ec6SMatthias Ringwald // AG parses new gen. ind. state 916*3deb3ec6SMatthias Ringwald log_info("Parsed Enable ag indicator state: %s\n", context->line_buffer); 917*3deb3ec6SMatthias Ringwald value = atoi((char *)&context->line_buffer[0]); 918*3deb3ec6SMatthias Ringwald if (!context->ag_indicators[context->parser_item_index].mandatory){ 919*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].enabled = value; 920*3deb3ec6SMatthias Ringwald } 921*3deb3ec6SMatthias Ringwald context->parser_item_index++; 922*3deb3ec6SMatthias Ringwald break; 923*3deb3ec6SMatthias Ringwald case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: 924*3deb3ec6SMatthias Ringwald // indicators are indexed starting with 1 925*3deb3ec6SMatthias Ringwald context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1; 926*3deb3ec6SMatthias Ringwald log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index); 927*3deb3ec6SMatthias Ringwald break; 928*3deb3ec6SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION: 929*3deb3ec6SMatthias Ringwald if (context->operator_name_format == 1){ 930*3deb3ec6SMatthias Ringwald if (context->line_buffer[0] == '3'){ 931*3deb3ec6SMatthias Ringwald log_info("Parsed Set network operator format : %s, ", context->line_buffer); 932*3deb3ec6SMatthias Ringwald break; 933*3deb3ec6SMatthias Ringwald } 934*3deb3ec6SMatthias Ringwald // TODO emit ERROR, wrong format 935*3deb3ec6SMatthias Ringwald log_info("ERROR Set network operator format: index %s not supported\n", context->line_buffer); 936*3deb3ec6SMatthias Ringwald break; 937*3deb3ec6SMatthias Ringwald } 938*3deb3ec6SMatthias Ringwald 939*3deb3ec6SMatthias Ringwald if (context->operator_name == 1) { 940*3deb3ec6SMatthias Ringwald context->network_operator.mode = atoi((char *)&context->line_buffer[0]); 941*3deb3ec6SMatthias Ringwald log_info("Parsed network operator mode: %d, ", context->network_operator.mode); 942*3deb3ec6SMatthias Ringwald break; 943*3deb3ec6SMatthias Ringwald } 944*3deb3ec6SMatthias Ringwald break; 945*3deb3ec6SMatthias Ringwald case HFP_CMD_ERROR: 946*3deb3ec6SMatthias Ringwald break; 947*3deb3ec6SMatthias Ringwald case HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR: 948*3deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = (uint8_t)atoi((char*)context->line_buffer); 949*3deb3ec6SMatthias Ringwald break; 950*3deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR: 951*3deb3ec6SMatthias Ringwald context->enable_extended_audio_gateway_error_report = (uint8_t)atoi((char*)context->line_buffer); 952*3deb3ec6SMatthias Ringwald context->send_ok = 1; 953*3deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = 0; 954*3deb3ec6SMatthias Ringwald break; 955*3deb3ec6SMatthias Ringwald default: 956*3deb3ec6SMatthias Ringwald break; 957*3deb3ec6SMatthias Ringwald } 958*3deb3ec6SMatthias Ringwald break; 959*3deb3ec6SMatthias Ringwald 960*3deb3ec6SMatthias Ringwald case HFP_PARSER_SECOND_ITEM: 961*3deb3ec6SMatthias Ringwald switch (context->command){ 962*3deb3ec6SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION: 963*3deb3ec6SMatthias Ringwald if (context->operator_name_format == 1) { 964*3deb3ec6SMatthias Ringwald log_info("format %s \n", context->line_buffer); 965*3deb3ec6SMatthias Ringwald context->network_operator.format = atoi((char *)&context->line_buffer[0]); 966*3deb3ec6SMatthias Ringwald break; 967*3deb3ec6SMatthias Ringwald } 968*3deb3ec6SMatthias Ringwald if (context->operator_name == 1){ 969*3deb3ec6SMatthias Ringwald log_info("format %s, ", context->line_buffer); 970*3deb3ec6SMatthias Ringwald context->network_operator.format = atoi((char *)&context->line_buffer[0]); 971*3deb3ec6SMatthias Ringwald } 972*3deb3ec6SMatthias Ringwald break; 973*3deb3ec6SMatthias Ringwald case HFP_CMD_GENERIC_STATUS_INDICATOR: 974*3deb3ec6SMatthias Ringwald context->generic_status_indicators[context->parser_item_index].state = (uint8_t)atoi((char*)context->line_buffer); 975*3deb3ec6SMatthias Ringwald break; 976*3deb3ec6SMatthias Ringwald case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS: 977*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].status = (uint8_t)atoi((char*)context->line_buffer); 978*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].status_changed = 1; 979*3deb3ec6SMatthias Ringwald break; 980*3deb3ec6SMatthias Ringwald case HFP_CMD_INDICATOR: 981*3deb3ec6SMatthias Ringwald if (context->retrieve_ag_indicators == 1){ 982*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].min_range = atoi((char *)context->line_buffer); 983*3deb3ec6SMatthias Ringwald log_info("%s, ", context->line_buffer); 984*3deb3ec6SMatthias Ringwald } 985*3deb3ec6SMatthias Ringwald break; 986*3deb3ec6SMatthias Ringwald default: 987*3deb3ec6SMatthias Ringwald break; 988*3deb3ec6SMatthias Ringwald } 989*3deb3ec6SMatthias Ringwald break; 990*3deb3ec6SMatthias Ringwald 991*3deb3ec6SMatthias Ringwald case HFP_PARSER_THIRD_ITEM: 992*3deb3ec6SMatthias Ringwald switch (context->command){ 993*3deb3ec6SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION: 994*3deb3ec6SMatthias Ringwald if (context->operator_name == 1){ 995*3deb3ec6SMatthias Ringwald strcpy(context->network_operator.name, (char *)context->line_buffer); 996*3deb3ec6SMatthias Ringwald log_info("name %s\n", context->line_buffer); 997*3deb3ec6SMatthias Ringwald } 998*3deb3ec6SMatthias Ringwald break; 999*3deb3ec6SMatthias Ringwald case HFP_CMD_INDICATOR: 1000*3deb3ec6SMatthias Ringwald if (context->retrieve_ag_indicators == 1){ 1001*3deb3ec6SMatthias Ringwald context->ag_indicators[context->parser_item_index].max_range = atoi((char *)context->line_buffer); 1002*3deb3ec6SMatthias Ringwald context->parser_item_index++; 1003*3deb3ec6SMatthias Ringwald context->ag_indicators_nr = context->parser_item_index; 1004*3deb3ec6SMatthias Ringwald log_info("%s)\n", context->line_buffer); 1005*3deb3ec6SMatthias Ringwald } 1006*3deb3ec6SMatthias Ringwald break; 1007*3deb3ec6SMatthias Ringwald default: 1008*3deb3ec6SMatthias Ringwald break; 1009*3deb3ec6SMatthias Ringwald } 1010*3deb3ec6SMatthias Ringwald break; 1011*3deb3ec6SMatthias Ringwald } 1012*3deb3ec6SMatthias Ringwald hfp_parser_next_state(context, byte); 1013*3deb3ec6SMatthias Ringwald } 1014*3deb3ec6SMatthias Ringwald 1015*3deb3ec6SMatthias Ringwald void hfp_init(uint16_t rfcomm_channel_nr){ 1016*3deb3ec6SMatthias Ringwald rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 0xffff); 1017*3deb3ec6SMatthias Ringwald sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL); 1018*3deb3ec6SMatthias Ringwald } 1019*3deb3ec6SMatthias Ringwald 1020*3deb3ec6SMatthias Ringwald void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid){ 1021*3deb3ec6SMatthias Ringwald hfp_connection_t * context = provide_hfp_connection_context_for_bd_addr(bd_addr); 1022*3deb3ec6SMatthias Ringwald log_info("hfp_connect %s, context %p", bd_addr_to_str(bd_addr), context); 1023*3deb3ec6SMatthias Ringwald 1024*3deb3ec6SMatthias Ringwald if (!context) { 1025*3deb3ec6SMatthias Ringwald log_error("hfp_establish_service_level_connection for addr %s failed", bd_addr_to_str(bd_addr)); 1026*3deb3ec6SMatthias Ringwald return; 1027*3deb3ec6SMatthias Ringwald } 1028*3deb3ec6SMatthias Ringwald switch (context->state){ 1029*3deb3ec6SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM: 1030*3deb3ec6SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 1031*3deb3ec6SMatthias Ringwald return; 1032*3deb3ec6SMatthias Ringwald case HFP_W4_RFCOMM_DISCONNECTED: 1033*3deb3ec6SMatthias Ringwald context->state = HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART; 1034*3deb3ec6SMatthias Ringwald return; 1035*3deb3ec6SMatthias Ringwald case HFP_IDLE: 1036*3deb3ec6SMatthias Ringwald memcpy(context->remote_addr, bd_addr, 6); 1037*3deb3ec6SMatthias Ringwald context->state = HFP_W4_SDP_QUERY_COMPLETE; 1038*3deb3ec6SMatthias Ringwald connection_doing_sdp_query = context; 1039*3deb3ec6SMatthias Ringwald context->service_uuid = service_uuid; 1040*3deb3ec6SMatthias Ringwald sdp_query_rfcomm_channel_and_name_for_uuid(context->remote_addr, service_uuid); 1041*3deb3ec6SMatthias Ringwald break; 1042*3deb3ec6SMatthias Ringwald default: 1043*3deb3ec6SMatthias Ringwald break; 1044*3deb3ec6SMatthias Ringwald } 1045*3deb3ec6SMatthias Ringwald } 1046*3deb3ec6SMatthias Ringwald 1047*3deb3ec6SMatthias Ringwald void hfp_release_service_level_connection(hfp_connection_t * context){ 1048*3deb3ec6SMatthias Ringwald if (!context) return; 1049*3deb3ec6SMatthias Ringwald 1050*3deb3ec6SMatthias Ringwald if (context->state < HFP_W4_RFCOMM_CONNECTED){ 1051*3deb3ec6SMatthias Ringwald context->state = HFP_IDLE; 1052*3deb3ec6SMatthias Ringwald return; 1053*3deb3ec6SMatthias Ringwald } 1054*3deb3ec6SMatthias Ringwald 1055*3deb3ec6SMatthias Ringwald if (context->state == HFP_W4_RFCOMM_CONNECTED){ 1056*3deb3ec6SMatthias Ringwald context->state = HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN; 1057*3deb3ec6SMatthias Ringwald return; 1058*3deb3ec6SMatthias Ringwald } 1059*3deb3ec6SMatthias Ringwald 1060*3deb3ec6SMatthias Ringwald if (context->state < HFP_CCE_W4_SCO_CONNECTION_ESTABLISHED){ 1061*3deb3ec6SMatthias Ringwald context->state = HFP_W2_DISCONNECT_RFCOMM; 1062*3deb3ec6SMatthias Ringwald return; 1063*3deb3ec6SMatthias Ringwald } 1064*3deb3ec6SMatthias Ringwald 1065*3deb3ec6SMatthias Ringwald if (context->state < HFP_W4_SCO_DISCONNECTED){ 1066*3deb3ec6SMatthias Ringwald context->state = HFP_W2_DISCONNECT_SCO; 1067*3deb3ec6SMatthias Ringwald return; 1068*3deb3ec6SMatthias Ringwald } 1069*3deb3ec6SMatthias Ringwald 1070*3deb3ec6SMatthias Ringwald return; 1071*3deb3ec6SMatthias Ringwald } 1072*3deb3ec6SMatthias Ringwald 1073*3deb3ec6SMatthias Ringwald void hfp_release_audio_connection(hfp_connection_t * connection){ 1074*3deb3ec6SMatthias Ringwald if (!connection) return; 1075*3deb3ec6SMatthias Ringwald if (connection->state >= HFP_W2_DISCONNECT_SCO) return; 1076*3deb3ec6SMatthias Ringwald connection->release_audio_connection = 1; 1077*3deb3ec6SMatthias Ringwald } 1078*3deb3ec6SMatthias Ringwald 1079*3deb3ec6SMatthias Ringwald 1080