xref: /btstack/src/classic/hfp_gsm_model.c (revision d210d9c4c04e085d9ff7b69e25d289dddd16b904)
174386ee0SMatthias Ringwald /*
274386ee0SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
374386ee0SMatthias Ringwald  *
474386ee0SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
574386ee0SMatthias Ringwald  * modification, are permitted provided that the following conditions
674386ee0SMatthias Ringwald  * are met:
774386ee0SMatthias Ringwald  *
874386ee0SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
974386ee0SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
1074386ee0SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1174386ee0SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
1274386ee0SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
1374386ee0SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
1474386ee0SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
1574386ee0SMatthias Ringwald  *    from this software without specific prior written permission.
1674386ee0SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
1774386ee0SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
1874386ee0SMatthias Ringwald  *    monetary gain.
1974386ee0SMatthias Ringwald  *
2074386ee0SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2174386ee0SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2274386ee0SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2374386ee0SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
2474386ee0SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2574386ee0SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2674386ee0SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2774386ee0SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2874386ee0SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2974386ee0SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3074386ee0SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3174386ee0SMatthias Ringwald  * SUCH DAMAGE.
3274386ee0SMatthias Ringwald  *
3374386ee0SMatthias Ringwald  * Please inquire about commercial licensing options at
3474386ee0SMatthias Ringwald  * [email protected]
3574386ee0SMatthias Ringwald  *
3674386ee0SMatthias Ringwald  */
3774386ee0SMatthias Ringwald 
3874386ee0SMatthias Ringwald // *****************************************************************************
3974386ee0SMatthias Ringwald //
4074386ee0SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
4174386ee0SMatthias Ringwald //
4274386ee0SMatthias Ringwald // *****************************************************************************
4374386ee0SMatthias Ringwald 
4474386ee0SMatthias Ringwald #include "btstack-config.h"
4574386ee0SMatthias Ringwald 
4674386ee0SMatthias Ringwald #include <stdint.h>
4774386ee0SMatthias Ringwald #include <stdio.h>
4874386ee0SMatthias Ringwald #include <stdlib.h>
4974386ee0SMatthias Ringwald #include <string.h>
5074386ee0SMatthias Ringwald 
5174386ee0SMatthias Ringwald #include "btstack_memory.h"
5274386ee0SMatthias Ringwald #include "classic/hfp.h"
5374386ee0SMatthias Ringwald #include "classic/hfp_gsm_model.h"
5474386ee0SMatthias Ringwald #include "classic/sdp.h"
5574386ee0SMatthias Ringwald #include "classic/sdp_query_rfcomm.h"
5674386ee0SMatthias Ringwald #include "debug.h"
5774386ee0SMatthias Ringwald #include "hci.h"
5874386ee0SMatthias Ringwald #include "hci_cmds.h"
5974386ee0SMatthias Ringwald #include "hci_dump.h"
6074386ee0SMatthias Ringwald #include "l2cap.h"
6174386ee0SMatthias Ringwald #include "run_loop.h"
6274386ee0SMatthias Ringwald 
6374386ee0SMatthias Ringwald #define HFP_GSM_MAX_NR_CALLS 3
6474386ee0SMatthias Ringwald 
6574386ee0SMatthias Ringwald typedef enum{
6674386ee0SMatthias Ringwald     CALL_NONE,
67*d210d9c4SMatthias Ringwald     CALL_INITIATED,
68*d210d9c4SMatthias Ringwald     CALL_RESPONSE_HOLD,
6974386ee0SMatthias Ringwald     CALL_ACTIVE,
7074386ee0SMatthias Ringwald     CALL_HELD
7174386ee0SMatthias Ringwald } hfp_gsm_call_status_t;
7274386ee0SMatthias Ringwald 
7374386ee0SMatthias Ringwald 
7474386ee0SMatthias Ringwald typedef struct {
7574386ee0SMatthias Ringwald     hfp_gsm_call_status_t status;
76*d210d9c4SMatthias Ringwald     uint8_t clip_type;
77*d210d9c4SMatthias Ringwald     char    clip_number[25];
7874386ee0SMatthias Ringwald } hfp_gsm_call_t;
7974386ee0SMatthias Ringwald 
8074386ee0SMatthias Ringwald static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS];
8174386ee0SMatthias Ringwald static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
8274386ee0SMatthias Ringwald 
83*d210d9c4SMatthias Ringwald void hfp_gsm_init(void){
84*d210d9c4SMatthias Ringwald     memset(gsm_calls, 0, sizeof(gsm_calls));
85*d210d9c4SMatthias Ringwald     int i;
86*d210d9c4SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
87*d210d9c4SMatthias Ringwald         gsm_calls[i].status = CALL_NONE;
88*d210d9c4SMatthias Ringwald     }
89*d210d9c4SMatthias Ringwald     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
90*d210d9c4SMatthias Ringwald }
9174386ee0SMatthias Ringwald 
9274386ee0SMatthias Ringwald static int get_number_calls_with_status(hfp_gsm_call_status_t status){
9374386ee0SMatthias Ringwald     int i, count = 0;
9474386ee0SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
9574386ee0SMatthias Ringwald         if (gsm_calls[i].status == status) count++;
9674386ee0SMatthias Ringwald     }
9774386ee0SMatthias Ringwald     return count;
9874386ee0SMatthias Ringwald }
9974386ee0SMatthias Ringwald 
10074386ee0SMatthias Ringwald static int get_call_index_with_status(hfp_gsm_call_status_t status){
10174386ee0SMatthias Ringwald     int i ;
10274386ee0SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
10374386ee0SMatthias Ringwald         if (gsm_calls[i].status == status) return i;
10474386ee0SMatthias Ringwald     }
10574386ee0SMatthias Ringwald     return -1;
10674386ee0SMatthias Ringwald }
10774386ee0SMatthias Ringwald 
10874386ee0SMatthias Ringwald static inline int get_none_call_index(){
10974386ee0SMatthias Ringwald     return get_call_index_with_status(CALL_NONE);
11074386ee0SMatthias Ringwald }
11174386ee0SMatthias Ringwald 
11274386ee0SMatthias Ringwald static inline int get_active_call_index(){
11374386ee0SMatthias Ringwald     return get_call_index_with_status(CALL_ACTIVE);
11474386ee0SMatthias Ringwald }
11574386ee0SMatthias Ringwald 
116*d210d9c4SMatthias Ringwald static inline int get_initiated_call_index(){
117*d210d9c4SMatthias Ringwald     return get_call_index_with_status(CALL_INITIATED);
118*d210d9c4SMatthias Ringwald }
119*d210d9c4SMatthias Ringwald 
120*d210d9c4SMatthias Ringwald static inline int get_held_call_index(){
121*d210d9c4SMatthias Ringwald     return get_call_index_with_status(CALL_HELD);
122*d210d9c4SMatthias Ringwald }
123*d210d9c4SMatthias Ringwald 
124*d210d9c4SMatthias Ringwald static inline int get_response_held_call_index(){
125*d210d9c4SMatthias Ringwald     return get_call_index_with_status(CALL_RESPONSE_HOLD);
126*d210d9c4SMatthias Ringwald }
127*d210d9c4SMatthias Ringwald 
128*d210d9c4SMatthias Ringwald static inline int get_number_none_calls(){
129*d210d9c4SMatthias Ringwald     return get_number_calls_with_status(CALL_NONE);
130*d210d9c4SMatthias Ringwald }
13174386ee0SMatthias Ringwald 
13274386ee0SMatthias Ringwald static inline int get_number_active_calls(){
13374386ee0SMatthias Ringwald     return get_number_calls_with_status(CALL_ACTIVE);
13474386ee0SMatthias Ringwald }
13574386ee0SMatthias Ringwald 
13674386ee0SMatthias Ringwald static inline int get_number_held_calls(){
13774386ee0SMatthias Ringwald     return get_number_calls_with_status(CALL_HELD);
13874386ee0SMatthias Ringwald }
13974386ee0SMatthias Ringwald 
140*d210d9c4SMatthias Ringwald static inline int get_number_response_held_calls(){
141*d210d9c4SMatthias Ringwald     return get_number_calls_with_status(CALL_RESPONSE_HOLD);
142*d210d9c4SMatthias Ringwald }
143*d210d9c4SMatthias Ringwald 
14474386ee0SMatthias Ringwald hfp_call_status_t hfp_gsm_call_status(){
145*d210d9c4SMatthias Ringwald     if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){
14674386ee0SMatthias Ringwald         return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT;
14774386ee0SMatthias Ringwald     }
14874386ee0SMatthias Ringwald     return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS;
14974386ee0SMatthias Ringwald }
15074386ee0SMatthias Ringwald 
15174386ee0SMatthias Ringwald hfp_callheld_status_t hfp_gsm_callheld_status(){
15274386ee0SMatthias Ringwald     // @note: order is important
15374386ee0SMatthias Ringwald     if (get_number_held_calls() == 0){
15474386ee0SMatthias Ringwald         return HFP_CALLHELD_STATUS_NO_CALLS_HELD;
15574386ee0SMatthias Ringwald     }
15674386ee0SMatthias Ringwald     if (get_number_active_calls() == 0) {
15774386ee0SMatthias Ringwald         return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS;
15874386ee0SMatthias Ringwald     }
15974386ee0SMatthias Ringwald     return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED;
16074386ee0SMatthias Ringwald }
16174386ee0SMatthias Ringwald 
16274386ee0SMatthias Ringwald hfp_callsetup_status_t hfp_gsm_callsetup_status(){
16374386ee0SMatthias Ringwald     return callsetup_status;
16474386ee0SMatthias Ringwald }
16574386ee0SMatthias Ringwald 
166*d210d9c4SMatthias Ringwald int hfp_gsm_response_held_active(){
167*d210d9c4SMatthias Ringwald     return get_response_held_call_index() != -1 ;
168*d210d9c4SMatthias Ringwald }
169*d210d9c4SMatthias Ringwald 
170*d210d9c4SMatthias Ringwald int hfp_gsm_call_possible(void){
171*d210d9c4SMatthias Ringwald     return get_number_none_calls() > 0;
172*d210d9c4SMatthias Ringwald }
173*d210d9c4SMatthias Ringwald 
17474386ee0SMatthias Ringwald void hfp_gsm_handle_event(hfp_ag_call_event_t event){
17574386ee0SMatthias Ringwald     int next_free_slot = get_none_call_index();
17674386ee0SMatthias Ringwald     int current_call_index = get_active_call_index();
177*d210d9c4SMatthias Ringwald     int initiated_call_index = get_initiated_call_index();
178*d210d9c4SMatthias Ringwald     int held_call_index = get_held_call_index();
179*d210d9c4SMatthias Ringwald     printf("hfp_gsm_handle_event %d \n", event);
18074386ee0SMatthias Ringwald     switch (event){
18174386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_INITIATED:
18274386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_REDIAL_INITIATED:
18374386ee0SMatthias Ringwald             if (next_free_slot == -1){
184*d210d9c4SMatthias Ringwald                 log_error("gsm: max call nr exceeded");
18574386ee0SMatthias Ringwald                 return;
18674386ee0SMatthias Ringwald             }
187*d210d9c4SMatthias Ringwald             break;
18874386ee0SMatthias Ringwald 
189*d210d9c4SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_REJECTED:
190*d210d9c4SMatthias Ringwald             if (current_call_index != -1){
191*d210d9c4SMatthias Ringwald                 gsm_calls[current_call_index].status = CALL_NONE;
192*d210d9c4SMatthias Ringwald             }
193*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
194*d210d9c4SMatthias Ringwald             break;
195*d210d9c4SMatthias Ringwald 
196*d210d9c4SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_ACCEPTED:
19774386ee0SMatthias Ringwald             if (current_call_index != -1){
19874386ee0SMatthias Ringwald                 gsm_calls[current_call_index].status = CALL_HELD;
19974386ee0SMatthias Ringwald             }
200*d210d9c4SMatthias Ringwald             gsm_calls[next_free_slot].status = CALL_INITIATED;
20174386ee0SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE;
20274386ee0SMatthias Ringwald             break;
203*d210d9c4SMatthias Ringwald 
20474386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_RINGING:
205*d210d9c4SMatthias Ringwald             if (current_call_index == -1){
206*d210d9c4SMatthias Ringwald                 log_error("gsm: no active call");
207*d210d9c4SMatthias Ringwald                 return;
208*d210d9c4SMatthias Ringwald             }
209*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE;
21074386ee0SMatthias Ringwald             break;
21174386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_ESTABLISHED:
212*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
213*d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
21474386ee0SMatthias Ringwald             break;
215*d210d9c4SMatthias Ringwald 
216*d210d9c4SMatthias Ringwald         case HFP_AG_INCOMING_CALL:
217*d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break;
218*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS;
219*d210d9c4SMatthias Ringwald             gsm_calls[next_free_slot].status = CALL_INITIATED;
220*d210d9c4SMatthias Ringwald             gsm_calls[next_free_slot].clip_type = 0;
221*d210d9c4SMatthias Ringwald             break;
222*d210d9c4SMatthias Ringwald 
223*d210d9c4SMatthias Ringwald         case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
224*d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
225*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
226*d210d9c4SMatthias Ringwald 
227*d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
228*d210d9c4SMatthias Ringwald                 gsm_calls[current_call_index].status = CALL_HELD;
229*d210d9c4SMatthias Ringwald             }
230*d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
231*d210d9c4SMatthias Ringwald             break;
232*d210d9c4SMatthias Ringwald 
233*d210d9c4SMatthias Ringwald         case HFP_AG_HELD_CALL_JOINED_BY_AG:
234*d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
235*d210d9c4SMatthias Ringwald 
236*d210d9c4SMatthias Ringwald             // TODO: mark joined calls with "multiparty flag" (if we cannot calculate it otherwise)
237*d210d9c4SMatthias Ringwald             // TODO: is following condition correct? Can we join incoming call before it is answered?
238*d210d9c4SMatthias Ringwald             if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
239*d210d9c4SMatthias Ringwald                 gsm_calls[initiated_call_index].status = CALL_ACTIVE;
240*d210d9c4SMatthias Ringwald                 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
241*d210d9c4SMatthias Ringwald                 break;
242*d210d9c4SMatthias Ringwald             }
243*d210d9c4SMatthias Ringwald 
244*d210d9c4SMatthias Ringwald             if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) {
245*d210d9c4SMatthias Ringwald                 gsm_calls[held_call_index].status = CALL_ACTIVE;
246*d210d9c4SMatthias Ringwald                 break;
247*d210d9c4SMatthias Ringwald             }
248*d210d9c4SMatthias Ringwald             break;
249*d210d9c4SMatthias Ringwald 
250*d210d9c4SMatthias Ringwald         case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
251*d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
252*d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
253*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
254*d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
255*d210d9c4SMatthias Ringwald             break;
256*d210d9c4SMatthias Ringwald 
257*d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG:
258*d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF:
259*d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
260*d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
261*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
262*d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_RESPONSE_HOLD;
263*d210d9c4SMatthias Ringwald             break;
264*d210d9c4SMatthias Ringwald 
265*d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG:
266*d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
267*d210d9c4SMatthias Ringwald             if (!hfp_gsm_response_held_active()) break;
268*d210d9c4SMatthias Ringwald             gsm_calls[get_response_held_call_index()].status = CALL_ACTIVE;
269*d210d9c4SMatthias Ringwald             break;
270*d210d9c4SMatthias Ringwald 
271*d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
272*d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF:
273*d210d9c4SMatthias Ringwald             if (!hfp_gsm_response_held_active()) break;
274*d210d9c4SMatthias Ringwald             gsm_calls[get_response_held_call_index()].status = CALL_NONE;
275*d210d9c4SMatthias Ringwald             break;
276*d210d9c4SMatthias Ringwald 
277*d210d9c4SMatthias Ringwald 
278*d210d9c4SMatthias Ringwald         case HFP_AG_TERMINATE_CALL_BY_HF:
279*d210d9c4SMatthias Ringwald             switch (hfp_gsm_call_status()){
280*d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
281*d210d9c4SMatthias Ringwald                     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
282*d210d9c4SMatthias Ringwald                     break;
283*d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
284*d210d9c4SMatthias Ringwald                     gsm_calls[current_call_index].status = CALL_NONE;
285*d210d9c4SMatthias Ringwald                     break;
286*d210d9c4SMatthias Ringwald             }
287*d210d9c4SMatthias Ringwald             break;
288*d210d9c4SMatthias Ringwald 
289*d210d9c4SMatthias Ringwald         case HFP_AG_TERMINATE_CALL_BY_AG:
290*d210d9c4SMatthias Ringwald             switch (hfp_gsm_call_status()){
291*d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
292*d210d9c4SMatthias Ringwald                     if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
293*d210d9c4SMatthias Ringwald                     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
294*d210d9c4SMatthias Ringwald                     break;
295*d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
296*d210d9c4SMatthias Ringwald                     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
297*d210d9c4SMatthias Ringwald                     gsm_calls[current_call_index].status = CALL_NONE;
298*d210d9c4SMatthias Ringwald                     break;
299*d210d9c4SMatthias Ringwald                 default:
300*d210d9c4SMatthias Ringwald                     break;
301*d210d9c4SMatthias Ringwald             }
302*d210d9c4SMatthias Ringwald             break;
303*d210d9c4SMatthias Ringwald 
304*d210d9c4SMatthias Ringwald         case HFP_AG_CALL_DROPPED:{
305*d210d9c4SMatthias Ringwald                 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
306*d210d9c4SMatthias Ringwald                 if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
307*d210d9c4SMatthias Ringwald 
308*d210d9c4SMatthias Ringwald                 int i ;
309*d210d9c4SMatthias Ringwald                 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
310*d210d9c4SMatthias Ringwald                     gsm_calls[i].status = CALL_NONE;
311*d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_type = 0;
312*d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_number[0] = '\0';
313*d210d9c4SMatthias Ringwald                 }
314*d210d9c4SMatthias Ringwald             }
315*d210d9c4SMatthias Ringwald             break;
316*d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_USER_BUSY:
317*d210d9c4SMatthias Ringwald             // Held or waiting call gets active,
318*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
319*d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_NONE;
320*d210d9c4SMatthias Ringwald             gsm_calls[held_call_index].status = CALL_ACTIVE;
321*d210d9c4SMatthias Ringwald             break;
322*d210d9c4SMatthias Ringwald 
323*d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
324*d210d9c4SMatthias Ringwald             int i ;
325*d210d9c4SMatthias Ringwald             for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
326*d210d9c4SMatthias Ringwald                 if (gsm_calls[i].status == CALL_ACTIVE){
327*d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_type = 0;
328*d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_number[0] = '\0';
329*d210d9c4SMatthias Ringwald                     gsm_calls[i].status = CALL_NONE;
330*d210d9c4SMatthias Ringwald                 }
331*d210d9c4SMatthias Ringwald             }
332*d210d9c4SMatthias Ringwald 
333*d210d9c4SMatthias Ringwald             if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
334*d210d9c4SMatthias Ringwald                 gsm_calls[initiated_call_index].status = CALL_ACTIVE;
335*d210d9c4SMatthias Ringwald             } else {
336*d210d9c4SMatthias Ringwald                 gsm_calls[held_call_index].status = CALL_ACTIVE;
337*d210d9c4SMatthias Ringwald             }
338*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
339*d210d9c4SMatthias Ringwald             break;
340*d210d9c4SMatthias Ringwald         }
341*d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:{
342*d210d9c4SMatthias Ringwald             int i ;
343*d210d9c4SMatthias Ringwald             for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
344*d210d9c4SMatthias Ringwald                 if (gsm_calls[i].status == CALL_ACTIVE){
345*d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_type = 0;
346*d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_number[0] = '\0';
347*d210d9c4SMatthias Ringwald                     gsm_calls[i].status = CALL_HELD;
348*d210d9c4SMatthias Ringwald                 }
349*d210d9c4SMatthias Ringwald             }
350*d210d9c4SMatthias Ringwald 
351*d210d9c4SMatthias Ringwald             if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
352*d210d9c4SMatthias Ringwald                 gsm_calls[initiated_call_index].status = CALL_ACTIVE;
353*d210d9c4SMatthias Ringwald             } else {
354*d210d9c4SMatthias Ringwald                 gsm_calls[held_call_index].status = CALL_ACTIVE;
355*d210d9c4SMatthias Ringwald             }
356*d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
357*d210d9c4SMatthias Ringwald             break;
358*d210d9c4SMatthias Ringwald         }
359*d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_ADD_HELD_CALL:{
360*d210d9c4SMatthias Ringwald             if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
361*d210d9c4SMatthias Ringwald                 int i ;
362*d210d9c4SMatthias Ringwald                 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
363*d210d9c4SMatthias Ringwald                     if (gsm_calls[i].status == CALL_HELD){
364*d210d9c4SMatthias Ringwald                         gsm_calls[i].clip_type = 0;
365*d210d9c4SMatthias Ringwald                         gsm_calls[i].clip_number[0] = '\0';
366*d210d9c4SMatthias Ringwald                         gsm_calls[i].status = CALL_ACTIVE;
367*d210d9c4SMatthias Ringwald                     }
368*d210d9c4SMatthias Ringwald                 }
369*d210d9c4SMatthias Ringwald             }
370*d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
371*d210d9c4SMatthias Ringwald 
372*d210d9c4SMatthias Ringwald             break;
373*d210d9c4SMatthias Ringwald         }
374*d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS:{
375*d210d9c4SMatthias Ringwald             int i ;
376*d210d9c4SMatthias Ringwald             for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
377*d210d9c4SMatthias Ringwald                 gsm_calls[i].clip_type = 0;
378*d210d9c4SMatthias Ringwald                 gsm_calls[i].clip_number[0] = '\0';
379*d210d9c4SMatthias Ringwald                 gsm_calls[i].status = CALL_NONE;
380*d210d9c4SMatthias Ringwald             }
381*d210d9c4SMatthias Ringwald 
382*d210d9c4SMatthias Ringwald             break;
383*d210d9c4SMatthias Ringwald         }
38474386ee0SMatthias Ringwald         default:
38574386ee0SMatthias Ringwald             break;
38674386ee0SMatthias Ringwald     }
38774386ee0SMatthias Ringwald }