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 "osi/allocator.h"
27 #include "bta_ag_at.h"
28 #include "bta/utl.h"
29
30 #if (BTA_AG_INCLUDED == TRUE)
31 /******************************************************************************
32 **
33 ** Function bta_ag_at_init
34 **
35 ** Description Initialize the AT command parser control block.
36 **
37 **
38 ** Returns void
39 **
40 ******************************************************************************/
bta_ag_at_init(tBTA_AG_AT_CB * p_cb)41 void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
42 {
43 p_cb->p_cmd_buf = NULL;
44 p_cb->cmd_pos = 0;
45 }
46
47 /******************************************************************************
48 **
49 ** Function bta_ag_at_reinit
50 **
51 ** Description Re-initialize the AT command parser control block. This
52 ** function resets the AT command parser state and frees
53 ** any GKI buffer.
54 **
55 **
56 ** Returns void
57 **
58 ******************************************************************************/
bta_ag_at_reinit(tBTA_AG_AT_CB * p_cb)59 void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
60 {
61 if (p_cb->p_cmd_buf != NULL) {
62 osi_free(p_cb->p_cmd_buf);
63 p_cb->p_cmd_buf = NULL;
64 }
65 p_cb->cmd_pos = 0;
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 {
81 UINT16 idx;
82 UINT8 arg_type;
83 char *p_arg;
84 INT16 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 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 arg_type = BTA_AG_AT_READ; /* we have a read */
103 }
104 /* else if arg is '=' */
105 else if (p_arg[0] == '=' && p_arg[1] != 0) {
106 if (p_arg[1] == '?' && p_arg[2] == 0) {
107 arg_type = BTA_AG_AT_TEST; /* we have a test */
108 } else {
109 arg_type = BTA_AG_AT_SET; /* we have a set */
110 p_arg++; /* skip past '=' */
111 }
112 }
113 /* else it is freeform argument */
114 else {
115 arg_type = BTA_AG_AT_FREE;
116 }
117 /* if arguments match command capabilities */
118 if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) {
119 /* if it's a set integer check max, min range */
120 if (arg_type == BTA_AG_AT_SET && p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) {
121 int_arg = utl_str2int(p_arg);
122 if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
123 int_arg > (INT16) p_cb->p_at_tbl[idx].max) {
124 /* arg out of range; error */
125 (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
126 } else {
127 (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
128 }
129 } else {
130 (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
131 }
132 } else {
133 /* else error */
134 (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
135 }
136 } else {
137 /* else no match call error callback */
138 (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
139 }
140 }
141
142 /******************************************************************************
143 **
144 ** Function bta_ag_at_parse
145 **
146 ** Description Parse AT commands. This function will take the input
147 ** character string and parse it for AT commands according to
148 ** the AT command table passed in the control block.
149 **
150 **
151 ** Returns void
152 **
153 ******************************************************************************/
bta_ag_at_parse(tBTA_AG_AT_CB * p_cb,char * p_buf,UINT16 len)154 void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
155 {
156 int i = 0;
157 char* p_save;
158
159 if (p_cb->p_cmd_buf == NULL) {
160 if ((p_cb->p_cmd_buf = (char *) osi_malloc(p_cb->cmd_max_len)) == NULL) {
161 APPL_TRACE_ERROR("%s: osi_malloc() failed allocation", __func__);
162 return;
163 }
164 p_cb->cmd_pos = 0;
165 }
166
167 for (i = 0; i < len;) {
168 while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len) {
169 /* Skip null characters between AT commands. */
170 if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) {
171 i++;
172 continue;
173 }
174 p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
175 if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') {
176 p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
177 if ((p_cb->cmd_pos > 2) &&
178 (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
179 (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) {
180 p_save = p_cb->p_cmd_buf;
181 p_cb->p_cmd_buf += 2;
182 bta_ag_process_at(p_cb);
183 p_cb->p_cmd_buf = p_save;
184 }
185 p_cb->cmd_pos = 0;
186 } else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
187 p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
188 (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
189 p_cb->cmd_pos = 0;
190 } else {
191 ++p_cb->cmd_pos;
192 }
193 }
194
195 if (i < len) {
196 p_cb->cmd_pos = 0;
197 }
198 }
199 }
200
201 #endif /* #if (BTA_AG_INCLUDED == TRUE) */
202