• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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