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 * BTA AG AT command interpreter.
22 *
23 ******************************************************************************/
24
25 #include <string.h>
26 #include "bt_common.h"
27 #include "bta_ag_at.h"
28 #include "utl.h"
29
30 /*****************************************************************************
31 ** Constants
32 *****************************************************************************/
33
34 /******************************************************************************
35 **
36 ** Function bta_ag_at_init
37 **
38 ** Description Initialize the AT command parser control block.
39 **
40 **
41 ** Returns void
42 **
43 ******************************************************************************/
bta_ag_at_init(tBTA_AG_AT_CB * p_cb)44 void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
45 {
46 p_cb->p_cmd_buf = NULL;
47 p_cb->cmd_pos = 0;
48 }
49
50 /******************************************************************************
51 **
52 ** Function bta_ag_at_reinit
53 **
54 ** Description Re-initialize the AT command parser control block. This
55 ** function resets the AT command parser state and frees
56 ** any GKI buffer.
57 **
58 **
59 ** Returns void
60 **
61 ******************************************************************************/
bta_ag_at_reinit(tBTA_AG_AT_CB * p_cb)62 void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
63 {
64 osi_free_and_reset((void **)&p_cb->p_cmd_buf);
65 p_cb->cmd_pos = 0;
66 }
67
68 /******************************************************************************
69 **
70 ** Function bta_ag_process_at
71 **
72 ** Description Parse AT commands. This function will take the input
73 ** character string and parse it for AT commands according to
74 ** the AT command table passed in the control block.
75 **
76 **
77 ** Returns void
78 **
79 ******************************************************************************/
bta_ag_process_at(tBTA_AG_AT_CB * p_cb)80 void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
81 {
82 UINT16 idx;
83 UINT8 arg_type;
84 char *p_arg;
85 INT16 int_arg = 0;
86 /* loop through at command table looking for match */
87 for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++)
88 {
89 if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf))
90 {
91 break;
92 }
93 }
94
95 /* if there is a match; verify argument type */
96 if (p_cb->p_at_tbl[idx].p_cmd[0] != 0)
97 {
98 /* start of argument is p + strlen matching command */
99 p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
100
101 /* if no argument */
102 if (p_arg[0] == 0)
103 {
104 arg_type = BTA_AG_AT_NONE;
105 }
106 /* else if arg is '?' and it is last character */
107 else if (p_arg[0] == '?' && p_arg[1] == 0)
108 {
109 /* we have a read */
110 arg_type = BTA_AG_AT_READ;
111 }
112 /* else if arg is '=' */
113 else if (p_arg[0] == '=' && p_arg[1] != 0)
114 {
115 if (p_arg[1] == '?' && p_arg[2] == 0)
116 {
117 /* we have a test */
118 arg_type = BTA_AG_AT_TEST;
119 }
120 else
121 {
122 /* we have a set */
123 arg_type = BTA_AG_AT_SET;
124
125 /* skip past '=' */
126 p_arg++;
127 }
128 }
129 else
130 /* else it is freeform argument */
131 {
132 arg_type = BTA_AG_AT_FREE;
133 }
134
135 /* if arguments match command capabilities */
136 if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0)
137 {
138 /* if it's a set integer check max, min range */
139 if (arg_type == BTA_AG_AT_SET &&
140 p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT)
141 {
142 int_arg = utl_str2int(p_arg);
143 if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
144 int_arg > (INT16) p_cb->p_at_tbl[idx].max)
145 {
146 /* arg out of range; error */
147 (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
148 }
149 else
150 {
151
152 (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
153 }
154 }
155 else
156 {
157 (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
158 }
159 }
160 /* else error */
161 else
162 {
163 (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
164 }
165 }
166 /* else no match call error callback */
167 else
168 {
169 (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
170 }
171 }
172
173 /******************************************************************************
174 **
175 ** Function bta_ag_at_parse
176 **
177 ** Description Parse AT commands. This function will take the input
178 ** character string and parse it for AT commands according to
179 ** the AT command table passed in the control block.
180 **
181 **
182 ** Returns void
183 **
184 ******************************************************************************/
bta_ag_at_parse(tBTA_AG_AT_CB * p_cb,char * p_buf,UINT16 len)185 void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
186 {
187 int i = 0;
188 char* p_save;
189
190 if (p_cb->p_cmd_buf == NULL) {
191 p_cb->p_cmd_buf = (char *)osi_malloc(p_cb->cmd_max_len);
192 p_cb->cmd_pos = 0;
193 }
194
195 for (i = 0; i < len;)
196 {
197 while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len)
198 {
199 /* Skip null characters between AT commands. */
200 if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0))
201 {
202 i++;
203 continue;
204 }
205
206 p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
207 if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n')
208 {
209 p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
210 if ((p_cb->cmd_pos > 2) &&
211 (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
212 (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
213 {
214 p_save = p_cb->p_cmd_buf;
215 p_cb->p_cmd_buf += 2;
216 bta_ag_process_at(p_cb);
217 p_cb->p_cmd_buf = p_save;
218 }
219
220 p_cb->cmd_pos = 0;
221
222 }
223 else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B )
224 {
225 p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
226 (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
227 p_cb->cmd_pos = 0;
228 }
229 else
230 {
231 ++p_cb->cmd_pos;
232 }
233 }
234
235 if (i < len)
236 p_cb->cmd_pos = 0;
237 }
238 }
239
240