[Feature][T8TSK-139][AT]common at update

Change-Id: Ibe0eca6a324ba5cc8768375a3b1d1f5a830b2f1f
diff --git a/src/lynq/lib/liblynq-at-common/LICENSE b/src/lynq/lib/liblynq-at-common/LICENSE
new file mode 100755
index 0000000..382fc78
--- /dev/null
+++ b/src/lynq/lib/liblynq-at-common/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:

+

+This software/firmware and related documentation ("Mobiletek Software") are

+protected under relevant copyright laws. The information contained herein is

+confidential and proprietary to Mobiletek Inc. and/or its licensors. Without

+the prior written permission of Mobiletek inc. and/or its licensors, any

+reproduction, modification, use or disclosure of Mobiletek Software, and

+information contained herein, in whole or in part, shall be strictly

+prohibited.

+

+Mobiletek Inc. (C) 2015. All rights reserved.

+

+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("Mobiletek SOFTWARE")

+RECEIVED FROM Mobiletek AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ON AN "AS-IS" BASIS ONLY. Mobiletek EXPRESSLY DISCLAIMS ANY AND ALL

+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+NONINFRINGEMENT. NEITHER DOES Mobiletek PROVIDE ANY WARRANTY WHATSOEVER WITH

+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+INCORPORATED IN, OR SUPPLIED WITH THE Mobiletek SOFTWARE, AND RECEIVER AGREES

+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN Mobiletek

+SOFTWARE. Mobiletek SHALL ALSO NOT BE RESPONSIBLE FOR ANY Mobiletek SOFTWARE

+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND Mobiletek'S

+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE Mobiletek SOFTWARE

+RELEASED HEREUNDER WILL BE, AT Mobiletek'S OPTION, TO REVISE OR REPLACE THE

