174386ee0SMatthias Ringwald /* 274386ee0SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 374386ee0SMatthias Ringwald * 474386ee0SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 574386ee0SMatthias Ringwald * modification, are permitted provided that the following conditions 674386ee0SMatthias Ringwald * are met: 774386ee0SMatthias Ringwald * 874386ee0SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 974386ee0SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 1074386ee0SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1174386ee0SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 1274386ee0SMatthias Ringwald * documentation and/or other materials provided with the distribution. 1374386ee0SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 1474386ee0SMatthias Ringwald * contributors may be used to endorse or promote products derived 1574386ee0SMatthias Ringwald * from this software without specific prior written permission. 1674386ee0SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 1774386ee0SMatthias Ringwald * personal benefit and not for any commercial purpose or for 1874386ee0SMatthias Ringwald * monetary gain. 1974386ee0SMatthias Ringwald * 2074386ee0SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2174386ee0SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2274386ee0SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2374386ee0SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 2474386ee0SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2574386ee0SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2674386ee0SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2774386ee0SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2874386ee0SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2974386ee0SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3074386ee0SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3174386ee0SMatthias Ringwald * SUCH DAMAGE. 3274386ee0SMatthias Ringwald * 3374386ee0SMatthias Ringwald * Please inquire about commercial licensing options at 3474386ee0SMatthias Ringwald * [email protected] 3574386ee0SMatthias Ringwald * 3674386ee0SMatthias Ringwald */ 3774386ee0SMatthias Ringwald 3874386ee0SMatthias Ringwald // ***************************************************************************** 3974386ee0SMatthias Ringwald // 4074386ee0SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!) 4174386ee0SMatthias Ringwald // 4274386ee0SMatthias Ringwald // ***************************************************************************** 4374386ee0SMatthias Ringwald 4474386ee0SMatthias Ringwald #include "btstack-config.h" 4574386ee0SMatthias Ringwald 4674386ee0SMatthias Ringwald #include <stdint.h> 4774386ee0SMatthias Ringwald #include <stdio.h> 4874386ee0SMatthias Ringwald #include <stdlib.h> 4974386ee0SMatthias Ringwald #include <string.h> 5074386ee0SMatthias Ringwald 5174386ee0SMatthias Ringwald #include "btstack_memory.h" 5274386ee0SMatthias Ringwald #include "classic/hfp.h" 5374386ee0SMatthias Ringwald #include "classic/hfp_gsm_model.h" 5474386ee0SMatthias Ringwald #include "classic/sdp.h" 5574386ee0SMatthias Ringwald #include "classic/sdp_query_rfcomm.h" 5616ece135SMatthias Ringwald #include "btstack_debug.h" 5774386ee0SMatthias Ringwald #include "hci.h" 5874386ee0SMatthias Ringwald #include "hci_cmds.h" 5974386ee0SMatthias Ringwald #include "hci_dump.h" 6074386ee0SMatthias Ringwald #include "l2cap.h" 61*82636622SMatthias Ringwald #include "btstack_run_loop.h" 6274386ee0SMatthias Ringwald 6374386ee0SMatthias Ringwald #define HFP_GSM_MAX_NR_CALLS 3 6474386ee0SMatthias Ringwald 6574386ee0SMatthias Ringwald typedef enum{ 6674386ee0SMatthias Ringwald CALL_NONE, 67d210d9c4SMatthias Ringwald CALL_INITIATED, 68d210d9c4SMatthias Ringwald CALL_RESPONSE_HOLD, 6974386ee0SMatthias Ringwald CALL_ACTIVE, 7074386ee0SMatthias Ringwald CALL_HELD 7174386ee0SMatthias Ringwald } hfp_gsm_call_status_t; 7274386ee0SMatthias Ringwald 7374386ee0SMatthias Ringwald 7474386ee0SMatthias Ringwald typedef struct { 7574386ee0SMatthias Ringwald hfp_gsm_call_status_t status; 76d0c20769SMatthias Ringwald int index; 77d210d9c4SMatthias Ringwald uint8_t clip_type; 78d210d9c4SMatthias Ringwald char clip_number[25]; 7974386ee0SMatthias Ringwald } hfp_gsm_call_t; 8074386ee0SMatthias Ringwald 8174386ee0SMatthias Ringwald static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS]; 8274386ee0SMatthias Ringwald static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 8374386ee0SMatthias Ringwald 84d0c20769SMatthias Ringwald static uint8_t clip_type; 85d0c20769SMatthias Ringwald static char clip_number[25]; 86d0c20769SMatthias Ringwald 87d0c20769SMatthias Ringwald static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number); 88d0c20769SMatthias Ringwald 89d210d9c4SMatthias Ringwald void hfp_gsm_init(void){ 90d0c20769SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 91d0c20769SMatthias Ringwald clip_type = 0; 92d0c20769SMatthias Ringwald memset(clip_number, 0, sizeof(clip_number)); 93d0c20769SMatthias Ringwald 94d210d9c4SMatthias Ringwald memset(gsm_calls, 0, sizeof(gsm_calls)); 95d210d9c4SMatthias Ringwald int i; 96d210d9c4SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 97d210d9c4SMatthias Ringwald gsm_calls[i].status = CALL_NONE; 98d210d9c4SMatthias Ringwald } 99d210d9c4SMatthias Ringwald } 10074386ee0SMatthias Ringwald 10174386ee0SMatthias Ringwald static int get_number_calls_with_status(hfp_gsm_call_status_t status){ 10274386ee0SMatthias Ringwald int i, count = 0; 10374386ee0SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 10474386ee0SMatthias Ringwald if (gsm_calls[i].status == status) count++; 10574386ee0SMatthias Ringwald } 10674386ee0SMatthias Ringwald return count; 10774386ee0SMatthias Ringwald } 10874386ee0SMatthias Ringwald 10974386ee0SMatthias Ringwald static int get_call_index_with_status(hfp_gsm_call_status_t status){ 11074386ee0SMatthias Ringwald int i ; 11174386ee0SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 11274386ee0SMatthias Ringwald if (gsm_calls[i].status == status) return i; 11374386ee0SMatthias Ringwald } 11474386ee0SMatthias Ringwald return -1; 11574386ee0SMatthias Ringwald } 11674386ee0SMatthias Ringwald 117d0c20769SMatthias Ringwald static inline int get_next_free_slot(){ 11874386ee0SMatthias Ringwald return get_call_index_with_status(CALL_NONE); 11974386ee0SMatthias Ringwald } 12074386ee0SMatthias Ringwald 12174386ee0SMatthias Ringwald static inline int get_active_call_index(){ 12274386ee0SMatthias Ringwald return get_call_index_with_status(CALL_ACTIVE); 12374386ee0SMatthias Ringwald } 12474386ee0SMatthias Ringwald 125d210d9c4SMatthias Ringwald static inline int get_initiated_call_index(){ 126d210d9c4SMatthias Ringwald return get_call_index_with_status(CALL_INITIATED); 127d210d9c4SMatthias Ringwald } 128d210d9c4SMatthias Ringwald 129d210d9c4SMatthias Ringwald static inline int get_held_call_index(){ 130d210d9c4SMatthias Ringwald return get_call_index_with_status(CALL_HELD); 131d210d9c4SMatthias Ringwald } 132d210d9c4SMatthias Ringwald 133d210d9c4SMatthias Ringwald static inline int get_response_held_call_index(){ 134d210d9c4SMatthias Ringwald return get_call_index_with_status(CALL_RESPONSE_HOLD); 135d210d9c4SMatthias Ringwald } 136d210d9c4SMatthias Ringwald 137d210d9c4SMatthias Ringwald static inline int get_number_none_calls(){ 138d210d9c4SMatthias Ringwald return get_number_calls_with_status(CALL_NONE); 139d210d9c4SMatthias Ringwald } 14074386ee0SMatthias Ringwald 14174386ee0SMatthias Ringwald static inline int get_number_active_calls(){ 14274386ee0SMatthias Ringwald return get_number_calls_with_status(CALL_ACTIVE); 14374386ee0SMatthias Ringwald } 14474386ee0SMatthias Ringwald 14574386ee0SMatthias Ringwald static inline int get_number_held_calls(){ 14674386ee0SMatthias Ringwald return get_number_calls_with_status(CALL_HELD); 14774386ee0SMatthias Ringwald } 14874386ee0SMatthias Ringwald 149d210d9c4SMatthias Ringwald static inline int get_number_response_held_calls(){ 150d210d9c4SMatthias Ringwald return get_number_calls_with_status(CALL_RESPONSE_HOLD); 151d210d9c4SMatthias Ringwald } 152d210d9c4SMatthias Ringwald 153d0c20769SMatthias Ringwald static int next_call_index(){ 154d0c20769SMatthias Ringwald return HFP_GSM_MAX_NR_CALLS + 1 - get_number_none_calls(); 155d0c20769SMatthias Ringwald } 156d0c20769SMatthias Ringwald 157d0c20769SMatthias Ringwald static void hfp_gsm_set_clip(int index_in_table, uint8_t type, const char * number){ 158d0c20769SMatthias Ringwald gsm_calls[index_in_table].clip_type = type; 159d0c20769SMatthias Ringwald 160d0c20769SMatthias Ringwald int clip_number_size = sizeof(gsm_calls[index_in_table].clip_number); 161d0c20769SMatthias Ringwald strncpy(gsm_calls[index_in_table].clip_number, number, clip_number_size); 162d0c20769SMatthias Ringwald gsm_calls[index_in_table].clip_number[clip_number_size-1] = '\0'; 163d0c20769SMatthias Ringwald } 164d0c20769SMatthias Ringwald 165d0c20769SMatthias Ringwald static void delete_call(int delete_index_in_table){ 166d0c20769SMatthias Ringwald int i ; 167d0c20769SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 168d0c20769SMatthias Ringwald if (gsm_calls[i].index > gsm_calls[delete_index_in_table].index){ 169d0c20769SMatthias Ringwald gsm_calls[i].index--; 170d0c20769SMatthias Ringwald } 171d0c20769SMatthias Ringwald } 172d0c20769SMatthias Ringwald 173d0c20769SMatthias Ringwald gsm_calls[delete_index_in_table].status = CALL_NONE; 174d0c20769SMatthias Ringwald gsm_calls[delete_index_in_table].clip_type = 0; 175d0c20769SMatthias Ringwald gsm_calls[delete_index_in_table].index = 0; 176d0c20769SMatthias Ringwald gsm_calls[delete_index_in_table].clip_number[0] = '\0'; 177d0c20769SMatthias Ringwald } 178d0c20769SMatthias Ringwald 179d0c20769SMatthias Ringwald static void create_call(){ 180d0c20769SMatthias Ringwald int next_free_slot = get_next_free_slot(); 181d0c20769SMatthias Ringwald gsm_calls[next_free_slot].index = next_call_index(); 182d0c20769SMatthias Ringwald gsm_calls[next_free_slot].status = CALL_INITIATED; 183d0c20769SMatthias Ringwald gsm_calls[next_free_slot].clip_type = 0; 184d0c20769SMatthias Ringwald gsm_calls[next_free_slot].clip_number[0] = '\0'; 185d0c20769SMatthias Ringwald 186d0c20769SMatthias Ringwald if (clip_type != 0){ 187d0c20769SMatthias Ringwald hfp_gsm_set_clip(next_free_slot, clip_type, clip_number); 188d0c20769SMatthias Ringwald clip_type = 0; 189d0c20769SMatthias Ringwald memset(clip_number, 0, sizeof(clip_number)); 190d0c20769SMatthias Ringwald } 191d0c20769SMatthias Ringwald } 192d0c20769SMatthias Ringwald 193d0c20769SMatthias Ringwald uint8_t hfp_gsm_clip_type(){ 194d0c20769SMatthias Ringwald if (clip_type != 0) return clip_type; 195d0c20769SMatthias Ringwald 196d0c20769SMatthias Ringwald int initiated_call_index = get_initiated_call_index(); 197d0c20769SMatthias Ringwald if (initiated_call_index != -1){ 198d0c20769SMatthias Ringwald if (gsm_calls[initiated_call_index].clip_type != 0) { 199d0c20769SMatthias Ringwald return gsm_calls[initiated_call_index].clip_type; 200d0c20769SMatthias Ringwald } 201d0c20769SMatthias Ringwald } 202d0c20769SMatthias Ringwald 203d0c20769SMatthias Ringwald int active_call_index = get_active_call_index(); 204d0c20769SMatthias Ringwald if (active_call_index != -1){ 205d0c20769SMatthias Ringwald if (gsm_calls[active_call_index].clip_type != 0) { 206d0c20769SMatthias Ringwald return gsm_calls[active_call_index].clip_type; 207d0c20769SMatthias Ringwald } 208d0c20769SMatthias Ringwald } 209d0c20769SMatthias Ringwald return 0; 210d0c20769SMatthias Ringwald } 211d0c20769SMatthias Ringwald 212d0c20769SMatthias Ringwald char * hfp_gsm_clip_number(){ 213d0c20769SMatthias Ringwald if (clip_type != 0) return clip_number; 214d0c20769SMatthias Ringwald 215d0c20769SMatthias Ringwald int initiated_call_index = get_initiated_call_index(); 216d0c20769SMatthias Ringwald if (initiated_call_index != -1){ 217d0c20769SMatthias Ringwald if (gsm_calls[initiated_call_index].clip_type != 0) { 218d0c20769SMatthias Ringwald return gsm_calls[initiated_call_index].clip_number; 219d0c20769SMatthias Ringwald } 220d0c20769SMatthias Ringwald } 221d0c20769SMatthias Ringwald 222d0c20769SMatthias Ringwald int active_call_index = get_active_call_index(); 223d0c20769SMatthias Ringwald if (active_call_index != -1){ 224d0c20769SMatthias Ringwald if (gsm_calls[active_call_index].clip_type != 0) { 225d0c20769SMatthias Ringwald return gsm_calls[active_call_index].clip_number; 226d0c20769SMatthias Ringwald } 227d0c20769SMatthias Ringwald } 228d0c20769SMatthias Ringwald clip_number[0] = 0; 229d0c20769SMatthias Ringwald return clip_number; 230d0c20769SMatthias Ringwald } 231d0c20769SMatthias Ringwald 23274386ee0SMatthias Ringwald hfp_call_status_t hfp_gsm_call_status(){ 233d210d9c4SMatthias Ringwald if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){ 23474386ee0SMatthias Ringwald return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; 23574386ee0SMatthias Ringwald } 23674386ee0SMatthias Ringwald return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; 23774386ee0SMatthias Ringwald } 23874386ee0SMatthias Ringwald 23974386ee0SMatthias Ringwald hfp_callheld_status_t hfp_gsm_callheld_status(){ 24074386ee0SMatthias Ringwald // @note: order is important 24174386ee0SMatthias Ringwald if (get_number_held_calls() == 0){ 24274386ee0SMatthias Ringwald return HFP_CALLHELD_STATUS_NO_CALLS_HELD; 24374386ee0SMatthias Ringwald } 24474386ee0SMatthias Ringwald if (get_number_active_calls() == 0) { 24574386ee0SMatthias Ringwald return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS; 24674386ee0SMatthias Ringwald } 24774386ee0SMatthias Ringwald return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED; 24874386ee0SMatthias Ringwald } 24974386ee0SMatthias Ringwald 25074386ee0SMatthias Ringwald hfp_callsetup_status_t hfp_gsm_callsetup_status(){ 25174386ee0SMatthias Ringwald return callsetup_status; 25274386ee0SMatthias Ringwald } 25374386ee0SMatthias Ringwald 254d210d9c4SMatthias Ringwald int hfp_gsm_response_held_active(){ 255d210d9c4SMatthias Ringwald return get_response_held_call_index() != -1 ; 256d210d9c4SMatthias Ringwald } 257d210d9c4SMatthias Ringwald 258d210d9c4SMatthias Ringwald int hfp_gsm_call_possible(void){ 259d210d9c4SMatthias Ringwald return get_number_none_calls() > 0; 260d210d9c4SMatthias Ringwald } 261d210d9c4SMatthias Ringwald 26274386ee0SMatthias Ringwald void hfp_gsm_handle_event(hfp_ag_call_event_t event){ 263d0c20769SMatthias Ringwald hfp_gsm_handler(event, 0, 0, NULL); 264d0c20769SMatthias Ringwald } 265d0c20769SMatthias Ringwald 266d0c20769SMatthias Ringwald void hfp_gsm_handle_event_with_clip(hfp_ag_call_event_t event, uint8_t type, const char * number){ 267d0c20769SMatthias Ringwald hfp_gsm_handler(event, 0, type, number); 268d0c20769SMatthias Ringwald } 269d0c20769SMatthias Ringwald 270d0c20769SMatthias Ringwald void hfp_gsm_handle_event_with_call_index(hfp_ag_call_event_t event, uint8_t index){ 271d0c20769SMatthias Ringwald hfp_gsm_handler(event, index, 0, NULL); 272d0c20769SMatthias Ringwald } 273d0c20769SMatthias Ringwald 274d0c20769SMatthias Ringwald static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number){ 275d0c20769SMatthias Ringwald int next_free_slot = get_next_free_slot(); 27674386ee0SMatthias Ringwald int current_call_index = get_active_call_index(); 277d210d9c4SMatthias Ringwald int initiated_call_index = get_initiated_call_index(); 278d210d9c4SMatthias Ringwald int held_call_index = get_held_call_index(); 279d0c20769SMatthias Ringwald int i; 280d0c20769SMatthias Ringwald 28174386ee0SMatthias Ringwald switch (event){ 28274386ee0SMatthias Ringwald case HFP_AG_OUTGOING_CALL_INITIATED: 28374386ee0SMatthias Ringwald case HFP_AG_OUTGOING_REDIAL_INITIATED: 28474386ee0SMatthias Ringwald if (next_free_slot == -1){ 285d210d9c4SMatthias Ringwald log_error("gsm: max call nr exceeded"); 28674386ee0SMatthias Ringwald return; 28774386ee0SMatthias Ringwald } 288d0c20769SMatthias Ringwald create_call(); 289d210d9c4SMatthias Ringwald break; 29074386ee0SMatthias Ringwald 291d210d9c4SMatthias Ringwald case HFP_AG_OUTGOING_CALL_REJECTED: 292d210d9c4SMatthias Ringwald if (current_call_index != -1){ 293d0c20769SMatthias Ringwald // gsm_calls[current_call_index].status = CALL_NONE; 294d0c20769SMatthias Ringwald delete_call(current_call_index); 295d210d9c4SMatthias Ringwald } 296d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 297d210d9c4SMatthias Ringwald break; 298d210d9c4SMatthias Ringwald 299d210d9c4SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ACCEPTED: 30074386ee0SMatthias Ringwald if (current_call_index != -1){ 30174386ee0SMatthias Ringwald gsm_calls[current_call_index].status = CALL_HELD; 30274386ee0SMatthias Ringwald } 303d0c20769SMatthias Ringwald create_call(); 30474386ee0SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE; 30574386ee0SMatthias Ringwald break; 306d210d9c4SMatthias Ringwald 30774386ee0SMatthias Ringwald case HFP_AG_OUTGOING_CALL_RINGING: 308d210d9c4SMatthias Ringwald if (current_call_index == -1){ 309d210d9c4SMatthias Ringwald log_error("gsm: no active call"); 310d210d9c4SMatthias Ringwald return; 311d210d9c4SMatthias Ringwald } 312d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE; 31374386ee0SMatthias Ringwald break; 31474386ee0SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ESTABLISHED: 315d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 316d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 31774386ee0SMatthias Ringwald break; 318d210d9c4SMatthias Ringwald 319d210d9c4SMatthias Ringwald case HFP_AG_INCOMING_CALL: 320d210d9c4SMatthias Ringwald if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break; 321d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS; 322d0c20769SMatthias Ringwald create_call(); 323d210d9c4SMatthias Ringwald break; 324d210d9c4SMatthias Ringwald 325d210d9c4SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 326d210d9c4SMatthias Ringwald if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 327d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 328d210d9c4SMatthias Ringwald 329d210d9c4SMatthias Ringwald if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 330d210d9c4SMatthias Ringwald gsm_calls[current_call_index].status = CALL_HELD; 331d210d9c4SMatthias Ringwald } 332d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 333d210d9c4SMatthias Ringwald break; 334d210d9c4SMatthias Ringwald 335d210d9c4SMatthias Ringwald case HFP_AG_HELD_CALL_JOINED_BY_AG: 336d210d9c4SMatthias Ringwald if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 337d210d9c4SMatthias Ringwald 338d210d9c4SMatthias Ringwald // TODO: mark joined calls with "multiparty flag" (if we cannot calculate it otherwise) 339d210d9c4SMatthias Ringwald // TODO: is following condition correct? Can we join incoming call before it is answered? 340d210d9c4SMatthias Ringwald if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 341d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 342d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 343d210d9c4SMatthias Ringwald break; 344d210d9c4SMatthias Ringwald } 345d210d9c4SMatthias Ringwald 346d210d9c4SMatthias Ringwald if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) { 347d210d9c4SMatthias Ringwald gsm_calls[held_call_index].status = CALL_ACTIVE; 348d210d9c4SMatthias Ringwald break; 349d210d9c4SMatthias Ringwald } 350d210d9c4SMatthias Ringwald break; 351d210d9c4SMatthias Ringwald 352d210d9c4SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 353d210d9c4SMatthias Ringwald if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 354d210d9c4SMatthias Ringwald if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 355d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 356d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 357d210d9c4SMatthias Ringwald break; 358d210d9c4SMatthias Ringwald 359d210d9c4SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: 360d210d9c4SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: 361d210d9c4SMatthias Ringwald if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 362d210d9c4SMatthias Ringwald if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 363d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 364d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_RESPONSE_HOLD; 365d210d9c4SMatthias Ringwald break; 366d210d9c4SMatthias Ringwald 367d210d9c4SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG: 368d210d9c4SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: 369d210d9c4SMatthias Ringwald if (!hfp_gsm_response_held_active()) break; 370d210d9c4SMatthias Ringwald gsm_calls[get_response_held_call_index()].status = CALL_ACTIVE; 371d210d9c4SMatthias Ringwald break; 372d210d9c4SMatthias Ringwald 373d210d9c4SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG: 374d210d9c4SMatthias Ringwald case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: 375d210d9c4SMatthias Ringwald if (!hfp_gsm_response_held_active()) break; 376d0c20769SMatthias Ringwald // gsm_calls[get_response_held_call_index()].status = CALL_NONE; 377d0c20769SMatthias Ringwald delete_call(get_response_held_call_index()); 378d210d9c4SMatthias Ringwald break; 379d210d9c4SMatthias Ringwald 380d210d9c4SMatthias Ringwald 381d210d9c4SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_HF: 382d210d9c4SMatthias Ringwald switch (hfp_gsm_call_status()){ 383d210d9c4SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 384d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 385d210d9c4SMatthias Ringwald break; 386d210d9c4SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 387d0c20769SMatthias Ringwald // gsm_calls[current_call_index].status = CALL_NONE; 388d0c20769SMatthias Ringwald delete_call(current_call_index); 389d210d9c4SMatthias Ringwald break; 390d210d9c4SMatthias Ringwald } 391d210d9c4SMatthias Ringwald break; 392d210d9c4SMatthias Ringwald 393d210d9c4SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_AG: 394d210d9c4SMatthias Ringwald switch (hfp_gsm_call_status()){ 395d210d9c4SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 396d210d9c4SMatthias Ringwald if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 397d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 398d210d9c4SMatthias Ringwald break; 399d210d9c4SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 400d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 401d0c20769SMatthias Ringwald // gsm_calls[current_call_index].status = CALL_NONE; 402d0c20769SMatthias Ringwald delete_call(current_call_index); 403d210d9c4SMatthias Ringwald break; 404d210d9c4SMatthias Ringwald default: 405d210d9c4SMatthias Ringwald break; 406d210d9c4SMatthias Ringwald } 407d210d9c4SMatthias Ringwald break; 408d210d9c4SMatthias Ringwald 409d0c20769SMatthias Ringwald case HFP_AG_CALL_DROPPED: 410d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 411d210d9c4SMatthias Ringwald if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 412d210d9c4SMatthias Ringwald 413d210d9c4SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 414d0c20769SMatthias Ringwald delete_call(i); 415d210d9c4SMatthias Ringwald } 416d210d9c4SMatthias Ringwald break; 417d0c20769SMatthias Ringwald 418d210d9c4SMatthias Ringwald case HFP_AG_CALL_HOLD_USER_BUSY: 419d210d9c4SMatthias Ringwald // Held or waiting call gets active, 420d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 421d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_NONE; 422d210d9c4SMatthias Ringwald gsm_calls[held_call_index].status = CALL_ACTIVE; 423d210d9c4SMatthias Ringwald break; 424d210d9c4SMatthias Ringwald 425d0c20769SMatthias Ringwald case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 426d0c20769SMatthias Ringwald if (index != 0 && index <= HFP_GSM_MAX_NR_CALLS ){ 427d0c20769SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 428d0c20769SMatthias Ringwald if (gsm_calls[i].index == index){ 429d0c20769SMatthias Ringwald delete_call(i); 430d0c20769SMatthias Ringwald continue; 431d0c20769SMatthias Ringwald } 432d0c20769SMatthias Ringwald } 433d0c20769SMatthias Ringwald } else { 434d210d9c4SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 435d210d9c4SMatthias Ringwald if (gsm_calls[i].status == CALL_ACTIVE){ 436d0c20769SMatthias Ringwald delete_call(i); 437d0c20769SMatthias Ringwald } 438d210d9c4SMatthias Ringwald } 439d210d9c4SMatthias Ringwald } 440d210d9c4SMatthias Ringwald 441d210d9c4SMatthias Ringwald if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 442d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 443d210d9c4SMatthias Ringwald } else { 444d210d9c4SMatthias Ringwald gsm_calls[held_call_index].status = CALL_ACTIVE; 445d210d9c4SMatthias Ringwald } 446d0c20769SMatthias Ringwald 447d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 448d210d9c4SMatthias Ringwald break; 449d0c20769SMatthias Ringwald 450d0c20769SMatthias Ringwald case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 451d210d9c4SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 452d0c20769SMatthias Ringwald if (gsm_calls[i].status == CALL_ACTIVE && gsm_calls[i].index != index){ 453d210d9c4SMatthias Ringwald gsm_calls[i].clip_type = 0; 454d210d9c4SMatthias Ringwald gsm_calls[i].clip_number[0] = '\0'; 455d210d9c4SMatthias Ringwald gsm_calls[i].status = CALL_HELD; 456d210d9c4SMatthias Ringwald } 457d210d9c4SMatthias Ringwald } 458d210d9c4SMatthias Ringwald 459d210d9c4SMatthias Ringwald if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 460d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 461d210d9c4SMatthias Ringwald } else { 462d210d9c4SMatthias Ringwald gsm_calls[held_call_index].status = CALL_ACTIVE; 463d210d9c4SMatthias Ringwald } 464d210d9c4SMatthias Ringwald callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 465d210d9c4SMatthias Ringwald break; 466d0c20769SMatthias Ringwald 467d0c20769SMatthias Ringwald case HFP_AG_CALL_HOLD_ADD_HELD_CALL: 468d210d9c4SMatthias Ringwald if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 469d210d9c4SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 470d210d9c4SMatthias Ringwald if (gsm_calls[i].status == CALL_HELD){ 471d210d9c4SMatthias Ringwald gsm_calls[i].clip_type = 0; 472d210d9c4SMatthias Ringwald gsm_calls[i].clip_number[0] = '\0'; 473d210d9c4SMatthias Ringwald gsm_calls[i].status = CALL_ACTIVE; 474d210d9c4SMatthias Ringwald } 475d210d9c4SMatthias Ringwald } 476d210d9c4SMatthias Ringwald } 477d210d9c4SMatthias Ringwald gsm_calls[initiated_call_index].status = CALL_ACTIVE; 478d210d9c4SMatthias Ringwald break; 479d0c20769SMatthias Ringwald 480d0c20769SMatthias Ringwald case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS: 481d210d9c4SMatthias Ringwald for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 482d0c20769SMatthias Ringwald delete_call(i); 483d210d9c4SMatthias Ringwald } 484d0c20769SMatthias Ringwald break; 485d210d9c4SMatthias Ringwald 486d0c20769SMatthias Ringwald case HFP_AG_SET_CLIP: 487d0c20769SMatthias Ringwald if (initiated_call_index != -1){ 488d0c20769SMatthias Ringwald hfp_gsm_set_clip(initiated_call_index, type, number); 489d210d9c4SMatthias Ringwald break; 490d210d9c4SMatthias Ringwald } 491d0c20769SMatthias Ringwald if (current_call_index != -1){ 492d0c20769SMatthias Ringwald hfp_gsm_set_clip(current_call_index, type, number); 493d0c20769SMatthias Ringwald break; 494d0c20769SMatthias Ringwald } 495d0c20769SMatthias Ringwald clip_type = type; 496d0c20769SMatthias Ringwald strncpy(clip_number, number, sizeof(clip_number)); 497d0c20769SMatthias Ringwald clip_number[sizeof(clip_number)-1] = '\0'; 498d0c20769SMatthias Ringwald 499d0c20769SMatthias Ringwald break; 50074386ee0SMatthias Ringwald default: 50174386ee0SMatthias Ringwald break; 50274386ee0SMatthias Ringwald } 50374386ee0SMatthias Ringwald }