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******************************************************************************/
44void 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******************************************************************************/
62void 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******************************************************************************/
83void 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******************************************************************************/
188void 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        p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len);
196        p_cb->cmd_pos = 0;
197    }
198
199    for (i = 0; i < len;)
200    {
201        while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len)
202        {
203            /* Skip null characters between AT commands. */
204            if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0))
205            {
206                i++;
207                continue;
208            }
209
210            p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
211            if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n')
212            {
213                p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
214                if ((p_cb->cmd_pos > 2)                                      &&
215                    (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
216                    (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't'))
217                {
218                    p_save = p_cb->p_cmd_buf;
219                    p_cb->p_cmd_buf += 2;
220                    bta_ag_process_at(p_cb);
221                    p_cb->p_cmd_buf = p_save;
222                }
223
224                p_cb->cmd_pos = 0;
225
226            }
227            else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B )
228            {
229                p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
230                (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
231                p_cb->cmd_pos = 0;
232            }
233            else
234            {
235                ++p_cb->cmd_pos;
236            }
237        }
238
239        if (i < len)
240            p_cb->cmd_pos = 0;
241    }
242}
243
244