+Mobiletek SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+CHARGE PAID BY RECEIVER TO Mobiletek FOR SUCH Mobiletek SOFTWARE AT ISSUE.
\ No newline at end of file
diff --git a/src/lynq/lib/liblynq-at-common/atci_at_util.cpp b/src/lynq/lib/liblynq-at-common/atci_at_util.cpp
new file mode 100755
index 0000000..4c215a7
--- /dev/null
+++ b/src/lynq/lib/liblynq-at-common/atci_at_util.cpp
@@ -0,0 +1,171 @@
+#include <string.h>
+#include <stdlib.h>
+#include <log/log.h>
+#include "atci_at_util.h"
+
+#undef LOG_TAG
+#define LOG_TAG "AT_COMMON"
+
+int atci_at_skip_space(char **p_cur) {
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  while (**p_cur == ATCI_SPACE) {
+    (*p_cur)++;
+  }
+  return SYS_SUCC;
+}
+int atci_at_hasmore(char **p_cur) {
+  if (*p_cur == NULL || **p_cur == ATCI_END_CHAR) {
+    return SYS_FAIL;
+  }
+  return SYS_SUCC;
+}
+
+int atci_at_to_equal(char **p_cur) {
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  *p_cur = strchr(*p_cur, ATCI_EQUAL);
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  (*p_cur)++;
+  return SYS_SUCC;
+}
+int atci_at_to_colon(char **p_cur) {
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  *p_cur = strchr(*p_cur, ATCI_COLON);
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  (*p_cur)++;
+  return SYS_SUCC;
+}
+int atci_at_skip_next_comma(char **p_cur) {
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  *p_cur = strchr(*p_cur, ATCI_COMMA);
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  (*p_cur)++;
+  return SYS_SUCC;
+}
+int atci_at_get_next_key(char **p_cur, char **p_out) {
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  atci_at_skip_space(p_cur);
+  if (**p_cur == ATCI_DOUBLE_QUOTE) {
+    (*p_cur)++;
+    *p_out = strsep(p_cur, "\"");
+    atci_at_skip_next_comma(p_cur);
+  } else {
+    *p_out = strsep(p_cur, ",");
+  }
+  return SYS_SUCC;
+}
+
+/**
+ * Parses the next integer in the  line and places it in *p_out
+ * "uns" is indicate in unsigned or not
+ * returns SYS_SUCC on success
+ * returns SYS_FAIL  on fail
+ * updates *p_cur
+ * "base" is the same as the base param in strtol
+ */
+int atci_at_get_nextint_base(char **p_cur, int *p_out, int base, int uns) {
+  char *ret;
+  if (*p_cur == NULL) {
+    return SYS_FAIL;
+  }
+  if (SYS_FAIL == atci_at_get_next_key(p_cur, &ret)) {
+    return SYS_FAIL;
+  } else {
+    long l;
+    char *end;
+    if (uns) {
+      l = strtoul(ret, &end, base);
+    } else {
+      l = strtol(ret, &end, base);
+    }
+    *p_out = (int) l;
+    if (end == ret) {
+      return SYS_FAIL;
+    }
+  }
+  return SYS_SUCC;
+}
+int atci_at_get_nextint(char **p_cur, int *p_out) {
+  return atci_at_get_nextint_base(p_cur, p_out, 10, 0);
+}
+int atci_at_get_nexthexint(char **p_cur, int *p_out) {
+  return atci_at_get_nextint_base(p_cur, p_out, 16, 1);
+}
+int atci_get_cmd_mode(char *line) {
+  int reasult = AT_WRONG_MODE;
+  char *p_cur = NULL;
+  if (NULL == line) {
+    reasult = AT_WRONG_MODE;
+    RLOGD("atci_get_cmd_mode error, input is NULL");
+    return reasult;
+  }
+  p_cur = strchr(line, ATCI_EQUAL);
+  if (NULL == p_cur) {
+    p_cur = strchr(line, ATCI_QUESTION_MARK);
+    if (NULL == p_cur) {
+      reasult = AT_ACTIVE_MODE;
+    } else {
+      reasult = AT_READ_MODE;
+    }
+  } else {
+    p_cur++;
+    atci_at_skip_space(&p_cur);
+    if (ATCI_QUESTION_MARK == *p_cur) {
+      reasult = AT_TEST_MODE;
+    } else {
+      reasult = AT_SET_MODE;
+    }
+  }
+  RLOGD("atci_get_cmd_mode success[%d]", reasult);
+  return reasult;
+}
+
+char* atci_get_cmd_prefix(char *line) {
+  int buf_len;
+  char *prefix;
+  char *end_ptr;
+  if (NULL == line) {
+    RLOGD("input is null");
+    return NULL;
+  }
+  end_ptr = line;
+  while (!ATCI_IS_CAHR(*end_ptr, ATCI_EQUAL)
+      && !ATCI_IS_CAHR(*end_ptr, ATCI_QUESTION_MARK)
+      && !ATCI_IS_CAHR(*end_ptr, ATCI_END_CHAR)
+      && !ATCI_IS_CAHR(*end_ptr, ATCI_CR) && !ATCI_IS_CAHR(*end_ptr, ATCI_LF)) {
+    end_ptr++;
+  }
+  buf_len = end_ptr - line + 1;
+  prefix = (char *) calloc(buf_len, 1);
+  if (prefix) {
+    int i;
+    char *in_ptr = line;
+    char *out_ptr = prefix;
+    for (i = 0; i < buf_len - 1; i++) {
+      if (!ATCI_IS_CAHR(*in_ptr, ATCI_SPACE)) {
+        *out_ptr = ATCI_UPPER_TO_LOWER(*in_ptr);
+        out_ptr++;
+      }
+      in_ptr++;
+    }
+    *out_ptr = ATCI_END_CHAR;
+  }
+  RLOGD("get cmd prefix [%d][%s]", buf_len, prefix);
+  return prefix;
+}
+
diff --git a/src/lynq/lib/liblynq-at-common/atci_at_util.h b/src/lynq/lib/liblynq-at-common/atci_at_util.h
new file mode 100755
index 0000000..d84fd63
--- /dev/null
+++ b/src/lynq/lib/liblynq-at-common/atci_at_util.h
@@ -0,0 +1,128 @@
+#ifndef _ATCI_AT_UTIL_H_
+#define _ATCI_AT_UTIL_H_
+
+#define SYS_SUCC                    0
+#define SYS_FAIL                    -1
+
+typedef enum {
+  ATCI_SPACE = ' ',
+  ATCI_EQUAL = '=',
+  ATCI_COMMA = ',',
+  ATCI_SEMICOLON = ';',
+  ATCI_COLON = ':',
+  ATCI_AT = '@',
+  ATCI_HAT = '^',
+  ATCI_MONEY = '$',
+  ATCI_DOUBLE_QUOTE = '"',
+  ATCI_QUESTION_MARK = '?',
+  ATCI_EXCLAMATION_MARK = '!',
+  ATCI_FORWARD_SLASH = '/',
+  ATCI_L_ANGLE_BRACKET = '<',
+  ATCI_R_ANGLE_BRACKET = '>',
+  ATCI_R_BRACKET = ')',
+  ATCI_L_BRACKET = '(',
+  ATCI_L_SQ_BRACKET = '[',
+  ATCI_R_SQ_BRACKET = ']',
+  ATCI_L_CURLY_BRACKET = '{',
+  ATCI_R_CURLY_BRACKET = '}',
+  ATCI_CHAR_STAR = '*',
+  ATCI_CHAR_POUND = '#',
+  ATCI_CHAR_AMPSAND = '&',
+  ATCI_CHAR_PERCENT = '%',
+  ATCI_CHAR_PLUS = '+',
+  ATCI_CHAR_MINUS = '-',
+  ATCI_CHAR_DOT = '.',
+  ATCI_CHAR_ULINE = '_',
+  ATCI_CHAR_TILDE = '~',
+  ATCI_CHAR_REVERSE_SOLIDUS = '\\',
+  ATCI_CHAR_VERTICAL_LINE = '|',
+  ATCI_END_CHAR = '\0',
+  ATCI_CR = '\r',
+  ATCI_LF = '\n',
+  ATCI_CHAR_0 = '0',
+  ATCI_CHAR_1 = '1',
+  ATCI_CHAR_2 = '2',
+  ATCI_CHAR_3 = '3',
+  ATCI_CHAR_4 = '4',
+  ATCI_CHAR_5 = '5',
+  ATCI_CHAR_6 = '6',
+  ATCI_CHAR_7 = '7',
+  ATCI_CHAR_8 = '8',
+  ATCI_CHAR_9 = '9',
+  ATCI_CHAR_A = 'A',
+  ATCI_CHAR_B = 'B',
+  ATCI_CHAR_C = 'C',
+  ATCI_CHAR_D = 'D',
+  ATCI_CHAR_E = 'E',
+  ATCI_CHAR_F = 'F',
+  ATCI_CHAR_G = 'G',
+  ATCI_CHAR_H = 'H',
+  ATCI_CHAR_I = 'I',
+  ATCI_CHAR_J = 'J',
+  ATCI_CHAR_K = 'K',
+  ATCI_CHAR_L = 'L',
+  ATCI_CHAR_M = 'M',
+  ATCI_CHAR_N = 'N',
+  ATCI_CHAR_O = 'O',
+  ATCI_CHAR_P = 'P',
+  ATCI_CHAR_Q = 'Q',
+  ATCI_CHAR_R = 'R',
+  ATCI_CHAR_S = 'S',
+  ATCI_CHAR_T = 'T',
+  ATCI_CHAR_U = 'U',
+  ATCI_CHAR_V = 'V',
+  ATCI_CHAR_W = 'W',
+  ATCI_CHAR_X = 'X',
+  ATCI_CHAR_Y = 'Y',
+  ATCI_CHAR_Z = 'Z',
+  ATCI_CHAR_a = 'a',
+  ATCI_CHAR_b = 'b',
+  ATCI_CHAR_c = 'c',
+  ATCI_CHAR_d = 'd',
+  ATCI_CHAR_e = 'e',
+  ATCI_CHAR_f = 'f',
+  ATCI_CHAR_g = 'g',
+  ATCI_CHAR_h = 'h',
+  ATCI_CHAR_i = 'i',
+  ATCI_CHAR_j = 'j',
+  ATCI_CHAR_k = 'k',
+  ATCI_CHAR_l = 'l',
+  ATCI_CHAR_m = 'm',
+  ATCI_CHAR_n = 'n',
+  ATCI_CHAR_o = 'o',
+  ATCI_CHAR_p = 'p',
+  ATCI_CHAR_q = 'q',
+  ATCI_CHAR_r = 'r',
+  ATCI_CHAR_s = 's',
+  ATCI_CHAR_t = 't',
+  ATCI_CHAR_u = 'u',
+  ATCI_CHAR_v = 'v',
+  ATCI_CHAR_w = 'w',
+  ATCI_CHAR_x = 'x',
+  ATCI_CHAR_y = 'y',
+  ATCI_CHAR_z = 'z',
+} atci_char_enum;
+
+typedef enum {
+  AT_WRONG_MODE, AT_SET_MODE, //Ex: at+eample=xxx
+  AT_READ_MODE, //Ex: at+eample?
+  AT_TEST_MODE, //Ex: at+eample=?
+  AT_ACTIVE_MODE //Ex: at+eample
+} atci_cmd_mode_e;
+
+#define ATCI_LOWER_TO_UPPER(alpha_char) (((alpha_char >= ATCI_CHAR_a)&&(alpha_char <= ATCI_CHAR_z)) ?  (alpha_char-32): (alpha_char))
+#define ATCI_UPPER_TO_LOWER(alpha_char) (((alpha_char >= ATCI_CHAR_A)&&(alpha_char <= ATCI_CHAR_Z)) ?  (alpha_char+32): (alpha_char))
+#define ATCI_IS_CAHR(input ,alpha_char) ((alpha_char == input)? 1 : 0)
+
+char* atci_get_cmd_prefix(char *line);
+int atci_get_cmd_mode(char *line);
+int atci_at_skip_space(char **p_cur);
+int atci_at_hasmore(char **p_cur);
+int atci_at_to_equal(char **p_cur);
+int atci_at_to_colon(char **p_cur);
+int atci_at_skip_next_comma(char **p_cur);
+int atci_at_get_nextint_base(char **p_cur, int *p_out, int base, int uns);
+int atci_at_get_nextint(char **p_cur, int *p_out);
+int atci_at_get_nexthexint(char **p_cur, int *p_out);
+int atci_at_get_next_key(char **p_cur, char **p_out);
+#endif
diff --git a/src/lynq/lib/liblynq-at-common/include/libat_common/lynq_at_common.h b/src/lynq/lib/liblynq-at-common/include/libat_common/lynq_at_common.h
new file mode 100755
index 0000000..6f68e04
--- /dev/null
+++ b/src/lynq/lib/liblynq-at-common/include/libat_common/lynq_at_common.h
@@ -0,0 +1,23 @@
+/*============================================================================= 

+#     FileName: lynq_at_factory.h

+#     Desc: about at of factory

+#     Author: lei 

+#     Version: V1.0

+#     LastChange: 2022-12-14 

+#     History: 

+      copyright:Mobiletek

+=============================================================================*/

