xref: /btstack/src/classic/hfp_gsm_model.c (revision 8257e5f9e1a9f15ac2fe1e69adc5d2eeeadf3fff)
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 }