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 27 #include "bt_common.h" 28 #include "bta_ag_at.h" 29 #include "utl.h" 30 31 /***************************************************************************** 32 * Constants 33 ****************************************************************************/ 34 35 /****************************************************************************** 36 * 37 * Function bta_ag_at_init 38 * 39 * Description Initialize the AT command parser control block. 40 * 41 * 42 * Returns void 43 * 44 *****************************************************************************/ 45 void bta_ag_at_init(tBTA_AG_AT_CB* p_cb) { 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 osi_free_and_reset((void**)&p_cb->p_cmd_buf); 64 p_cb->cmd_pos = 0; 65 } 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 *****************************************************************************/ 79 void bta_ag_process_at(tBTA_AG_AT_CB* p_cb) { 80 uint16_t idx; 81 uint8_t arg_type; 82 char* p_arg; 83 int16_t int_arg = 0; 84 /* loop through at command table looking for match */ 85 for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++) { 86 if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf)) { 87 break; 88 } 89 } 90 91 /* if there is a match; verify argument type */ 92 if (p_cb->p_at_tbl[idx].p_cmd[0] != 0) { 93 /* start of argument is p + strlen matching command */ 94 p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd); 95 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 /* we have a read */ 103 arg_type = BTA_AG_AT_READ; 104 } 105 /* else if arg is '=' */ 106 else if (p_arg[0] == '=' && p_arg[1] != 0) { 107 if (p_arg[1] == '?' && p_arg[2] == 0) { 108 /* we have a test */ 109 arg_type = BTA_AG_AT_TEST; 110 } else { 111 /* we have a set */ 112 arg_type = BTA_AG_AT_SET; 113 114 /* skip past '=' */ 115 p_arg++; 116 } 117 } else 118 /* else it is freeform argument */ 119 { 120 arg_type = BTA_AG_AT_FREE; 121 } 122 123 /* if arguments match command capabilities */ 124 if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) { 125 /* if it's a set integer check max, min range */ 126 if (arg_type == BTA_AG_AT_SET && 127 p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) { 128 int_arg = utl_str2int(p_arg); 129 if (int_arg < (int16_t)p_cb->p_at_tbl[idx].min || 130 int_arg > (int16_t)p_cb->p_at_tbl[idx].max) { 131 /* arg out of range; error */ 132 (*p_cb->p_err_cback)(p_cb->p_user, false, NULL); 133 } else { 134 (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id, 135 arg_type, p_arg, int_arg); 136 } 137 } else { 138 (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id, 139 arg_type, p_arg, int_arg); 140 } 141 } 142 /* else error */ 143 else { 144 (*p_cb->p_err_cback)(p_cb->p_user, false, NULL); 145 } 146 } 147 /* else no match call error callback */ 148 else { 149 (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf); 150 } 151 } 152 153 /****************************************************************************** 154 * 155 * Function bta_ag_at_parse 156 * 157 * Description Parse AT commands. This function will take the input 158 * character string and parse it for AT commands according to 159 * the AT command table passed in the control block. 160 * 161 * 162 * Returns void 163 * 164 *****************************************************************************/ 165 void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len) { 166 int i = 0; 167 char* p_save; 168 169 if (p_cb->p_cmd_buf == NULL) { 170 p_cb->p_cmd_buf = (char*)osi_malloc(p_cb->cmd_max_len); 171 p_cb->cmd_pos = 0; 172 } 173 174 for (i = 0; i < len;) { 175 while (p_cb->cmd_pos < p_cb->cmd_max_len - 1 && i < len) { 176 /* Skip null characters between AT commands. */ 177 if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) { 178 i++; 179 continue; 180 } 181 182 p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++]; 183 if (p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || 184 p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') { 185 p_cb->p_cmd_buf[p_cb->cmd_pos] = 0; 186 if ((p_cb->cmd_pos > 2) && 187 (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') && 188 (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) { 189 p_save = p_cb->p_cmd_buf; 190 p_cb->p_cmd_buf += 2; 191 bta_ag_process_at(p_cb); 192 p_cb->p_cmd_buf = p_save; 193 } 194 195 p_cb->cmd_pos = 0; 196 197 } else if (p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || 198 p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) { 199 p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0; 200 (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf); 201 p_cb->cmd_pos = 0; 202 } else { 203 ++p_cb->cmd_pos; 204 } 205 } 206 207 if (i < len) p_cb->cmd_pos = 0; 208 } 209 } 210