+#ifndef LYNQ_AT_COMMON_H

+#define LYNQ_AT_COMMON_H 1

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+typedef void ( *lynq_atsvc_incb )( const char *input,const int length);

+typedef void ( *lynq_atsvc_outcb )(char *output, int out_max_size, int mode);

+lynq_atsvc_incb lynq_register_at_common(lynq_atsvc_outcb out_cb);

+

+#ifdef __cplusplus

+}

+#endif

+#endif
\ No newline at end of file
diff --git a/src/lynq/lib/liblynq-at-common/lynq_at_common.cpp b/src/lynq/lib/liblynq-at-common/lynq_at_common.cpp
new file mode 100755
index 0000000..6afe8cc
--- /dev/null
+++ b/src/lynq/lib/liblynq-at-common/lynq_at_common.cpp
@@ -0,0 +1,319 @@
+

+

+#include <string.h>

+#include <stdio.h>

+#include <stdlib.h>

+#include <log/log.h>

+#include "include/libat_common/lynq_at_common.h"

+#include "atci_at_util.h"

+

+#undef LOG_TAG

+#define LOG_TAG "AT_COMMON"

+

+int g_mnetcall_mode = 0;

+int g_gtarndis_mode = 0;

+int g_version_mode = 0;

+

+lynq_atsvc_outcb handle_output;

