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 // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!) 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.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 65 typedef enum{ 66 CALL_NONE, 67 CALL_INITIATED, 68 CALL_RESPONSE_HOLD, 69 CALL_ACTIVE, 70 CALL_HELD 71 } hfp_gsm_call_status_t; 72 73 74 typedef struct { 75 hfp_gsm_call_status_t status; 76 int index; 77 uint8_t clip_type; 78 char clip_number[25]; 79 } hfp_gsm_call_t; 80 81 static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS]; 82 static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 83 84 static uint8_t clip_type; 85 static char clip_number[25]; 86 87 static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number); 88 89 void hfp_gsm_init(void){ 90 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 91 clip_type = 0; 92 memset(clip_number, 0, sizeof(clip_number)); 93 94 memset(gsm_calls, 0, sizeof(gsm_calls)); 95 int i; 96 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 97 gsm_calls[i].status = CALL_NONE; 98 } 99 } 100 101 static int get_number_calls_with_status(hfp_gsm_call_status_t status){ 102 int i, count = 0; 103 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 104 if (gsm_calls[i].status == status) count++; 105 } 106 return count; 107 } 108 109 static int get_call_index_with_status(hfp_gsm_call_status_t status){ 110 int i ; 111 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 112 if (gsm_calls[i].status == status) return i; 113 } 114 return -1; 115 } 116 117 static inline int get_next_free_slot(){ 118 return get_call_index_with_status(CALL_NONE); 119 } 120 121 static inline int get_active_call_index(){ 122 return get_call_index_with_status(CALL_ACTIVE); 123 } 124 125 static inline int get_initiated_call_index(){ 126 return get_call_index_with_status(CALL_INITIATED); 127 } 128 129 static inline int get_held_call_index(){ 130 return get_call_index_with_status(CALL_HELD); 131 } 132 133 static inline int get_response_held_call_index(){ 134 return get_call_index_with_status(CALL_RESPONSE_HOLD); 135 } 136 137 static inline int get_number_none_calls(){ 138 return get_number_calls_with_status(CALL_NONE); 139 } 140 141 static inline int get_number_active_calls(){ 142 return get_number_calls_with_status(CALL_ACTIVE); 143 } 144 145 static inline int get_number_held_calls(){ 146 return get_number_calls_with_status(CALL_HELD); 147 } 148 149 static inline int get_number_response_held_calls(){ 150 return get_number_calls_with_status(CALL_RESPONSE_HOLD); 151 } 152 153 static int next_call_index(){ 154 return HFP_GSM_MAX_NR_CALLS + 1 - get_number_none_calls(); 155 } 156 157 static void hfp_gsm_set_clip(int index_in_table, uint8_t type, const char * number){ 158 gsm_calls[index_in_table].clip_type = type; 159 160 int clip_number_size = sizeof(gsm_calls[index_in_table].clip_number); 161 strncpy(gsm_calls[index_in_table].clip_number, number, clip_number_size); 162 gsm_calls[index_in_table].clip_number[clip_number_size-1] = '\0'; 163 } 164 165 static void delete_call(int delete_index_in_table){ 166 int i ; 167 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 168 if (gsm_calls[i].index > gsm_calls[delete_index_in_table].index){ 169 gsm_calls[i].index--; 170 } 171 } 172 173 gsm_calls[delete_index_in_table].status = CALL_NONE; 174 gsm_calls[delete_index_in_table].clip_type = 0; 175 gsm_calls[delete_index_in_table].index = 0; 176 gsm_calls[delete_index_in_table].clip_number[0] = '\0'; 177 } 178 179 static void create_call(){ 180 int next_free_slot = get_next_free_slot(); 181 gsm_calls[next_free_slot].index = next_call_index(); 182 gsm_calls[next_free_slot].status = CALL_INITIATED; 183 gsm_calls[next_free_slot].clip_type = 0; 184 gsm_calls[next_free_slot].clip_number[0] = '\0'; 185 186 if (clip_type != 0){ 187 hfp_gsm_set_clip(next_free_slot, clip_type, clip_number); 188 clip_type = 0; 189 memset(clip_number, 0, sizeof(clip_number)); 190 } 191 } 192 193 uint8_t hfp_gsm_clip_type(){ 194 if (clip_type != 0) return clip_type; 195 196 int initiated_call_index = get_initiated_call_index(); 197 if (initiated_call_index != -1){ 198 if (gsm_calls[initiated_call_index].clip_type != 0) { 199 return gsm_calls[initiated_call_index].clip_type; 200 } 201 } 202 203 int active_call_index = get_active_call_index(); 204 if (active_call_index != -1){ 205 if (gsm_calls[active_call_index].clip_type != 0) { 206 return gsm_calls[active_call_index].clip_type; 207 } 208 } 209 return 0; 210 } 211 212 char * hfp_gsm_clip_number(){ 213 if (clip_type != 0) return clip_number; 214 215 int initiated_call_index = get_initiated_call_index(); 216 if (initiated_call_index != -1){ 217 if (gsm_calls[initiated_call_index].clip_type != 0) { 218 return gsm_calls[initiated_call_index].clip_number; 219 } 220 } 221 222 int active_call_index = get_active_call_index(); 223 if (active_call_index != -1){ 224 if (gsm_calls[active_call_index].clip_type != 0) { 225 return gsm_calls[active_call_index].clip_number; 226 } 227 } 228 clip_number[0] = 0; 229 return clip_number; 230 } 231 232 hfp_call_status_t hfp_gsm_call_status(){ 233 if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){ 234 return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT; 235 } 236 return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; 237 } 238 239 hfp_callheld_status_t hfp_gsm_callheld_status(){ 240 // @note: order is important 241 if (get_number_held_calls() == 0){ 242 return HFP_CALLHELD_STATUS_NO_CALLS_HELD; 243 } 244 if (get_number_active_calls() == 0) { 245 return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS; 246 } 247 return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED; 248 } 249 250 hfp_callsetup_status_t hfp_gsm_callsetup_status(){ 251 return callsetup_status; 252 } 253 254 int hfp_gsm_response_held_active(){ 255 return get_response_held_call_index() != -1 ; 256 } 257 258 int hfp_gsm_call_possible(void){ 259 return get_number_none_calls() > 0; 260 } 261 262 void hfp_gsm_handle_event(hfp_ag_call_event_t event){ 263 hfp_gsm_handler(event, 0, 0, NULL); 264 } 265 266 void hfp_gsm_handle_event_with_clip(hfp_ag_call_event_t event, uint8_t type, const char * number){ 267 hfp_gsm_handler(event, 0, type, number); 268 } 269 270 void hfp_gsm_handle_event_with_call_index(hfp_ag_call_event_t event, uint8_t index){ 271 hfp_gsm_handler(event, index, 0, NULL); 272 } 273 274 static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number){ 275 int next_free_slot = get_next_free_slot(); 276 int current_call_index = get_active_call_index(); 277 int initiated_call_index = get_initiated_call_index(); 278 int held_call_index = get_held_call_index(); 279 int i; 280 281 switch (event){ 282 case HFP_AG_OUTGOING_CALL_INITIATED: 283 case HFP_AG_OUTGOING_REDIAL_INITIATED: 284 if (next_free_slot == -1){ 285 log_error("gsm: max call nr exceeded"); 286 return; 287 } 288 create_call(); 289 break; 290 291 case HFP_AG_OUTGOING_CALL_REJECTED: 292 if (current_call_index != -1){ 293 // gsm_calls[current_call_index].status = CALL_NONE; 294 delete_call(current_call_index); 295 } 296 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 297 break; 298 299 case HFP_AG_OUTGOING_CALL_ACCEPTED: 300 if (current_call_index != -1){ 301 gsm_calls[current_call_index].status = CALL_HELD; 302 } 303 create_call(); 304 callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE; 305 break; 306 307 case HFP_AG_OUTGOING_CALL_RINGING: 308 if (current_call_index == -1){ 309 log_error("gsm: no active call"); 310 return; 311 } 312 callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE; 313 break; 314 case HFP_AG_OUTGOING_CALL_ESTABLISHED: 315 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 316 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 317 break; 318 319 case HFP_AG_INCOMING_CALL: 320 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break; 321 callsetup_status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS; 322 create_call(); 323 break; 324 325 case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 326 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 327 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 328 329 if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 330 gsm_calls[current_call_index].status = CALL_HELD; 331 } 332 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 333 break; 334 335 case HFP_AG_HELD_CALL_JOINED_BY_AG: 336 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 337 338 // TODO: mark joined calls with "multiparty flag" (if we cannot calculate it otherwise) 339 // TODO: is following condition correct? Can we join incoming call before it is answered? 340 if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){ 341 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 342 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 343 break; 344 } 345 346 if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) { 347 gsm_calls[held_call_index].status = CALL_ACTIVE; 348 break; 349 } 350 break; 351 352 case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 353 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 354 if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 355 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 356 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 357 break; 358 359 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG: 360 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF: 361 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 362 if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break; 363 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 364 gsm_calls[initiated_call_index].status = CALL_RESPONSE_HOLD; 365 break; 366 367 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG: 368 case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF: 369 if (!hfp_gsm_response_held_active()) break; 370 gsm_calls[get_response_held_call_index()].status = CALL_ACTIVE; 371 break; 372 373 case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG: 374 case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF: 375 if (!hfp_gsm_response_held_active()) break; 376 // gsm_calls[get_response_held_call_index()].status = CALL_NONE; 377 delete_call(get_response_held_call_index()); 378 break; 379 380 381 case HFP_AG_TERMINATE_CALL_BY_HF: 382 switch (hfp_gsm_call_status()){ 383 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 384 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 385 break; 386 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 387 // gsm_calls[current_call_index].status = CALL_NONE; 388 delete_call(current_call_index); 389 break; 390 } 391 break; 392 393 case HFP_AG_TERMINATE_CALL_BY_AG: 394 switch (hfp_gsm_call_status()){ 395 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 396 if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break; 397 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 398 break; 399 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 400 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 401 // gsm_calls[current_call_index].status = CALL_NONE; 402 delete_call(current_call_index); 403 break; 404 default: 405 break; 406 } 407 break; 408 409 case HFP_AG_CALL_DROPPED: 410 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 411 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break; 412 413 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 414 delete_call(i); 415 } 416 break; 417 418 case HFP_AG_CALL_HOLD_USER_BUSY: 419 // Held or waiting call gets active, 420 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 421 gsm_calls[initiated_call_index].status = CALL_NONE; 422 gsm_calls[held_call_index].status = CALL_ACTIVE; 423 break; 424 425 case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 426 if (index != 0 && index <= HFP_GSM_MAX_NR_CALLS ){ 427 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 428 if (gsm_calls[i].index == index){ 429 delete_call(i); 430 continue; 431 } 432 } 433 } else { 434 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 435 if (gsm_calls[i].status == CALL_ACTIVE){ 436 delete_call(i); 437 } 438 } 439 } 440 441 if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 442 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 443 } else { 444 gsm_calls[held_call_index].status = CALL_ACTIVE; 445 } 446 447 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 448 break; 449 450 case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL: 451 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 452 if (gsm_calls[i].status == CALL_ACTIVE && gsm_calls[i].index != index){ 453 gsm_calls[i].clip_type = 0; 454 gsm_calls[i].clip_number[0] = '\0'; 455 gsm_calls[i].status = CALL_HELD; 456 } 457 } 458 459 if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 460 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 461 } else { 462 gsm_calls[held_call_index].status = CALL_ACTIVE; 463 } 464 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 465 break; 466 467 case HFP_AG_CALL_HOLD_ADD_HELD_CALL: 468 if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 469 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 470 if (gsm_calls[i].status == CALL_HELD){ 471 gsm_calls[i].clip_type = 0; 472 gsm_calls[i].clip_number[0] = '\0'; 473 gsm_calls[i].status = CALL_ACTIVE; 474 } 475 } 476 } 477 gsm_calls[initiated_call_index].status = CALL_ACTIVE; 478 break; 479 480 case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS: 481 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){ 482 delete_call(i); 483 } 484 break; 485 486 case HFP_AG_SET_CLIP: 487 if (initiated_call_index != -1){ 488 hfp_gsm_set_clip(initiated_call_index, type, number); 489 break; 490 } 491 if (current_call_index != -1){ 492 hfp_gsm_set_clip(current_call_index, type, number); 493 break; 494 } 495 clip_type = type; 496 strncpy(clip_number, number, sizeof(clip_number)); 497 clip_number[sizeof(clip_number)-1] = '\0'; 498 499 break; 500 default: 501 break; 502 } 503 }