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