+

+typedef struct

+{

+    char *cmd;

+    void (*func)(char *input,int mode);

+}Command;

+

+enum

+{

+    Response = 0,

+    Urc

+};

+

+void lynq_response_ok()

+{

+    char *str = "\r\nOK\r\n";

+    handle_output(str, strlen(str), Response);

+}

+

+void lynq_response_error()

+{

+    char *str = "\r\n+CME ERROR:100\r\n";

+    handle_output(str, strlen(str), Response);

+}

+

+static int lynq_catrndis_mode(void)

+{

+    FILE *fp;

+    char buf[2];

+    fp = popen("cat /data/rndis.conf","r");

+    fgets(buf,sizeof(buf),fp);

+    if(buf != NULL)

+    {

+        if(buf[0] == '0')

+        {

+            return 0;

+        }

+        if(buf[0] == '1')

+        {

+           return 1;

+        }

+        else

+        {

+            return 2;//not config

+        }

+    }

+    pclose(fp);

+    return;

+}

+

+static void lynq_get_poepn_buf(char *cmd)

+{

+    FILE *fp;

+    char buf[128] = {0};

+    fp = popen(cmd,"r");

+    while(fgets(buf, sizeof(buf), fp) != NULL){}

+    pclose(fp);

+    RLOGD("buf is %s size %d\n", buf, sizeof(buf));

+    handle_output(buf, strlen(buf), Response);

+    return;

+}

