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