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