+

+void lynq_handle_rndis(char *input,int type)

+{

+    RLOGD("lynq_handle_rndis type %d\n", type);

+    char buf[128] = {0}; 

+    if(type == AT_SET_MODE)//set

+    {

+        int mode;

+        if (SYS_FAIL == atci_at_to_equal(&input))

+        {

+            lynq_response_error();

+            return SYS_FAIL;

+        }

+        if (SYS_FAIL == atci_at_get_nexthexint(&input, &mode))

+        {

+            lynq_response_error();

+            return SYS_FAIL;

+        }

+        if(mode == 1)

+        {

+            g_mnetcall_mode = mode;

+            system("connmanctl enable gadget");

+            system("connmanctl tether gadget on");

+            lynq_response_ok();

+        }

+        else if (mode == 0)

+        {

+            g_mnetcall_mode = mode;

+            system("connmanctl disable gadget");

+            lynq_response_ok();

+        }

+        else

+        {

+            lynq_response_error();

+        }

+    }

+    else if(type == AT_TEST_MODE)//list

+    {

+        sprintf(buf,"+MNETCALL:(0-1)");

+        handle_output(buf, strlen(buf), Response);

+        lynq_response_ok();

+    }

+    else if(type == AT_READ_MODE)//get

+    {

+        sprintf(buf,"+MNETCALL:%d", g_mnetcall_mode);

+        handle_output(buf, strlen(buf), Response);

+        lynq_response_ok();

+    }

+    else

+    {

+        lynq_response_error();

+    }

+    return;

+}

+

+void lynq_handle_rndis_configure(char *input,int type)

+{

+    RLOGD("lynq_handle_rndis_configure type %d\n", type);

+    char buf[128] = {0}; 

+    if(type == AT_SET_MODE)//set

+    {

+        int mode;

+        if (SYS_FAIL == atci_at_to_equal(&input))

+        {

+            lynq_response_error();

+            return SYS_FAIL;

+        }

+        if (SYS_FAIL == atci_at_get_nexthexint(&input, &mode))

+        {

+            lynq_response_error();

+            return SYS_FAIL;

+        }

+        if(mode == 1)

+        {

+            g_gtarndis_mode = mode;

+            system("echo \"1\" > /data/rndis.conf");

+            lynq_response_ok();

+        }

+        else if (mode == 0)

+        {

+            g_gtarndis_mode = mode;

+            system("echo \"0\" > /data/rndis.conf");

+            lynq_response_ok();

+        }

+        else

+        {

+            lynq_response_error();

+        }

+    }

+    else if(type == AT_TEST_MODE)//list

+    {

+        sprintf(buf,"+GTARNDIS:(0-1)");

+        handle_output(buf, strlen(buf), Response);

+        lynq_response_ok();

+    }

+    else if(type == AT_READ_MODE)//get

+    {

+        sprintf(buf,"+GTARNDIS:%d", g_gtarndis_mode);

+        handle_output(buf, strlen(buf), Response);

+        lynq_response_ok();

+    }

+    else

+    {

+        lynq_response_error();

+    }

+    return;

+}

+

+void lynq_handle_version(char *input,int type)

