[Feature][ZXW-112][ATCID] add framework of at plugins

Only Configure:No
Affected branch:master
Affected module:atcid
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No

Change-Id: I92d42fef70696655e352aabf9509eddcdb4f14dc
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf b/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf
index 8d07dc3..29985f1 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf
+++ b/cap/zx297520v3/sources/meta-zxic-custom/conf/distro/vehicle_dc_ref.conf
@@ -269,6 +269,7 @@
         lynq-qser-sms-demo \
         lynq-qser-data-demo \
         lynq-autosuspend \
+	lynq-atcid \
         "
 
 zxic_app_open += "${@bb.utils.contains('CONFIG_TEL_API_SUPPORT', 'RIL', 'rild', '', d)}"
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-atcid/lynq-atcid.bb b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-atcid/lynq-atcid.bb
new file mode 100755
index 0000000..fba6060
--- /dev/null
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-atcid/lynq-atcid.bb
@@ -0,0 +1,50 @@
+#inherit externalsrc package
+#inherit externalsrc package systemd
+DESCRIPTION = "lynq atcid"
+LICENSE = "CLOSED"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=b1e07e8d88e26263e71d3a9e2aa9a2ff"
+DEPENDS += "libxml2 libatreg libsoftap libatutils libnvram libsclog libsofttimer libbinder liblynq-log"
+#inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/lynq/framework/lynq-atcid"
+FILESEXTRAPATHS_prepend :="${TOPDIR}/../src/lynq/framework/:"
+SRC_URI = " \
+          file://lynq-atcid \
+          "
+
+SRC-DIR = "${S}/../lynq-atcid"
+TARGET_CC_ARCH += "${LDFLAGS}"
+SYSTEMD_PACKAGES = "${PN}"
+SYSTEMD_SERVICE_${PN} = "lynq_atcid.service"
+FILES_${PN} += "${systemd_unitdir}/system/lynq_atcid.service"
+FILES_${PN} += "${bindir} /data/atsvc"
+#Parameters passed to do_compile()
+
+EXTRA_OEMAKE = "'TARGET_PLATFORM = ${TARGET_PLATFORM}'"
+
+#INHIBIT_PACKAGE_STRIP = "1"
+do_compile () {
+	if test "${PACKAGE_ARCH}" = "cortexa7hf-vfp-vfpv4-neon" || test "${PACKAGE_ARCH}" = "cortexa7hf-neon-vfpv4"; then
+		oe_runmake all -C ${SRC-DIR} ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -mhard-float"
+	else
+		oe_runmake all -C ${SRC-DIR} ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST}"
+	fi
+}
+
+do_install() {
+	install -d ${D}${bindir}/
+	install -m 0755 ${SRC-DIR}/lynq-atcid ${D}${bindir}/
+	if test "${LYNQ_ATSVC_SUPPORT}" = "yes"; then
+		install -d ${D}/data/atsvc
+		install -m 644 ${WORKONSRC}/lynq_atsvc_plugin.xml ${D}/data/atsvc
+	fi
+
+	if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+		install -d ${D}${systemd_unitdir}/system/
+		install -m 0644 ${B}/lynq_atcid.service ${D}${systemd_unitdir}/system
+	else
+		install -d ${D}${sysconfdir}/init.d
+		install -m 0755  ${SRC-DIR}/lynq-atcid.sh ${D}${sysconfdir}/init.d/lynq-atcid.sh
+		install -d ${D}${sysconfdir}/rcS.d
+		ln -s ../init.d/lynq-atcid.sh ${D}${sysconfdir}/rcS.d/S83lynq-atcid
+	fi
+}
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/LICENSE b/cap/zx297520v3/src/lynq/framework/lynq-atcid/LICENSE
new file mode 100755
index 0000000..605b7ea
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/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.
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq-atcid.sh b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq-atcid.sh
new file mode 100755
index 0000000..ff91ada
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq-atcid.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# Run the daemon
+#
+
+DAEMON="lynq-atcid"
+PIDFILE="/var/run/$DAEMON.pid"
+EXEC="/usr/bin/lynq-atcid"
+EXEC_ARGS=""
+
+
+start() {
+        echo -n "Starting $DAEMON... "
+        start-stop-daemon --no-close -S -b -m -p $PIDFILE -x $EXEC -- $EXEC_ARGS
+        [ $? -eq 0 ] && echo "OK" || echo "ERROR"
+}
+
+stop() {
+        echo -n "Stopping $DAEMON... "
+        start-stop-daemon -K -p $PIDFILE
+        [ $? -eq 0 ] && echo "OK" || echo "ERROR"
+}
+
+restart() {
+        stop
+        start
+}
+
+case "$1" in
+  start|stop|restart)
+        "$1"
+        ;;
+  *)
+        echo "Usage: $0 {start|stop|restart}"
+        exit 1
+esac
+
+exit $?
+
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atcid.service b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atcid.service
new file mode 100755
index 0000000..5734cd2
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atcid.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=lynq atcid
+After=at_ctl.service
+Requires=at_ctl.service
+
+[Service]
+StandardOutput=kmsg+console
+Type=simple
+RemainAfterExit=no
+ExecStart=/usr/bin/lynq-atcid
+Restart=always
+RestartSec=500ms
+StartLimitInterval=0
+User=root
+Group=root
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_controller.cpp b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_controller.cpp
new file mode 100755
index 0000000..9776c62
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_controller.cpp
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include "lynq_atsvc_controller.h"
+#include "liblog/lynq_deflog.h"
+
+#define FUNC __FUNCTION__
+#define LINE __LINE__
+
+typedef enum
+{
+    INIT_SUCCESS=0,
+    INIT_PULGIN_FAIL,
+    INIT_SOCKET_FAIL,
+    INIT_THREAD_FAIL
+}init_reuslt_t;
+
+typedef struct
+{
+    xmlChar* name;
+    xmlChar* reg;
+    xmlChar* cmd;
+}plugin_conf_t;
+
+void upper_string(char *org_string)
+{
+    int len = strlen(org_string);
+    for(int i=0;i<len;i++)
+    {
+        if(org_string[i]>=97 && org_string[i]<=122)
+        {
+            org_string[i]=org_string[i]-32;
+        }
+    }
+    return;
+}
+
+int load_pulgin(const char * plugin_conf_path)
+{
+    ALOGD("[%d][%s]load pulgin",LINE,FUNC);
+    int count = 0;
+    char *atcmd = NULL;
+    int atcmd_len = 0;
+    xmlDocPtr pdoc = NULL;
+    xmlNodePtr root = NULL;
+    plugin_conf_t plugin_conf;
+    //memset(plugin_msg_array,0,sizeof(plugin_msg_array));
+    pdoc = xmlReadFile(plugin_conf_path ,"UTF-8",XML_PARSE_RECOVER);
+    if(NULL == pdoc)
+    {
+        ALOGI("[%d][%s]copy file %s" ,LINE,FUNC, plugin_conf_path);
+        system("cp -r /data/atsvc /mnt/userdata/");
+        pdoc = xmlReadFile(plugin_conf_path ,"UTF-8",XML_PARSE_RECOVER);
+        if (NULL == pdoc)
+        {
+            ALOGE("[%d][%s]open file %s" ,LINE,FUNC, plugin_conf_path);
+            return -1;
+        }
+    }
+    root = xmlDocGetRootElement(pdoc);
+    if(NULL == root)
+    {
+        ALOGE("get xmlDocGetRootElement() empty document fail");
+        return -1;
+    }
+    ALOGD("root->name :%s",root->name);
+    root = root->xmlChildrenNode;
+    while (root != NULL)
+    {
+        ALOGD("count is:%d",count);
+        if(PLUGINE_MAX_COUNT <= count)
+        {
+            ALOGW("plugin too many!!!");
+            break;
+        }
+        if ((!xmlStrcmp(root->name, (const xmlChar *)"module")))
+        {
+            ALOGD("find module");
+            plugin_conf.name = xmlGetProp(root, "name");
+            plugin_conf.reg = xmlGetProp(root, "register");
+            plugin_conf.cmd = xmlGetProp(root, "cmd");
+            if((NULL == plugin_conf.name)||(NULL == plugin_conf.reg)||(NULL == plugin_conf.cmd))
+            {
+                ALOGE("get prop fail,name:%s,reg:%s,cmd=%s",plugin_conf.name,plugin_conf.reg,plugin_conf.cmd);
+                root = root->next;
+                continue;
+            }
+            ALOGD("[%d][%s]plugin_conf name:%s,reg:%s,cmd=%s",LINE,FUNC,plugin_conf.name,plugin_conf.reg,plugin_conf.cmd);
+            plugin_msg_array[count].dlHandle_plugin = dlopen(plugin_conf.name, RTLD_NOW);
+            if(NULL == plugin_msg_array[count].dlHandle_plugin)
+            {
+                ALOGE("open lib %s fail",plugin_conf.name);
+                root = root->next;
+                continue;
+            }
+            ALOGD("plugin_msg_array[%d].dlHandle_plugin :%p",count,plugin_msg_array[count].dlHandle_plugin);
+            plugin_msg_array[count].register_module = (lynq_atsvc_incb(*)(lynq_atsvc_outcb out_cb))dlsym(plugin_msg_array[count].dlHandle_plugin, plugin_conf.reg);
+            if(NULL == plugin_msg_array[count].register_module)
+            {
+                ALOGE("open plugin_msg_array[%d].%p fail",count,plugin_msg_array[count].register_module);
+                ALOGE("dlsym failed: %s", dlerror());
+                root = root->next;
+                continue;
+            }
+            plugin_msg_array[count].atsvc_incb = plugin_msg_array[count].register_module(plugin_msg_array[count].plugin_cb);
+            if(NULL == plugin_msg_array[count].atsvc_incb)
+            {
+                ALOGE("call %s fail",plugin_conf.reg);
+                root = root->next;
+                continue;
+            }
+            atcmd_len = strlen(plugin_conf.cmd);
+            atcmd = (char *)malloc(atcmd_len*(sizeof(char)+1));
+            if(NULL == atcmd)
+            {
+                ALOGE("count %d atcmd malloc fail",count);
+                root = root->next;
+                continue;
+            }
+            plugin_msg_array[count].state = 1;
+            memcpy(atcmd,plugin_conf.cmd,atcmd_len);
+            atcmd[atcmd_len] = '\0';
+            //plugin_msg_array[count].atcmd = atcmd;
+            upper_string(atcmd);
+            plugin_msg_array[count].atcmd = atcmd;
+            count++;
+        }
+        root = root->next;
+    }
+    ALOGD("pcurnode->name return");
+    xmlFreeDoc(pdoc);
+    xmlCleanupParser();
+    return 0;
+}
+
+int lynq_atsvc_init(int count,const char * plugin_conf_path)
+{
+    ALOGD("start [%d][%s]",LINE,FUNC);
+    int res = 0;
+    res = load_pulgin(PLUGIN_CONF_PATH);
+    if(0 > res)
+    {
+        for(int i = 0;i < PLUGINE_MAX_COUNT; i++)
+        {
+            if(NULL != plugin_msg_array[i].atcmd)
+            {
+                free(plugin_msg_array[i].atcmd);
+            }
+        }
+        ALOGE("load_pulgin fail,code is %d",res);
+        return INIT_PULGIN_FAIL;
+    }
+    for(int i = 0;i < PLUGINE_MAX_COUNT; i++)
+    {
+        if(NULL != plugin_msg_array[i].atcmd)
+        {
+            ALOGD("atcmd:%s",plugin_msg_array[i].atcmd);
+        }
+    }
+    //todo at liblynq-at-extension
+    /*create thread for reacive ril msg*/
+    /*load pulgin from plugin config*/
+    return 0;
+}
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_controller.h b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_controller.h
new file mode 100755
index 0000000..1db3571
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_controller.h
@@ -0,0 +1,87 @@
+/**********************************************************************************************
+* @file lynq_atsvc_controller.h
+* @brief Control the initialization of lynq at, and dispacthing, etc.
+* @details None
+* @author   Hong Liu。
+* @date     2022-11-24
+* @version  V1.0
+* @copyright   Copyright (c) MobileTek 
+***********************************************************************************************/
+
+
+#ifndef LYNQ_ATSVC_COBTROLLER_H
+#define LYNQ_ATSVC_COBTROLLER_H 1
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <pthread.h>
+#define PLUGIN_CONF_PATH "/mnt/userdata/atsvc/lynq_atsvc_plugin.xml"
+#define RIL_SOCKET_NAME "/dev/socket/lynq_atsvc_socket_1"
+#define PLUGINE_MAX_COUNT 16
+
+
+
+/**********************************************************************************************
+* @brief this is a callback function,atsvc will call this function if the at command is this \
+**module command
+* @param input [IN] at command
+* @param length [IN] at command length
+* @return NULL
+************************************************************************************************/
+typedef void ( *lynq_atsvc_incb )(const char *input,const int length);
+
+/**********************************************************************************************
+* @brief this is a callback function,plugin will call this function when the plugin needs to \
+**return the response or urc
+* @param input [IN] response or urc
+* @param length [IN] response or urc length
+* @param type 
+** 0:response 
+** 1:unsolictedresponse
+* @return NULL
+************************************************************************************************/
+typedef void ( *lynq_atsvc_outcb )(char *output,int out_size,int type);
+
+/**********************************************************************************************
+* @brief this is a register function, atsvc will call this function when a plugin register in atsvc.
+* @param lynq_atsvc_outcb [IN]
+* @return lynq_atsvc_incb
+************************************************************************************************/
+typedef lynq_atsvc_incb (*lynq_register_module)(lynq_atsvc_outcb out_cb);
+
+
+typedef struct
+{
+    lynq_atsvc_incb atsvc_incb;
+    lynq_register_module register_module;
+    void *dlHandle_plugin;
+    char * atcmd;
+    int state;
+    lynq_atsvc_outcb plugin_cb;
+    char * output_buffer;
+}plugin_msg_t;
+
+extern plugin_msg_t plugin_msg_array[PLUGINE_MAX_COUNT];
+extern int has_registe_cmd;
+/**********************************************************************************************
+* @brief initalize lynq atsvc,it will load plugin and create socket process
+* @param plugin_conf_path [IN] plugin config file path
+* @return 
+*     0:success
+*     1:load pugin config file fail
+*     2:create socket fail
+*     3:create thread fail
+************************************************************************************************/
+int lynq_atsvc_init(int count,const char * plugin_conf_path);
+int lynq_check_extension_atcmd(char * atcmd);
+int send_msg_to_at_extension(char *atcmd,int size);
+int create_socket(const int domain, const int type, const int protocol,const int port,const char *IP,const char *socket_name,void * addr,int backlog);
+int send_msg(int socket_fd,const struct sockaddr *dest_addr,const char *msg);
+int lynq_dispatch_atcmd(char* atcmd);
+
+
+
+#endif
+
+
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_plugin.xml b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_plugin.xml
new file mode 100755
index 0000000..3cdb250
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/lynq_atsvc_plugin.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lynq_atsvc_plugin >
+  <module name="/lib64/liblynq-test-data.so"
+                 register="lynq_register_test_data"
+                 cmd="AT+LETEST;AT+LEABC;AT+LEDEF"
+  />
+  <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;AT+LGMDS;AT+LRNDISHANDLE"
+  />
+  <module name="/lib64/liblynq-at-factory.so"
+                 register="lynq_register_at_factory"
+                 cmd="AT+LYNQFACTORY"
+  />
+</lynq_atsvc_plugin>
\ No newline at end of file
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/main.cpp b/cap/zx297520v3/src/lynq/framework/lynq-atcid/main.cpp
new file mode 100755
index 0000000..5bec9af
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/main.cpp
@@ -0,0 +1,41 @@
+/*
+*  Copyright (C) 2014 MediaTek Inc.
+*
+*  Modification based on code covered by the below mentioned copyright
+*  and/or permission notice(s).
+*/
+
+/* 
+**
+** Copyright 2006 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include "zxic_at_func_wrapper.h"
+#include "liblog/lynq_deflog.h"
+
+int main(int argc, char **argv) {
+    ALOGI("atcid started");
+    init_zxic_at_plugin_env();
+
+    while (true) {
+        sleep(5);
+    }
+}
+
+DEFINE_LYNQ_EXE_LOG(LYNQ_ATCID)
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/makefile b/cap/zx297520v3/src/lynq/framework/lynq-atcid/makefile
new file mode 100755
index 0000000..fa4f4ad
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/makefile
@@ -0,0 +1,76 @@
+SHELL = /bin/sh
+RM = rm -f
+
+LOCAL_CFLAGS := -Wall \
+                -std=gnu++14 \
+				-pthread \
+                -g -Os \
+                -flto \
+                -fPIC \
+                -fpermissive \
+
+ifeq ($(strip $(TARGET_PLATFORM)), T106)
+LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 -DHAVE_ENDIAN_H -DHAVE_PTHREADS -DHAVE_SYS_UIO_H -DHAVE_POSIX_FILEMAP -DHAVE_STRLCPY -DHAVE_PRCTL -DHAVE_MEMSET16 -DHAVE_MEMSET32 -DANDROID_SMP=0
+endif
+
+$(warning ################# lynq qser sms demo ROOT: $(ROOT),includedir:$(includedir))
+LOCAL_PATH   = .
+
+LOCAL_C_INCLUDES = \
+  -I. \
+  -I$(LOCAL_PATH)/include/ \
+  -I$(ROOT)$(includedir)/logger \
+  -I$(ROOT)$(includedir)/liblog \
+  -I$(ROOT)$(includedir)/libxml2 \
+
+
+LOCAL_LIBS := \
+    -L. \
+    -lstdc++ \
+    -ldl \
+    -lcutils \
+    -lutils \
+    -lpthread \
+    -lxml2 \
+    -latreg \
+    -lsoftap \
+    -latutils \
+    -lnvram \
+    -lsclog \
+    -lsofttimer \
+    -lbinder \
+    -llynq-log \
+
+
+SOURCES = $(wildcard *.c wildcard *.h *.cpp)
+
+EXECUTABLE = lynq-atcid
+
+OBJECTS=$(SOURCES:.cpp=.o)
+
+
+.PHONY: build clean install pack_rootfs 
+all: build
+$(EXECUTABLE): $(OBJECTS)
+	$(CXX) $(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/cap/zx297520v3/src/lynq/framework/lynq-atcid/zxic_at_func_wrapper.cpp b/cap/zx297520v3/src/lynq/framework/lynq-atcid/zxic_at_func_wrapper.cpp
new file mode 100755
index 0000000..3037e62
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/zxic_at_func_wrapper.cpp
@@ -0,0 +1,232 @@
+#include "zxic_at_func_wrapper.h"
+#include <string.h>
+#include <stdio.h>
+#include "lynq_atsvc_controller.h"
+#include "liblog/lynq_deflog.h"
+
+extern "C"
+{
+    typedef void (*ZXIC_AT_CALLBACK_FUNC_PTR) (unsigned char *, unsigned char *);
+
+    extern int reg_at_serv_func(char *at_cmd_prefix, ZXIC_AT_CALLBACK_FUNC_PTR cb);
+    extern int unreg_at_serv_func(char *at_cmd_prefix);
+}
+
+struct callback_entry
+{
+    char at_prefix[64];
+    ZXIC_AT_CALLBACK_FUNC_PTR callback_func;
+    plugin_msg_t *plugin_entry;
+};
+
+const int entry_count = 256;
+static volatile int g_zxic_at_plugin_env_flag = 0;
+static struct callback_entry *g_all_reg_entry[entry_count] = {0};
+static int g_curr_reg_index = 0;
+
+plugin_msg_t plugin_msg_array[PLUGINE_MAX_COUNT] = {0};
+
+template <int n>
+void zxic_at_callback(unsigned char * input, unsigned char * output)
+{
+    char org_cmd[64] = {0};
+    if (input == NULL || output == NULL)
+    {
+        ALOGE("zxic_at_callback invalid params %p-%p \n", input, output);
+        return;
+    }
+    strcpy((char*)output, "\r\n");
+    struct callback_entry *pEntry = g_all_reg_entry[n];
+    strcat(org_cmd, pEntry->at_prefix);
+    strcat(org_cmd, (char *)input);
+    pEntry->plugin_entry->output_buffer = (char*)output;
+    ALOGD("zxic_at_callback org_cmd -- %s \n", org_cmd);
+    pEntry->plugin_entry->atsvc_incb(org_cmd, strlen(org_cmd));
+    pEntry->plugin_entry->output_buffer = NULL;
+    ALOGD("zxic_at_callback output -- %s \n", output);
+    //return 0;
+}
+
+template <int n>
+void reg_callback_function()
+{
+    g_all_reg_entry[n] = new struct callback_entry;
+    g_all_reg_entry[n]->callback_func = &zxic_at_callback<n>;
+    reg_callback_function<n-1>();
+}
+
+template <>
+void reg_callback_function<0>()
+{
+    g_all_reg_entry[0] = new struct callback_entry;
+    g_all_reg_entry[0]->callback_func = &zxic_at_callback<0>;
+}
+
+template <int n>
+void lynq_atsvc_outcb_entity(char *output,int out_size,int type)
+{
+    ALOGD("lynq_atsvc_outcb_entity%d called\n",n);
+    if (plugin_msg_array[n].output_buffer == NULL)
+    {
+        ALOGE("no output buffer");
+        return;
+    }
+    if(NULL == output)
+    {
+        ALOGE("output is null");
+    }
+    int length = 0;
+    length = strlen(output);
+    if(length != out_size)
+    {
+        ALOGW("strlen length != output");
+    }
+    ALOGD("ouput:%s,len:%d",output,out_size);
+
+	//not first line add \r\n
+    if (plugin_msg_array[n].output_buffer[0] != '\0')
+    {
+        strcat(plugin_msg_array[n].output_buffer, "\r\n");
+    }
+
+    strcat(plugin_msg_array[n].output_buffer, output);
+}
+
+template <int n>
+void reg_lynq_atsvc_outcb_entity()
+{
+    plugin_msg_array[n].plugin_cb = &lynq_atsvc_outcb_entity<n>;
+    plugin_msg_array[n].output_buffer = NULL;
+    reg_lynq_atsvc_outcb_entity<n-1>();
+}
+
+template <>
+void reg_lynq_atsvc_outcb_entity<0>()
+{
+    plugin_msg_array[0].plugin_cb = &lynq_atsvc_outcb_entity<0>;
+    plugin_msg_array[0].output_buffer = NULL;
+}
+
+static int lynq_split(char * str, int len, char delimiter, char * results[]) {
+    int ret = 0;
+    char * end = str + len - 1;
+    results[ret++] = str;
+    while(str < end)
+    {
+        if (*str == delimiter)
+    {
+            *str++ = '\0';
+            results[ret++] = str;
+            continue;
+        }
+        str++;
+    }
+    if (*str == delimiter)
+    {
+        *str = '\0';
+    }
+
+    results[ret] = NULL;
+
+    return ret;
+}
+
+static int local_reg_at_serv_func(char *at_cmd_prefix, ZXIC_AT_CALLBACK_FUNC_PTR cb) //@todo to check if registered
+{
+    int ret;
+    ret = reg_at_serv_func(at_cmd_prefix, cb);
+    ALOGD("reg_at_serv_func return:%d", ret);
+    if (ret == 0)
+    {
+        return 0;
+    }
+    unreg_at_serv_func(at_cmd_prefix);
+    return reg_at_serv_func(at_cmd_prefix, cb);
+}
+
+static int local_reg_one_at_cmd(const char* reg_fmt, char*reg_word, char * at_cmd, plugin_msg_t *plugin_entry)
+{
+    struct callback_entry *entry;
+    char reg_cmd[32] = {0};
+    entry = g_all_reg_entry[g_curr_reg_index];
+    snprintf(reg_cmd, sizeof (reg_cmd), reg_fmt, reg_word);
+    snprintf(entry->at_prefix, sizeof (entry->at_prefix), reg_fmt, at_cmd);
+    if (local_reg_at_serv_func(reg_cmd, g_all_reg_entry[g_curr_reg_index]->callback_func) == 0)
+    {
+        entry->plugin_entry = plugin_entry;
+        g_curr_reg_index++;
+        ALOGI("reg_at_serv_func [%s] success\n", reg_cmd);
+    }
+    else
+    {
+        ALOGE("reg_at_serv_func [%s] fail\n", reg_cmd);
+    }
+
+    return 0;
+}
+
+static int reg_at_cmd(char * at_cmd, plugin_msg_t *plugin_entry)
+{
+    int words_count;
+    char *split_words[64] = {0};
+    char cmd[32] = {0};
+
+    strcpy(cmd, at_cmd);
+    words_count = lynq_split(cmd, strlen(cmd), '+', split_words);
+    if (words_count != 2 || strlen(split_words[1]) == 0)
+    {
+        ALOGE("bad format command [%s]", cmd);
+        return -1;
+    }
+
+    ALOGD("reg_at_cmd [%s] begin", at_cmd);
+    local_reg_one_at_cmd("%s", split_words[1], at_cmd, plugin_entry);
+    local_reg_one_at_cmd("%s?", split_words[1], at_cmd, plugin_entry);
+    local_reg_one_at_cmd("%s=", split_words[1], at_cmd, plugin_entry);
+    local_reg_one_at_cmd("%s=?", split_words[1], at_cmd, plugin_entry);
+    ALOGD("reg_at_cmd [%s] end", at_cmd);
+
+    return 0;
+}
+
+static int reg_at_cmds_of_plugin(plugin_msg_t *plugin_entry)
+{
+    int cmds_count, i;
+    char *split_cmds[64] = {0};
+    char *cmd_buffer = new char[strlen(plugin_entry->atcmd)+1];
+    strcpy(cmd_buffer, plugin_entry->atcmd);
+
+    cmds_count = lynq_split(cmd_buffer, strlen(plugin_entry->atcmd), ';', split_cmds);
+
+    ALOGD("reg_at_cmds_of_plugin cmd count %d ,%s", cmds_count, cmd_buffer);
+    for(i=0;i<cmds_count;i++)
+    {
+        reg_at_cmd(split_cmds[i], plugin_entry) ;
+    }
+    delete [] cmd_buffer;
+    return 0;
+}
+
+int init_zxic_at_plugin_env()
+{
+    if (g_zxic_at_plugin_env_flag != 0)
+        return -1;
+    memset(plugin_msg_array,0,sizeof(plugin_msg_array));
+    reg_callback_function<entry_count-1>();
+    reg_lynq_atsvc_outcb_entity<PLUGINE_MAX_COUNT-1>();
+    g_zxic_at_plugin_env_flag = 1;
+
+    lynq_atsvc_init(0,NULL);
+
+    for(int i = 0;i < PLUGINE_MAX_COUNT; i++)
+    {
+        if(NULL != plugin_msg_array[i].atcmd)
+        {
+            ALOGD("atcmd:%s",plugin_msg_array[i].atcmd);
+            reg_at_cmds_of_plugin(&plugin_msg_array[i]);
+        }
+    }
+
+    return 0;
+}
+
diff --git a/cap/zx297520v3/src/lynq/framework/lynq-atcid/zxic_at_func_wrapper.h b/cap/zx297520v3/src/lynq/framework/lynq-atcid/zxic_at_func_wrapper.h
new file mode 100755
index 0000000..fddfbd1
--- /dev/null
+++ b/cap/zx297520v3/src/lynq/framework/lynq-atcid/zxic_at_func_wrapper.h
@@ -0,0 +1,13 @@
+#ifndef ZXIC_AT_FUNC_WRAPPER_H
+#define ZXIC_AT_FUNC_WRAPPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int init_zxic_at_plugin_env();
+
+#ifdef __cplusplus
+}
+#endif
+#endif // ZXIC_AT_FUNC_WRAPPER_H