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