+{

+    RLOGD("lynq_handle_version type %d\n", type);

+    char buf[128] = {0}; 

+    if(type == AT_SET_MODE)//set

+    {

+        int mode;

+        if (SYS_FAIL == atci_at_to_equal(&input))

+        {

+            lynq_response_error();

+            return SYS_FAIL;

+        }

+        if (SYS_FAIL == atci_at_get_nexthexint(&input, &mode))

+        {

+            lynq_response_error();

+            return SYS_FAIL;

+        }

+        if(mode == 1)

+        {

+            g_version_mode = mode;

+            lynq_get_poepn_buf("uci get lynq_uci_ro.lynq_version.LYNQ_SW_INSIDE_VERSION");

+            //handle_output(buf, strlen(buf), Response);

+            lynq_response_ok();

+        }

+        else if (mode == 0)

+        {

+            g_version_mode = mode;

+            lynq_get_poepn_buf("uci get lynq_uci_ro.lynq_version.LYNQ_SW_VERSION");

+            //handle_output(buf, strlen(buf), Response);

+            lynq_response_ok();

+        }

+        else

+        {

+            lynq_response_error();

+        }

+    }

+    else if(type == AT_TEST_MODE)//list

+    {

+        sprintf(buf,"+CGIR:(0-1)");

+        handle_output(buf, strlen(buf), Response);

+        lynq_response_ok();

+    }

+    else if(type == AT_READ_MODE)//get

+    {

+        sprintf(buf,"+CGIR:%d", g_version_mode);

+        handle_output(buf, strlen(buf), Response);

+        lynq_response_ok();

+    }

+    else if(type == AT_ACTIVE_MODE)//active

+    {

+        if(g_version_mode == 0)

+        {

+            lynq_get_poepn_buf("uci get lynq_uci_ro.lynq_version.LYNQ_SW_VERSION");

+            //handle_output(buf, strlen(buf), Response);

+            lynq_response_ok();

+        }

+        else if(g_version_mode == 1)

+        {

+            lynq_get_poepn_buf("uci get lynq_uci_ro.lynq_version.LYNQ_SW_INSIDE_VERSION");

+            //handle_output(buf, strlen(buf), Response);

+            lynq_response_ok();

+        }

+    }

+    return;

+}

+

+static Command commands[] = 

+{

+{"at+mnetcall",lynq_handle_rndis},

+{"at+gtarndis",lynq_handle_rndis_configure},

+{"at+cgir",lynq_handle_version},

+{NULL, NULL}

+};

+

+Command* find_command (char *input)

+{

+    RLOGD("function %s line %d input %s\n", __FUNCTION__, __LINE__, input);

+    int i;

+    int ret = -1;

+    for (i = 0; commands[i].cmd; i++)

+    {

+        ret = strcmp(input, commands[i].cmd);

+        if(ret == 0)

+        {

+            RLOGD("function %s line %d find input %s commands[i].cmd %s  strlen %d ret %d\n", __FUNCTION__, __LINE__, input, commands[i].cmd, strlen(commands[i].cmd), ret);

+            return (&commands[i]);

+        }

+    }

+    RLOGD("function %s line %d not find ret %d \n", __FUNCTION__, __LINE__, ret);

+    return ((Command *)NULL);

+}

+

+void lynq_at_common_cb(char *input, int input_max_size)

+{

+    if(handle_output != NULL)

+    {

+        RLOGD("function %s line %d input %s\n", __FUNCTION__, __LINE__, input);

+        if(input != NULL)

+        {

+            char *prefix = NULL;

+            prefix = atci_get_cmd_prefix(input);

+            if (NULL == prefix) {

+                RLOGD("atci_cut_cmd_prefix error");

+                return SYS_FAIL;

+            }

+            RLOGD("find prefix [%s]", prefix);

+            Command *cmd = find_command(prefix);

+            if(cmd != NULL)

+            {

+                int cmd_mode = atci_get_cmd_mode(input);

+                RLOGD("function %s line %d\n", __FUNCTION__, __LINE__);

+                (*(cmd->func))(input,cmd_mode);

+                free(prefix);

+                return;

+            }

+            else

+            {

+                RLOGD("not find prefix in list");

+            }

+            free(prefix);

+        }

+    }

+}

+

+lynq_atsvc_incb lynq_register_at_common(lynq_atsvc_outcb out_cb)

+{

+    if(out_cb != NULL)

+    {

+        handle_output = out_cb;

+        RLOGD("function %s line %d\n", __FUNCTION__, __LINE__);

+        return lynq_at_common_cb;

+    }

+}

diff --git a/src/lynq/lib/liblynq-at-common/makefile b/src/lynq/lib/liblynq-at-common/makefile
new file mode 100755
index 0000000..3f9f757
--- /dev/null
+++ b/src/lynq/lib/liblynq-at-common/makefile
@@ -0,0 +1,72 @@
+

