Home | History | Annotate | Download | only in ag
      1 /******************************************************************************
      2  *
      3  *  Copyright 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 <cstring>
     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 = nullptr;
     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)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
    133         } else {
    134           (*p_cb->p_cmd_cback)((tBTA_AG_SCB*)p_cb->p_user,
    135                                p_cb->p_at_tbl[idx].command_id, arg_type, p_arg,
    136                                int_arg);
    137         }
    138       } else {
    139         (*p_cb->p_cmd_cback)((tBTA_AG_SCB*)p_cb->p_user,
    140                              p_cb->p_at_tbl[idx].command_id, arg_type, p_arg,
    141                              int_arg);
    142       }
    143     }
    144     /* else error */
    145     else {
    146       (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
    147     }
    148   }
    149   /* else no match call error callback */
    150   else {
    151     (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, true, p_cb->p_cmd_buf);
    152   }
    153 }
    154 
    155 /******************************************************************************
    156  *
    157  * Function         bta_ag_at_parse
    158  *
    159  * Description      Parse AT commands.  This function will take the input
    160  *                  character string and parse it for AT commands according to
    161  *                  the AT command table passed in the control block.
    162  *
    163  *
    164  * Returns          void
    165  *
    166  *****************************************************************************/
    167 void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len) {
    168   int i = 0;
    169   char* p_save;
    170 
    171   if (p_cb->p_cmd_buf == nullptr) {
    172     p_cb->p_cmd_buf = (char*)osi_malloc(p_cb->cmd_max_len);
    173     p_cb->cmd_pos = 0;
    174   }
    175 
    176   for (i = 0; i < len;) {
    177     while (p_cb->cmd_pos < p_cb->cmd_max_len - 1 && i < len) {
    178       /* Skip null characters between AT commands. */
    179       if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) {
    180         i++;
    181         continue;
    182       }
    183 
    184       p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
    185       if (p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' ||
    186           p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') {
    187         p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
    188         if ((p_cb->cmd_pos > 2) &&
    189             (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
    190             (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) {
    191           p_save = p_cb->p_cmd_buf;
    192           p_cb->p_cmd_buf += 2;
    193           bta_ag_process_at(p_cb);
    194           p_cb->p_cmd_buf = p_save;
    195         }
    196 
    197         p_cb->cmd_pos = 0;
    198 
    199       } else if (p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A ||
    200                  p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
    201         p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
    202         (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, true, p_cb->p_cmd_buf);
    203         p_cb->cmd_pos = 0;
    204       } else {
    205         ++p_cb->cmd_pos;
    206       }
    207     }
    208 
    209     if (i < len) p_cb->cmd_pos = 0;
    210   }
    211 }
    212