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 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