+SHELL = /bin/sh

+RM = rm -f

+

+LOCAL_CFLAGS := -Wall \

+                -std=gnu++14 \

+                -g -Os \

+                -flto \

+                -DRIL_SHLIB \

+                -DATCI_PARSE \

+                -fPIC \

+                -DKEEP_ALIVE \

+                -DECALL_SUPPORT \

+                -fpermissive \

+

+$(warning ################# lynq at factory demo ROOT: $(ROOT),includedir:$(includedir))

+LOCAL_PATH   = .

+

+LOCAL_C_INCLUDES = \

+  -I. \

+  -I$(LOCAL_PATH)/include/libat \

+  -I$(ROOT)$(includedir)/logger \

+  -I$(ROOT)$(includedir)/liblog \

+  -I$(ROOT)$(includedir)/vendor-ril \

+

+

+LOCAL_LIBS := \

+    -L. \

+    -ldl \

+    -lstdc++ \

+    -llog \

+    -lcutils \

+    -lutils \

+    -lbinder \

+    -lpthread \

+

+

+SOURCES = $(wildcard *.cpp)

+

+EXECUTABLE = liblynq-at-common.so

+

+OBJECTS=$(SOURCES:.cpp=.o)

+

+.PHONY: build clean install pack_rootfs

+

+all: build

+$(EXECUTABLE): $(OBJECTS)

+	$(CXX) -shared -Wl,--no-undefined $(OBJECTS) $(LOCAL_LIBS) $(LOCAL_CFLAGS) $(LOCAL_C_INCLUDES) -o $@

+

+%.o : %.cpp

+	$(CXX) $(LOCAL_C_INCLUDES) $(LOCAL_CFLAGS) $(LOCAL_LIBS) -o $@ -c $<

+

+build:  $(EXECUTABLE)

+	$(warning ########## build $(EXECUTABLE)  ##########)

+

+install:

+	mkdir -p $(ROOT)$(base_libdir)/

+	install $(EXECUTABLE) $(ROOT)$(base_libdir)/

+	mkdir -p $(ROOT)$(includedir)/$(NAME)/sdk

+

+pack_rootfs:

+	mkdir -p $(PACK_INITRAMFS_TO)$(base_libdir)/

+	cp -af $(EXECUTABLE) $(PACK_INITRAMFS_TO)$(base_libdir)/

+	$(CROSS)strip $(PACK_INITRAMFS_TO)$(base_libdir)/$(EXECUTABLE)

+	mkdir -p $(PACK_TO)$(base_libdir)/

+	cp -af $(EXECUTABLE) $(PACK_TO)$(base_libdir)/

+	$(CROSS)strip $(PACK_TO)$(base_libdir)/$(EXECUTABLE)

+	

+.PHONY: clean

+clean:

+	$(RM) $(OBJECTS) $(EXECUTABLE)

+	-find . -name "*.o" -delete

diff --git a/src/telephonyware/3.0/atcid/atci/src/lynq-private/lynq_atsvc_plugin.xml b/src/telephonyware/3.0/atcid/atci/src/lynq-private/lynq_atsvc_plugin.xml
index 389f4f8..a371624 100755
--- a/src/telephonyware/3.0/atcid/atci/src/lynq-private/lynq_atsvc_plugin.xml
+++ b/src/telephonyware/3.0/atcid/atci/src/lynq-private/lynq_atsvc_plugin.xml
@@ -4,8 +4,16 @@
                  register="lynq_register_test_data"
                  cmd="AT+LETEST;AT+LEABC;AT+LEDEF"
   />
-   <module name="/lib64/liblynq-gnss.so"
+  <module name="/lib64/liblynq-gnss.so"
                  register="lynq_register_gnss"
                  cmd="AT+CGPS;AT+CGPSNMEA"
   />
+  <module name="/lib64/liblynq-at-common.so"
+                 register="lynq_register_at_common"
+                 cmd="AT+MNETCALL;AT+GTARNDIS;AT+CGIR"
+  />
+  <module name="/lib64/liblynq-at-factory.so"
+                 register="lynq_register_at_factory"
+                 cmd="AT+LYNQFACTORY"
+  />
 </lynq_atsvc_plugin>
\ No newline at end of file