1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 // ***************************************************************************** 39 // 40 // GSM Model 41 // 42 // ***************************************************************************** 43 44 #include "btstack_config.h" 45 46 #include <stdint.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 51 #include "btstack_memory.h" 52 #include "classic/hfp.h" 53 #include "classic/hfp_gsm_model.h" 54 #include "classic/sdp_server.h" 55 #include "classic/sdp_query_rfcomm.h" 56 #include "btstack_debug.h" 57 #include "hci.h" 58 #include "hci_cmd.h" 59 #include "hci_dump.h" 60 #include "l2cap.h" 61 #include "btstack_run_loop.h" 62 63 #define HFP_GSM_MAX_NR_CALLS 3 64 #define HFP_GSM_MAX_CALL_NUMBER_SIZE 25 65 66 static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS]; 67 static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 68 69 static uint8_t clip_type; 70 static char clip_number[HFP_GSM_MAX_CALL_NUMBER_SIZE]; 71 static char last_dialed_number[HFP_GSM_MAX_CALL_NUMBER_SIZE]; 72 73 static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number); 74 static inline int get_number_active_calls(void); 75 76 static void set_callsetup_status(hfp_callsetup_status_t status){ 77 callsetup_status = status; 78 if (callsetup_status != HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE) return; 79 80 int i ; 81 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 82 if (gsm_calls[i].direction == HFP_ENHANCED_CALL_DIR_OUTGOING){ 83 gsm_calls[i].enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING; 84 } 85 } 86 } 87 88 static inline void set_enhanced_call_status_active(int index_in_table){ 89 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_ACTIVE; 90 gsm_calls[index_in_table].used_slot = 1; 91 } 92 93 static inline void set_enhanced_call_status_held(int index_in_table){ 94 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_HELD; 95 gsm_calls[index_in_table].used_slot = 1; 96 } 97 98 static inline void set_enhanced_call_status_response_hold(int index_in_table){ 99 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD; 100 gsm_calls[index_in_table].used_slot = 1; 101 } 102 103 static inline void set_enhanced_call_status_initiated(int index_in_table){ 104 if (gsm_calls[index_in_table].direction == HFP_ENHANCED_CALL_DIR_OUTGOING){ 105 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING; 106 } else { 107 if (get_number_active_calls() > 0){ 108 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING; 109 } else { 110 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING; 111 } 112 } 113 gsm_calls[index_in_table].used_slot = 1; 114 } 115 116 static int get_enhanced_call_status(int index_in_table){ 117 if (!gsm_calls[index_in_table].used_slot) return -1; 118 return gsm_calls[index_in_table].enhanced_status; 119 } 120 121 static inline int is_enhanced_call_status_active(int index_in_table){ 122 return get_enhanced_call_status(index_in_table) == HFP_ENHANCED_CALL_STATUS_ACTIVE; 123 } 124 125 static inline int is_enhanced_call_status_initiated(int index_in_table){ 126 switch (get_enhanced_call_status(index_in_table)){ 127 case HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING: 128 case HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING: 129 case HFP_ENHANCED_CALL_STATUS_INCOMING: 130 case HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING: 131 return 1; 132 default: 133 return 0; 134 } 135 } 136 137 static void free_call_slot(int index_in_table){ 138 gsm_calls[index_in_table].used_slot = 0; 139 } 140 141 void hfp_gsm_init(void){ 142 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 143 clip_type = 0; 144 memset(clip_number, 0, sizeof(clip_number)); 145 memset(last_dialed_number, 0, sizeof(last_dialed_number)); 146 memset(gsm_calls, 0, sizeof(gsm_calls)); 147 int i; 148 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 149 free_call_slot(i); 150 } 151 } 152 153 static int get_number_calls_with_enhanced_status(hfp_enhanced_call_status_t enhanced_status){ 154 int i, count = 0; 155 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 156 if (get_enhanced_call_status(i) == enhanced_status) count++; 157 } 158 return count; 159 } 160 161 static int get_call_index_with_enhanced_status(hfp_enhanced_call_status_t enhanced_status){ 162 int i ; 163 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 164 if (get_enhanced_call_status(i) == enhanced_status) return i; 165 } 166 return -1; 167 } 168 169 static inline int get_initiated_call_index(void){ 170 int i ; 171 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 172 if (is_enhanced_call_status_initiated(i)) return i; 173 } 174 return -1; 175 } 176 177 static inline int get_next_free_slot(void){ 178 int i ; 179 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 180 if (!gsm_calls[i].used_slot) return i; 181 } 182 return -1; 183 } 184 185 static inline int get_active_call_index(void){ 186 return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_ACTIVE); 187 } 188 189 static inline int get_held_call_index(void){ 190 return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_HELD); 191 } 192 193 static inline int get_response_held_call_index(void){ 194 return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD); 195 } 196 197 static inline int get_number_none_calls(void){ 198 int i, count = 0; 199 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 200 if (!gsm_calls[i].used_slot) count++; 201 } 202 return count; 203 } 204 205 static inline int get_number_active_calls(void){ 206 return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_ACTIVE); 207 } 208 209 static inline int get_number_held_calls(void){ 210 return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_HELD); 211 } 212 213 static inline int get_number_response_held_calls(void){ 214 return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD); 215 } 216 217 static int next_call_index(void){ 218 return HFP_GSM_MAX_NR_CALLS + 1 - get_number_none_calls(); 219 } 220 221 static void hfp_gsm_set_clip(int index_in_table, uint8_t type, const char * number){ 222 if (strlen(number) == 0) return; 223 224 gsm_calls[index_in_table].clip_type = type; 225 226 int clip_number_size = strlen(number) < HFP_GSM_MAX_CALL_NUMBER_SIZE ? strlen(number) : HFP_GSM_MAX_CALL_NUMBER_SIZE-1; 227 strncpy(gsm_calls[index_in_table].clip_number, number, clip_number_size); 228 gsm_calls[index_in_table].clip_number[clip_number_size] = '\0'; 229 strncpy(last_dialed_number, number, clip_number_size); 230 last_dialed_number[clip_number_size] = '\0'; 231 232 clip_type = 0; 233 memset(clip_number, 0, sizeof(clip_number)); 234 } 235 236 static void delete_call(int delete_index_in_table){ 237 int i ; 238 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 239 if (gsm_calls[i].index > gsm_calls[delete_index_in_table].index){ 240 gsm_calls[i].index--; 241 } 242 } 243 free_call_slot(delete_index_in_table); 244 245 gsm_calls[delete_index_in_table].clip_type = 0; 246 gsm_calls[delete_index_in_table].index = 0; 247 gsm_calls[delete_index_in_table].clip_number[0] = '\0'; 248 gsm_calls[delete_index_in_table].mpty = HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL; 249 } 250 251 252 static void create_call(hfp_enhanced_call_dir_t direction){ 253 int next_free_slot = get_next_free_slot(); 254 gsm_calls[next_free_slot].direction = direction; 255 gsm_calls[next_free_slot].index = next_call_index(); 256 set_enhanced_call_status_initiated(next_free_slot); 257 gsm_calls[next_free_slot].clip_type = 0; 258 gsm_calls[next_free_slot].clip_number[0] = '\0'; 259 gsm_calls[next_free_slot].mpty = HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL; 260 261 hfp_gsm_set_clip(next_free_slot, clip_type, clip_number); 262 } 263 264 265 int hfp_gsm_get_number_of_calls(void){ 266 return HFP_GSM_MAX_NR_CALLS - get_number_none_calls(); 267 } 268 269 void hfp_gsm_clear_last_dialed_number(void){ 270 memset(last_dialed_number, 0, sizeof(last_dialed_number)); 271 } 272 273 char * hfp_gsm_last_dialed_number(void){ 274 return &last_dialed_number[0]; 275 } 276 277 hfp_gsm_call_t * hfp_gsm_call(int call_index){ 278 int i; 279 280 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 281 hfp_gsm_call_t * call = &gsm_calls[i]; 282 if (call->index != call_index) continue; 283 return call; 284 } 285 return NULL; 286 } 287 288 uint8_t hfp_gsm_clip_type(void){ 289 if (clip_type != 0) return clip_type; 290 291 int initiated_call_index = get_initiated_call_index(); 292 if (initiated_call_index != -1){ 293 if (gsm_calls[initiated_call_index].clip_type != 0) { 294 return gsm_calls[initiated_call_index].clip_type; 295 } 296 } 297 298 int active_call_index = get_active_call_index(); 299 if (active_call_index != -1){ 300 if (gsm_calls[active_call_index].clip_type != 0) { 301 return gsm_calls[active_call_index].clip_type; 302 } 303 } 304 return 0; 305 } 306 307 char * hfp_gsm_clip_number(void){ 308 if (strlen(clip_number) != 0) return clip_number; 309 310 int initiated_call_index = get_initiated_call_index(); 311 if (initiated_call_index != -1){ 312 if (gsm_calls[initiated_call_index].clip_type != 0) { 313 return gsm_calls[initiated_call_index].clip_number; 314 } 315 } 316 317 int active_call_index = get_active_call_index(); 318 if (active_call_index != -1){ 319 if (gsm_calls[active_call_index].clip_type != 0) { 320 return gsm_calls[active_call_index].clip_number; 321 } 322 } 323 clip_number[0] = 0; 324 return clip_number; 325 } 326 327 hfp_call_status_t hfp_gsm_call_status(void){ 328 if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){ 329 return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; 330 } 331 return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; 332 } 333 334 hfp_callheld_status_t hfp_gsm_callheld_status(void){ 335 // @note: order is important 336 if (get_number_held_calls() == 0){ 337 return HFP_CALLHELD_STATUS_NO_CALLS_HELD; 338 } 339 if (get_number_active_calls() == 0) { 340 return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS; 341 } 342 return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED; 343 } 344 345 hfp_callsetup_status_t hfp_gsm_callsetup_status(void){ 346 return callsetup_status; 347 } 348 349 static int hfp_gsm_response_held_active(void){ 350 return get_response_held_call_index() != -1 ; 351 } 352 353 int hfp_gsm_call_possible(void){ 354 return get_number_none_calls() > 0; 355 } 356 357 void hfp_gsm_handle_event(hfp_ag_call_event_t event){ 358 hfp_gsm_handler(event, 0, 0, NULL); 359 } 360 361 void hfp_gsm_handle_event_with_clip(hfp_ag_call_event_t event, uint8_t type, const char * number){ 362 hfp_gsm_handler(event, 0, type, number); 363 } 364 365 void hfp_gsm_handle_event_with_call_index(hfp_ag_call_event_t event, uint8_t index){ 366 hfp_gsm_handler(event, index, 0, NULL); 367 } 368 369 void hfp_gsm_handle_event_with_call_number(hfp_ag_call_event_t event, const char * number){ 370 hfp_gsm_handler(event, 0, 0, number); 371 } 372 373 static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number){ 374 int next_free_slot = get_next_free_slot(); 375 int current_call_index = get_active_call_index(); 376 int initiated_call_index = get_initiated_call_index(); 377 int held_call_index = get_held_call_index(); 378 int i; 379 380 switch (event){ 381 case HFP_AG_OUTGOING_CALL_INITIATED: 382 case HFP_AG_OUTGOING_REDIAL_INITIATED: 383 if (next_free_slot == -1){ 384 log_error("gsm: max call nr exceeded"); 385 return; 386 } 387 create_call(HFP_ENHANCED_CALL_DIR_OUTGOING); 388 break; 389 390 case HFP_AG_OUTGOING_CALL_REJECTED: 391 if (current_call_index != -1){ 392 delete_call(current_call_index); 393 } 394 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 395 break; 396 397 case HFP_AG_OUTGOING_CALL_ACCEPTED: 398 if (current_call_index != -1){ 399 set_enhanced_call_status_held(current_call_index); 400 } 401 set_callsetup_status(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE); 402 break; 403 404 case HFP_AG_OUTGOING_CALL_RINGING: 405 if (current_call_index == -1){ 406 log_error("gsm: no active call"); 407 return; 408 } 409 set_callsetup_status(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE); 410 break; 411 case HFP_AG_OUTGOING_CALL_ESTABLISHED: 412 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 413 set_enhanced_call_status_active(initiated_call_index); 414 break; 415 416 case HFP_AG_INCOMING_CALL: 417 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break; 418 set_callsetup_status(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); 419 create_call(HFP_ENHANCED_CALL_DIR_INCOMING); 420 break; 421 422 case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 423 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 424 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 425 426 if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 427 set_enhanced_call_status_held(current_call_index); 428 } 429 set_enhanced_call_status_active(initiated_call_index); 430 break; 431 432 case HFP_AG_HELD_CALL_JOINED_BY_AG: 433 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 434 435 // TODO: is following condition correct? Can we join incoming call before it is answered? 436 if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 437 set_enhanced_call_status_active(initiated_call_index); 438 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 439 } else if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) { 440 set_enhanced_call_status_active(held_call_index); 441 } 442 443 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 444 if (is_enhanced_call_status_active(i)){ 445 gsm_calls[i].mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL; 446 } 447 } 448 break; 449 450 case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 451 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 452 if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 453 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 454 set_enhanced_call_status_active(initiated_call_index); 455 break; 456 457 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: 458 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: 459 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 460 if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 461 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 462 set_enhanced_call_status_response_hold(initiated_call_index); 463 break; 464 465 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG: 466 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: 467 if (!hfp_gsm_response_held_active()) break; 468 set_enhanced_call_status_active(get_response_held_call_index()); 469 break; 470 471 case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG: 472 case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: 473 if (!hfp_gsm_response_held_active()) break; 474 delete_call(get_response_held_call_index()); 475 break; 476 477 478 case HFP_AG_TERMINATE_CALL_BY_HF: 479 switch (hfp_gsm_call_status()){ 480 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 481 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 482 break; 483 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 484 delete_call(current_call_index); 485 break; 486 } 487 break; 488 489 case HFP_AG_TERMINATE_CALL_BY_AG: 490 switch (hfp_gsm_call_status()){ 491 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 492 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 493 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 494 break; 495 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 496 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 497 delete_call(current_call_index); 498 break; 499 default: 500 break; 501 } 502 break; 503 504 case HFP_AG_CALL_DROPPED: 505 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 506 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 507 508 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 509 delete_call(i); 510 } 511 break; 512 513 case HFP_AG_CALL_HOLD_USER_BUSY: 514 // Held or waiting call gets active, 515 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 516 free_call_slot(initiated_call_index); 517 set_enhanced_call_status_active(held_call_index); 518 break; 519 520 case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 521 if (index != 0 && index <= HFP_GSM_MAX_NR_CALLS ){ 522 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 523 if (gsm_calls[i].index == index){ 524 delete_call(i); 525 continue; 526 } 527 } 528 } else { 529 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 530 if (is_enhanced_call_status_active(i)){ 531 delete_call(i); 532 } 533 } 534 } 535 536 if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 537 set_enhanced_call_status_active(initiated_call_index); 538 } else { 539 set_enhanced_call_status_active(held_call_index); 540 } 541 542 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 543 break; 544 545 case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 546 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 547 if (is_enhanced_call_status_active(i) && gsm_calls[i].index != index){ 548 set_enhanced_call_status_held(i); 549 } 550 } 551 552 if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 553 set_enhanced_call_status_active(initiated_call_index); 554 } else { 555 set_enhanced_call_status_active(held_call_index); 556 } 557 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 558 break; 559 560 case HFP_AG_CALL_HOLD_ADD_HELD_CALL: 561 if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 562 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 563 if (gsm_calls[i].used_slot){ 564 set_enhanced_call_status_active(i); 565 gsm_calls[i].mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL; 566 } 567 } 568 } 569 break; 570 571 case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS: 572 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 573 delete_call(i); 574 } 575 break; 576 577 case HFP_AG_SET_CLIP: 578 if (initiated_call_index != -1){ 579 hfp_gsm_set_clip(initiated_call_index, type, number); 580 break; 581 } 582 583 clip_type = type; 584 strncpy(clip_number, number, sizeof(clip_number)); 585 clip_number[sizeof(clip_number)-1] = '\0'; 586 587 break; 588 default: 589 break; 590 } 591 }