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