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/core.h" 53 #include "classic/hfp.h" 54 #include "classic/hfp_gsm_model.h" 55 #include "classic/sdp_server.h" 56 #include "classic/sdp_client_rfcomm.h" 57 #include "btstack_debug.h" 58 #include "hci.h" 59 #include "hci_cmd.h" 60 #include "hci_dump.h" 61 #include "l2cap.h" 62 #include "btstack_run_loop.h" 63 64 #define HFP_GSM_MAX_NR_CALLS 3 65 #define HFP_GSM_MAX_CALL_NUMBER_SIZE 25 66 67 static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS]; 68 static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 69 70 static uint8_t clip_type; 71 static char clip_number[HFP_GSM_MAX_CALL_NUMBER_SIZE]; 72 static char last_dialed_number[HFP_GSM_MAX_CALL_NUMBER_SIZE]; 73 74 static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number); 75 static inline int get_number_active_calls(void); 76 77 static void set_callsetup_status(hfp_callsetup_status_t status){ 78 callsetup_status = status; 79 if (callsetup_status != HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE) return; 80 81 int i ; 82 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 83 if (gsm_calls[i].direction == HFP_ENHANCED_CALL_DIR_OUTGOING){ 84 gsm_calls[i].enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING; 85 } 86 } 87 } 88 89 static inline void set_enhanced_call_status_active(int index_in_table){ 90 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_ACTIVE; 91 gsm_calls[index_in_table].used_slot = 1; 92 } 93 94 static inline void set_enhanced_call_status_held(int index_in_table){ 95 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_HELD; 96 gsm_calls[index_in_table].used_slot = 1; 97 } 98 99 static inline void set_enhanced_call_status_response_hold(int index_in_table){ 100 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD; 101 gsm_calls[index_in_table].used_slot = 1; 102 } 103 104 static inline void set_enhanced_call_status_initiated(int index_in_table){ 105 if (gsm_calls[index_in_table].direction == HFP_ENHANCED_CALL_DIR_OUTGOING){ 106 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING; 107 } else { 108 if (get_number_active_calls() > 0){ 109 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING; 110 } else { 111 gsm_calls[index_in_table].enhanced_status = HFP_ENHANCED_CALL_STATUS_INCOMING; 112 } 113 } 114 gsm_calls[index_in_table].used_slot = 1; 115 } 116 117 static int get_enhanced_call_status(int index_in_table){ 118 if (!gsm_calls[index_in_table].used_slot) return -1; 119 return gsm_calls[index_in_table].enhanced_status; 120 } 121 122 static inline int is_enhanced_call_status_active(int index_in_table){ 123 return get_enhanced_call_status(index_in_table) == HFP_ENHANCED_CALL_STATUS_ACTIVE; 124 } 125 126 static inline int is_enhanced_call_status_initiated(int index_in_table){ 127 switch (get_enhanced_call_status(index_in_table)){ 128 case HFP_ENHANCED_CALL_STATUS_OUTGOING_DIALING: 129 case HFP_ENHANCED_CALL_STATUS_OUTGOING_ALERTING: 130 case HFP_ENHANCED_CALL_STATUS_INCOMING: 131 case HFP_ENHANCED_CALL_STATUS_INCOMING_WAITING: 132 return 1; 133 default: 134 return 0; 135 } 136 } 137 138 static void free_call_slot(int index_in_table){ 139 gsm_calls[index_in_table].used_slot = 0; 140 } 141 142 void hfp_gsm_init(void){ 143 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 144 clip_type = 0; 145 memset(clip_number, 0, sizeof(clip_number)); 146 memset(last_dialed_number, 0, sizeof(last_dialed_number)); 147 memset(gsm_calls, 0, sizeof(gsm_calls)); 148 int i; 149 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 150 free_call_slot(i); 151 } 152 } 153 154 static int get_number_calls_with_enhanced_status(hfp_enhanced_call_status_t enhanced_status){ 155 int i, count = 0; 156 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 157 if (get_enhanced_call_status(i) == enhanced_status) count++; 158 } 159 return count; 160 } 161 162 static int get_call_index_with_enhanced_status(hfp_enhanced_call_status_t enhanced_status){ 163 int i ; 164 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 165 if (get_enhanced_call_status(i) == enhanced_status) return i; 166 } 167 return -1; 168 } 169 170 static inline int get_initiated_call_index(void){ 171 int i ; 172 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 173 if (is_enhanced_call_status_initiated(i)) return i; 174 } 175 return -1; 176 } 177 178 static inline int get_next_free_slot(void){ 179 int i ; 180 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 181 if (!gsm_calls[i].used_slot) return i; 182 } 183 return -1; 184 } 185 186 static inline int get_active_call_index(void){ 187 return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_ACTIVE); 188 } 189 190 static inline int get_held_call_index(void){ 191 return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_HELD); 192 } 193 194 static inline int get_response_held_call_index(void){ 195 return get_call_index_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD); 196 } 197 198 static inline int get_number_none_calls(void){ 199 int i, count = 0; 200 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 201 if (!gsm_calls[i].used_slot) count++; 202 } 203 return count; 204 } 205 206 static inline int get_number_active_calls(void){ 207 return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_ACTIVE); 208 } 209 210 static inline int get_number_held_calls(void){ 211 return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_HELD); 212 } 213 214 static inline int get_number_response_held_calls(void){ 215 return get_number_calls_with_enhanced_status(HFP_ENHANCED_CALL_STATUS_CALL_HELD_BY_RESPONSE_AND_HOLD); 216 } 217 218 static int next_call_index(void){ 219 return HFP_GSM_MAX_NR_CALLS + 1 - get_number_none_calls(); 220 } 221 222 static void hfp_gsm_set_clip(int index_in_table, uint8_t type, const char * number){ 223 if (strlen(number) == 0) return; 224 225 gsm_calls[index_in_table].clip_type = type; 226 227 int clip_number_size = strlen(number) < HFP_GSM_MAX_CALL_NUMBER_SIZE ? (int) strlen(number) : HFP_GSM_MAX_CALL_NUMBER_SIZE-1; 228 strncpy(gsm_calls[index_in_table].clip_number, number, clip_number_size); 229 gsm_calls[index_in_table].clip_number[clip_number_size] = '\0'; 230 strncpy(last_dialed_number, number, clip_number_size); 231 last_dialed_number[clip_number_size] = '\0'; 232 233 clip_type = 0; 234 memset(clip_number, 0, sizeof(clip_number)); 235 } 236 237 static void delete_call(int delete_index_in_table){ 238 int i ; 239 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 240 if (gsm_calls[i].index > gsm_calls[delete_index_in_table].index){ 241 gsm_calls[i].index--; 242 } 243 } 244 free_call_slot(delete_index_in_table); 245 246 gsm_calls[delete_index_in_table].clip_type = 0; 247 gsm_calls[delete_index_in_table].index = 0; 248 gsm_calls[delete_index_in_table].clip_number[0] = '\0'; 249 gsm_calls[delete_index_in_table].mpty = HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL; 250 } 251 252 253 static void create_call(hfp_enhanced_call_dir_t direction){ 254 int next_free_slot = get_next_free_slot(); 255 gsm_calls[next_free_slot].direction = direction; 256 gsm_calls[next_free_slot].index = next_call_index(); 257 set_enhanced_call_status_initiated(next_free_slot); 258 gsm_calls[next_free_slot].clip_type = 0; 259 gsm_calls[next_free_slot].clip_number[0] = '\0'; 260 gsm_calls[next_free_slot].mpty = HFP_ENHANCED_CALL_MPTY_NOT_A_CONFERENCE_CALL; 261 262 hfp_gsm_set_clip(next_free_slot, clip_type, clip_number); 263 } 264 265 266 int hfp_gsm_get_number_of_calls(void){ 267 return HFP_GSM_MAX_NR_CALLS - get_number_none_calls(); 268 } 269 270 void hfp_gsm_clear_last_dialed_number(void){ 271 memset(last_dialed_number, 0, sizeof(last_dialed_number)); 272 } 273 274 char * hfp_gsm_last_dialed_number(void){ 275 return &last_dialed_number[0]; 276 } 277 278 hfp_gsm_call_t * hfp_gsm_call(int call_index){ 279 int i; 280 281 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 282 hfp_gsm_call_t * call = &gsm_calls[i]; 283 if (call->index != call_index) continue; 284 return call; 285 } 286 return NULL; 287 } 288 289 uint8_t hfp_gsm_clip_type(void){ 290 if (clip_type != 0) return clip_type; 291 292 int initiated_call_index = get_initiated_call_index(); 293 if (initiated_call_index != -1){ 294 if (gsm_calls[initiated_call_index].clip_type != 0) { 295 return gsm_calls[initiated_call_index].clip_type; 296 } 297 } 298 299 int active_call_index = get_active_call_index(); 300 if (active_call_index != -1){ 301 if (gsm_calls[active_call_index].clip_type != 0) { 302 return gsm_calls[active_call_index].clip_type; 303 } 304 } 305 return 0; 306 } 307 308 char * hfp_gsm_clip_number(void){ 309 if (strlen(clip_number) != 0) return clip_number; 310 311 int initiated_call_index = get_initiated_call_index(); 312 if (initiated_call_index != -1){ 313 if (gsm_calls[initiated_call_index].clip_type != 0) { 314 return gsm_calls[initiated_call_index].clip_number; 315 } 316 } 317 318 int active_call_index = get_active_call_index(); 319 if (active_call_index != -1){ 320 if (gsm_calls[active_call_index].clip_type != 0) { 321 return gsm_calls[active_call_index].clip_number; 322 } 323 } 324 clip_number[0] = 0; 325 return clip_number; 326 } 327 328 hfp_call_status_t hfp_gsm_call_status(void){ 329 if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){ 330 return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; 331 } 332 return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; 333 } 334 335 hfp_callheld_status_t hfp_gsm_callheld_status(void){ 336 // @note: order is important 337 if (get_number_held_calls() == 0){ 338 return HFP_CALLHELD_STATUS_NO_CALLS_HELD; 339 } 340 if (get_number_active_calls() == 0) { 341 return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS; 342 } 343 return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED; 344 } 345 346 hfp_callsetup_status_t hfp_gsm_callsetup_status(void){ 347 return callsetup_status; 348 } 349 350 static int hfp_gsm_response_held_active(void){ 351 return get_response_held_call_index() != -1 ; 352 } 353 354 int hfp_gsm_call_possible(void){ 355 return get_number_none_calls() > 0; 356 } 357 358 void hfp_gsm_handle_event(hfp_ag_call_event_t event){ 359 hfp_gsm_handler(event, 0, 0, NULL); 360 } 361 362 void hfp_gsm_handle_event_with_clip(hfp_ag_call_event_t event, uint8_t type, const char * number){ 363 hfp_gsm_handler(event, 0, type, number); 364 } 365 366 void hfp_gsm_handle_event_with_call_index(hfp_ag_call_event_t event, uint8_t index){ 367 hfp_gsm_handler(event, index, 0, NULL); 368 } 369 370 void hfp_gsm_handle_event_with_call_number(hfp_ag_call_event_t event, const char * number){ 371 hfp_gsm_handler(event, 0, 0, number); 372 } 373 374 static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number){ 375 int next_free_slot = get_next_free_slot(); 376 int current_call_index = get_active_call_index(); 377 int initiated_call_index = get_initiated_call_index(); 378 int held_call_index = get_held_call_index(); 379 int i; 380 381 switch (event){ 382 case HFP_AG_OUTGOING_CALL_INITIATED: 383 case HFP_AG_OUTGOING_REDIAL_INITIATED: 384 if (next_free_slot == -1){ 385 log_error("gsm: max call nr exceeded"); 386 return; 387 } 388 create_call(HFP_ENHANCED_CALL_DIR_OUTGOING); 389 break; 390 391 case HFP_AG_OUTGOING_CALL_REJECTED: 392 if (current_call_index != -1){ 393 delete_call(current_call_index); 394 } 395 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 396 break; 397 398 case HFP_AG_OUTGOING_CALL_ACCEPTED: 399 if (current_call_index != -1){ 400 set_enhanced_call_status_held(current_call_index); 401 } 402 set_callsetup_status(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE); 403 break; 404 405 case HFP_AG_OUTGOING_CALL_RINGING: 406 if (current_call_index == -1){ 407 log_error("gsm: no active call"); 408 return; 409 } 410 set_callsetup_status(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE); 411 break; 412 case HFP_AG_OUTGOING_CALL_ESTABLISHED: 413 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 414 set_enhanced_call_status_active(initiated_call_index); 415 break; 416 417 case HFP_AG_INCOMING_CALL: 418 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break; 419 set_callsetup_status(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); 420 create_call(HFP_ENHANCED_CALL_DIR_INCOMING); 421 break; 422 423 case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 424 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 425 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 426 427 if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 428 set_enhanced_call_status_held(current_call_index); 429 } 430 set_enhanced_call_status_active(initiated_call_index); 431 break; 432 433 case HFP_AG_HELD_CALL_JOINED_BY_AG: 434 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 435 436 // TODO: is following condition correct? Can we join incoming call before it is answered? 437 if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 438 set_enhanced_call_status_active(initiated_call_index); 439 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 440 } else if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) { 441 set_enhanced_call_status_active(held_call_index); 442 } 443 444 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 445 if (is_enhanced_call_status_active(i)){ 446 gsm_calls[i].mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL; 447 } 448 } 449 break; 450 451 case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 452 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 453 if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 454 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 455 set_enhanced_call_status_active(initiated_call_index); 456 break; 457 458 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: 459 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: 460 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 461 if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 462 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 463 set_enhanced_call_status_response_hold(initiated_call_index); 464 break; 465 466 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG: 467 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: 468 if (!hfp_gsm_response_held_active()) break; 469 set_enhanced_call_status_active(get_response_held_call_index()); 470 break; 471 472 case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG: 473 case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: 474 if (!hfp_gsm_response_held_active()) break; 475 delete_call(get_response_held_call_index()); 476 break; 477 478 479 case HFP_AG_TERMINATE_CALL_BY_HF: 480 switch (hfp_gsm_call_status()){ 481 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 482 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 483 break; 484 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 485 delete_call(current_call_index); 486 break; 487 } 488 break; 489 490 case HFP_AG_TERMINATE_CALL_BY_AG: 491 switch (hfp_gsm_call_status()){ 492 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 493 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 494 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 495 break; 496 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 497 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 498 delete_call(current_call_index); 499 break; 500 default: 501 break; 502 } 503 break; 504 505 case HFP_AG_CALL_DROPPED: 506 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 507 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 508 509 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 510 delete_call(i); 511 } 512 break; 513 514 case HFP_AG_CALL_HOLD_USER_BUSY: 515 // Held or waiting call gets active, 516 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 517 free_call_slot(initiated_call_index); 518 set_enhanced_call_status_active(held_call_index); 519 break; 520 521 case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 522 if (index != 0 && index <= HFP_GSM_MAX_NR_CALLS ){ 523 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 524 if (gsm_calls[i].index == index){ 525 delete_call(i); 526 continue; 527 } 528 } 529 } else { 530 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 531 if (is_enhanced_call_status_active(i)){ 532 delete_call(i); 533 } 534 } 535 } 536 537 if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 538 set_enhanced_call_status_active(initiated_call_index); 539 } else { 540 set_enhanced_call_status_active(held_call_index); 541 } 542 543 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 544 break; 545 546 case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 547 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 548 if (is_enhanced_call_status_active(i) && gsm_calls[i].index != index){ 549 set_enhanced_call_status_held(i); 550 } 551 } 552 553 if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 554 set_enhanced_call_status_active(initiated_call_index); 555 } else { 556 set_enhanced_call_status_active(held_call_index); 557 } 558 set_callsetup_status(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 559 break; 560 561 case HFP_AG_CALL_HOLD_ADD_HELD_CALL: 562 if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 563 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 564 if (gsm_calls[i].used_slot){ 565 set_enhanced_call_status_active(i); 566 gsm_calls[i].mpty = HFP_ENHANCED_CALL_MPTY_CONFERENCE_CALL; 567 } 568 } 569 } 570 break; 571 572 case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS: 573 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 574 delete_call(i); 575 } 576 break; 577 578 case HFP_AG_SET_CLIP: 579 if (initiated_call_index != -1){ 580 hfp_gsm_set_clip(initiated_call_index, type, number); 581 break; 582 } 583 584 clip_type = type; 585 strncpy(clip_number, number, sizeof(clip_number)); 586 clip_number[sizeof(clip_number)-1] = '\0'; 587 588 break; 589 default: 590 break; 591 } 592 }