1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * This file contains functions for processing AT commands and results.
22 *
23 ******************************************************************************/
24 #include "bt_target.h"
25 #include "bt_types.h"
26 #include "gki.h"
27 #include "bd.h"
28 #include "bta_api.h"
29 #include "bta_sys.h"
30 #include "bta_ag_api.h"
31 #include "bta_ag_int.h"
32 #include "bta_ag_at.h"
33 #include "port_api.h"
34 #include "utl.h"
35 #include <stdio.h>
36 #include <string.h>
37
38 /*****************************************************************************
39 ** Constants
40 *****************************************************************************/
41
42 /* ring timeout */
43 #define BTA_AG_RING_TOUT 5000
44
45 #define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */
46
47
48
49 /* clip type constants */
50 #define BTA_AG_CLIP_TYPE_MIN 128
51 #define BTA_AG_CLIP_TYPE_MAX 175
52 #define BTA_AG_CLIP_TYPE_DEFAULT 129
53 #define BTA_AG_CLIP_TYPE_VOIP 255
54
55 #if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
56 #define BTA_AG_AT_MULTI_LEN 2
57 #define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;}
58
59 /* type for AT result code block */
60 typedef struct
61 {
62 UINT8 code;
63 char *p_arg;
64 INT16 int_arg;
65 } tBTA_AG_RESULT_CB;
66
67 /* type for multiple AT result codes block */
68 typedef struct
69 {
70 UINT8 num_result;
71 tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN];
72 } tBTA_AG_MULTI_RESULT_CB;
73 #endif
74
75 /* enumeration of HSP AT commands matches HSP command interpreter table */
76 enum
77 {
78 BTA_AG_HS_CMD_CKPD,
79 BTA_AG_HS_CMD_VGS,
80 BTA_AG_HS_CMD_VGM
81 };
82
83 /* enumeration of HFP AT commands matches HFP command interpreter table */
84 enum
85 {
86 BTA_AG_HF_CMD_A,
87 BTA_AG_HF_CMD_D,
88 BTA_AG_HF_CMD_VGS,
89 BTA_AG_HF_CMD_VGM,
90 BTA_AG_HF_CMD_CCWA,
91 BTA_AG_HF_CMD_CHLD,
92 BTA_AG_HF_CMD_CHUP,
93 BTA_AG_HF_CMD_CIND,
94 BTA_AG_HF_CMD_CLIP,
95 BTA_AG_HF_CMD_CMER,
96 BTA_AG_HF_CMD_VTS,
97 BTA_AG_HF_CMD_BINP,
98 BTA_AG_HF_CMD_BLDN,
99 BTA_AG_HF_CMD_BVRA,
100 BTA_AG_HF_CMD_BRSF,
101 BTA_AG_HF_CMD_NREC,
102 BTA_AG_HF_CMD_CNUM,
103 BTA_AG_HF_CMD_BTRH,
104 BTA_AG_HF_CMD_CLCC,
105 BTA_AG_HF_CMD_COPS,
106 BTA_AG_HF_CMD_CMEE,
107 BTA_AG_HF_CMD_BIA,
108 BTA_AG_HF_CMD_CBC,
109 BTA_AG_HF_CMD_BCC,
110 BTA_AG_HF_CMD_BCS,
111 BTA_AG_HF_CMD_BAC
112 };
113
114 /* AT command interpreter table for HSP */
115 const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] =
116 {
117 {"+CKPD", BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
118 {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
119 {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
120 {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
121 };
122
123 /* AT command interpreter table for HFP */
124 const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] =
125 {
126 {"A", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
127 {"D", (BTA_AG_AT_NONE | BTA_AG_AT_FREE), BTA_AG_AT_STR, 0, 0},
128 {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
129 {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
130 {"+CCWA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
131 /* Consider CHLD as str to take care of indexes for ECC */
132 {"+CHLD", (BTA_AG_AT_SET | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 4},
133 {"+CHUP", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
134 {"+CIND", (BTA_AG_AT_READ | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 0},
135 {"+CLIP", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
136 {"+CMER", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
137 {"+VTS", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
138 {"+BINP", BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
139 {"+BLDN", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
140 {"+BVRA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
141 {"+BRSF", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
142 {"+NREC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
143 {"+CNUM", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
144 {"+BTRH", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_INT, 0, 2},
145 {"+CLCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
146 {"+COPS", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_STR, 0, 0},
147 {"+CMEE", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
148 {"+BIA", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
149 {"+CBC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
150 {"+BCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
151 {"+BCS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
152 {"+BAC", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
153 {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
154 };
155
156 /* AT result code table element */
157 typedef struct
158 {
159 const char *p_res; /* AT result string */
160 UINT8 fmt; /* whether argument is int or string */
161 } tBTA_AG_RESULT;
162
163 /* AT result code argument types */
164 enum
165 {
166 BTA_AG_RES_FMT_NONE, /* no argument */
167 BTA_AG_RES_FMT_INT, /* integer argument */
168 BTA_AG_RES_FMT_STR /* string argument */
169 };
170
171 /* enumeration of AT result codes, matches constant table */
172 enum
173 {
174 BTA_AG_RES_OK,
175 BTA_AG_RES_ERROR,
176 BTA_AG_RES_RING,
177 BTA_AG_RES_VGS,
178 BTA_AG_RES_VGM,
179 BTA_AG_RES_CCWA,
180 BTA_AG_RES_CHLD,
181 BTA_AG_RES_CIND,
182 BTA_AG_RES_CLIP,
183 BTA_AG_RES_CIEV,
184 BTA_AG_RES_BINP,
185 BTA_AG_RES_BVRA,
186 BTA_AG_RES_BRSF,
187 BTA_AG_RES_BSIR,
188 BTA_AG_RES_CNUM,
189 BTA_AG_RES_BTRH,
190 BTA_AG_RES_CLCC,
191 BTA_AG_RES_COPS,
192 BTA_AG_RES_CMEE,
193 BTA_AG_RES_BCS,
194 BTA_AG_RES_UNAT
195 };
196
197 #if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
198 #define COLON_IDX_4_VGSVGM 4
199 #endif
200 /* AT result code constant table (Indexed by result code) */
201 const tBTA_AG_RESULT bta_ag_result_tbl[] =
202 {
203 {"OK", BTA_AG_RES_FMT_NONE},
204 {"ERROR", BTA_AG_RES_FMT_NONE},
205 {"RING", BTA_AG_RES_FMT_NONE},
206 {"+VGS: ", BTA_AG_RES_FMT_INT},
207 {"+VGM: ", BTA_AG_RES_FMT_INT},
208 {"+CCWA: ", BTA_AG_RES_FMT_STR},
209 {"+CHLD: ", BTA_AG_RES_FMT_STR},
210 {"+CIND: ", BTA_AG_RES_FMT_STR},
211 {"+CLIP: ", BTA_AG_RES_FMT_STR},
212 {"+CIEV: ", BTA_AG_RES_FMT_STR},
213 {"+BINP: ", BTA_AG_RES_FMT_STR},
214 {"+BVRA: ", BTA_AG_RES_FMT_INT},
215 {"+BRSF: ", BTA_AG_RES_FMT_INT},
216 {"+BSIR: ", BTA_AG_RES_FMT_INT},
217 {"+CNUM: ", BTA_AG_RES_FMT_STR},
218 {"+BTRH: ", BTA_AG_RES_FMT_INT},
219 {"+CLCC: ", BTA_AG_RES_FMT_STR},
220 {"+COPS: ", BTA_AG_RES_FMT_STR},
221 {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
222 {"+BCS: ", BTA_AG_RES_FMT_INT},
223 {"", BTA_AG_RES_FMT_STR}
224 };
225
226 const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] =
227 {
228 bta_ag_hsp_cmd,
229 bta_ag_hfp_cmd
230 };
231
232 /* callback event lookup table for HSP */
233 const tBTA_AG_EVT bta_ag_hsp_cb_evt[] =
234 {
235 BTA_AG_AT_CKPD_EVT, /* BTA_AG_HS_CMD_CKPD */
236 BTA_AG_SPK_EVT, /* BTA_AG_HS_CMD_VGS */
237 BTA_AG_MIC_EVT /* BTA_AG_HS_CMD_VGM */
238 };
239
240 /* callback event lookup table for HFP (Indexed by command) */
241 const tBTA_AG_EVT bta_ag_hfp_cb_evt[] =
242 {
243 BTA_AG_AT_A_EVT, /* BTA_AG_HF_CMD_A */
244 BTA_AG_AT_D_EVT, /* BTA_AG_HF_CMD_D */
245 BTA_AG_SPK_EVT, /* BTA_AG_HF_CMD_VGS */
246 BTA_AG_MIC_EVT, /* BTA_AG_HF_CMD_VGM */
247 0, /* BTA_AG_HF_CMD_CCWA */
248 BTA_AG_AT_CHLD_EVT, /* BTA_AG_HF_CMD_CHLD */
249 BTA_AG_AT_CHUP_EVT, /* BTA_AG_HF_CMD_CHUP */
250 BTA_AG_AT_CIND_EVT, /* BTA_AG_HF_CMD_CIND */
251 0, /* BTA_AG_HF_CMD_CLIP */
252 0, /* BTA_AG_HF_CMD_CMER */
253 BTA_AG_AT_VTS_EVT, /* BTA_AG_HF_CMD_VTS */
254 BTA_AG_AT_BINP_EVT, /* BTA_AG_HF_CMD_BINP */
255 BTA_AG_AT_BLDN_EVT, /* BTA_AG_HF_CMD_BLDN */
256 BTA_AG_AT_BVRA_EVT, /* BTA_AG_HF_CMD_BVRA */
257 0, /* BTA_AG_HF_CMD_BRSF */
258 BTA_AG_AT_NREC_EVT, /* BTA_AG_HF_CMD_NREC */
259 BTA_AG_AT_CNUM_EVT, /* BTA_AG_HF_CMD_CNUM */
260 BTA_AG_AT_BTRH_EVT, /* BTA_AG_HF_CMD_BTRH */
261 BTA_AG_AT_CLCC_EVT, /* BTA_AG_HF_CMD_CLCC */
262 BTA_AG_AT_COPS_EVT, /* BTA_AG_HF_CMD_COPS */
263 0, /* BTA_AG_HF_CMD_CMEE */
264 0, /* BTA_AG_HF_CMD_BIA */
265 BTA_AG_AT_CBC_EVT, /* BTA_AG_HF_CMD_CBC */
266 0, /* BTA_AG_HF_CMD_BCC */
267 BTA_AG_AT_BCS_EVT, /* BTA_AG_HF_CMD_BCS */
268 BTA_AG_AT_BAC_EVT /* BTA_AG_HF_CMD_BAC */
269 };
270
271 /* translation of API result code values to internal values */
272 const UINT8 bta_ag_trans_result[] =
273 {
274 BTA_AG_RES_VGS, /* BTA_AG_SPK_RES */
275 BTA_AG_RES_VGM, /* BTA_AG_MIC_RES */
276 BTA_AG_RES_BSIR, /* BTA_AG_INBAND_RING_RES */
277 BTA_AG_RES_CIND, /* BTA_AG_CIND_RES */
278 BTA_AG_RES_BINP, /* BTA_AG_BINP_RES */
279 BTA_AG_RES_CIEV, /* BTA_AG_IND_RES */
280 BTA_AG_RES_BVRA, /* BTA_AG_BVRA_RES */
281 BTA_AG_RES_CNUM, /* BTA_AG_CNUM_RES */
282 BTA_AG_RES_BTRH, /* BTA_AG_BTRH_RES */
283 BTA_AG_RES_CLCC, /* BTA_AG_CLCC_RES */
284 BTA_AG_RES_COPS, /* BTA_AG_COPS_RES */
285 0, /* BTA_AG_IN_CALL_RES */
286 0, /* BTA_AG_IN_CALL_CONN_RES */
287 BTA_AG_RES_CCWA, /* BTA_AG_CALL_WAIT_RES */
288 0, /* BTA_AG_OUT_CALL_ORIG_RES */
289 0, /* BTA_AG_OUT_CALL_ALERT_RES */
290 0, /* BTA_AG_OUT_CALL_CONN_RES */
291 0, /* BTA_AG_CALL_CANCEL_RES */
292 0, /* BTA_AG_END_CALL_RES */
293 0, /* BTA_AG_IN_CALL_HELD_RES */
294 BTA_AG_RES_UNAT /* BTA_AG_UNAT_RES */
295 };
296
297 /* callsetup indicator value lookup table */
298 const UINT8 bta_ag_callsetup_ind_tbl[] =
299 {
300 0, /* BTA_AG_SPK_RES */
301 0, /* BTA_AG_MIC_RES */
302 0, /* BTA_AG_INBAND_RING_RES */
303 0, /* BTA_AG_CIND_RES */
304 0, /* BTA_AG_BINP_RES */
305 0, /* BTA_AG_IND_RES */
306 0, /* BTA_AG_BVRA_RES */
307 0, /* BTA_AG_CNUM_RES */
308 0, /* BTA_AG_BTRH_RES */
309 0, /* BTA_AG_CLCC_RES */
310 0, /* BTA_AG_COPS_RES */
311 BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_IN_CALL_RES */
312 BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_CONN_RES */
313 BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_CALL_WAIT_RES */
314 BTA_AG_CALLSETUP_OUTGOING, /* BTA_AG_OUT_CALL_ORIG_RES */
315 BTA_AG_CALLSETUP_ALERTING, /* BTA_AG_OUT_CALL_ALERT_RES */
316 BTA_AG_CALLSETUP_NONE, /* BTA_AG_OUT_CALL_CONN_RES */
317 BTA_AG_CALLSETUP_NONE, /* BTA_AG_CALL_CANCEL_RES */
318 BTA_AG_CALLSETUP_NONE, /* BTA_AG_END_CALL_RES */
319 BTA_AG_CALLSETUP_NONE /* BTA_AG_IN_CALL_HELD_RES */
320 };
321
322 /*******************************************************************************
323 **
324 ** Function bta_ag_send_result
325 **
326 ** Description Send an AT result code.
327 **
328 **
329 ** Returns void
330 **
331 *******************************************************************************/
bta_ag_send_result(tBTA_AG_SCB * p_scb,UINT8 code,char * p_arg,INT16 int_arg)332 static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg,
333 INT16 int_arg)
334 {
335 char buf[BTA_AG_AT_MAX_LEN + 16];
336 char *p = buf;
337 UINT16 len;
338
339 #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
340 memset(buf, NULL, sizeof(buf));
341 #endif
342 /* init with \r\n */
343 *p++ = '\r';
344 *p++ = '\n';
345
346 /* copy result code string */
347 BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[code].p_res);
348 #if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
349 if(p_scb->conn_service == BTA_AG_HSP)
350 {
351 /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
352 switch(code)
353 {
354 case BTA_AG_RES_VGS:
355 case BTA_AG_RES_VGM:
356 if(*(p+COLON_IDX_4_VGSVGM) == ':')
357 {
358 #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
359 APPL_TRACE_DEBUG("[HSP] ':'symbol is changed as '=' for HSP compatibility");
360 #endif
361 *(p+COLON_IDX_4_VGSVGM) = '=';
362 }
363 break;
364 }
365 }
366 #endif
367 p += strlen(bta_ag_result_tbl[code].p_res);
368
369 /* copy argument if any */
370 if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT)
371 {
372 p += utl_itoa((UINT16) int_arg, p);
373 }
374 else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR)
375 {
376 BCM_STRCPY_S(p, sizeof(buf), p_arg);
377 p += strlen(p_arg);
378 }
379
380 /* finish with \r\n */
381 *p++ = '\r';
382 *p++ = '\n';
383
384 #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
385 APPL_TRACE_DEBUG("bta_ag_send_result: %s", buf);
386 #endif
387
388 /* send to RFCOMM */
389 PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
390 }
391
392 #if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
393 /*******************************************************************************
394 **
395 ** Function bta_ag_send_multi_result
396 **
397 ** Description Send multiple AT result codes.
398 **
399 **
400 ** Returns void
401 **
402 *******************************************************************************/
bta_ag_send_multi_result(tBTA_AG_SCB * p_scb,tBTA_AG_MULTI_RESULT_CB * m_res_cb)403 static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb)
404 {
405 char buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16];
406 char *p = buf;
407 UINT16 len;
408 UINT8 res_idx = 0;
409
410 if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN))
411 {
412 APPL_TRACE_DEBUG("m_res_cb is NULL or num_result is out of range.");
413 return;
414 }
415
416 #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
417 memset(buf, NULL, sizeof(buf));
418 #endif
419
420 while(res_idx < m_res_cb->num_result)
421 {
422 /* init with \r\n */
423 *p++ = '\r';
424 *p++ = '\n';
425
426 /* copy result code string */
427 BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
428 p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
429
430 /* copy argument if any */
431 if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT)
432 {
433 p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p);
434 }
435 else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR)
436 {
437 BCM_STRCPY_S(p, sizeof(buf), m_res_cb->res_cb[res_idx].p_arg);
438 p += strlen(m_res_cb->res_cb[res_idx].p_arg);
439 }
440
441 /* finish with \r\n */
442 *p++ = '\r';
443 *p++ = '\n';
444
445 res_idx++;
446 }
447
448 #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
449 APPL_TRACE_DEBUG("send_result: %s", buf);
450 #endif
451
452 /* send to RFCOMM */
453 PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
454 }
455 #endif
456
457 /*******************************************************************************
458 **
459 ** Function bta_ag_send_ok
460 **
461 ** Description Send an OK result code.
462 **
463 **
464 ** Returns void
465 **
466 *******************************************************************************/
bta_ag_send_ok(tBTA_AG_SCB * p_scb)467 static void bta_ag_send_ok(tBTA_AG_SCB *p_scb)
468 {
469 bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0);
470 }
471
472 /*******************************************************************************
473 **
474 ** Function bta_ag_send_error
475 **
476 ** Description Send an ERROR result code.
477 ** errcode - used to send verbose errocode
478 **
479 **
480 ** Returns void
481 **
482 *******************************************************************************/
bta_ag_send_error(tBTA_AG_SCB * p_scb,INT16 errcode)483 static void bta_ag_send_error(tBTA_AG_SCB *p_scb, INT16 errcode)
484 {
485 /* If HFP and extended audio gateway error codes are enabled */
486 if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
487 bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode);
488 else
489 bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0);
490 }
491
492 /*******************************************************************************
493 **
494 ** Function bta_ag_send_ind
495 **
496 ** Description Send an indicator CIEV result code.
497 **
498 **
499 ** Returns void
500 **
501 *******************************************************************************/
bta_ag_send_ind(tBTA_AG_SCB * p_scb,UINT16 id,UINT16 value,BOOLEAN on_demand)502 static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN on_demand)
503 {
504 char str[12];
505 char *p = str;
506
507 /* If the indicator is masked out, just return */
508 /* Mandatory indicators can not be masked out. */
509 if ((p_scb->bia_masked_out & ((UINT32)1 << id)) &&
510 ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && (id != BTA_AG_IND_CALLHELD)))
511 return;
512
513 /* Ensure we do not send duplicate indicators if not requested by app */
514 /* If it was requested by app, transmit CIEV even if it is duplicate. */
515 if (id == BTA_AG_IND_CALL)
516 {
517 if ((value == p_scb->call_ind) && (on_demand == FALSE))
518 return;
519
520 p_scb->call_ind = (UINT8)value;
521 }
522
523 if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == FALSE))
524 {
525 if (value == p_scb->callsetup_ind)
526 return;
527
528 p_scb->callsetup_ind = (UINT8)value;
529 }
530
531 if ((id == BTA_AG_IND_SERVICE) && (on_demand == FALSE))
532 {
533 if (value == p_scb->service_ind)
534 return;
535
536 p_scb->service_ind = (UINT8)value;
537 }
538 if ((id == BTA_AG_IND_SIGNAL) && (on_demand == FALSE))
539 {
540 if (value == p_scb->signal_ind)
541 return;
542
543 p_scb->signal_ind = (UINT8)value;
544 }
545 if ((id == BTA_AG_IND_ROAM) && (on_demand == FALSE))
546 {
547 if (value == p_scb->roam_ind)
548 return;
549
550 p_scb->roam_ind = (UINT8)value;
551 }
552 if ((id == BTA_AG_IND_BATTCHG) && (on_demand == FALSE))
553 {
554 if (value == p_scb->battchg_ind)
555 return;
556
557 p_scb->battchg_ind = (UINT8)value;
558 }
559
560 if ((id == BTA_AG_IND_CALLHELD) && (on_demand == FALSE))
561 {
562 /* call swap could result in sending callheld=1 multiple times */
563 if ((value != 1) && (value == p_scb->callheld_ind))
564 return;
565
566 p_scb->callheld_ind = (UINT8)value;
567 }
568
569 if (p_scb->cmer_enabled)
570 {
571 p += utl_itoa(id, p);
572 *p++ = ',';
573 utl_itoa(value, p);
574 bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0);
575 }
576 }
577
578 /*******************************************************************************
579 **
580 ** Function bta_ag_parse_cmer
581 **
582 ** Description Parse AT+CMER parameter string.
583 **
584 **
585 ** Returns TRUE if parsed ok, FALSE otherwise.
586 **
587 *******************************************************************************/
bta_ag_parse_cmer(char * p_s,BOOLEAN * p_enabled)588 static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled)
589 {
590 INT16 n[4] = {-1, -1, -1, -1};
591 int i;
592 char *p;
593
594 for (i = 0; i < 4; i++)
595 {
596 /* skip to comma delimiter */
597 for (p = p_s; *p != ',' && *p != 0; p++);
598
599 /* get integer value */
600 *p = 0;
601 n[i] = utl_str2int(p_s);
602 p_s = p + 1;
603 if (p_s == 0)
604 {
605 break;
606 }
607 }
608
609 /* process values */
610 if (n[0] < 0 || n[3] < 0)
611 {
612 return FALSE;
613 }
614
615 if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0)))
616 {
617 *p_enabled = (BOOLEAN) n[3];
618 }
619
620 return TRUE;
621 }
622
623 /*******************************************************************************
624 **
625 ** Function bta_ag_parse_chld
626 **
627 ** Description Parse AT+CHLD parameter string.
628 **
629 **
630 ** Returns Returns idx (1-7), or 0 if ECC not enabled or idx doesn't exist
631 **
632 *******************************************************************************/
bta_ag_parse_chld(tBTA_AG_SCB * p_scb,char * p_s)633 static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s)
634 {
635 UINT8 retval = 0;
636 INT16 idx = -1;
637 UNUSED(p_scb);
638
639 if (p_s[1] != 0)
640 {
641 /* p_idxstr++; point to beginning of call number */
642 idx = utl_str2int(&p_s[1]);
643 if (idx != -1 && idx < 255)
644 retval = (UINT8)idx;
645 }
646
647 return (retval);
648 }
649
650 #if (BTM_WBS_INCLUDED == TRUE )
651 /*******************************************************************************
652 **
653 ** Function bta_ag_parse_bac
654 **
655 ** Description Parse AT+BAC parameter string.
656 **
657 ** Returns Returns bitmap of supported codecs.
658 **
659 *******************************************************************************/
bta_ag_parse_bac(tBTA_AG_SCB * p_scb,char * p_s)660 static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
661 {
662 tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE;
663 UINT16 uuid_codec;
664 BOOLEAN cont = FALSE; /* Continue processing */
665 char *p;
666
667 while(p_s)
668 {
669 /* skip to comma delimiter */
670 for(p = p_s; *p != ',' && *p != 0; p++);
671
672 /* get integre value */
673 if (*p != 0)
674 {
675 *p = 0;
676 cont = TRUE;
677 }
678 else
679 cont = FALSE;
680
681 uuid_codec = utl_str2int(p_s);
682 switch(uuid_codec)
683 {
684 case UUID_CODEC_CVSD: retval |= BTA_AG_CODEC_CVSD; break;
685 case UUID_CODEC_MSBC: retval |= BTA_AG_CODEC_MSBC; break;
686 default:
687 APPL_TRACE_ERROR("Unknown Codec UUID(%d) received", uuid_codec);
688 return BTA_AG_CODEC_NONE;
689 }
690
691 if (cont)
692 p_s = p + 1;
693 else
694 break;
695 }
696
697 return (retval);
698 }
699 #endif
700
701 /*******************************************************************************
702 **
703 ** Function bta_ag_process_unat_res
704 **
705 ** Description Process the unat response data and remove extra carriage return
706 ** and line feed
707 **
708 **
709 ** Returns void
710 **
711 *******************************************************************************/
712
bta_ag_process_unat_res(char * unat_result)713 static void bta_ag_process_unat_res(char *unat_result)
714 {
715 UINT8 str_leng;
716 UINT8 i = 0;
717 UINT8 j = 0;
718 UINT8 pairs_of_nl_cr;
719 char trim_data[BTA_AG_AT_MAX_LEN];
720
721
722
723 str_leng = strlen(unat_result);
724
725 /* If no extra CR and LF, just return */
726 if(str_leng < 4)
727 return;
728
729 /* Remove the carriage return and left feed */
730 while(unat_result[0] =='\r' && unat_result[1] =='\n'
731 && unat_result[str_leng-2] =='\r' && unat_result[str_leng-1] =='\n')
732 {
733 pairs_of_nl_cr = 1;
734 for (i=0;i<(str_leng-4*pairs_of_nl_cr);i++)
735 {
736 trim_data[j++] = unat_result[i+pairs_of_nl_cr*2];
737 }
738 /* Add EOF */
739 trim_data[j] = '\0';
740 str_leng = str_leng - 4;
741 BCM_STRNCPY_S(unat_result, BTA_AG_AT_MAX_LEN+1, trim_data,str_leng+1);
742 i=0;
743 j=0;
744
745 if(str_leng <4)
746 return;
747
748
749 }
750 return;
751 }
752
753
754 /*******************************************************************************
755 **
756 ** Function bta_ag_inband_enabled
757 **
758 ** Description Determine whether in-band ring can be used.
759 **
760 **
761 ** Returns void
762 **
763 *******************************************************************************/
bta_ag_inband_enabled(tBTA_AG_SCB * p_scb)764 BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb)
765 {
766 /* if feature is enabled and no other scbs connected */
767 if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb))
768 {
769 return TRUE;
770 }
771 else
772 {
773 return FALSE;
774 }
775 }
776
777 /*******************************************************************************
778 **
779 ** Function bta_ag_send_call_inds
780 **
781 ** Description Send call and callsetup indicators.
782 **
783 **
784 ** Returns void
785 **
786 *******************************************************************************/
bta_ag_send_call_inds(tBTA_AG_SCB * p_scb,tBTA_AG_RES result)787 void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
788 {
789 UINT8 call = p_scb->call_ind;
790 UINT8 callsetup;
791
792 /* set new call and callsetup values based on BTA_AgResult */
793 callsetup = bta_ag_callsetup_ind_tbl[result];
794
795 if (result == BTA_AG_END_CALL_RES)
796 {
797 call = BTA_AG_CALL_INACTIVE;
798 }
799 else if (result == BTA_AG_IN_CALL_CONN_RES || result == BTA_AG_OUT_CALL_CONN_RES
800 || result == BTA_AG_IN_CALL_HELD_RES)
801 {
802 call = BTA_AG_CALL_ACTIVE;
803 }
804 else
805 {
806 call = p_scb->call_ind;
807 }
808
809 /* Send indicator function tracks if the values have actually changed */
810 bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, FALSE);
811 bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, FALSE);
812 }
813
814 /*******************************************************************************
815 **
816 ** Function bta_ag_at_hsp_cback
817 **
818 ** Description AT command processing callback for HSP.
819 **
820 **
821 ** Returns void
822 **
823 *******************************************************************************/
bta_ag_at_hsp_cback(tBTA_AG_SCB * p_scb,UINT16 cmd,UINT8 arg_type,char * p_arg,INT16 int_arg)824 void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
825 char *p_arg, INT16 int_arg)
826 {
827 tBTA_AG_VAL val;
828
829 APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
830 int_arg, p_arg);
831
832 /* send OK */
833 bta_ag_send_ok(p_scb);
834
835 val.hdr.handle = bta_ag_scb_to_idx(p_scb);
836 val.hdr.app_id = p_scb->app_id;
837 val.num = (UINT16) int_arg;
838 BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
839 val.str[BTA_AG_AT_MAX_LEN] = 0;
840
841 /* call callback with event */
842 (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val);
843 }
844
845 /*******************************************************************************
846 **
847 ** Function bta_ag_at_hfp_cback
848 **
849 ** Description AT command processing callback for HFP.
850 **
851 **
852 ** Returns void
853 **
854 *******************************************************************************/
bta_ag_at_hfp_cback(tBTA_AG_SCB * p_scb,UINT16 cmd,UINT8 arg_type,char * p_arg,INT16 int_arg)855 void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
856 char *p_arg, INT16 int_arg)
857 {
858 tBTA_AG_VAL val;
859 tBTA_AG_EVT event;
860 tBTA_AG_SCB *ag_scb;
861 UINT32 i, ind_id;
862 UINT32 bia_masked_out;
863 #if (BTM_WBS_INCLUDED == TRUE )
864 tBTA_AG_PEER_CODEC codec_type, codec_sent;
865 #endif
866
867 APPL_TRACE_DEBUG("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
868 int_arg, p_arg);
869
870 val.hdr.handle = bta_ag_scb_to_idx(p_scb);
871 val.hdr.app_id = p_scb->app_id;
872 val.num = int_arg;
873 bdcpy(val.bd_addr, p_scb->peer_addr);
874 BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
875 val.str[BTA_AG_AT_MAX_LEN] = 0;
876
877 event = bta_ag_hfp_cb_evt[cmd];
878
879 switch (cmd)
880 {
881 case BTA_AG_HF_CMD_A:
882 case BTA_AG_HF_CMD_VGS:
883 case BTA_AG_HF_CMD_VGM:
884 case BTA_AG_HF_CMD_CHUP:
885 case BTA_AG_HF_CMD_CBC:
886 /* send OK */
887 bta_ag_send_ok(p_scb);
888 break;
889
890 case BTA_AG_HF_CMD_BLDN:
891 /* Do not send OK, App will send error or OK depending on
892 ** last dial number enabled or not */
893 break;
894
895 case BTA_AG_HF_CMD_D:
896 /* Do not send OK for Dial cmds
897 ** Let application decide whether to send OK or ERROR*/
898
899 /* if mem dial cmd, make sure string contains only digits */
900 if(p_arg[0] == '>')
901 {
902 if(!utl_isintstr(p_arg+1))
903 {
904 event = 0;
905 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
906 }
907 }
908 else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */
909 {
910 /* We do not check string. Code will be added later if needed. */
911 if(!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && (p_scb->features & BTA_AG_FEAT_VOIP)))
912 {
913 event = 0;
914 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
915 }
916 }
917 /* If dial cmd, make sure string contains only dial digits
918 ** Dial digits are 0-9, A-C, *, #, + */
919 else
920 {
921 if(!utl_isdialstr(p_arg))
922 {
923 event = 0;
924 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
925 }
926 }
927 break;
928
929 case BTA_AG_HF_CMD_CCWA:
930 /* store setting */
931 p_scb->ccwa_enabled = (BOOLEAN) int_arg;
932
933 /* send OK */
934 bta_ag_send_ok(p_scb);
935 break;
936
937 case BTA_AG_HF_CMD_CHLD:
938 if (arg_type == BTA_AG_AT_TEST)
939 {
940 /* don't call callback */
941 event = 0;
942
943 /* send CHLD string */
944 /* Form string based on supported 1.5 feature */
945 if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
946 (p_scb->features & BTA_AG_FEAT_ECC) &&
947 (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
948 bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0);
949 else
950 bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0);
951
952 /* send OK */
953 bta_ag_send_ok(p_scb);
954
955 /* if service level conn. not already open, now it's open */
956 bta_ag_svc_conn_open(p_scb, NULL);
957
958 }
959 else
960 {
961 val.idx = bta_ag_parse_chld(p_scb, val.str);
962
963 if(val.idx && !((p_scb->features & BTA_AG_FEAT_ECC) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)))
964 {
965 /* we do not support ECC, but HF is sending us a CHLD with call index*/
966 event = 0;
967 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
968
969 }
970 else
971 {
972
973 /* If it is swap between calls, set call held indicator to 3(out of valid 0-2)
974 ** Application will set it back to 1
975 ** callheld indicator will be sent across to the peer. */
976 if(val.str[0] == '2')
977 {
978 for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
979 {
980 if (ag_scb->in_use)
981 {
982 if((ag_scb->call_ind == BTA_AG_CALL_ACTIVE)
983 && (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
984 ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
985 }
986 }
987 }
988 }
989
990 /* Do not send OK. Let app decide after parsing the val str */
991 /* bta_ag_send_ok(p_scb); */
992 }
993 break;
994
995 case BTA_AG_HF_CMD_CIND:
996 if (arg_type == BTA_AG_AT_TEST)
997 {
998 /* don't call callback */
999 event = 0;
1000
1001 /* send CIND string, send OK */
1002 bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0);
1003 bta_ag_send_ok(p_scb);
1004 }
1005 break;
1006
1007 case BTA_AG_HF_CMD_CLIP:
1008 /* store setting, send OK */
1009 p_scb->clip_enabled = (BOOLEAN) int_arg;
1010 bta_ag_send_ok(p_scb);
1011 break;
1012
1013 case BTA_AG_HF_CMD_CMER:
1014 /* if parsed ok store setting, send OK */
1015 if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled))
1016 {
1017 bta_ag_send_ok(p_scb);
1018
1019 /* if service level conn. not already open and our features and
1020 ** peer features do not have 3-way, service level conn. now open
1021 */
1022 if (!p_scb->svc_conn &&
1023 !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY)))
1024 {
1025 bta_ag_svc_conn_open(p_scb, NULL);
1026 }
1027 }
1028 else
1029 {
1030 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
1031 }
1032 break;
1033
1034 case BTA_AG_HF_CMD_VTS:
1035 /* check argument */
1036 if (strlen(p_arg) == 1)
1037 {
1038 bta_ag_send_ok(p_scb);
1039 }
1040 else
1041 {
1042 event = 0;
1043 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
1044 }
1045 break;
1046
1047 case BTA_AG_HF_CMD_BINP:
1048 /* if feature not set don't call callback, send ERROR */
1049 if (!(p_scb->features & BTA_AG_FEAT_VTAG))
1050 {
1051 event = 0;
1052 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1053 }
1054 break;
1055
1056 case BTA_AG_HF_CMD_BVRA:
1057 /* if feature not supported don't call callback, send ERROR. App will send OK */
1058 if (!(p_scb->features & BTA_AG_FEAT_VREC))
1059 {
1060 event = 0;
1061 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1062 }
1063 break;
1064
1065 case BTA_AG_HF_CMD_BRSF:
1066 /* store peer features */
1067 p_scb->peer_features = (UINT16) int_arg;
1068
1069 /* send BRSF, send OK */
1070 bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL,
1071 (INT16) (p_scb->features & BTA_AG_BSRF_FEAT_SPEC));
1072 bta_ag_send_ok(p_scb);
1073 break;
1074
1075 case BTA_AG_HF_CMD_NREC:
1076 /* if feature send OK, else don't call callback, send ERROR */
1077 if (p_scb->features & BTA_AG_FEAT_ECNR)
1078 {
1079 bta_ag_send_ok(p_scb);
1080 }
1081 else
1082 {
1083 event = 0;
1084 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1085 }
1086 break;
1087
1088 case BTA_AG_HF_CMD_BTRH:
1089 /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
1090 if (p_scb->features & BTA_AG_FEAT_BTRH)
1091 {
1092 /* If set command; send response and notify app */
1093 if (arg_type == BTA_AG_AT_SET)
1094 {
1095 for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++)
1096 {
1097 if (ag_scb->in_use)
1098 {
1099 bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg);
1100 }
1101 }
1102 bta_ag_send_ok(p_scb);
1103 }
1104 else /* Read Command */
1105 {
1106 val.num = BTA_AG_BTRH_READ;
1107 }
1108 }
1109 else
1110 {
1111 event = 0;
1112 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1113 }
1114 break;
1115
1116 case BTA_AG_HF_CMD_COPS:
1117 if (arg_type == BTA_AG_AT_SET)
1118 {
1119 /* don't call callback */
1120 event = 0;
1121
1122 /* send OK */
1123 bta_ag_send_ok(p_scb);
1124 }
1125 break;
1126
1127 case BTA_AG_HF_CMD_CMEE:
1128 if (p_scb->features & BTA_AG_FEAT_EXTERR)
1129 {
1130 /* store setting */
1131 p_scb->cmee_enabled = (BOOLEAN) int_arg;
1132
1133 /* send OK */
1134 bta_ag_send_ok(p_scb);
1135 }
1136 else
1137 {
1138 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1139 }
1140 /* don't call callback */
1141 event = 0;
1142 break;
1143
1144 case BTA_AG_HF_CMD_BIA:
1145 /* don't call callback */
1146 event = 0;
1147
1148 bia_masked_out = p_scb->bia_masked_out;
1149
1150 /* Parse the indicator mask */
1151 for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); i++, ind_id++)
1152 {
1153 if (val.str[i] == ',')
1154 continue;
1155
1156 if (val.str[i] == '0')
1157 bia_masked_out |= ((UINT32)1 << ind_id);
1158 else if (val.str[i] == '1')
1159 bia_masked_out &= ~((UINT32)1 << ind_id);
1160 else
1161 break;
1162
1163 i++;
1164 if ( (val.str[i] != 0) && (val.str[i] != ',') )
1165 break;
1166 }
1167 if (val.str[i] == 0)
1168 {
1169 p_scb->bia_masked_out = bia_masked_out;
1170 bta_ag_send_ok (p_scb);
1171 }
1172 else
1173 bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
1174 break;
1175
1176 case BTA_AG_HF_CMD_CNUM:
1177 break;
1178 case BTA_AG_HF_CMD_CLCC:
1179 if(!(p_scb->features & BTA_AG_FEAT_ECS))
1180 {
1181 event = 0;
1182 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1183 }
1184 break;
1185
1186 #if (BTM_WBS_INCLUDED == TRUE )
1187 case BTA_AG_HF_CMD_BAC:
1188 bta_ag_send_ok(p_scb);
1189
1190 /* store available codecs from the peer */
1191 if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC))
1192 {
1193 p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
1194 p_scb->codec_updated = TRUE;
1195
1196 if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC)
1197 {
1198 p_scb->sco_codec = UUID_CODEC_MSBC;
1199 APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to MSBC");
1200 }
1201 else
1202 {
1203 p_scb->sco_codec = UUID_CODEC_CVSD;
1204 APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to CVSD");
1205 }
1206 /* The above logic sets the stack preferred codec based on local and peer codec
1207 capabilities. This can be overridden by the application depending on its preference
1208 using the bta_ag_setcodec API. We send the peer_codecs to the application. */
1209 val.num = p_scb->peer_codecs;
1210 /* Received BAC while in codec negotiation. */
1211 if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb))
1212 {
1213 bta_ag_codec_negotiate (p_scb);
1214 }
1215 }
1216 else
1217 {
1218 p_scb->peer_codecs = BTA_AG_CODEC_NONE;
1219 APPL_TRACE_ERROR("Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
1220 }
1221 break;
1222
1223 case BTA_AG_HF_CMD_BCS:
1224 bta_ag_send_ok(p_scb);
1225
1226 /* stop cn timer */
1227 bta_sys_stop_timer(&p_scb->cn_timer);
1228
1229 switch(int_arg)
1230 {
1231 case UUID_CODEC_CVSD: codec_type = BTA_AG_CODEC_CVSD; break;
1232 case UUID_CODEC_MSBC: codec_type = BTA_AG_CODEC_MSBC; break;
1233 default:
1234 APPL_TRACE_ERROR("Unknown codec_uuid %d", int_arg);
1235 codec_type = 0xFFFF;
1236 break;
1237 }
1238
1239 if (p_scb->codec_fallback)
1240 codec_sent = BTA_AG_CODEC_CVSD;
1241 else
1242 codec_sent = p_scb->sco_codec;
1243
1244 if(codec_type == codec_sent)
1245 bta_ag_sco_codec_nego(p_scb, TRUE);
1246 else
1247 bta_ag_sco_codec_nego(p_scb, FALSE);
1248
1249 /* send final codec info to callback */
1250 val.num = codec_sent;
1251 break;
1252
1253 case BTA_AG_HF_CMD_BCC:
1254 bta_ag_send_ok(p_scb);
1255 bta_ag_sco_open(p_scb, NULL);
1256 break;
1257 #endif
1258
1259 default:
1260 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1261 break;
1262 }
1263
1264 /* call callback */
1265 if (event != 0)
1266 {
1267 (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &val);
1268 }
1269 }
1270
1271 /*******************************************************************************
1272 **
1273 ** Function bta_ag_at_err_cback
1274 **
1275 ** Description AT command parser error callback.
1276 **
1277 **
1278 ** Returns void
1279 **
1280 *******************************************************************************/
bta_ag_at_err_cback(tBTA_AG_SCB * p_scb,BOOLEAN unknown,char * p_arg)1281 void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg)
1282 {
1283 tBTA_AG_VAL val;
1284
1285 if(unknown && (!strlen(p_arg)))
1286 {
1287 APPL_TRACE_DEBUG("Empty AT cmd string received");
1288 bta_ag_send_ok(p_scb);
1289 return;
1290 }
1291
1292 /* if unknown AT command and configured to pass these to app */
1293 if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT))
1294 {
1295 val.hdr.handle = bta_ag_scb_to_idx(p_scb);
1296 val.hdr.app_id = p_scb->app_id;
1297 val.num = 0;
1298 BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
1299 val.str[BTA_AG_AT_MAX_LEN] = 0;
1300 (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
1301 }
1302 else
1303 {
1304 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
1305 }
1306 }
1307
1308 /*******************************************************************************
1309 **
1310 ** Function bta_ag_hsp_result
1311 **
1312 ** Description Handle API result for HSP connections.
1313 **
1314 **
1315 ** Returns void
1316 **
1317 *******************************************************************************/
bta_ag_hsp_result(tBTA_AG_SCB * p_scb,tBTA_AG_API_RESULT * p_result)1318 void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
1319 {
1320 UINT8 code = bta_ag_trans_result[p_result->result];
1321
1322 APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result);
1323
1324 switch(p_result->result)
1325 {
1326 case BTA_AG_SPK_RES:
1327 case BTA_AG_MIC_RES:
1328 bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
1329 break;
1330
1331 case BTA_AG_IN_CALL_RES:
1332 /* tell sys to stop av if any */
1333 bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1334
1335 /* if sco already opened or no inband ring send ring now */
1336 if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
1337 (p_scb->features & BTA_AG_FEAT_NOSCO))
1338 {
1339 bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
1340 }
1341 /* else open sco, send ring after sco opened */
1342 else
1343 {
1344 /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
1345 if (p_scb->hsp_version >= HSP_VERSION_1_2)
1346 p_scb->post_sco = BTA_AG_POST_SCO_NONE;
1347 else
1348 p_scb->post_sco = BTA_AG_POST_SCO_RING;
1349
1350 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1351 }
1352 break;
1353
1354 case BTA_AG_IN_CALL_CONN_RES:
1355 case BTA_AG_OUT_CALL_ORIG_RES:
1356 /* if incoming call connected stop ring timer */
1357 if (p_result->result == BTA_AG_IN_CALL_CONN_RES)
1358 {
1359 bta_sys_stop_timer(&p_scb->act_timer);
1360 }
1361
1362 if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
1363 {
1364 /* if audio connected to this scb open sco */
1365 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
1366 {
1367 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1368 }
1369 /* else if no audio at call close sco */
1370 else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
1371 {
1372 bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
1373 }
1374 }
1375 break;
1376
1377 case BTA_AG_END_CALL_RES:
1378 /* stop ring timer */
1379 bta_sys_stop_timer(&p_scb->act_timer);
1380
1381 /* close sco */
1382 if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
1383 {
1384 bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
1385 }
1386 else
1387 {
1388 /* if av got suspended by this call, let it resume. */
1389 bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1390 }
1391 break;
1392
1393 case BTA_AG_INBAND_RING_RES:
1394 p_scb->inband_enabled = p_result->data.state;
1395 APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
1396 break;
1397
1398 case BTA_AG_UNAT_RES:
1399 if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
1400 {
1401 if (p_result->data.str[0] != 0)
1402 {
1403 bta_ag_send_result(p_scb, code, p_result->data.str, 0);
1404 }
1405
1406 if (p_result->data.ok_flag == BTA_AG_OK_DONE)
1407 bta_ag_send_ok(p_scb);
1408 }
1409 else
1410 {
1411 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
1412 }
1413 break;
1414
1415 default:
1416 /* ignore all others */
1417 break;
1418 }
1419 }
1420
1421 /*******************************************************************************
1422 **
1423 ** Function bta_ag_hfp_result
1424 **
1425 ** Description Handle API result for HFP connections.
1426 **
1427 **
1428 ** Returns void
1429 **
1430 *******************************************************************************/
bta_ag_hfp_result(tBTA_AG_SCB * p_scb,tBTA_AG_API_RESULT * p_result)1431 void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
1432 {
1433 UINT8 code = bta_ag_trans_result[p_result->result];
1434
1435 APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
1436
1437 switch(p_result->result)
1438 {
1439 case BTA_AG_SPK_RES:
1440 case BTA_AG_MIC_RES:
1441 bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
1442 break;
1443
1444 case BTA_AG_IN_CALL_RES:
1445 /* tell sys to stop av if any */
1446 bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1447
1448 /* store caller id string.
1449 * append type info at the end.
1450 * make sure a valid type info is passed.
1451 * otherwise add 129 as default type */
1452 if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || (p_result->data.num > BTA_AG_CLIP_TYPE_MAX))
1453 {
1454 if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
1455 p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
1456 }
1457
1458 APPL_TRACE_DEBUG("CLIP type :%d", p_result->data.num);
1459 p_scb->clip[0] = 0;
1460 if (p_result->data.str[0] != 0)
1461 sprintf(p_scb->clip,"%s,%d", p_result->data.str, p_result->data.num);
1462
1463 /* send callsetup indicator */
1464 if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)
1465 {
1466 /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO close. */
1467 p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
1468 }
1469 else
1470 {
1471 bta_ag_send_call_inds(p_scb, p_result->result);
1472
1473 /* if sco already opened or no inband ring send ring now */
1474 if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
1475 (p_scb->features & BTA_AG_FEAT_NOSCO))
1476 {
1477 bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
1478 }
1479 /* else open sco, send ring after sco opened */
1480 else
1481 {
1482 p_scb->post_sco = BTA_AG_POST_SCO_RING;
1483 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1484 }
1485 }
1486 break;
1487
1488 case BTA_AG_IN_CALL_CONN_RES:
1489 /* stop ring timer */
1490 bta_sys_stop_timer(&p_scb->act_timer);
1491
1492 /* if sco not opened and we need to open it, open sco first
1493 ** then send indicators
1494 */
1495 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
1496 !bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
1497 {
1498 p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
1499 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1500 }
1501 /* else if sco open and we need to close it, close sco first
1502 ** then send indicators
1503 */
1504 else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
1505 bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
1506 {
1507 p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN;
1508 bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
1509 }
1510 /* else send indicators now */
1511 else
1512 {
1513 bta_ag_send_call_inds(p_scb, p_result->result);
1514 }
1515 break;
1516
1517 case BTA_AG_IN_CALL_HELD_RES:
1518 /* stop ring timer */
1519 bta_sys_stop_timer(&p_scb->act_timer);
1520
1521 bta_ag_send_call_inds(p_scb, p_result->result);
1522
1523 break;
1524
1525 case BTA_AG_OUT_CALL_ORIG_RES:
1526 /* if sco open and we need to close it, close sco first
1527 ** then send indicators; else send indicators now
1528 */
1529 if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
1530 bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
1531 {
1532 p_scb->post_sco = BTA_AG_POST_SCO_CALL_ORIG;
1533 bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
1534 }
1535 else
1536 {
1537 bta_ag_send_call_inds(p_scb, p_result->result);
1538 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
1539 !(p_scb->features & BTA_AG_FEAT_NOSCO))
1540 {
1541 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1542 }
1543 }
1544 break;
1545
1546 case BTA_AG_OUT_CALL_ALERT_RES:
1547 /* send indicators */
1548 bta_ag_send_call_inds(p_scb, p_result->result);
1549 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
1550 !(p_scb->features & BTA_AG_FEAT_NOSCO))
1551 {
1552 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1553 }
1554 break;
1555
1556 case BTA_AG_OUT_CALL_CONN_RES:
1557 /* send indicators */
1558 bta_ag_send_call_inds(p_scb, p_result->result);
1559
1560 /* open or close sco */
1561 if (!(p_scb->features & BTA_AG_FEAT_NOSCO))
1562 {
1563 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
1564 {
1565 bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
1566 }
1567 else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
1568 {
1569 bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
1570 }
1571 }
1572 break;
1573
1574 case BTA_AG_CALL_CANCEL_RES:
1575 /* send indicators */
1576 bta_ag_send_call_inds(p_scb, p_result->result);
1577 break;
1578
1579 case BTA_AG_END_CALL_RES:
1580 /* stop ring timer */
1581 bta_sys_stop_timer(&p_scb->act_timer);
1582
1583 /* if sco open, close sco then send indicator values */
1584 if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO))
1585 {
1586 p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
1587 bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
1588 }
1589 else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL)
1590 {
1591 /* sco closing for outgoing call because of incoming call */
1592 /* Send only callsetup end indicator after sco close */
1593 p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
1594 }
1595 else
1596 {
1597 bta_ag_send_call_inds(p_scb, p_result->result);
1598
1599 /* if av got suspended by this call, let it resume. */
1600 bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1601 }
1602 break;
1603
1604 case BTA_AG_INBAND_RING_RES:
1605 p_scb->inband_enabled = p_result->data.state;
1606 APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
1607 bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
1608 break;
1609
1610 case BTA_AG_CIND_RES:
1611 /* store local values */
1612 p_scb->call_ind = p_result->data.str[0] - '0';
1613 p_scb->callsetup_ind = p_result->data.str[2] - '0';
1614 p_scb->service_ind = p_result->data.str[4] - '0';
1615 p_scb->signal_ind = p_result->data.str[6] - '0';
1616 p_scb->roam_ind = p_result->data.str[8] - '0';
1617 p_scb->battchg_ind = p_result->data.str[10] - '0';
1618 APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind);
1619
1620 bta_ag_send_result(p_scb, code, p_result->data.str, 0);
1621 bta_ag_send_ok(p_scb);
1622 break;
1623
1624 case BTA_AG_BINP_RES:
1625 case BTA_AG_CNUM_RES:
1626 case BTA_AG_CLCC_RES:
1627 case BTA_AG_COPS_RES:
1628 if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
1629 {
1630 if (p_result->data.str[0] != 0)
1631 {
1632 bta_ag_send_result(p_scb, code, p_result->data.str, 0);
1633 }
1634
1635 if (p_result->data.ok_flag == BTA_AG_OK_DONE)
1636 bta_ag_send_ok(p_scb);
1637 }
1638 else
1639 {
1640 bta_ag_send_error(p_scb, p_result->data.errcode);
1641 }
1642 break;
1643
1644
1645 case BTA_AG_UNAT_RES:
1646 if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
1647 {
1648 if (p_result->data.str[0] != 0)
1649 {
1650 bta_ag_process_unat_res(p_result->data.str);
1651 APPL_TRACE_DEBUG("BTA_AG_RES :%s",p_result->data.str);
1652 bta_ag_send_result(p_scb, code, p_result->data.str, 0);
1653 }
1654
1655 if (p_result->data.ok_flag == BTA_AG_OK_DONE)
1656 bta_ag_send_ok(p_scb);
1657 }
1658 else
1659 {
1660 bta_ag_send_error(p_scb, p_result->data.errcode);
1661 }
1662 break;
1663
1664 case BTA_AG_CALL_WAIT_RES:
1665 if (p_scb->ccwa_enabled)
1666 {
1667 bta_ag_send_result(p_scb, code, p_result->data.str, 0);
1668 }
1669 bta_ag_send_call_inds(p_scb, p_result->result);
1670 break;
1671
1672 case BTA_AG_IND_RES:
1673 bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value, FALSE);
1674 break;
1675
1676 case BTA_AG_BVRA_RES:
1677 bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
1678 break;
1679
1680 case BTA_AG_BTRH_RES:
1681 if (p_result->data.ok_flag != BTA_AG_OK_ERROR)
1682 {
1683 /* Don't respond to read if not in response & hold state */
1684 if (p_result->data.num != BTA_AG_BTRH_NO_RESP)
1685 {
1686 bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
1687 }
1688
1689 /* In case of a response to a read request we need to send OK */
1690 if (p_result->data.ok_flag == BTA_AG_OK_DONE)
1691 bta_ag_send_ok(p_scb);
1692 }
1693 else
1694 {
1695 bta_ag_send_error(p_scb, p_result->data.errcode);
1696 }
1697 break;
1698
1699 default:
1700 break;
1701 }
1702 }
1703
1704
1705 /*******************************************************************************
1706 **
1707 ** Function bta_ag_result
1708 **
1709 ** Description Handle API result.
1710 **
1711 **
1712 ** Returns void
1713 **
1714 *******************************************************************************/
bta_ag_result(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1715 void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1716 {
1717 if (p_scb->conn_service == BTA_AG_HSP)
1718 {
1719 bta_ag_hsp_result(p_scb, &p_data->api_result);
1720 }
1721 else
1722 {
1723 bta_ag_hfp_result(p_scb, &p_data->api_result);
1724 }
1725 }
1726
1727 #if (BTM_WBS_INCLUDED == TRUE )
1728 /*******************************************************************************
1729 **
1730 ** Function bta_ag_send_bcs
1731 **
1732 ** Description Send +BCS AT command to peer.
1733 **
1734 ** Returns void
1735 **
1736 *******************************************************************************/
bta_ag_send_bcs(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1737 void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1738 {
1739 UINT16 codec_uuid;
1740
1741 if (p_scb->codec_fallback)
1742 {
1743 codec_uuid = UUID_CODEC_CVSD;
1744 }
1745 else
1746 {
1747 switch(p_scb->sco_codec)
1748 {
1749 case BTA_AG_CODEC_NONE: codec_uuid = UUID_CODEC_CVSD; break;
1750 case BTA_AG_CODEC_CVSD: codec_uuid = UUID_CODEC_CVSD; break;
1751 case BTA_AG_CODEC_MSBC: codec_uuid = UUID_CODEC_MSBC; break;
1752 default:
1753 APPL_TRACE_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD", p_scb->sco_codec);
1754 codec_uuid = UUID_CODEC_CVSD;
1755 break;
1756 }
1757 }
1758
1759 /* send +BCS */
1760 APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid);
1761 bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid);
1762
1763 }
1764 #endif
1765
1766 /*******************************************************************************
1767 **
1768 ** Function bta_ag_send_ring
1769 **
1770 ** Description Send RING result code to peer.
1771 **
1772 **
1773 ** Returns void
1774 **
1775 *******************************************************************************/
bta_ag_send_ring(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1776 void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1777 {
1778 UNUSED(p_data);
1779
1780 #if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
1781 tBTA_AG_MULTI_RESULT_CB m_res_cb;
1782
1783 if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
1784 {
1785 memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB));
1786
1787 m_res_cb.num_result = 2;
1788 AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0)
1789 AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0)
1790
1791 bta_ag_send_multi_result(p_scb, &m_res_cb);
1792 }
1793 else
1794 {
1795 /* send RING ONLY */
1796 bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
1797 }
1798 #else
1799 /* send RING */
1800 bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
1801
1802 /* if HFP and clip enabled and clip data send CLIP */
1803 if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0)
1804 {
1805 bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0);
1806 }
1807 #endif
1808
1809 /* restart ring timer */
1810 bta_sys_start_timer(&p_scb->act_timer, BTA_AG_RING_TOUT_EVT, BTA_AG_RING_TOUT);
1811 }
1812
1813
1814