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