xref: /btstack/src/classic/hfp_gsm_model.c (revision 56042629188ece1ffe1766326545c3c2833c10e8)
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"
5616ece135SMatthias Ringwald #include "btstack_debug.h"
5774386ee0SMatthias Ringwald #include "hci.h"
58*56042629SMatthias Ringwald #include "hci_cmd.h"
5974386ee0SMatthias Ringwald #include "hci_dump.h"
6074386ee0SMatthias Ringwald #include "l2cap.h"
6182636622SMatthias Ringwald #include "btstack_run_loop.h"
6274386ee0SMatthias Ringwald 
6374386ee0SMatthias Ringwald #define HFP_GSM_MAX_NR_CALLS 3
6474386ee0SMatthias Ringwald 
6574386ee0SMatthias Ringwald typedef enum{
6674386ee0SMatthias Ringwald     CALL_NONE,
67d210d9c4SMatthias Ringwald     CALL_INITIATED,
68d210d9c4SMatthias 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;
76d0c20769SMatthias Ringwald     int index;
77d210d9c4SMatthias Ringwald     uint8_t clip_type;
78d210d9c4SMatthias Ringwald     char    clip_number[25];
7974386ee0SMatthias Ringwald } hfp_gsm_call_t;
8074386ee0SMatthias Ringwald 
8174386ee0SMatthias Ringwald static hfp_gsm_call_t gsm_calls[HFP_GSM_MAX_NR_CALLS];
8274386ee0SMatthias Ringwald static hfp_callsetup_status_t callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
8374386ee0SMatthias Ringwald 
84d0c20769SMatthias Ringwald static uint8_t clip_type;
85d0c20769SMatthias Ringwald static char clip_number[25];
86d0c20769SMatthias Ringwald 
87d0c20769SMatthias Ringwald static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number);
88d0c20769SMatthias Ringwald 
89d210d9c4SMatthias Ringwald void hfp_gsm_init(void){
90d0c20769SMatthias Ringwald     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
91d0c20769SMatthias Ringwald     clip_type = 0;
92d0c20769SMatthias Ringwald     memset(clip_number, 0, sizeof(clip_number));
93d0c20769SMatthias Ringwald 
94d210d9c4SMatthias Ringwald     memset(gsm_calls, 0, sizeof(gsm_calls));
95d210d9c4SMatthias Ringwald     int i;
96d210d9c4SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
97d210d9c4SMatthias Ringwald         gsm_calls[i].status = CALL_NONE;
98d210d9c4SMatthias Ringwald     }
99d210d9c4SMatthias Ringwald }
10074386ee0SMatthias Ringwald 
10174386ee0SMatthias Ringwald static int get_number_calls_with_status(hfp_gsm_call_status_t status){
10274386ee0SMatthias Ringwald     int i, count = 0;
10374386ee0SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
10474386ee0SMatthias Ringwald         if (gsm_calls[i].status == status) count++;
10574386ee0SMatthias Ringwald     }
10674386ee0SMatthias Ringwald     return count;
10774386ee0SMatthias Ringwald }
10874386ee0SMatthias Ringwald 
10974386ee0SMatthias Ringwald static int get_call_index_with_status(hfp_gsm_call_status_t status){
11074386ee0SMatthias Ringwald     int i ;
11174386ee0SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
11274386ee0SMatthias Ringwald         if (gsm_calls[i].status == status) return i;
11374386ee0SMatthias Ringwald     }
11474386ee0SMatthias Ringwald     return -1;
11574386ee0SMatthias Ringwald }
11674386ee0SMatthias Ringwald 
117d0c20769SMatthias Ringwald static inline int get_next_free_slot(){
11874386ee0SMatthias Ringwald     return get_call_index_with_status(CALL_NONE);
11974386ee0SMatthias Ringwald }
12074386ee0SMatthias Ringwald 
12174386ee0SMatthias Ringwald static inline int get_active_call_index(){
12274386ee0SMatthias Ringwald     return get_call_index_with_status(CALL_ACTIVE);
12374386ee0SMatthias Ringwald }
12474386ee0SMatthias Ringwald 
125d210d9c4SMatthias Ringwald static inline int get_initiated_call_index(){
126d210d9c4SMatthias Ringwald     return get_call_index_with_status(CALL_INITIATED);
127d210d9c4SMatthias Ringwald }
128d210d9c4SMatthias Ringwald 
129d210d9c4SMatthias Ringwald static inline int get_held_call_index(){
130d210d9c4SMatthias Ringwald     return get_call_index_with_status(CALL_HELD);
131d210d9c4SMatthias Ringwald }
132d210d9c4SMatthias Ringwald 
133d210d9c4SMatthias Ringwald static inline int get_response_held_call_index(){
134d210d9c4SMatthias Ringwald     return get_call_index_with_status(CALL_RESPONSE_HOLD);
135d210d9c4SMatthias Ringwald }
136d210d9c4SMatthias Ringwald 
137d210d9c4SMatthias Ringwald static inline int get_number_none_calls(){
138d210d9c4SMatthias Ringwald     return get_number_calls_with_status(CALL_NONE);
139d210d9c4SMatthias Ringwald }
14074386ee0SMatthias Ringwald 
14174386ee0SMatthias Ringwald static inline int get_number_active_calls(){
14274386ee0SMatthias Ringwald     return get_number_calls_with_status(CALL_ACTIVE);
14374386ee0SMatthias Ringwald }
14474386ee0SMatthias Ringwald 
14574386ee0SMatthias Ringwald static inline int get_number_held_calls(){
14674386ee0SMatthias Ringwald     return get_number_calls_with_status(CALL_HELD);
14774386ee0SMatthias Ringwald }
14874386ee0SMatthias Ringwald 
149d210d9c4SMatthias Ringwald static inline int get_number_response_held_calls(){
150d210d9c4SMatthias Ringwald     return get_number_calls_with_status(CALL_RESPONSE_HOLD);
151d210d9c4SMatthias Ringwald }
152d210d9c4SMatthias Ringwald 
153d0c20769SMatthias Ringwald static int next_call_index(){
154d0c20769SMatthias Ringwald     return HFP_GSM_MAX_NR_CALLS + 1 - get_number_none_calls();
155d0c20769SMatthias Ringwald }
156d0c20769SMatthias Ringwald 
157d0c20769SMatthias Ringwald static void hfp_gsm_set_clip(int index_in_table, uint8_t type, const char * number){
158d0c20769SMatthias Ringwald     gsm_calls[index_in_table].clip_type = type;
159d0c20769SMatthias Ringwald 
160d0c20769SMatthias Ringwald     int clip_number_size = sizeof(gsm_calls[index_in_table].clip_number);
161d0c20769SMatthias Ringwald     strncpy(gsm_calls[index_in_table].clip_number, number, clip_number_size);
162d0c20769SMatthias Ringwald     gsm_calls[index_in_table].clip_number[clip_number_size-1] = '\0';
163d0c20769SMatthias Ringwald }
164d0c20769SMatthias Ringwald 
165d0c20769SMatthias Ringwald static void delete_call(int delete_index_in_table){
166d0c20769SMatthias Ringwald     int i ;
167d0c20769SMatthias Ringwald     for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
168d0c20769SMatthias Ringwald         if (gsm_calls[i].index > gsm_calls[delete_index_in_table].index){
169d0c20769SMatthias Ringwald             gsm_calls[i].index--;
170d0c20769SMatthias Ringwald         }
171d0c20769SMatthias Ringwald     }
172d0c20769SMatthias Ringwald 
173d0c20769SMatthias Ringwald     gsm_calls[delete_index_in_table].status = CALL_NONE;
174d0c20769SMatthias Ringwald     gsm_calls[delete_index_in_table].clip_type = 0;
175d0c20769SMatthias Ringwald     gsm_calls[delete_index_in_table].index = 0;
176d0c20769SMatthias Ringwald     gsm_calls[delete_index_in_table].clip_number[0] = '\0';
177d0c20769SMatthias Ringwald }
178d0c20769SMatthias Ringwald 
179d0c20769SMatthias Ringwald static void create_call(){
180d0c20769SMatthias Ringwald     int next_free_slot = get_next_free_slot();
181d0c20769SMatthias Ringwald     gsm_calls[next_free_slot].index = next_call_index();
182d0c20769SMatthias Ringwald     gsm_calls[next_free_slot].status = CALL_INITIATED;
183d0c20769SMatthias Ringwald     gsm_calls[next_free_slot].clip_type = 0;
184d0c20769SMatthias Ringwald     gsm_calls[next_free_slot].clip_number[0] = '\0';
185d0c20769SMatthias Ringwald 
186d0c20769SMatthias Ringwald     if (clip_type != 0){
187d0c20769SMatthias Ringwald         hfp_gsm_set_clip(next_free_slot, clip_type, clip_number);
188d0c20769SMatthias Ringwald         clip_type = 0;
189d0c20769SMatthias Ringwald         memset(clip_number, 0, sizeof(clip_number));
190d0c20769SMatthias Ringwald     }
191d0c20769SMatthias Ringwald }
192d0c20769SMatthias Ringwald 
193d0c20769SMatthias Ringwald uint8_t hfp_gsm_clip_type(){
194d0c20769SMatthias Ringwald     if (clip_type != 0) return clip_type;
195d0c20769SMatthias Ringwald 
196d0c20769SMatthias Ringwald     int initiated_call_index = get_initiated_call_index();
197d0c20769SMatthias Ringwald     if (initiated_call_index != -1){
198d0c20769SMatthias Ringwald         if (gsm_calls[initiated_call_index].clip_type != 0) {
199d0c20769SMatthias Ringwald             return gsm_calls[initiated_call_index].clip_type;
200d0c20769SMatthias Ringwald         }
201d0c20769SMatthias Ringwald     }
202d0c20769SMatthias Ringwald 
203d0c20769SMatthias Ringwald     int active_call_index = get_active_call_index();
204d0c20769SMatthias Ringwald     if (active_call_index != -1){
205d0c20769SMatthias Ringwald         if (gsm_calls[active_call_index].clip_type != 0) {
206d0c20769SMatthias Ringwald             return gsm_calls[active_call_index].clip_type;
207d0c20769SMatthias Ringwald         }
208d0c20769SMatthias Ringwald     }
209d0c20769SMatthias Ringwald     return 0;
210d0c20769SMatthias Ringwald }
211d0c20769SMatthias Ringwald 
212d0c20769SMatthias Ringwald char *  hfp_gsm_clip_number(){
213d0c20769SMatthias Ringwald     if (clip_type != 0) return clip_number;
214d0c20769SMatthias Ringwald 
215d0c20769SMatthias Ringwald     int initiated_call_index = get_initiated_call_index();
216d0c20769SMatthias Ringwald     if (initiated_call_index != -1){
217d0c20769SMatthias Ringwald         if (gsm_calls[initiated_call_index].clip_type != 0) {
218d0c20769SMatthias Ringwald             return gsm_calls[initiated_call_index].clip_number;
219d0c20769SMatthias Ringwald         }
220d0c20769SMatthias Ringwald     }
221d0c20769SMatthias Ringwald 
222d0c20769SMatthias Ringwald     int active_call_index = get_active_call_index();
223d0c20769SMatthias Ringwald     if (active_call_index != -1){
224d0c20769SMatthias Ringwald         if (gsm_calls[active_call_index].clip_type != 0) {
225d0c20769SMatthias Ringwald             return gsm_calls[active_call_index].clip_number;
226d0c20769SMatthias Ringwald         }
227d0c20769SMatthias Ringwald     }
228d0c20769SMatthias Ringwald     clip_number[0] = 0;
229d0c20769SMatthias Ringwald     return clip_number;
230d0c20769SMatthias Ringwald }
231d0c20769SMatthias Ringwald 
23274386ee0SMatthias Ringwald hfp_call_status_t hfp_gsm_call_status(){
233d210d9c4SMatthias Ringwald     if (get_number_active_calls() + get_number_held_calls() + get_number_response_held_calls()){
23474386ee0SMatthias Ringwald         return HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT;
23574386ee0SMatthias Ringwald     }
23674386ee0SMatthias Ringwald     return HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS;
23774386ee0SMatthias Ringwald }
23874386ee0SMatthias Ringwald 
23974386ee0SMatthias Ringwald hfp_callheld_status_t hfp_gsm_callheld_status(){
24074386ee0SMatthias Ringwald     // @note: order is important
24174386ee0SMatthias Ringwald     if (get_number_held_calls() == 0){
24274386ee0SMatthias Ringwald         return HFP_CALLHELD_STATUS_NO_CALLS_HELD;
24374386ee0SMatthias Ringwald     }
24474386ee0SMatthias Ringwald     if (get_number_active_calls() == 0) {
24574386ee0SMatthias Ringwald         return HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS;
24674386ee0SMatthias Ringwald     }
24774386ee0SMatthias Ringwald     return HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED;
24874386ee0SMatthias Ringwald }
24974386ee0SMatthias Ringwald 
25074386ee0SMatthias Ringwald hfp_callsetup_status_t hfp_gsm_callsetup_status(){
25174386ee0SMatthias Ringwald     return callsetup_status;
25274386ee0SMatthias Ringwald }
25374386ee0SMatthias Ringwald 
254d210d9c4SMatthias Ringwald int hfp_gsm_response_held_active(){
255d210d9c4SMatthias Ringwald     return get_response_held_call_index() != -1 ;
256d210d9c4SMatthias Ringwald }
257d210d9c4SMatthias Ringwald 
258d210d9c4SMatthias Ringwald int hfp_gsm_call_possible(void){
259d210d9c4SMatthias Ringwald     return get_number_none_calls() > 0;
260d210d9c4SMatthias Ringwald }
261d210d9c4SMatthias Ringwald 
26274386ee0SMatthias Ringwald void hfp_gsm_handle_event(hfp_ag_call_event_t event){
263d0c20769SMatthias Ringwald     hfp_gsm_handler(event, 0, 0, NULL);
264d0c20769SMatthias Ringwald }
265d0c20769SMatthias Ringwald 
266d0c20769SMatthias Ringwald void hfp_gsm_handle_event_with_clip(hfp_ag_call_event_t event, uint8_t type, const char * number){
267d0c20769SMatthias Ringwald     hfp_gsm_handler(event, 0, type, number);
268d0c20769SMatthias Ringwald }
269d0c20769SMatthias Ringwald 
270d0c20769SMatthias Ringwald void hfp_gsm_handle_event_with_call_index(hfp_ag_call_event_t event, uint8_t index){
271d0c20769SMatthias Ringwald     hfp_gsm_handler(event, index, 0, NULL);
272d0c20769SMatthias Ringwald }
273d0c20769SMatthias Ringwald 
274d0c20769SMatthias Ringwald static void hfp_gsm_handler(hfp_ag_call_event_t event, uint8_t index, uint8_t type, const char * number){
275d0c20769SMatthias Ringwald     int next_free_slot = get_next_free_slot();
27674386ee0SMatthias Ringwald     int current_call_index = get_active_call_index();
277d210d9c4SMatthias Ringwald     int initiated_call_index = get_initiated_call_index();
278d210d9c4SMatthias Ringwald     int held_call_index = get_held_call_index();
279d0c20769SMatthias Ringwald     int i;
280d0c20769SMatthias Ringwald 
28174386ee0SMatthias Ringwald     switch (event){
28274386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_INITIATED:
28374386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_REDIAL_INITIATED:
28474386ee0SMatthias Ringwald             if (next_free_slot == -1){
285d210d9c4SMatthias Ringwald                 log_error("gsm: max call nr exceeded");
28674386ee0SMatthias Ringwald                 return;
28774386ee0SMatthias Ringwald             }
288d0c20769SMatthias Ringwald             create_call();
289d210d9c4SMatthias Ringwald             break;
29074386ee0SMatthias Ringwald 
291d210d9c4SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_REJECTED:
292d210d9c4SMatthias Ringwald             if (current_call_index != -1){
293d0c20769SMatthias Ringwald                 // gsm_calls[current_call_index].status = CALL_NONE;
294d0c20769SMatthias Ringwald                 delete_call(current_call_index);
295d210d9c4SMatthias Ringwald             }
296d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
297d210d9c4SMatthias Ringwald             break;
298d210d9c4SMatthias Ringwald 
299d210d9c4SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_ACCEPTED:
30074386ee0SMatthias Ringwald             if (current_call_index != -1){
30174386ee0SMatthias Ringwald                 gsm_calls[current_call_index].status = CALL_HELD;
30274386ee0SMatthias Ringwald             }
303d0c20769SMatthias Ringwald             create_call();
30474386ee0SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE;
30574386ee0SMatthias Ringwald             break;
306d210d9c4SMatthias Ringwald 
30774386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_RINGING:
308d210d9c4SMatthias Ringwald             if (current_call_index == -1){
309d210d9c4SMatthias Ringwald                 log_error("gsm: no active call");
310d210d9c4SMatthias Ringwald                 return;
311d210d9c4SMatthias Ringwald             }
312d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE;
31374386ee0SMatthias Ringwald             break;
31474386ee0SMatthias Ringwald         case HFP_AG_OUTGOING_CALL_ESTABLISHED:
315d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
316d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
31774386ee0SMatthias Ringwald             break;
318d210d9c4SMatthias Ringwald 
319d210d9c4SMatthias Ringwald         case HFP_AG_INCOMING_CALL:
320d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS) break;
321d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS;
322d0c20769SMatthias Ringwald             create_call();
323d210d9c4SMatthias Ringwald             break;
324d210d9c4SMatthias Ringwald 
325d210d9c4SMatthias Ringwald         case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG:
326d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
327d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
328d210d9c4SMatthias Ringwald 
329d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
330d210d9c4SMatthias Ringwald                 gsm_calls[current_call_index].status = CALL_HELD;
331d210d9c4SMatthias Ringwald             }
332d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
333d210d9c4SMatthias Ringwald             break;
334d210d9c4SMatthias Ringwald 
335d210d9c4SMatthias Ringwald         case HFP_AG_HELD_CALL_JOINED_BY_AG:
336d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
337d210d9c4SMatthias Ringwald 
338d210d9c4SMatthias Ringwald             // TODO: mark joined calls with "multiparty flag" (if we cannot calculate it otherwise)
339d210d9c4SMatthias Ringwald             // TODO: is following condition correct? Can we join incoming call before it is answered?
340d210d9c4SMatthias Ringwald             if (callsetup_status == HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS){
341d210d9c4SMatthias Ringwald                 gsm_calls[initiated_call_index].status = CALL_ACTIVE;
342d210d9c4SMatthias Ringwald                 callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
343d210d9c4SMatthias Ringwald                 break;
344d210d9c4SMatthias Ringwald             }
345d210d9c4SMatthias Ringwald 
346d210d9c4SMatthias Ringwald             if (hfp_gsm_callheld_status() == HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED) {
347d210d9c4SMatthias Ringwald                 gsm_calls[held_call_index].status = CALL_ACTIVE;
348d210d9c4SMatthias Ringwald                 break;
349d210d9c4SMatthias Ringwald             }
350d210d9c4SMatthias Ringwald             break;
351d210d9c4SMatthias Ringwald 
352d210d9c4SMatthias Ringwald         case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF:
353d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
354d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
355d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
356d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
357d210d9c4SMatthias Ringwald             break;
358d210d9c4SMatthias Ringwald 
359d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_AG:
360d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_INCOMING_CALL_BY_HF:
361d210d9c4SMatthias Ringwald             if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
362d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS) break;
363d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
364d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_RESPONSE_HOLD;
365d210d9c4SMatthias Ringwald             break;
366d210d9c4SMatthias Ringwald 
367d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_AG:
368d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_ACCEPT_HELD_CALL_BY_HF:
369d210d9c4SMatthias Ringwald             if (!hfp_gsm_response_held_active()) break;
370d210d9c4SMatthias Ringwald             gsm_calls[get_response_held_call_index()].status = CALL_ACTIVE;
371d210d9c4SMatthias Ringwald             break;
372d210d9c4SMatthias Ringwald 
373d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_AG:
374d210d9c4SMatthias Ringwald         case HFP_AG_RESPONSE_AND_HOLD_REJECT_HELD_CALL_BY_HF:
375d210d9c4SMatthias Ringwald             if (!hfp_gsm_response_held_active()) break;
376d0c20769SMatthias Ringwald             // gsm_calls[get_response_held_call_index()].status = CALL_NONE;
377d0c20769SMatthias Ringwald             delete_call(get_response_held_call_index());
378d210d9c4SMatthias Ringwald             break;
379d210d9c4SMatthias Ringwald 
380d210d9c4SMatthias Ringwald 
381d210d9c4SMatthias Ringwald         case HFP_AG_TERMINATE_CALL_BY_HF:
382d210d9c4SMatthias Ringwald             switch (hfp_gsm_call_status()){
383d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
384d210d9c4SMatthias Ringwald                     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
385d210d9c4SMatthias Ringwald                     break;
386d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
387d0c20769SMatthias Ringwald                     // gsm_calls[current_call_index].status = CALL_NONE;
388d0c20769SMatthias Ringwald                     delete_call(current_call_index);
389d210d9c4SMatthias Ringwald                     break;
390d210d9c4SMatthias Ringwald             }
391d210d9c4SMatthias Ringwald             break;
392d210d9c4SMatthias Ringwald 
393d210d9c4SMatthias Ringwald         case HFP_AG_TERMINATE_CALL_BY_AG:
394d210d9c4SMatthias Ringwald             switch (hfp_gsm_call_status()){
395d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS:
396d210d9c4SMatthias Ringwald                     if (hfp_gsm_callsetup_status() != HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS) break;
397d210d9c4SMatthias Ringwald                     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
398d210d9c4SMatthias Ringwald                     break;
399d210d9c4SMatthias Ringwald                 case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT:
400d210d9c4SMatthias Ringwald                     callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
401d0c20769SMatthias Ringwald                     // gsm_calls[current_call_index].status = CALL_NONE;
402d0c20769SMatthias Ringwald                     delete_call(current_call_index);
403d210d9c4SMatthias Ringwald                     break;
404d210d9c4SMatthias Ringwald                 default:
405d210d9c4SMatthias Ringwald                     break;
406d210d9c4SMatthias Ringwald             }
407d210d9c4SMatthias Ringwald             break;
408d210d9c4SMatthias Ringwald 
409d0c20769SMatthias Ringwald         case HFP_AG_CALL_DROPPED:
410d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
411d210d9c4SMatthias Ringwald             if (hfp_gsm_call_status() != HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT) break;
412d210d9c4SMatthias Ringwald 
413d210d9c4SMatthias Ringwald             for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
414d0c20769SMatthias Ringwald                 delete_call(i);
415d210d9c4SMatthias Ringwald             }
416d210d9c4SMatthias Ringwald             break;
417d0c20769SMatthias Ringwald 
418d210d9c4SMatthias Ringwald         case HFP_AG_CALL_HOLD_USER_BUSY:
419d210d9c4SMatthias Ringwald             // Held or waiting call gets active,
420d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
421d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_NONE;
422d210d9c4SMatthias Ringwald             gsm_calls[held_call_index].status = CALL_ACTIVE;
423d210d9c4SMatthias Ringwald             break;
424d210d9c4SMatthias Ringwald 
425d0c20769SMatthias Ringwald         case HFP_AG_CALL_HOLD_RELEASE_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:
426d0c20769SMatthias Ringwald             if (index != 0 && index <= HFP_GSM_MAX_NR_CALLS ){
427d0c20769SMatthias Ringwald                 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
428d0c20769SMatthias Ringwald                     if (gsm_calls[i].index == index){
429d0c20769SMatthias Ringwald                         delete_call(i);
430d0c20769SMatthias Ringwald                         continue;
431d0c20769SMatthias Ringwald                     }
432d0c20769SMatthias Ringwald                 }
433d0c20769SMatthias Ringwald             } else {
434d210d9c4SMatthias Ringwald                 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
435d210d9c4SMatthias Ringwald                     if (gsm_calls[i].status == CALL_ACTIVE){
436d0c20769SMatthias Ringwald                         delete_call(i);
437d0c20769SMatthias Ringwald                     }
438d210d9c4SMatthias Ringwald                 }
439d210d9c4SMatthias Ringwald             }
440d210d9c4SMatthias Ringwald 
441d210d9c4SMatthias Ringwald             if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
442d210d9c4SMatthias Ringwald                 gsm_calls[initiated_call_index].status = CALL_ACTIVE;
443d210d9c4SMatthias Ringwald             } else {
444d210d9c4SMatthias Ringwald                 gsm_calls[held_call_index].status = CALL_ACTIVE;
445d210d9c4SMatthias Ringwald             }
446d0c20769SMatthias Ringwald 
447d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
448d210d9c4SMatthias Ringwald             break;
449d0c20769SMatthias Ringwald 
450d0c20769SMatthias Ringwald         case HFP_AG_CALL_HOLD_PARK_ACTIVE_ACCEPT_HELD_OR_WAITING_CALL:
451d210d9c4SMatthias Ringwald             for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
452d0c20769SMatthias Ringwald                 if (gsm_calls[i].status == CALL_ACTIVE && gsm_calls[i].index != index){
453d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_type = 0;
454d210d9c4SMatthias Ringwald                     gsm_calls[i].clip_number[0] = '\0';
455d210d9c4SMatthias Ringwald                     gsm_calls[i].status = CALL_HELD;
456d210d9c4SMatthias Ringwald                 }
457d210d9c4SMatthias Ringwald             }
458d210d9c4SMatthias Ringwald 
459d210d9c4SMatthias Ringwald             if (callsetup_status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
460d210d9c4SMatthias Ringwald                 gsm_calls[initiated_call_index].status = CALL_ACTIVE;
461d210d9c4SMatthias Ringwald             } else {
462d210d9c4SMatthias Ringwald                 gsm_calls[held_call_index].status = CALL_ACTIVE;
463d210d9c4SMatthias Ringwald             }
464d210d9c4SMatthias Ringwald             callsetup_status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
465d210d9c4SMatthias Ringwald             break;
466d0c20769SMatthias Ringwald 
467d0c20769SMatthias Ringwald         case HFP_AG_CALL_HOLD_ADD_HELD_CALL:
468d210d9c4SMatthias Ringwald             if (hfp_gsm_callheld_status() != HFP_CALLHELD_STATUS_NO_CALLS_HELD){
469d210d9c4SMatthias Ringwald                 for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
470d210d9c4SMatthias Ringwald                     if (gsm_calls[i].status == CALL_HELD){
471d210d9c4SMatthias Ringwald                         gsm_calls[i].clip_type = 0;
472d210d9c4SMatthias Ringwald                         gsm_calls[i].clip_number[0] = '\0';
473d210d9c4SMatthias Ringwald                         gsm_calls[i].status = CALL_ACTIVE;
474d210d9c4SMatthias Ringwald                     }
475d210d9c4SMatthias Ringwald                 }
476d210d9c4SMatthias Ringwald             }
477d210d9c4SMatthias Ringwald             gsm_calls[initiated_call_index].status = CALL_ACTIVE;
478d210d9c4SMatthias Ringwald             break;
479d0c20769SMatthias Ringwald 
480d0c20769SMatthias Ringwald         case HFP_AG_CALL_HOLD_EXIT_AND_JOIN_CALLS:
481d210d9c4SMatthias Ringwald             for (i = 0; i < HFP_GSM_MAX_NR_CALLS; i++){
482d0c20769SMatthias Ringwald                 delete_call(i);
483d210d9c4SMatthias Ringwald             }
484d0c20769SMatthias Ringwald             break;
485d210d9c4SMatthias Ringwald 
486d0c20769SMatthias Ringwald         case HFP_AG_SET_CLIP:
487d0c20769SMatthias Ringwald             if (initiated_call_index != -1){
488d0c20769SMatthias Ringwald                 hfp_gsm_set_clip(initiated_call_index, type, number);
489d210d9c4SMatthias Ringwald                 break;
490d210d9c4SMatthias Ringwald             }
491d0c20769SMatthias Ringwald             if (current_call_index != -1){
492d0c20769SMatthias Ringwald                 hfp_gsm_set_clip(current_call_index, type, number);
493d0c20769SMatthias Ringwald                 break;
494d0c20769SMatthias Ringwald             }
495d0c20769SMatthias Ringwald             clip_type = type;
496d0c20769SMatthias Ringwald             strncpy(clip_number, number, sizeof(clip_number));
497d0c20769SMatthias Ringwald             clip_number[sizeof(clip_number)-1] = '\0';
498d0c20769SMatthias Ringwald 
499d0c20769SMatthias Ringwald             break;
50074386ee0SMatthias Ringwald         default:
50174386ee0SMatthias Ringwald             break;
50274386ee0SMatthias Ringwald     }
50374386ee0SMatthias Ringwald }