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