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 "gki.h"
27 #include "bta_ag_at.h"
28 #include "utl.h"
29 
30 /*****************************************************************************
31 **  Constants
32 *****************************************************************************/
33 
34 /******************************************************************************
35 **
36 ** Function         bta_ag_at_init
37 **
38 ** Description      Initialize the AT command parser control block.
39 **
40 **
41 ** Returns          void
42 **
43 ******************************************************************************/
bta_ag_at_init(tBTA_AG_AT_CB * p_cb)44 void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
45 {
46     p_cb->p_cmd_buf = NULL;
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 {
64     if (p_cb->p_cmd_buf != NULL)
65     {
66         GKI_freebuf(p_cb->p_cmd_buf);
67         p_cb->p_cmd_buf = NULL;
68     }
69     p_cb->cmd_pos = 0;
70 }
71 /******************************************************************************
72 **
73 ** Function         bta_ag_process_at
74 **
75 ** Description      Parse AT commands.  This function will take the input
76 **                  character string and parse it for AT commands according to
77 **                  the AT command table passed in the control block.
78 **
79 **
80 ** Returns          void
81 **
82 ******************************************************************************/
bta_ag_process_at(tBTA_AG_AT_CB * p_cb)83 void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
84 {
85     UINT16      idx;
86     UINT8       arg_type;
87     char        *p_arg;
88     INT16       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     {
92         if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf))
93         {
94             break;
95         }
96     }
97 
98     /* if there is a match; verify argument type */
99     if (p_cb->p_at_tbl[idx].p_cmd[0] != 0)
100     {
101         /* start of argument is p + strlen matching command */
102         p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
103 
104         /* if no argument */
105         if (p_arg[0] == 0)
106         {
107             arg_type = BTA_AG_AT_NONE;
108         }
109         /* else if arg is '?' and it is last character */
110         else if (p_arg[0] == '?' && p_arg[1] == 0)
111         {
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         {
118             if (p_arg[1] == '?' && p_arg[2] == 0)
119             {
120                 /* we have a test */
121                 arg_type = BTA_AG_AT_TEST;
122             }
123             else
124             {
125                 /* we have a set */
126                 arg_type = BTA_AG_AT_SET;
127 
128                 /* skip past '=' */
129                 p_arg++;
130             }
131         }
132         else
133         /* else it is freeform argument */
134         {
135             arg_type = BTA_AG_AT_FREE;
136         }
137 
138         /* if arguments match command capabilities */
139         if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0)
140         {
141             /* if it's a set integer check max, min range */
142             if (arg_type == BTA_AG_AT_SET &&
143                 p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT)
144             {
145                 int_arg = utl_str2int(p_arg);
146                 if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
147                     int_arg > (INT16) p_cb->p_at_tbl[idx].max)
148                 {
149                     /* arg out of range; error */
150                     (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
151                 }
152                 else
153                 {
154 
155                     (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
156                 }
157             }
158             else
159             {
160                 (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
161             }
162         }
163         /* else error */
164         else
165         {
166             (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
167         }
168     }
169     /* else no match call error callback */
170     else
171     {
172         (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
173     }
174 }
175 
176 /******************************************************************************
177 **
178 ** Function         bta_ag_at_parse
179 **
180 ** Description      Parse AT commands.  This function will take the input
181 **                  character string and parse it for AT commands according to
182 **                  the AT command table passed in the control block.
183 **
184 **
185 ** Returns          void
186 **
187 ******************************************************************************/
bta_ag_at_parse(tBTA_AG_AT_CB * p_cb,char * p_buf,UINT16 len)188 void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
189 {
190     int i = 0;
191     char* p_save;
192 
193     if (p_cb->p_cmd_buf == NULL)
194     {
195         if ((p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len)) == NULL)
196         {
197             APPL_TRACE_ERROR("%s: GKI_getbuf() failed allocation", __func__);
198             return;
199         }
200         p_cb->cmd_pos = 0;
201     }
202 
203     for (i = 0; i < len;)
204     {
205         while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len)
206         {
207             /* Skip null characters between AT commands. */
208             if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0))
209             {
210                 i++;
211                 continue;
212             }
213 
214             p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
215             if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n')
216             {
217                 p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
218                 if ((p_cb->cmd_pos > 2)                                      &&
219                     (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
220                     (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
221                 {
222                     p_save = p_cb->p_cmd_buf;
223                     p_cb->p_cmd_buf += 2;
224                     bta_ag_process_at(p_cb);
225                     p_cb->p_cmd_buf = p_save;
226                 }
227 
228                 p_cb->cmd_pos = 0;
229 
230             }
231             else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B )
232             {
233                 p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
234                 (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
235                 p_cb->cmd_pos = 0;
236             }
237             else
238             {
239                 ++p_cb->cmd_pos;
240             }
241         }
242 
243         if (i < len)
244             p_cb->cmd_pos = 0;
245     }
246 }
247 
248