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