Add mbtk/liblynq_lib_v2/ mbtk/libql_lib_v2/

Change-Id: Idbb802cd805b34603ccf65bff9818725a6955e51
diff --git a/mbtk/libql_lib_v2/Makefile b/mbtk/libql_lib_v2/Makefile
new file mode 100755
index 0000000..43259aa
--- /dev/null
+++ b/mbtk/libql_lib_v2/Makefile
@@ -0,0 +1,51 @@
+BUILD_ROOT = $(shell pwd)/..
+include $(BUILD_ROOT)/Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/libql_lib_v2
+
+INC_DIR +=
+
+LIB_DIR +=
+
+LIBS += -llog -lubus -lubox -lblobmsg_json -lrilutil -lmbtk_lib -lmbtk_ril -lmbtk_fota -lmbtk_http -lmbtk_factory -lmbtk_audio
+
+CFLAGS += -shared -Wl,-shared,-Bsymbolic
+
+DEFINE +=
+
+MY_FILES_PATH:=$(LOCAL_PATH)/src
+#ifeq ($(CONFIG_MBTK_QL_SUPPORT),y)
+#MY_FILES_PATH += $(LOCAL_PATH)/ql
+#endif
+
+#ifeq ($(CONFIG_MBTK_PLATFORM),linux)
+#MY_FILES_PATH += $(LOCAL_PATH)/platform/linux
+#endif
+
+#MY_FILES_SUFFIX:=%.c %.cpp
+#My_All_Files := $(foreach src_path,$(MY_FILES_PATH), $(shell find "$(src_path)" -type f))
+#MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(My_All_Files))
+#MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)
+
+LOCAL_SRC_FILES = $(wildcard src/*.c) $(wildcard src/*.cpp)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+OBJS = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(LOCAL_SRC_FILES)))
+$(info OBJS = $(OBJS))
+
+dtarget := $(OUT_DIR)/lib/libql_lib.so
+
+all: $(dtarget)
+
+$(dtarget): $(OBJS)
+	$(CC) $(CFLAGS) $(LIB_DIR) $(LIBS) $(OBJS) -o $@
+
+%.o:%.c
+	$(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+%.o:%.cpp
+	$(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+clean:
+	rm -f $(OBJS) $(dtarget)
+
diff --git a/mbtk/libql_lib_v2/src/ql_adc.c b/mbtk/libql_lib_v2/src/ql_adc.c
new file mode 100755
index 0000000..812427e
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_adc.c
@@ -0,0 +1,12 @@
+#include "mbtk_adc.h"
+#include "ql/ql_adc.h"
+
+int ql_adc_show(Enum_QADC qadc)
+{
+    if(qadc == ADC0 || qadc == ADC1) {
+        return mbtk_adc_get((mbtk_adc_enum)qadc);
+    } else {
+        return -1;
+    }
+}
+
diff --git a/mbtk/libql_lib_v2/src/ql_atc.c b/mbtk/libql_lib_v2/src/ql_atc.c
new file mode 100755
index 0000000..cd1cf49
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_atc.c
@@ -0,0 +1,43 @@
+#include "mbtk_at.h"
+/*******************************************************
+* @method: ql_atc_init
+* @Description: initialize environment variables.
+* @param: void
+* @return:
+         success: return 0
+         error: return !0
+********************************************************/
+int ql_atc_init()
+{
+    return mbtk_at_init();
+}
+
+/*******************************************************
+* @method: ql_atc_release
+* @Description: release environment variables.
+* @param: void
+* @return:
+         success: return 0
+         error: return !0
+********************************************************/
+int ql_atc_release()
+{
+    return mbtk_at_deinit();
+}
+
+/*******************************************************
+* @method: ql_atc_send
+* @Description: send at command(synchronous)
+                use this api should first call init api and finish call release api
+* @param:
+         cmd: at command
+         resp: at return value
+         len: response value length
+* @return:
+         success: return 0
+         error: return !0
+********************************************************/
+int ql_atc_send(char* cmd, char* resp, int resp_len)
+{
+    return mbtk_at_send(cmd, resp, resp_len);
+}
diff --git a/mbtk/libql_lib_v2/src/ql_audio.c b/mbtk/libql_lib_v2/src/ql_audio.c
new file mode 100755
index 0000000..d95ca9e
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_audio.c
@@ -0,0 +1,875 @@
+
+#include "ql/ql_audio.h"
+#include "mbtk_log.h"
+#include "mbtk_audio2.h"
+
+typedef enum {
+    AUDIO_PLAY_STATE_STOP,
+    AUDIO_PLAY_STATE_RUNNING,
+    AUDIO_PLAY_STATE_PAUSE
+} audio_play_state_enum;
+
+#define AUDIO_HANDLE 1
+#define WAV_PLAY_BUFF 1024
+
+#ifdef MBTK_AF_SUPPORT
+static mbtk_audio_handle player_hdl = NULL;
+static int player_hdl_1 = AUDIO_HANDLE;
+static _cb_onRecorder record_cb_fun = NULL;
+static int Samprate = 8000;
+#endif
+
+static int sample_rate = 8000;
+static int play_handle = AUDIO_HANDLE;
+static _cb_onPlayer play_cb_func = NULL;
+static _cb_onRecorder recorder_cb_fun = NULL;
+static int is_running = 0;
+static audio_play_state_enum play_state = AUDIO_PLAY_STATE_STOP;
+static int play_exit = 1;
+
+static void recorder_cb_func(void *data, uint32 data_len)
+{
+    if(recorder_cb_fun) {
+        recorder_cb_fun(AUD_RECORDER_START, (unsigned char*)data, data_len);
+    }
+}
+
+static int play_stream(unsigned char* pData, unsigned int length)
+{
+    int rc, len, frames = 0;
+    int result = 0;
+
+    play_state = AUDIO_PLAY_STATE_RUNNING;
+    play_exit = 0;
+    int data_send = 0;
+
+    if (mbtk_audio_pcm_play_start()) {
+        printf("%s: error opening output device.", __FUNCTION__);
+        return -1;
+    }
+
+    if(pData && length > 0) {
+        while (play_state != AUDIO_PLAY_STATE_STOP) {
+            if(play_state == AUDIO_PLAY_STATE_RUNNING) {
+                if (data_send >= length) {
+                    LOGE("%s: Read pcm stream end.", __FUNCTION__);
+                    break;
+                }
+
+                if(length - data_send > WAV_PLAY_BUFF) {
+                    len = WAV_PLAY_BUFF;
+                } else {
+                    len = length - data_send;
+                }
+
+                if((rc = mbtk_audio_pcm_play_data_send(pData + data_send, len)) != len) {
+                    LOGE("Send data %d/%d", rc, len);
+                    result = -1;
+                    goto thread_end;
+                }
+
+                data_send += len;
+
+                LOGD("%s: No.%d frame playback", __FUNCTION__, ++frames);
+            } else {
+                usleep(200000);
+            }
+        }
+    } else {
+        result = -1;
+    }
+
+    play_state = AUDIO_PLAY_STATE_STOP;
+
+
+thread_end:
+    mbtk_audio_pcm_play_stop();
+    play_exit = 1;
+    LOGD("%s: finished pcm playback.", __FUNCTION__);
+    return result;
+}
+
+static int play_by_fd(int fd, int offset)
+{
+    int rc, len, frames = 0;
+    int result = 0;
+    char buf[WAV_PLAY_BUFF];
+
+    play_state = AUDIO_PLAY_STATE_RUNNING;
+    if(play_cb_func)
+        play_cb_func(play_handle , AUDIO_PLAY_STATE_RUNNING);
+    play_exit = 0;
+    if(fd > 0) {
+        if(offset > 0) {
+            lseek(fd, offset, SEEK_SET);
+        }
+        
+        if (mbtk_audio_pcm_play_start()) {
+            printf("%s: error opening output device.", __FUNCTION__);
+            return -1;
+        }
+
+        
+        while (play_state != AUDIO_PLAY_STATE_STOP) {
+            if(play_state == AUDIO_PLAY_STATE_RUNNING) {
+                memset(buf, 0x00, sizeof(buf));
+                len = read(fd, buf, WAV_PLAY_BUFF);
+                if (len == -1) {
+                    LOGE("%s: error reading from file", __FUNCTION__);
+                    result = -1;
+                    goto thread_end;
+                }
+
+                if (len == 0) {
+                    /* reached EOF */
+                    LOGE("%s: Read wav file end.", __FUNCTION__);
+                    break;
+                }
+
+                if((rc = mbtk_audio_pcm_play_data_send(buf, len)) < len) {
+                    LOGE("Send data %d/%d", rc, len);
+                    result = -1;
+                    goto thread_end;
+                }
+
+                LOGD("%s: No.%d frame playback", __FUNCTION__, ++frames);
+            } else {
+                usleep(200000);
+            }
+        }
+    } else {
+        result = -1;
+    }
+
+    play_state = AUDIO_PLAY_STATE_STOP;
+    if(play_cb_func)
+        play_cb_func(play_handle , AUDIO_PLAY_STATE_STOP);
+
+thread_end:
+    mbtk_audio_pcm_play_stop();
+    play_exit = 1;
+    LOGD("%s: finished pcm playback.", __FUNCTION__);
+    return result;
+}
+
+/*****************************************************************
+* Function:     Ql_AudPlayer_Open
+*
+* Description:
+*               Open audio play device, and specify the callback function.
+*               This function can be called twice to play different audio sources.
+*
+* Parameters:
+*               device  : a string that specifies the PCM device.
+*                         NULL, means the audio will be played on the default PCM device.
+*
+*                         If you want to mixedly play audio sources, you can call this
+*                         API twice with specifying different PCM device.
+*                         The string devices available:
+*                            "hw:0,0"  (the default play device)
+*                            "hw:0,13" (this device can mix audio and TTS)
+*                            "hw:0,14"
+*
+*		        cb_func : callback function for audio player.
+*                         The results of all operations on audio player
+*                         are informed in callback function.
+*
+* Return:
+*               pcm device handle on success
+*               -1 for failure
+*****************************************************************/
+int Ql_AudPlayer_Open(char* device, _cb_onPlayer cb_func)
+{
+#ifdef MBTK_AF_SUPPORT
+    player_hdl = mbtk_audio_open_new(MBTK_AUTIO_TYPE_OUT, 1, Samprate, cb_func);
+    if(player_hdl == NULL)
+    {
+        return -1;
+    }
+    else
+    {
+        return player_hdl_1 = AUDIO_HANDLE;
+    }
+#else
+    if(is_running || mbtk_audio_pcm_init()) {
+        return -1;
+    } else {
+        play_cb_func = cb_func;
+        is_running = 1;
+        return play_handle;
+    }
+#endif
+}
+
+/*========================================================================
+  FUNCTION:  Ql_AudPlayer_Play
+=========================================================================*/
+/** @brief
+    This function writes pcm data to pcm device to play.
+
+    @param[in] hdl, the handle returned by Ql_AudPlayer_Open().
+    @param[in] pData, pointer to the start address of pcm data.
+    @param[in] length, the length of pcm data.
+
+    @return
+    on success, the return value is the number of bytes to play
+    on failure, the return value is -1;
+
+    @dependencies
+    Ql_AudPlayer_Open() must be first called successfully.
+*/
+/*=======================================================================*/
+int Ql_AudPlayer_Play(int hdl, unsigned char* pData, unsigned int length)
+{
+#ifdef MBTK_AF_SUPPORT
+    if(hdl != player_hdl_1 || player_hdl == NULL){
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+    return mbtk_audio_play_stream_new((void *)player_hdl, pData, length,50);
+
+#else
+    if(!is_running || hdl != play_handle) {
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+
+    return play_stream(pData, length);
+#endif
+}
+
+/*========================================================================
+  FUNCTION:  Ql_AudPlayer_PlayFrmFile
+=========================================================================*/
+/** @brief
+    This function plays the pcm data from the specified file.
+
+    @param[in] hdl, the handle returned by Ql_AudPlayer_Open().
+    @param[in] fd, a file descriptor that contains pcm data.
+               Note:
+                 the file offset should be set to the start position of pcm
+                 data region, which means you should move the file offset
+                 skipping the file header (such as wave header, amr header).
+    @param[in] offset, file offset. Please set it to -1 if no need to use.
+
+    @return
+       0 on success
+      -1 on failure
+
+    @dependencies
+    Ql_AudPlayer_Open() must be first called successfully.
+*/
+/*=======================================================================*/
+
+int  Ql_AudPlayer_PlayFrmFile(int hdl, int fd, int offset)
+{
+#ifdef MBTK_AF_SUPPORT
+    if(hdl != player_hdl_1 || player_hdl == NULL){
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+
+    return mbtk_audio_play_file_new((void *)player_hdl, fd, offset);
+
+#else
+    if(!is_running || hdl != play_handle) {
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+
+    return play_by_fd(fd, offset);
+#endif
+}
+
+//
+// Function:  Ql_AudPlayer_Pause
+//
+// Description:
+//   Pause playing.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+int  Ql_AudPlayer_Pause(int hdl)
+{
+    if(!is_running || hdl != play_handle) {
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+
+    play_state = AUDIO_PLAY_STATE_PAUSE;
+
+    while(!play_exit) {
+        usleep(10000);
+    }
+
+    return 0;
+}
+
+//
+// Function:  Ql_AudPlayer_Resume
+//
+// Description:
+//   Resume playing.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+int  Ql_AudPlayer_Resume(int hdl)
+{
+    if(!is_running || hdl != play_handle) {
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+
+    play_state = AUDIO_PLAY_STATE_RUNNING;
+
+    while(!play_exit) {
+        usleep(10000);
+    }
+    return 0;
+}
+
+//
+// Function:  Ql_AudPlayer_Stop
+//
+// Description:
+//   Stop playing audio
+// hdl:
+//   Handle received from Ql_AudPlayer_Open().
+void Ql_AudPlayer_Stop(int hdl)
+{
+    if(!is_running || hdl != play_handle) {
+        LOGE("Handle error : %d", hdl);
+        return;
+    }
+
+    play_state = AUDIO_PLAY_STATE_STOP;
+
+    while(!play_exit) {
+        usleep(10000);
+    }
+}
+
+//
+// Function:  Ql_AudPlayer_Close
+//
+// Description:
+//   Close player, and free the resource.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+void Ql_AudPlayer_Close(int hdl)
+{
+#ifdef MBTK_AF_SUPPORT
+    if(hdl != player_hdl_1 || player_hdl == NULL){
+        LOGE("Handle error : %d", hdl);
+        return -1;
+    }
+
+    mbtk_audio_close_new((void *)player_hdl);
+    player_hdl_1 = 0;
+
+#else
+    if(!is_running || hdl != play_handle) {
+        LOGE("Handle error : %d", hdl);
+        return;
+    }
+    play_state = AUDIO_PLAY_STATE_STOP;
+
+    while(!play_exit) {
+        usleep(10000);
+    }
+
+    is_running = 0;
+    mbtk_audio_pcm_deinit();
+#endif
+}
+
+
+int Ql_AudPlayer_set_LessDataThreshold(int hdl, unsigned short threshSize)
+{
+
+    return 0;
+}
+
+int Ql_AudPlayer_get_freeSpace(int hdl)
+{
+
+    return 0;
+}
+
+
+/*****************************************************************
+* Function:     Ql_AudRecorder_Open
+*
+* Description:
+*               Open audio record device, and specify the callback function.
+*
+* Parameters:
+*               device  : not used. MUST be NULL.
+*
+*		        cb_func : callback function for audio player.
+*                         The results of all operations on audio recorder
+*                         are informed in callback function.
+*
+* Return:
+*               pcm device handle
+*               -1 for failure
+*****************************************************************/
+int  Ql_AudRecorder_Open(char* device, _cb_onRecorder cb_fun)
+{
+    if(is_running || mbtk_audio_pcm_init()) {
+        return -1;
+    } else {
+        is_running = 1;
+        recorder_cb_fun = cb_fun;
+        return play_handle;
+    }
+}
+
+//
+// Function:  Ql_AudRecorder_StartRecord
+//
+// Description:
+//   Start to record.
+//   The record data is output in _cb_onRecorder.
+//
+// Return:
+//            0 on success
+//            -1 on failure
+int  Ql_AudRecorder_StartRecord(void)
+{
+    if(!is_running) {
+        LOGE("No open device.");
+        return -1;
+    }
+
+    return mbtk_audio_pcm_recorder_start(recorder_cb_func);
+}
+
+//
+// Function:  Ql_AudRecorder_Pause
+//
+// Description:
+//   Pause recording
+int  Ql_AudRecorder_Pause(void)
+{
+    if(!is_running) {
+        LOGE("No open device.");
+        return -1;
+    }
+
+    return mbtk_audio_pcm_recorder_pause();
+}
+
+//
+// Function:  Ql_AudRecorder_Resume
+//
+// Description:
+//   Resume recording
+int  Ql_AudRecorder_Resume(void)
+{
+    if(!is_running) {
+        LOGE("No open device.");
+        return -1;
+    }
+
+    return mbtk_audio_pcm_recorder_resume();
+}
+
+//
+// Function:  Ql_AudRecorder_Stop
+//
+// Description:
+//   Stop recording
+void Ql_AudRecorder_Stop(void)
+{
+    if(!is_running) {
+        LOGE("No open device.");
+        return;
+    }
+
+    mbtk_audio_pcm_recorder_stop();
+}
+
+//
+// Function:  Ql_AudRecorder_Close
+//
+// Description:
+//   Close recorder, and free the resource
+void Ql_AudRecorder_Close(void)
+{
+    if(!is_running) {
+        LOGE("No open device.");
+        return;
+    }
+
+    is_running = 0;
+    mbtk_audio_pcm_deinit();
+}
+
+//
+// Function:  Ql_clt_set_mixer_value
+//
+// Description:
+//   Close recorder, and free the resource
+boolean Ql_clt_set_mixer_value(const char *device, int count, const char *value)
+{
+
+    return FALSE;
+}
+
+
+int Ql_AudTone_Open(char* device, _cb_onPlayer cb)//cb not support now
+{
+    return 0;
+}
+
+int Ql_AudTone_Start(int hdl, struct Ql_TonePara *para)
+{
+    return 0;
+}
+
+void Ql_AudTone_Stop(int hdl)
+{
+
+}
+
+void Ql_AudTone_Close(int hdl)
+{
+
+}
+
+
+//****************QL Codec API************************//
+
+//
+// Function:  Ql_AudCodec_Set_ALC5616_DRCAGC
+//
+// Description:
+//   Set ALC5616 DRC/AGC configuration
+int Ql_AudCodec_Set_ALC5616_DRCAGC(const char *i2c, struct Ql_ALC5616_DRCAGC *cfg)
+{
+    return 0;
+}
+
+//
+// Function:   Ql_Update_wav_size
+//
+// Description:
+//   update wav format file size in the header
+// @param fd:
+//   wav file discriptor
+// @param size:
+//   wav file size to update
+int Ql_Update_wav_size(int fd, int size)
+{
+    return 0;
+}
+
+//add by grady, 2018-5-29
+/*
+ * describe : this function is use to open pcm device
+ * paras    :
+ *        device : this should be fix to hw:0,0
+ *        flags ; pcm play flags
+ *        rate: sample rate
+ *        channels  : audio channal 1 or 2
+ *        format: format to play or record, 16bit line,MP3
+ *        hostless: if there is no file it is true
+ * return    :
+ *        pcm : pcm handle, use can use this handle to read write data
+ */
+struct pcm *quec_pcm_open(char *device, unsigned flags, unsigned rate, unsigned channels, unsigned format, unsigned hostless)
+{
+    return NULL;
+}
+
+/*
+ * describe : this function is use to close pcm handle
+ * paras    :
+ *        pcm : pcm handle to close
+ * return    :
+ */
+int quec_pcm_close(struct pcm *pcm )
+{
+    return 0;
+}
+
+/*
+ * describe : this function is use to read pcm buffer
+ * paras    :
+ *        pcm : pcm handle to write date
+ *        buffer: data buffer
+ *        lenth: data length
+ * return    :
+ */
+int quec_read_pcm(struct pcm *pcm, void * buffer, int length)
+{
+
+    return 0;
+}
+
+/*
+ * describe : this function is use to get pcm buffer lenth
+ * paras    :
+ *        lenth: data length
+ * return
+ *        buffer length
+ */
+int quec_get_pem_buffer_len(struct pcm *pcm)
+{
+
+    return 0;
+}
+
+void dtmf_cb1(char dtmf)
+{
+    printf("%s:%c\n", __FUNCTION__, dtmf);
+}
+
+/**
+ * @brief Set RX DSP Gain
+ * @details
+ *      Gain support [-36,12] dB
+ *
+ * @param gain
+ *      DSP gain
+ */
+
+int Ql_Rxgain_Set(int value)
+{
+#ifdef MBTK_AF_SUPPORT
+    int volume =0;
+    if(value < -36 || value > 13)
+    {
+        volume = 0;
+    }
+    else
+    {
+        volume = value;
+    }
+
+    if(player_hdl==NULL)
+       return 0;
+
+    char databuf[1025]={0};
+    memcpy(databuf, "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                ", 1024);
+
+    mbtk_audio_play_stream_new(player_hdl, databuf, 1024, volume);
+    return 0;
+#else
+    mbtk_dsp_gain_set(1, value);
+    return 0;
+#endif
+    return 0;
+}
+
+
+/** Ql_Playback_Samprate_Set
+ * @brief Set Playback PCM Samprate
+ * @details
+ *      0 for NB 1 for WB
+ *
+ * @param samprate
+ *      samprate for PCM playback,default value is PCM NB
+ */
+int Ql_Playback_Samprate_Set(int samprate)
+{
+    printf("samprate is %d \n",samprate);
+    if(samprate == 1)
+    {
+        sample_rate = 16000;
+        mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
+    }
+    else{
+        mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
+        sample_rate = 8000;
+    }
+
+    return 0;
+}
+
+int Ql_Mp3_To_Wav(const char *wavpath, char *mp3path)
+{
+    return 0;
+}
+
+int Ql_Mp3_To_Play(char *mp3path, int hdl,int sample_rate)
+{
+    return 0;
+}
+
+//add by grady, 2018-6-2
+/*
+ * describe : this function is use to open mixer device
+ * paras        :
+ *              device: mixer device
+ * return
+ *              mixer handle
+ */
+struct mixer *quec_mixer_open(const char *device)
+{
+
+    return NULL;
+}
+
+/*
+ * describe : this function is use to close mixer device
+ * paras        :
+ *              mixer: mixer handle
+ * return
+ *              none
+ */
+void quec_mixer_close(struct mixer *mixer)
+{
+
+
+}
+
+/*
+ * describe : this function is use to get mixer devie control
+ * paras        :
+ *              mixer: mixer handle
+ *              name: mixer device
+ *              index: mixer index
+ * return
+ *              mixer control
+ */
+struct mixer_ctl *quec_mixer_get_control(struct mixer *mixer, const char *name, unsigned index)
+{
+
+    return NULL;
+}
+
+/*
+ * describe : this function is use to set mulvalues
+ * paras        :
+ *              mixer: mixer handle
+ *              count: count
+ *              argv: data
+ * return       :
+ *
+ */
+int quec_mixer_ctl_mulvalues(struct mixer_ctl *ctl, int count, char ** argv)
+{
+
+    return 0;
+}
+
+
+//end grady
+
+/*****************************************************************
+* Function:     Ql_AudPlayer_OpenExt
+*
+* Description:
+*               expend function from Ql_AudPlayer_OpenExt
+*               Open audio play device, and specify the callback function.
+*               This function can be called twice to play different audio sources.
+*
+* Parameters:
+*               device  : a string that specifies the PCM device.
+*                         NULL, means the audio will be played on the default PCM device.
+*
+*                         If you want to mixedly play audio sources, you can call this
+*                         API twice with specifying different PCM device.
+*                         The string devices available:
+*                            "hw:0,0"  (the default play device)
+*                            "hw:0,13" (this device can mix audio and TTS)
+*                            "hw:0,14"
+*
+*		        cb_func : callback function for audio player.
+*                         The results of all operations on audio player
+*                         are informed in callback function.
+*
+*               flags   : pcm flags, eg: PCM_MMAP, PCM_NMMAP.
+*
+*               channels: pcm sample channels.
+*
+*               rate    : pcm sample rate.
+*
+*               format  : pcm sample fromat
+*
+* Return:
+*               pcm device handle
+*               NULL, fail
+*****************************************************************/
+int Ql_AudPlayer_OpenExt(
+            char *dev,
+            _cb_onPlayer cb_fun,
+            int flags,
+            int channels,
+            int rate,
+            int format)
+{
+    return 0;
+}
+
+/*****************************************************************
+* Function:     Ql_AudRecorder_Open
+*
+* Description:
+*               Open audio record device, and specify the callback function.
+*
+* Parameters:
+*               device  : not used. MUST be NULL.
+*
+*		        cb_func : callback function for audio player.
+*                         The results of all operations on audio recorder
+*                         are informed in callback function.
+*
+*               flags   : pcm flags, eg: PCM_MMAP, PCM_NMMAP.
+*
+*               channels: pcm sample channels.
+*
+*               rate    : pcm sample rate.
+*
+*               format  : pcm sample fromat
+*
+* Return:
+*               pcm device handle
+*               NULL, fail
+*****************************************************************/
+int Ql_AudRecorder_OpenExt(
+            char *dev,
+            _cb_onRecorder cb_fun,
+            int flags,
+            int channels,
+            int rate,
+            int format)
+{
+
+
+    return 0;
+}
+
+/*
+* Function:     uac enable
+*
+* Description:
+*               uac enable
+*
+* Parameters:
+*               none
+* Return:
+*               TURE or FALSE
+*/
+int ql_uac_enable(void)
+{
+
+    return 0;
+}
+
+/*
+* Function:     uac disable
+*
+* Description:
+*               uac disable
+*
+* Parameters:
+*               none
+* Return:
+*               TURE or FALSE
+*/
+int ql_uac_disable(void)
+{
+
+    return 0;
+}
diff --git a/mbtk/libql_lib_v2/src/ql_call.c b/mbtk/libql_lib_v2/src/ql_call.c
new file mode 100755
index 0000000..700f93d
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_call.c
@@ -0,0 +1,821 @@
+/**
+ *   \file ql_call.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang<js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-01-18
+ */
+#include "ql/ql_mcm_call.h"
+#include <telephony/ril.h>
+#include <telephony/ril_ext.h>
+#include "ql/ql_mcm.h"
+#include "rilutil.h"
+#include "mbtk_log.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+	#define mbtk_call_log(...)                    printf(__VA_ARGS__)
+#else
+	#define mbtk_call_log(...)
+#endif
+
+struct ql_call_ubus_t
+{
+    struct ubus_context     *ctx;
+
+    /* RIL */
+    struct ubus_subscriber 	ril_ind_event;
+    uint32_t	 		    ril_subscriber_id;
+    uint32_t	 		    ril_request_id;
+    uint8_t	 		        auto_answer;
+    uint32_t                answer_time;
+    pthread_t  call_status_pthread;
+    ql_mcm_voice_calls_state_t  call_state;
+    QL_VoiceCall_CommonStateHandlerFunc_t _voice_call_common_state_handler;
+    QL_VoiceCall_StateHandlerFunc_t   _voice_call_state_handler;
+};
+
+const char *RIL_MessageMap[] =
+{
+        "RIL_CALL_ACTIVE",       //0,
+        "RIL_CALL_HOLDING",      //1,
+        "RIL_CALL_DIALING",      //2,    /* MO call only */
+        "RIL_CALL_ALERTING",     //3,    /* MO call only */
+        "RIL_CALL_INCOMING",     //4,    /* MT call only */
+        "RIL_CALL_WAITING",      //5,    /* MT call only */
+        "RIL_CALL_OFFERING",     //6,    /* MT call offering (call setup) */
+        "RIL_CALL_DISCONNECTING",//7,    /* call in disconnect procedure */
+        "RIL_CALL_DISCONNECTED"  //8,    /* call is disconnected */
+};
+static struct ql_call_ubus_t *ql_call_ubus = NULL;
+static void ql_voice_call_answer(struct uloop_timeout *timeout);
+static struct uloop_timeout voice_call_answer_timeout =
+{
+    .cb = ql_voice_call_answer,
+};
+
+static void ql_voice_call_answer(struct uloop_timeout *timeout)
+{
+    QL_Voice_Call_Answer(ql_call_ubus, 0);
+    // uloop_timeout_set(timeout, 2000);
+    return;
+}
+
+int ql_call_handle_ril_ind(struct ubus_context *ctx, unsigned int rilid, unsigned int rilerror, char *data, int data_len)
+{
+	UNUSED(data_len);
+	UNUSED(ctx);
+
+    int datalen = 0, callID = 0;
+	int ret = 0;
+
+	if (rilerror) {
+		return -1;
+	}
+
+	mbtk_call_log("call_handle_ril_ind: rcv %d\n", rilid);
+
+	 switch(rilid)
+	 {
+		case RIL_UNSOL_ECALLDATA:								//+ecalldata
+			// ecallHandleEcalldata(data);
+			break;
+
+		case RIL_UNSOL_ECALLONLY:								//+ecallonly
+			// ecallHandleEcallonly(data);
+			break;
+
+        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT: /*"CC" 1510*/
+        {
+            RIL_Call *rilCall = (RIL_Call *)data;
+            callID = rilCall->index;
+
+            mbtk_call_log("%s: id %d=RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED_EXT (len=%d) (state=%s), call index=%d\n",
+                    __FUNCTION__, rilid, datalen, RIL_MessageMap[(int)rilCall->state], callID);
+
+            mbtk_call_log("Received from Ril, name=%s, num=%s\n", rilCall->name, rilCall->number);
+            ql_call_ubus->call_state.calls_len = 1;
+            ql_call_ubus->call_state.calls[0].call_id;
+            memcpy(ql_call_ubus->call_state.calls[0].number, rilCall->number, strlen(rilCall->number));
+            ql_call_ubus->call_state.calls[0].state = rilCall->state;
+            switch (rilCall->state)
+            {
+                //Call connected,  for MO & MT both
+                case RIL_CALL_ACTIVE:
+                    mbtk_call_log("%s, RIL_CALL_ACTIVE, call index=%d connected!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_ACTIVE;
+                    break;
+
+                //MT call only
+                case RIL_CALL_INCOMING:
+                    mbtk_call_log("%s, RIL_CALL_INCOMING!!\n", __FUNCTION__);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_INCOMING;
+                    if(!ql_call_ubus->auto_answer)
+                    {
+                        mbtk_call_log("%s, auto_answer:%d!!\n", __FUNCTION__, ql_call_ubus->answer_time);
+                        uloop_timeout_set(&voice_call_answer_timeout, ql_call_ubus->answer_time);
+                    }
+                    break;
+
+                //MO call only
+                case RIL_CALL_ALERTING:
+                    mbtk_call_log("%s, RIL_CALL_ALERTING, call index=%d alerting!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_ALERTING;
+                    break;
+
+                case RIL_CALL_WAITING:  //MT call only
+                    mbtk_call_log("%s, RIL_CALL_WAITING, call index=%d alerting!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_WAITING;
+                    break;
+
+                case RIL_CALL_DISCONNECTED:
+                    mbtk_call_log("%s, RIL_CALL_DISCONNECTED, call index=%d disconnected!!\n", __FUNCTION__, callID);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+                    break;
+
+                case RIL_CALL_HOLDING:
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_HOLDING;
+                    mbtk_call_log("%s, RIL_CALL_HOLDING, call index=%d hold!!\n", __FUNCTION__, callID);
+                    break;
+
+                case RIL_CALL_DIALING:  //MO call only
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_DIALING;
+                    mbtk_call_log("%s, RIL_CALL_DIALING, call index=%d hold!!\n", __FUNCTION__, callID);
+                    break;
+                case RIL_CALL_OFFERING:
+                case RIL_CALL_DISCONNECTING:
+                default:
+                    printf("%s, state=%s ignored!!\n", __FUNCTION__, RIL_MessageMap[(int)rilCall->state]);
+                    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+                    break;
+            }
+            if(ql_call_ubus->_voice_call_common_state_handler && ql_call_ubus)
+            {
+                ql_call_ubus->_voice_call_common_state_handler(E_QL_MCM_VOICE_CALL_IND, &ql_call_ubus->call_state, sizeof(ql_mcm_voice_call_ind));
+            }
+        }
+        break;
+        case RIL_UNSOL_CALL_NO_CARRIER_EXT: /*"CC" 1511*/
+            mbtk_call_log("%s: id %d=RIL_UNSOL_CALL_NO_CARRIER_EXT (len=%d)\n",
+                    __FUNCTION__, rilid, datalen);
+            ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+            if(ql_call_ubus->_voice_call_common_state_handler && ql_call_ubus)
+            {
+                ql_call_ubus->_voice_call_common_state_handler(E_QL_MCM_VOICE_CALL_IND, &ql_call_ubus->call_state, sizeof(ql_mcm_voice_call_ind));
+            }
+            break;
+
+        case RIL_UNSOL_CALL_RING: /*"CC" 1018*/
+            printf("%s: id %d=RIL_UNSOL_CALL_RING (len=%d), ignored!!\n",
+                    __FUNCTION__, rilid, datalen);
+            break;
+
+        case RIL_UNSOL_DISCONNECT_CALLID: /*"CC" 1538*/
+            callID = *(int *)data;
+            ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+            mbtk_call_log("%s: id %d=RIL_UNSOL_DISCONNECT_CALLID (len=%d), call index=%d!\n",
+                        __FUNCTION__, rilid, datalen, *(int *)data);
+            break;
+		default:
+			break;
+	 }
+
+	 return ret;
+}
+static void ql_call_requset_cb(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+    unsigned int requestid;
+    unsigned int rilerrno;
+    void *response = NULL;
+    int responselen;
+    int ret = 0;
+
+    ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &response, &responselen);
+    if(ret)
+    {
+        fprintf(stderr, "parse blob error\n");
+        goto done;
+    }
+
+    if(rilerrno)
+    {
+        // RIL_REQUEST_RELEASE_CALL
+        fprintf(stderr, "unsolicited id %d, error code %d\n", requestid, rilerrno);
+        goto done;
+    }
+
+    //process response here
+
+done:
+    if(response)
+        rilutil_freeResponseData(requestid, response, responselen);
+
+    return;
+}
+
+int ql_call_subscriber_cb(struct ubus_context *ctx, struct ubus_object *obj,
+			    struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	UNUSED(ctx);
+	UNUSED(obj);
+	UNUSED(req);
+	UNUSED(method);
+
+	unsigned int requestid = 0;
+	unsigned int rilerrno = 0;
+	void *response = NULL;
+	int responselen = 0;
+	int ret = 0;
+
+	ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &response, &responselen);
+	if (ret)
+		goto end;
+
+	mbtk_call_log("call_subscriber_cb: rcv %d\n", requestid);
+
+    ql_call_handle_ril_ind(ctx, requestid, rilerrno, response, responselen);
+
+end:
+	if (response)
+		rilutil_freeResponseData(requestid,response,responselen);
+
+	return 0;
+}
+
+void ql_call_subscriber_remove_cb(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id)
+{
+	UNUSED(ctx);
+	UNUSED(obj);
+	UNUSED(id);
+	mbtk_call_log("ql_call_subscriber_remove_cb\n");
+}
+
+static void ql_call_register_ril(void* hdl)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)hdl;
+    int ret;
+
+    if(hdl == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    pthread_detach(pthread_self());
+	ret = ubus_register_subscriber(voice_call_ubus->ctx, &voice_call_ubus->ril_ind_event);
+	if (ret) {
+		printf("call_daemon: Failed to add ecall_subscriber: %s\n", ubus_strerror(ret));
+        return ret;
+    }
+
+	voice_call_ubus->ril_ind_event.cb = ql_call_subscriber_cb;
+	voice_call_ubus->ril_ind_event.remove_cb = ql_call_subscriber_remove_cb;
+
+	//register for CC ind
+	if (ubus_lookup_id(voice_call_ubus->ctx, "ril.unsol.cc", &voice_call_ubus->ril_subscriber_id)) {
+		printf("call_daemon: Failed to look up ril.unsol.cc object\n");
+        return ret;
+	}
+
+	ubus_subscribe(voice_call_ubus->ctx, &voice_call_ubus->ril_ind_event, voice_call_ubus->ril_subscriber_id);
+	mbtk_call_log("call_daemon: subscribe ril.unsol.cc object ok\n");
+    mbtk_call_log("%s!\n", __FUNCTION__);
+    while(1)
+    {
+        uloop_run();
+        printf("%s uloop_run done!\n", __FUNCTION__);
+    }
+    pthread_exit(NULL);
+}
+/* Init voice module and return h_voice, this should be called before any other APIs */
+int QL_Voice_Call_Client_Init(voice_client_handle_type *ph_voice)
+{
+    int id;
+    // Set call handle.
+    //*ph_voice = 1;
+    if(ph_voice == NULL)
+    {
+        printf("ARG error or has inited.");
+        return -1;
+    }
+    ql_call_ubus = malloc(sizeof(struct ql_call_ubus_t));
+    if(NULL == ql_call_ubus)
+    {
+        printf("malloc memory error\n");
+    }
+    memset(ql_call_ubus, 0, sizeof(struct ql_call_ubus_t));
+    uloop_init();
+
+    ql_call_ubus->ctx = ubus_connect(NULL);
+    if(!ql_call_ubus->ctx)
+    {
+        printf("Failed to connect to ubus");
+        goto out;
+    }
+
+    ubus_add_uloop(ql_call_ubus->ctx);
+
+    if (ubus_lookup_id(ql_call_ubus->ctx, "ril", &ql_call_ubus->ril_request_id)) {
+    	fprintf(stderr, "%s, Failed to look up test object\n", __FUNCTION__);
+    	return -1;
+    }
+    ql_call_ubus->auto_answer = E_QL_MCM_VOICE_AUTO_ANSWER_DISABLE;
+    ql_call_ubus->call_state.calls[0].state = E_QL_MCM_VOICE_CALL_STATE_END;
+    pthread_create(&ql_call_ubus->call_status_pthread, NULL, (void *)ql_call_register_ril, (void *)ql_call_ubus);
+    *ph_voice = ql_call_ubus;
+
+    return 0;
+out:
+    //uloop_done();
+
+    return 0;
+}
+
+/* DeInit voice module and release resources, this should be called at last */
+int QL_Voice_Call_Client_Deinit(voice_client_handle_type h_voice)
+{
+    int ret;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    // Free handle.
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    ret = pthread_cancel(voice_call_ubus->call_status_pthread);
+    mbtk_call_log("kill pthread : %d \n", ret);
+    pthread_join(voice_call_ubus->call_status_pthread, NULL);
+    do{
+        ret = pthread_kill(voice_call_ubus->call_status_pthread, 0);
+        mbtk_call_log("kill pthread: %d \n", ret);
+        if(ret == ESRCH)
+            printf("The specified thread does not exist or has terminated\n");
+        else if(ret == EINVAL)
+            printf("Useless signal\n");
+        else
+            mbtk_call_log("The thread exists\n");
+        usleep(100000);
+    }while(0 == ret);
+    free(h_voice);
+    ql_call_ubus = NULL;
+    uloop_done();
+    ubus_free(voice_call_ubus->ctx);
+    return 0;
+}
+
+/* Add callback function, if any call state changed, handlerPtr will be called to notify App */
+int QL_Voice_Call_AddStateHandler(voice_client_handle_type h_voice,
+                                  QL_VoiceCall_StateHandlerFunc_t   handlerPtr,
+                                  void*                             contextPtr)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    ret = pthread_kill(voice_call_ubus->call_status_pthread, 0);
+    mbtk_call_log("kill pthread: %d \n", ret);
+    if(ret == ESRCH)
+        mbtk_call_log("The specified thread does not exist or has terminated\n");
+    else if(ret == EINVAL)
+        printf("Useless signal\n");
+    else
+        mbtk_call_log("The thread exists\n");
+    if(voice_call_ubus->ril_subscriber_id)
+    {
+        voice_call_ubus->_voice_call_state_handler = handlerPtr;
+    }
+    else
+    {
+        printf("%s error!!\n", __func__);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* Remove callback function, won't receive any notify anymore */
+int QL_Voice_Call_RemoveStateHandler(voice_client_handle_type        h_voice)
+{
+	struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        return -1;
+    }
+    voice_call_ubus->_voice_call_state_handler = NULL;
+
+    return 0;
+}
+
+
+/* Add callback function, if any call state changed, handlerPtr will be called to notify App */
+int QL_Voice_Call_AddCommonStateHandler(voice_client_handle_type h_voice,
+                                  QL_VoiceCall_CommonStateHandlerFunc_t   handlerPtr)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        return -1;
+    }
+    ret = pthread_kill(voice_call_ubus->call_status_pthread, 0);
+    mbtk_call_log("kill pthread: %d \n", ret);
+    if(ret == ESRCH)
+        mbtk_call_log("The specified thread does not exist or has terminated\n");
+    else if(ret == EINVAL)
+        printf("Useless signal\n");
+    else
+        mbtk_call_log("The thread exists\n");
+    if(voice_call_ubus->ril_subscriber_id)
+    {
+        voice_call_ubus->_voice_call_common_state_handler = handlerPtr;
+    }
+    else
+    {
+        printf("%s error!!\n", __func__);
+        return -1;
+    }
+
+
+    return 0;
+}
+
+/* Remove callback function, won't receive any notify anymore */
+int QL_Voice_Call_RemoveCommonStateHandler(voice_client_handle_type          h_voice)
+{
+	struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        LOGE("ARG error or not inited.");
+        return -1;
+    }
+    voice_call_ubus->_voice_call_common_state_handler = NULL;
+
+    return 0;
+}
+
+
+/* Start call and return call_id, this can be used in the later */
+int QL_Voice_Call_Start(voice_client_handle_type    h_voice,
+                        E_QL_VCALL_ID_T             simId,
+                        char*                       phone_number,   ///< [IN] Destination identifier for the voice
+                        int                         *call_id)      ///< [OUT] call id
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int id, ret;
+	RIL_Dial dial_data;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    if(voice_call_ubus->call_state.calls[0].state == E_QL_MCM_VOICE_CALL_STATE_ACTIVE ||
+       voice_call_ubus->call_state.calls[0].state == E_QL_MCM_VOICE_CALL_STATE_INCOMING ||
+       voice_call_ubus->call_state.calls[0].state == E_QL_MCM_VOICE_CALL_STATE_ALERTING)
+    {
+        printf("A call already exists, Voice Call incoming or active!!\n");
+        return -1;
+    }
+    memset(&dial_data, 0, sizeof(RIL_Dial));
+    dial_data.address = phone_number;
+    printf("call number %s\n", dial_data.address);
+    if (ubus_lookup_id(ql_call_ubus->ctx, "ril", &ql_call_ubus->ril_request_id)) {
+    	fprintf(stderr, "%s, Failed to look up test object\n", __FUNCTION__);
+    	return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_DIAL, &dial_data, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("sim_get_imsi,ubus_invoke Failed %s\n", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+/* End call of call_id, which returned by QL_Voice_Call_Start or callback func register via QL_Voice_Call_AddStateHandler */
+int QL_Voice_Call_End(voice_client_handle_type    h_voice,
+                      int                         call_id)        ///< [IN] call id, return by QL_Voice_Start
+{
+    static struct ubus_request req;
+    static struct blob_buf b;
+    int ret;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    mbtk_call_log("Voice Call State:%s, %d\n", voice_call_ubus->call_state.calls[0].number, voice_call_ubus->call_state.calls[0].state);
+    if(voice_call_ubus->call_state.calls[0].state != E_QL_MCM_VOICE_CALL_STATE_ACTIVE &&
+       voice_call_ubus->call_state.calls[0].state != E_QL_MCM_VOICE_CALL_STATE_INCOMING &&
+       voice_call_ubus->call_state.calls[0].state != E_QL_MCM_VOICE_CALL_STATE_ALERTING)
+    {
+        printf("No Voice Call incoming or active!!\n");
+        return -1;
+    }
+    //use rilutil's API, just a example
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_RELEASE_CALL, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("sim_get_imsi,ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+/* Answer the call of call_id, which returned by callback func register via QL_Voice_Call_AddStateHandler */
+int QL_Voice_Call_Answer(voice_client_handle_type    h_voice,
+                         int                         call_id )
+{
+    static struct ubus_request req;
+    static struct blob_buf b;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_ANSWER, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_Hold( voice_client_handle_type    h_voice)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_HANGUP, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_UnHold( voice_client_handle_type h_voice)
+{
+
+    return 0;
+}
+
+int QL_Voice_Call_Conference( voice_client_handle_type h_voice)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_CONFERENCE, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_EndConference( voice_client_handle_type   h_voice)
+{
+
+    return 0;
+}
+
+int QL_Voice_Call_Ecall(voice_client_handle_type    h_voice,
+                        E_QL_VCALL_ID_T             simId,
+                        char*                       phone_number,
+                        ql_mcm_ecall_info           ecall_info,
+                        int                         *call_id)
+{
+// RIL_REQUEST_SET_CECALL
+// RIL_REQUEST_GET_CECALL
+//         RIL_REQUEST_SET_ECALLONLY
+//         RIL_REQUEST_GET_ECALLONLY
+//         RIL_REQUEST_SET_ECALLREG
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    //use rilutil's API, just a example
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_CONFERENCE, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+
+int QL_Voice_Call_SetAutoAnswer(voice_client_handle_type        h_voice,
+                                E_QL_MCM_VOICE_AUTO_ANSWER_T    eAnswerType,
+                                uint32_t                        uAnswerTime)
+{
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    voice_call_ubus->auto_answer = eAnswerType;
+    voice_call_ubus->answer_time = uAnswerTime;
+
+    return 0;
+}
+
+int QL_Voice_Call_Ecall_HangUp(voice_client_handle_type h_voice)
+{
+    return 0;
+}
+
+int QL_Voice_Call_Ecall_UpdateMsd(voice_client_handle_type    h_voice,const char *msd,uint32_t   msd_len)
+{
+    return 0;
+}
+
+//Ecall Push caommand
+int QL_Voice_Call_Ecall_MsdPush(voice_client_handle_type h_voice,
+                                        E_QL_MCM_ECALL_STATE_T *ecall_state)
+{
+    return 0;
+}
+
+//Get Ecall config info
+int QL_Voice_Call_Ecall_GetConfigInfo(voice_client_handle_type h_voice,
+                                        ql_mcm_ecall_config_info *ecall_config)
+{
+//         RIL_REQUEST_SET_ECALLCFG
+//         RIL_REQUEST_GET_ECALLCFG
+    return 0;
+}
+
+int QL_Voice_Call_Ecall_SetConfigInfo(voice_client_handle_type h_voice,
+                                        E_QL_MCM_ECALL_CONFIG_T ecall_config_type,
+                                        uint8_t value)
+{
+    return 0;
+}
+
+//Cancel dial
+int QL_Voice_Call_CancelDial( voice_client_handle_type   h_voice)
+{
+    static struct ubus_request req;
+    static struct blob_buf b;
+    int ret;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    //use rilutil's API, just a example
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_RELEASE_CALL, NULL, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("sim_get_imsi,ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+//VTS API
+int QL_Voice_Call_Dtmf(voice_client_handle_type h_voice, uint8_t digit, int call_id)
+{
+    static struct ubus_request req;
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+    static struct blob_buf b;
+    int ret;
+    char code = digit;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    rilutil_makeRequestBlob(&b, RIL_REQUEST_DTMF, &code, 0);
+    ret = ubus_invoke(voice_call_ubus->ctx, voice_call_ubus->ril_request_id, "ril_request", b.head, ql_call_requset_cb, 0,0);
+    if(ret != 0)
+    {
+        printf("ql call, ubus_invoke Failed %s", ubus_strerror(ret));
+        return E_QL_ERROR_GENERIC;
+    }
+    return 0;
+}
+
+int QL_Voice_Call_GetCallStatus
+(
+    int                         h_voice,
+    int                         call_id, // If call_id<0, means to get all calls state, or get specified call_id info
+    ql_mcm_voice_calls_state_t  *pt_callstate
+)
+{
+    struct ql_call_ubus_t *voice_call_ubus = (struct ql_call_ubus_t *)h_voice;
+
+    if(h_voice == NULL || ql_call_ubus == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    memcpy((void *)pt_callstate, &voice_call_ubus->call_state, sizeof(ql_mcm_voice_calls_state_t));
+    return 0;
+}
+
+//Set forwarding
+int QL_Voice_Call_SetForwarding
+(
+    int                             h_voice,
+    E_QL_MCM_VOICE_CALL_SERVICE_T   service,
+    E_QL_MCM_VOICE_CALL_FORWARDING_REASON_T  reason,
+    char *number
+)
+{
+
+    return 0;
+}
+
+//Get forwarding status
+int QL_Voice_Call_GetForwardingStatus(
+        int                             h_voice,
+        E_QL_MCM_VOICE_CALL_FORWARDING_REASON_T  reason,
+        ql_mcm_voice_call_forwarding_status_list_t *pt_status)
+{
+
+    return 0;
+}
+
+
+//Set voice call waiting
+int QL_Voice_Call_SetWaiting
+(
+    int                                 h_voice,
+    ql_mcm_voice_call_waiting_service_t e_service
+)
+{
+// RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
+    return 0;
+}
+
+//Get voice call waiting status
+int QL_Voice_Call_GetWaitingStatus
+(
+    int                                 h_voice,
+    ql_mcm_voice_call_waiting_service_t *pe_service
+)
+{
+
+    return 0;
+}
diff --git a/mbtk/libql_lib_v2/src/ql_cell_locator.c b/mbtk/libql_lib_v2/src/ql_cell_locator.c
new file mode 100755
index 0000000..b36075d
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_cell_locator.c
@@ -0,0 +1,347 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define LOG_TAG "mbtk_http"
+#include "mbtk_type.h"
+#include "mbtk_http.h"
+#include "mbtk_log.h"
+#include "mbtk_info_api.h"
+#include "ql/ql_cell_locator.h"
+
+
+static int http_handle;
+static int http_session;
+
+static char Server[128]={0};
+static char Token[128] = {0};
+static char Loction[128]={0};
+static int PORT = 0;
+static int locator_timeout = 60;  // 60s for default.
+
+static int mbtk_lbs_http_parse_location(char* buf, int len, char* rspBuf)
+{
+    if(buf != NULL && len != 0)
+    {
+        char* pos0 = NULL;
+        char* pos1 = NULL;
+        char fac[64] = {'\0'};
+        pos0 = strstr(buf, "<info>");
+        if(pos0 != NULL)
+        {
+            pos1 = strstr(pos0 + 1, "</info>");
+            if(pos1 != NULL)
+            {
+                strncpy(fac, pos0 + 6, pos1 - pos0 - 6);
+            }
+            if(strcmp(fac, "OK") == 0)
+            {
+                char* l_pos0 = NULL;
+                char* l_pos1 = NULL;
+                char* type_pos0 = NULL;
+                char* type_pos1 = NULL;
+                char fac_type[64] = {'\0'};
+                type_pos0 = strstr(buf, "<type>");
+                if(type_pos0 != NULL)
+                {
+                    type_pos1 = strstr(type_pos0 + 1, "</type>");
+                    if(type_pos1 != NULL)
+                    {
+                        strncpy(fac_type, type_pos0 + 6, type_pos1 - type_pos0 - 6);
+                        if(strcmp(fac_type, "0") == 0)
+                        {
+                            return -1;
+                        }
+                    }
+                }
+                l_pos0 = strstr(buf, "<location>");
+                if(l_pos0 != NULL)
+                {
+                   l_pos1 = strstr(l_pos0 + 1, "</location>");
+                    if(l_pos1 != NULL)
+                    {
+                        strncpy(rspBuf, l_pos0 + 10, l_pos1 - l_pos0 - 10);
+                    }
+                    return 0;
+                }
+            }
+            else //key error http chunk
+            {
+                printf("info is %s", fac);
+            }
+        }
+    }
+    return -1;
+}
+
+
+
+static void http_data_cb_func1(
+    int session_id, mbtk_http_data_type_enum type,
+    void *data,int data_len)
+{
+    if(type == MBTK_HTTP_DATA_HEADER) {
+        LOGE("Header(%d):%s\n",data_len,(char*)data);
+    } else if(type == MBTK_HTTP_DATA_CONTENT) {
+        LOGE("Data(%d):%s\n",data_len,(char*)data);
+		mbtk_lbs_http_parse_location((char*)data, data_len, Loction);
+    } else {
+        LOGI(">>>>>Complete<<<<<\n");
+    }
+}
+
+
+int ql_cell_locator_init()
+{
+    http_handle = mbtk_http_handle_get(TRUE, http_data_cb_func1);
+    if(http_handle < 0)
+    {
+        LOGE("mbtk_http_handle_get() fail.");
+        return -1;
+    }
+
+	http_session = mbtk_http_session_create(http_handle,HTTP_OPTION_GET,HTTP_VERSION_1_1);
+    if(http_session < 0)
+    {
+        LOGE("mbtk_http_session_create() fail.");
+        return -1;
+    }
+
+	return 0;
+}
+
+
+int ql_cell_locator_release()
+{
+    if(mbtk_http_handle_free(http_handle))
+    {
+        LOGE("mbtk_http_handle_free() fail.");
+        return -1;
+    }
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief set locator query server and port, server length must be less than 255 bytes.
+  @param[in] server the query server ip address
+  @param[in] port the query server port
+  @return if success return 0, else return -1
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_cell_locator_set_server(const char *server, unsigned short port)
+{
+	if(server == NULL)
+	{
+		return -1;
+	}
+
+	memset(Server, 0, sizeof(Server));
+	memcpy(Server, server, strlen(server));
+	PORT = port;
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief set locator query timeout, the value must between 1-300 [seconds]
+  @param[in] timeout value of query timeout
+  @return if success return 0, else return -1
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_cell_locator_set_timeout(unsigned short timeout)
+{
+    locator_timeout = timeout;
+	return 0;
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief set locator query token, token length must be 16 bytes. the token Used to verify that
+         the client accessing the service is valid.
+  @param[in] token string of token which want to be setted.
+  @param[in] length of token string.
+  @return if success return 0, else return -1
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_cell_locator_set_token(const char *token, int len)
+{
+	if(token == NULL && (strlen(token) != len) && len > 128)
+	{
+		return -1;
+	}
+
+	memset(Token, 0, sizeof(token));
+	memcpy(Token, token, strlen(token));
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief perform cell locator query
+  @param[out] resp include query result or set the error_msg and error_code
+  @return if success return 0, else return -1
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_cell_locator_perform(ql_cell_resp *resp)
+{
+
+    int ret = 0;
+    int ret1 = 0;
+
+    char url[1024] = {0};
+    char imei[50] ={0};
+    char cellinfo[512] = {0};
+    char *p = cellinfo;
+    	int i =0;
+    int mcc,mnc,tac,ci,rsrp;
+
+    mbtk_info_handle_t* info_handle = mbtk_info_handle_get();
+    if(!info_handle)
+    {
+        return -1;
+    }
+
+    mbtk_imei_get(info_handle, imei);
+
+    list_node_t* cell_list = NULL;
+    int type, err;
+    int CellId;
+    err = mbtk_cell_get(info_handle, &type, &cell_list);
+    if(err || cell_list == NULL) {
+        printf("Error : %d\n", err);
+    }
+    else
+    {
+        list_first(cell_list);
+        mbtk_cell_info_t* cell = (mbtk_cell_info_t*) list_next(cell_list);
+        if(cell)
+        { // Current server cell.
+            switch(type)
+            {
+                case 0:
+                    LOGE("GSM : mcc=%d, mnc=%d, lac=%d, ci=%d, arfcn=%d, bsic=%d\n",cell->value5, cell->value6,cell->value1, cell->value2, cell->value3, cell->value4);
+                    mcc = cell->value5;
+                    mnc = cell->value6;
+                    tac = cell->value1;
+                    ci = cell->value2;
+                    rsrp = 30;
+                    break;
+                case 1:
+                    LOGE("UMTS : lac=%d, ci=%d, arfcn=%d\n", cell->value1, cell->value2, cell->value3);
+                    break;
+                case 2:
+                    LOGE("LTE : tac=%d, PCI=%d, dlEuarfcn=%d, ulEuarfcn=%d, band=%d, mcc=%d, mnc=%d ,cid=%d, rsrp=%d\n",
+                    cell->value1, cell->value2, cell->value3, cell->value4, cell->value5,cell->value6, cell->value7, cell->value8,cell->value9);
+//// LTE server cell: tac, PCI, dlEuarfcn, ulEuarfcn, band, mcc, mnc ,cid, rsrp
+                    mcc = cell->value6;
+                    mnc = cell->value7;
+                    tac = cell->value1;
+                    ci = cell->value10;
+                    rsrp = cell->value9;
+
+                    //	LOGE(cellinfo,"&bts=%X,%X,%d,%d,%d&nearbts=",mcc,mnc,tac,ci,rsrp-140);
+                    //	LOGE("cellinfo:%s\n", cellinfo);
+
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        sprintf(cellinfo,"&bts=%X,%X,%d,%d,%d&nearbts=",mcc,mnc,tac,ci,rsrp-140);
+        while ((cell = (mbtk_cell_info_t*) list_next(cell_list)))
+        {
+            switch(type)
+            {
+                case 0:
+                    LOGE("CELL : %d, %d, %d, %d, %d", cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+                    if(i < 3)
+                    {
+                        sprintf(p+strlen(p),"%X,%X,%d,%d,%d|",cell->value5,cell->value6,cell->value1,cell->value2,29-140);
+                        i++;
+                    }
+                    break;
+                case 1:
+                    LOGE("CELL : lac=%d, ci=%d, arfcn=%d\n", cell->value1, cell->value2, cell->value3);
+                    break;
+                case 2:
+                    CellId = cell->value5;
+                //    if(CellId > 0 && cell->value5 != -1)
+                    if(CellId > 0 )
+                    {
+                        if(i < 3)
+                        {
+                            sprintf(p+strlen(p),"%X,%X,%d,%d,%d|",mcc,mnc,tac,cell->value5,cell->value3-140);
+                            i++;
+                        }
+                    }
+                    LOGE("CELL : phyCellId=%d, euArfcn=%d, rsrp=%d, rsrq=%d, cellId:%d\n", cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+                    break;
+                default:
+                    break;
+           }
+        }
+    }
+    list_free(cell_list);
+
+    sprintf(url,"http://%s:%d/position?accesstype=0&imei=%s&cdma=0%s&output=xml&key=%s",\
+            Server, PORT, imei,cellinfo, Token);
+
+
+    memset(Loction, 0, sizeof(Loction));
+
+
+    if(mbtk_http_session_url_set(http_handle, http_session, url)) {
+        LOGE("mbtk_http_session_url_set() fail.\n");
+        return -1;
+    }
+
+    const mbtk_http_session_t* session = mbtk_http_session_get(http_handle, http_session);
+    LOGI("HTTP:%d,%s,%d,%s\n",session->option,session->host,session->port,session->uri);
+
+
+    mbtk_http_session_head_add(http_handle, http_session, "Connection", "KeepAlive");
+
+
+    if(mbtk_http_session_start(http_handle, http_session)) {
+        LOGE("mbtk_http_session_start() fail.\n");
+        return -1;
+    }
+
+    if(strlen(Loction))
+    {
+        char Lon[20] ={0};
+        char Lat[20] = {0};
+        char *lon = Loction;
+        char *lat = strstr(Loction, ",");
+        if(lat != NULL )
+        {
+            memcpy(Lon, Loction, lat- lon);
+
+            lat++;
+            memcpy(Lat, lat, strlen(lat));
+
+            sscanf((char*)Lon,"%lf",&resp->lon);
+            sscanf((char*)Lat,"%lf",&resp->lat);
+        }
+
+    }
+
+//    printf("lon:%f, lat:%f\n", resp->lon, resp->lat);
+//	printf("\nloction:%s\n", Loction);
+
+	return 0;
+}
+
+
+
+
+
diff --git a/mbtk/libql_lib_v2/src/ql_common.c b/mbtk/libql_lib_v2/src/ql_common.c
new file mode 100755
index 0000000..70d0ad3
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_common.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>

+#include "ql/ql_common.h"

+

+void Ql_Powerdown(int mode)

+{

+    switch (mode)

+        {

+        case 1:

+            system("halt");

+            break;

+        case 2:

+            system("reboot");

+            break;

+        default:

+            printf("mode error");

+        }

+

+    return ;

+

+}

+

diff --git a/mbtk/libql_lib_v2/src/ql_data_call.c b/mbtk/libql_lib_v2/src/ql_data_call.c
new file mode 100755
index 0000000..218e14b
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_data_call.c
@@ -0,0 +1,658 @@
+#include "ql/DSI_ConnectManager.h"
+#include "mbtk_info_api.h"
+#include <fcntl.h>
+
+extern mbtk_info_handle_t* ql_info_handle;
+extern int ql_info_handle_num;
+static bool inited = FALSE;
+
+typedef struct
+{
+    bool active;
+    uint8 cid;
+    int ip_type;
+    char user[128];
+    char pass[128];
+    QL_DSI_AUTH_PREF_T auth;
+} apn_info;
+
+// 2 - 7
+static apn_info ql_apn_info[9]={0};
+static int mbtk_interval_sec = 0;
+static nw_status_cb ql_net_status_cb = NULL;
+static ex_conn_status_cb ql_net_ex_status_cb = NULL;
+static int now_cid = 0;
+
+void ql_wan_net_state_change_cb(const void* data, int data_len)
+{
+    uint8 *net_data = NULL;
+    net_data = (uint8 *)data;
+
+    if(*net_data > 100 && *net_data < 200)
+    {
+        int cid;
+        cid = *net_data;
+        cid = cid - 100;
+        ql_apn_info[cid].active = FALSE;//close
+        if(ql_net_ex_status_cb != NULL)
+        {
+            ql_net_ex_status_cb(cid, ql_apn_info[cid].ip_type, CONNECT_DISCON, 0);
+        }
+    }
+    else if(*net_data > 200)
+    {
+        int cid;
+        cid = *net_data;
+        cid = cid - 200;
+        ql_apn_info[cid].active = TRUE;//open
+    }
+    else
+    {
+        if(ql_net_status_cb != NULL)
+        {
+            ql_net_status_cb(*net_data);
+
+            if(*net_data == 25 || *net_data == 26 || *net_data == 27)
+            {
+                ql_net_status_cb(CONNECT_CONSUCCESS);
+            }
+        }
+
+        if(ql_net_ex_status_cb != NULL)
+        {
+            if(*net_data == 1)
+            {
+                ql_net_ex_status_cb(now_cid, ql_apn_info[now_cid].ip_type, CONNECT_CONSUCCESS, 0);
+            }
+        }
+    }
+
+}
+
+int ql_wan_init(void)
+{
+    if(!inited && ql_info_handle == NULL)
+    {
+        ql_info_handle = mbtk_info_handle_get();
+        if(ql_info_handle)
+        {
+            ql_info_handle_num++;
+            inited = TRUE;
+            mbtk_pdp_state_change_cb_reg(ql_info_handle, ql_wan_net_state_change_cb);
+
+            //return 0;
+        } else {
+            LOGE("mbtk_info_handle_get() fail.");
+            return -1;
+        }
+    } else {
+        if(!inited) {
+            ql_info_handle_num++;
+            inited = TRUE;
+            mbtk_pdp_state_change_cb_reg(ql_info_handle, ql_wan_net_state_change_cb);
+        }
+        //return 0;
+    }
+
+    mbtk_apn_info_t apns[10] = {0};
+    int apn_num = MBTK_APN_CID_MAX;
+    int ret = mbtk_apn_get(ql_info_handle, &apn_num, apns);
+    if(ret != 0)
+    {
+        LOGD("mbtk_apn_get ret = %d",ret);
+    }
+    else
+    {
+        int i;
+        int profile_idx;
+        for(i=0;i<MBTK_APN_CID_MAX;i++)
+        {
+            if(apns[i].cid > 0 && apns[i].cid <= MBTK_APN_CID_MAX)
+            {
+                profile_idx = apns[i].cid;
+                if(apns[i].ip_type == MBTK_IP_TYPE_IPV4V6) // IPV4V6
+                    ql_apn_info[profile_idx].ip_type = 0;
+                else if(apns[i].ip_type == MBTK_IP_TYPE_IP) // IPV4
+                    ql_apn_info[profile_idx].ip_type = 1;
+                else if(apns[i].ip_type == MBTK_IP_TYPE_IPV6) // IPV6
+                    ql_apn_info[profile_idx].ip_type = 2;
+                else
+                    ql_apn_info[profile_idx].ip_type = 0;
+            }
+        }
+    }
+    return 0;
+}
+
+int ql_wan_release(void)
+{
+    if(ql_info_handle)
+    {
+        LOGD("ql_info_handle_num = %d", ql_info_handle_num);
+        if(ql_info_handle_num == 1) { // 最后一个引用,可释放。
+            int ret = mbtk_info_handle_free(&ql_info_handle);
+            if(ret) {
+                LOGE("mbtk_info_handle_free() fail.");
+                return -1;
+            }
+            else
+            {
+                ql_info_handle_num = 0;
+                ql_info_handle = NULL;
+                return 0;
+            }
+        } else {
+            ql_info_handle_num--;
+            return 0;
+        }
+    }
+    else
+    {
+        LOGE("DATA handle not inited.");
+        return -1;
+    }
+}
+/*
+*Set data call over time.
+*/
+int ql_wan_set_autoconnect(int auto_status, int interval_sec)
+{
+    if(auto_status == 0)                    //不开启失败重连
+        mbtk_interval_sec = 0;
+    else                                    //开启失败重连等待时间
+    {
+        if(interval_sec <= 0)
+            mbtk_interval_sec = interval_sec;
+        else
+            mbtk_interval_sec = 5; // 默认为5s
+    }
+    return 0;
+}
+
+#ifdef MBTK_AF_SUPPORT
+int mbtk_route_config(int profile_idx)
+{
+    char buf[1024] = {0};
+    char dns[128] = {0};
+    int offset = 0;
+    int fd = -1;
+    mbtk_ipv4_info_t ipv4;
+    mbtk_ipv6_info_t ipv6;
+    sprintf(buf, "route add default dev ccinet%d", profile_idx -1);
+    system(buf);
+
+    int ret = mbtk_data_call_state_get(ql_info_handle, profile_idx, &ipv4, &ipv6);
+    if(ret != 0)
+        return -1;
+    else
+    {
+        memset(buf, 0x0, 1024);
+        memset(dns, 0x0, 128);
+        offset = sprintf(buf, "search lan\n");
+        if(ipv4.valid)
+        {
+            if(inet_ntop(AF_INET, &(ipv4.PrimaryDNS), dns, 32) == NULL) {
+                LOGD("PrimaryDNS error.");
+            } else {
+                LOGD("PrimaryDNS : %s", dns);
+            }
+            offset += sprintf(buf + offset, "nameserver %s\n", dns);
+            memset(dns, 0x0, 128);
+            if(inet_ntop(AF_INET, &(ipv4.SecondaryDNS), dns, 32) == NULL) {
+                LOGD("SecondaryDNS error.");
+            } else {
+                LOGD("SecondaryDNS : %s", dns);
+            }
+            offset += sprintf(buf + offset, "nameserver %s\n", dns);
+        }
+        if(ipv6.valid)
+        {
+            memset(dns, 0x0, 128);
+			if(ipv6_2_str(&(ipv6.PrimaryDNS), dns))
+            {
+				LOGD("PrimaryDNS error.");
+			} else {
+				LOGD("PrimaryDNS : %s", dns);
+			}
+            offset += sprintf(buf + offset, "nameserver %s\n", dns);
+            memset(dns, 0x0, 128);
+			if(ipv6_2_str(&(ipv6.SecondaryDNS), dns))
+            {
+				LOGD("SecondaryDNS error.");
+			} else {
+				LOGD("SecondaryDNS : %s", dns);
+			}
+            offset += sprintf(buf + offset, "nameserver %s\n", dns);
+        }
+
+        if(offset > 0)
+        {
+            fd = open("/tmp/resolv.conf", O_WRONLY | O_TRUNC);
+            if(fd < 0)
+            {
+                LOGD("mbtk_route_config : open fail.");
+                return -1;
+            }
+
+            ret = write(fd, buf, offset);
+            if(ret < 0)
+            {
+                LOGD("mbtk_route_config : write fail.");
+            }
+
+            close(fd);
+        }
+    }
+
+    return 0;
+}
+#endif
+
+int ql_wan_start_ex(int profile_idx, int op, ex_conn_status_cb nw_cb)
+{
+    int ret = -1;
+    int count = 0;
+    if(ql_info_handle == NULL)
+    {
+        return -1;
+    }
+
+    ql_net_ex_status_cb = nw_cb;
+    ql_net_status_cb = NULL;
+    now_cid = profile_idx;
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        LOGD("ql_wan_start_ex() cid out of range.");
+#if 0
+        if(ql_net_ex_status_cb)
+            ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type ,PDP_CID_EXIST_FAIL, 0);
+#endif
+        return -1;
+    }
+
+    //ql_netw_status_cb(ql_apn_info[profile_idx].cid);
+    if(op == 0)
+    {
+        ret = ql_wan_stop(profile_idx);
+        goto exit;
+    }
+
+#if 0
+    if(ql_apn_info[profile_idx].active)
+    {
+        if(ql_net_ex_status_cb)
+            ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type, PDP_CID_EXIST_FAIL, 0);
+        return -1;
+    }
+#endif
+
+    if(ql_net_ex_status_cb) {
+        ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type, CONNECT_DIAL_IMMEDIATELY, 0);
+        ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type, CONNECT_CONNING, 0);
+    }
+    
+data_call_continue:
+    ret = mbtk_data_call_start(ql_info_handle, profile_idx, 0, op == 3 ? TRUE : FALSE, 0);
+    if(ret != 0)
+    {
+        if(mbtk_interval_sec <= 0)
+        {
+            if(ql_net_ex_status_cb)
+                ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type, CONNECT_DISCON, 0);
+            return ret;
+        }
+        else
+        {
+            if(count >= 5)
+                goto exit;
+            sleep(mbtk_interval_sec);
+            count++;
+            if(ql_net_ex_status_cb)
+                ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type, CONNECT_REDIAL, 0);
+            goto data_call_continue;
+        }
+        LOGD("mbtk_data_call_start() fail.");
+    }
+    else
+    {
+        //ql_apn_info[8].cid=profile_idx;
+        //ql_netw_status_cb(CONNECT_CONSUCCESS);
+#ifdef MBTK_AF_SUPPORT
+        if(profile_idx == 1)
+        {
+            mbtk_route_config(profile_idx);
+            
+        }
+#endif
+        LOGD("mbtk_data_call_start() success.");
+    }
+exit:
+    return ret;
+}
+
+
+/*
+* Start data call.
+*/
+int ql_wan_start(int profile_idx, int op, nw_status_cb nw_cb)
+{
+    int ret = -1;
+    int count = 0;
+    if(ql_info_handle == NULL)
+    {
+        return -1;
+    }
+
+    ql_net_status_cb = nw_cb;
+    ql_net_ex_status_cb = NULL;
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        ql_net_status_cb(PDP_ERROR_UNSPECIFIED);
+        return -1;
+    }
+
+    //ql_netw_status_cb(ql_apn_info[profile_idx].cid);
+    if(op == 0)
+    {
+        ret = ql_wan_stop(profile_idx);
+        goto exit;
+    }
+
+    if(ql_apn_info[profile_idx].active)
+    {
+        ql_net_status_cb(PDP_CID_EXIST_FAIL);
+        return -1;
+    }
+
+    ql_net_status_cb(CONNECT_DIAL_IMMEDIATELY);
+    ql_net_status_cb(CONNECT_CONNING);
+data_call_continue:
+    ret = mbtk_data_call_start(ql_info_handle, profile_idx, 0, op == 3 ? TRUE : FALSE, 0);
+    if(ret != 0)
+    {
+        if(mbtk_interval_sec <= 0)
+        {
+            ql_net_status_cb(CONNECT_DISCON);
+            return ret;
+        }
+        else
+        {
+            if(count >= 5)
+                goto exit;
+            sleep(mbtk_interval_sec);
+            count++;
+            ql_net_status_cb(CONNECT_REDIAL);
+            goto data_call_continue;
+        }
+    }
+    else
+    {
+        //ql_apn_info[8].cid=profile_idx;
+        //ql_netw_status_cb(CONNECT_CONSUCCESS);
+        LOGD("mbtk_data_call_start() success.");
+    }
+exit:
+    return ret;
+}
+
+/*
+* Stop data call.
+*/
+int ql_wan_stop(int profile_idx)
+{
+    int err;
+    if(ql_info_handle == NULL)
+    {
+        return -1;
+    }
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        LOGE("CID error.");
+        return -1;
+    }
+
+#if 0 //mbtk wyq for data_call add "if 0"
+    if(!ql_apn_info[profile_idx].active)
+    {
+        if(ql_net_ex_status_cb)
+            ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type ,PDP_CID_EXIST_FAIL, 0);
+        if(ql_net_status_cb)
+            ql_net_status_cb(PDP_CID_EXIST_FAIL);
+        return -1;
+    }
+#endif
+    err = mbtk_data_call_stop(ql_info_handle, profile_idx, 15);
+
+    return err;
+}
+
+/*
+* Query data call state.
+*/
+int ql_get_data_call_info(int profile_idx, ql_data_call_info *info)
+{
+    if(ql_info_handle == NULL || info == NULL)
+    {
+        return -1;
+    }
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        LOGE("CID error.");
+        return -1;
+    }
+    mbtk_ipv4_info_t ipv4;
+    mbtk_ipv6_info_t ipv6;
+    memset(info, 0, sizeof(ql_data_call_info));
+    int ret = mbtk_data_call_state_get(ql_info_handle, profile_idx, &ipv4, &ipv6);
+    if(ret != 0)
+        return -1;
+    else
+    {
+        info->profile_idx = profile_idx;
+        if(ipv4.valid)
+        {
+            info->ip_type = 1; // IPV4
+            info->v4.state = 1;
+            sprintf(info->v4.addr.name, "ccinet%d", profile_idx - 1);
+            if(inet_ntop(AF_INET, &(ipv4.IPAddr), info->v4.addr.ip, 32) == NULL) {
+                LOGD("IP error.");
+            } else {
+                LOGD("IP : %s", info->v4.addr.ip);
+            }
+            if(inet_ntop(AF_INET, &(ipv4.PrimaryDNS), info->v4.addr.pri_dns, 32) == NULL) {
+                LOGD("PrimaryDNS error.");
+            } else {
+                LOGD("PrimaryDNS : %s", info->v4.addr.pri_dns);
+            }
+            if(inet_ntop(AF_INET, &(ipv4.SecondaryDNS), info->v4.addr.sec_dns, 32) == NULL) {
+                LOGD("SecondaryDNS error.");
+            } else {
+                LOGD("SecondaryDNS : %s", info->v4.addr.sec_dns);
+            }
+        }
+        if(ipv6.valid)
+        {
+            info->ip_type = 2; // IPV6
+            info->v6.state = 1;
+            sprintf(info->v6.addr.name, "ccinet%d", profile_idx - 1);
+			if(ipv6_2_str(&(ipv6.IPV6Addr), info->v6.addr.ip))
+            {
+				LOGD("IP error.");
+			} else {
+				LOGD("IP : %s", info->v6.addr.ip);
+			}
+			if(ipv6_2_str(&(ipv6.PrimaryDNS), info->v6.addr.pri_dns))
+            {
+				LOGD("PrimaryDNS error.");
+			} else {
+				LOGD("PrimaryDNS : %s", info->v6.addr.pri_dns);
+			}
+			if(ipv6_2_str(&(ipv6.SecondaryDNS), info->v6.addr.sec_dns))
+            {
+				LOGD("SecondaryDNS error.");
+			} else {
+				LOGD("SecondaryDNS : %s", info->v6.addr.sec_dns);
+			}
+        }
+        if(ipv4.valid && ipv6.valid)
+            info->ip_type = 0; // IPV4V6
+        if(!ipv4.valid && !ipv6.valid)
+        {
+            info->v4.state = 0;
+            info->v6.state = 0;
+        }
+        return 0;
+    }
+
+}
+
+/*
+* Set specific APN informations.
+*
+* cid : 2-7
+*/
+int ql_wan_setapn(int profile_idx, int ip_type, const char *apn, const char *userName,
+                            const char *password, QL_DSI_AUTH_PREF_T auth)
+{
+    if(ql_info_handle == NULL)
+    {
+        return -1;
+    }
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        LOGE("CID error.");
+        return -1;
+    }
+    /*
+     QL_DSI_AUTH_PREF_NULL = 0,         //无认证
+     QL_DSI_AUTH_PREF_ONLY_PAP,         //PAP 认证
+     QL_DSI_AUTH_PREF_ONLY_CHAP,        //CHAP 认证
+     QL_DSI_AUTH_PREF_BOTH_PAP_CHAP     //PAP 和 CHAP 认证
+    */
+    char mbtk_auth[64]={0};
+    if(auth == QL_DSI_AUTH_PREF_NULL)
+        memcpy(mbtk_auth,"NONE",strlen("NONE")+1);
+    else if(auth == QL_DSI_AUTH_PREF_ONLY_PAP)
+        memcpy(mbtk_auth,"PAP",strlen("PAP")+1);
+    else if(auth == QL_DSI_AUTH_PREF_ONLY_CHAP)
+        memcpy(mbtk_auth,"CHAP",strlen("CHAP")+1);
+    else
+    {
+        LOGD("auth input error!");
+        return -1;
+    }
+
+    memset(&(ql_apn_info[profile_idx]), 0, sizeof(apn_info));
+    ql_apn_info[profile_idx].cid = profile_idx;
+    ql_apn_info[profile_idx].ip_type = ip_type;
+    if(!str_empty(userName) && !str_empty(password)) {
+        memcpy(ql_apn_info[profile_idx].user, userName, strlen(userName));
+        memcpy(ql_apn_info[profile_idx].pass, password, strlen(password));
+        ql_apn_info[profile_idx].auth = auth;
+        LOGD("ql_wan_setapn: %d, %d, %s, %s, %s, %s",profile_idx, ip_type, apn, userName, password, mbtk_auth);
+    } else {
+        LOGD("ql_wan_setapn: %d, %d, %s, NULL, NULL, %s",profile_idx, ip_type, apn, mbtk_auth);
+    }
+
+     /*
+    if(ip_type < 0 || ip_type > 3)
+        ql_netw_status_cb(PDP_UNKNOWN_PDP_ADDRESS_TYPE);
+    */
+    if(ip_type == 0) // IPV4V6
+        ip_type = MBTK_IP_TYPE_IPV4V6;
+    else if(ip_type == 1) // IPV4
+        ip_type = MBTK_IP_TYPE_IP;
+    else if(ip_type == 2) // IPV6
+        ip_type = MBTK_IP_TYPE_IPV6;
+
+    return mbtk_apn_set(ql_info_handle, profile_idx, ip_type, apn, userName, password, mbtk_auth);
+}
+
+/*
+* Get current all APN informations.
+*/
+int __ql_wan_getapn(int profile_idx, int *ip_type, char *apn, int apnLen, char *userName, int userLen, char *password, int pwdLen,int* auth)
+{
+    if(ql_info_handle == NULL || apn == NULL)
+    {
+        return -1;
+    }
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        LOGE("CID error.");
+        return -1;
+    }
+    mbtk_apn_info_t apns[10];
+    int apn_num = MBTK_APN_CID_MAX;
+    int ret = mbtk_apn_get(ql_info_handle, &apn_num, apns);
+    if(ret != 0)
+    {
+        LOGD("mbtk_apn_get ret = %d",ret);
+        return -1;
+    }
+    else
+    {
+        int i;
+        for(i=0;i<MBTK_APN_CID_MAX;i++)
+        {
+            if(apns[i].cid == profile_idx)
+                break;
+        }
+        if(i == MBTK_APN_CID_MAX)
+            return -1;
+        LOGD("cid = %d",i);
+        if(apns[i].ip_type == MBTK_IP_TYPE_IPV4V6) // IPV4V6
+            *ip_type = 0;
+        else if(apns[i].ip_type == MBTK_IP_TYPE_IP) // IPV4
+            *ip_type = 1;
+        else if(apns[i].ip_type == MBTK_IP_TYPE_IPV6) // IPV6
+            *ip_type = 2;
+        else
+            *ip_type = 0;
+
+        if(strlen(apns[i].apn)+1 > apnLen)
+            return -1;
+        else
+            memcpy(apn, apns[i].apn,strlen(apns[i].apn)+1);
+
+        if(strlen(apns[i].user)+1 > userLen)
+            return -1;
+        else
+        {
+            if(strlen(apns[i].user) > 0)
+                memcpy(userName, apns[i].user, strlen(apns[i].user)+1);
+            else
+                memcpy(userName, ql_apn_info[profile_idx].user, strlen(ql_apn_info[profile_idx].user)+1);
+        }
+
+        if(strlen(apns[i].pass)+1 > pwdLen)
+            return -1;
+        else
+        {
+            if(strlen(apns[i].pass) > 0)
+                memcpy(password, apns[i].pass, strlen(apns[i].pass)+1);
+            else
+                memcpy(password, ql_apn_info[profile_idx].pass, strlen(ql_apn_info[profile_idx].pass)+1);
+        }
+
+        if(strlen(apns[i].auth) > 0) {
+            if(strcmp(apns[i].auth, "NONE") == 0)
+                *auth = QL_DSI_AUTH_PREF_NULL;
+            else if(strcmp(apns[i].auth, "PAP") == 0)
+                *auth = QL_DSI_AUTH_PREF_ONLY_PAP;
+            else if(strcmp(apns[i].auth, "CHAP") == 0)
+                *auth = QL_DSI_AUTH_PREF_ONLY_CHAP;
+            else
+            {
+                LOGD("auth error!");
+                return -1;
+            }
+        } else {
+            *auth = ql_apn_info[profile_idx].auth;
+        }
+
+        return 0;
+    }
+}
+
+
diff --git a/mbtk/libql_lib_v2/src/ql_dev_api.c b/mbtk/libql_lib_v2/src/ql_dev_api.c
new file mode 100755
index 0000000..d473ab8
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_dev_api.c
@@ -0,0 +1,179 @@
+//**********************
+#include "ql/ql_dev.h"
+#include "mbtk_type.h"
+#include "mbtk_info_api.h"
+
+//**********************
+
+mbtk_info_handle_t* ql_info_handle = NULL;
+int ql_info_handle_num = 0;
+static bool inited = FALSE;
+
+//**********************
+QL_DEV_ERROR_CODE ql_dev_init()
+{
+    if(!inited && ql_info_handle == NULL)
+    {
+        ql_info_handle = mbtk_info_handle_get();
+        if(ql_info_handle)
+        {
+            ql_info_handle_num++;
+            inited = TRUE;
+            return QL_DEV_SUCCESS;
+        } else {
+            LOGE("mbtk_info_handle_get() fail.");
+            return QL_DEV_GENERIC_FAILURE;
+        }
+    } else {
+        if(!inited) {
+            ql_info_handle_num++;
+            inited = TRUE;
+        }
+        return QL_DEV_SUCCESS;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_release()
+{
+    if(ql_info_handle)
+    {
+        LOGD("ql_info_handle_num = %d", ql_info_handle_num);
+        if(ql_info_handle_num == 1) { // 最后一个引用,可释放。
+            int ret = mbtk_info_handle_free(&ql_info_handle);
+            if(ret) {
+                LOGE("mbtk_info_handle_free() fail.");
+                return QL_DEV_GENERIC_FAILURE;
+            }
+            else
+            {
+                ql_info_handle_num = 0;
+                ql_info_handle = NULL;
+                return QL_DEV_SUCCESS;
+            }
+        } else {
+            ql_info_handle_num--;
+            return QL_DEV_SUCCESS;
+        }
+    }
+    else
+    {
+        LOGE("DEV handle not inited.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_get_imei(char* imei)
+{
+    if(ql_info_handle == NULL || imei == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+
+    if(mbtk_imei_get(ql_info_handle, imei)) {
+        return QL_DEV_GENERIC_FAILURE;
+    } else {
+        return QL_DEV_SUCCESS;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_get_firmware_version(char* version)
+{
+    if(ql_info_handle == NULL || version == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+
+    if(mbtk_version_get(ql_info_handle, version)) {
+        return QL_DEV_GENERIC_FAILURE;
+    } else {
+        return QL_DEV_SUCCESS;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_get_model(char* model)
+{
+    if(ql_info_handle == NULL || model == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+
+    if(mbtk_model_get(ql_info_handle, model)) {
+        return QL_DEV_GENERIC_FAILURE;
+    } else {
+        return QL_DEV_SUCCESS;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_get_sn(char* sn)
+{
+    if(ql_info_handle == NULL || sn == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+
+    if(mbtk_sn_get(ql_info_handle, sn)) {
+        return QL_DEV_GENERIC_FAILURE;
+    } else {
+        return QL_DEV_SUCCESS;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_set_modem_fun(QL_DEV_MODEM_FUNCTION function, int rst)
+{
+    if(ql_info_handle == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+    mbtk_modem_info_t modem;
+    modem.rst = rst;
+    switch (function)
+    {
+        case QL_DEV_MODEM_MIN_FUN:
+            modem.fun = MBTK_DEV_MODEM_MIN_FUN;
+            break;
+        case QL_DEV_MODEM_FULL_FUN:
+            modem.fun = MBTK_DEV_MODEM_FULL_FUN;
+            break;
+        case QL_DEV_MODEM_DISABLE_RECEIVE_RF_CIRCUITS:
+            modem.fun = MBTK_DEV_MODEM_DISABLE_RECEIVE_RF_CIRCUITS;
+            break;
+        case QL_DEV_MODEM_DISABLE_TRANSMIT_AND_RECEIVE_RF_CIRCUITS:
+            modem.fun = MBTK_DEV_MODEM_DISABLE_TRANSMIT_AND_RECEIVE_RF_CIRCUITS;
+            break;
+        case QL_DEV_MODEM_DISABLE_SIM:
+            modem.fun = MBTK_DEV_MODEM_DISABLE_SIM;
+            break;
+        case QL_DEV_MODEM_TURN_OFF_FULL_SECONDARY_RECEIVE:
+            modem.fun = MBTK_DEV_MODEM_TURN_OFF_FULL_SECONDARY_RECEIVE;
+            break;
+        default:
+            break;
+    }
+    if(mbtk_set_modem_fun(ql_info_handle, &modem)) {
+        return QL_DEV_GENERIC_FAILURE;
+    } else {
+        return QL_DEV_SUCCESS;
+    }
+}
+
+QL_DEV_ERROR_CODE ql_dev_get_modem_fun(int *function)
+{
+    if(ql_info_handle == NULL || function == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_DEV_GENERIC_FAILURE;
+    }
+
+    if(mbtk_get_modem_fun(ql_info_handle, function)) {
+        return QL_DEV_GENERIC_FAILURE;
+    } else {
+        return QL_DEV_SUCCESS;
+    }
+}
+
+//**********************
diff --git a/mbtk/libql_lib_v2/src/ql_fota.c b/mbtk/libql_lib_v2/src/ql_fota.c
new file mode 100755
index 0000000..eb0afc7
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_fota.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mbtk_fota.h"
+
+
+int ql_fota_init(fota_callback cb)
+{
+    return mbtk_fota_init(cb);
+}
+
+/*******************************************************************************
+* @brief write firmware package, the firmware package is written in segments.
+         and The result of the write is output by calling the callback function.
+         the firmware package size must less than 32MB
+  @param
+           fname: firmware package file
+    segment_size: the length of once write, recommending 3*1024*1024 bytes
+  @return
+        if success return 0, else return -1
+ *******************************************************************************/
+int ql_fota_fw_write(char* fname, int segment_size)
+{
+    return mbtk_fota_fw_write(fname, segment_size);
+}
+
+
+/*******************************************************************************
+* @brief download firmware by url, and write firmware package, the firmware
+         package is written in segments. The result of the write is output by
+         calling the callback function. the firmware package size must less than
+         32MB
+  @param
+                 url: [IN] the address of download firmware package file, the url
+                           support http or https protocol.
+        segment_size: [IN] the length of once write, recommending 3*1024*1024 bytes
+        conn_timeout: [IN] timeout to connect to the server, if set 0 that means
+                           switch to the default build-in connection timeout(300s)
+    download_timeout: [IN] timeout for download the firmware file. if set 0 that means
+                           it never time out
+  @return
+        if success return 0, else return -1
+ *******************************************************************************/
+int ql_fota_fw_write_by_url(char* url, int segment_size,
+                            int conn_timeout, int download_timeout)
+{
+    return mbtk_fota_fw_write_by_url(url, segment_size,conn_timeout, download_timeout);
+}
+/*******************************************************************************
+* @brief reboot system and clear env
+  @param
+   is_reboot: if set 1, after fota success, reboot system
+  @return
+        if success return 0, else return -1
+ *******************************************************************************/
+int ql_fota_done(int is_reboot)
+{
+    return mbtk_fota_done1(is_reboot);
+}
diff --git a/mbtk/libql_lib_v2/src/ql_gpio.c b/mbtk/libql_lib_v2/src/ql_gpio.c
new file mode 100755
index 0000000..9be2026
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_gpio.c
@@ -0,0 +1,741 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+#include "ql/ql_gpio.h"
+
+typedef struct {
+    int pin;
+    int gpio;
+} pin_gpio_mmap_s;
+
+#ifdef MBTK_PROJECT_L508
+static pin_gpio_mmap_s pin_gpio_mmap[] = {
+    {PINNAME_GPIO1, -1},            /*PIN-1*/
+    {PINNAME_GPIO2, -1},             /*PIN-2*/
+    {PINNAME_GPIO3, -1},             /*PIN-3*/
+    {PINNAME_GPIO4, -1},             /*PIN-4*/
+    {PINNAME_GPIO5, -1},             /*PIN-5*/
+    {PINNAME_NET_STATUS, -1},        /*PIN-6*/
+    {PINNAME_DBG_RXD, -1},          /*PIN-11*/
+    {PINNAME_DBG_TXD, -1},          /*PIN-12*/
+    {PINNAME_USIM_PRESENCE, 19},    /*PIN-13*/
+    {PINNAME_SD_INT_DET, -1},       /*PIN-23*/
+    {PINNAME_PCM_IN, 28},           /*PIN-24*/
+    {PINNAME_PCM_OUT, 27},          /*PIN-25*/
+    {PINNAME_PCM_SYNC, -1},         /*PIN-26*/
+    {PINNAME_PCM_CLK, -1},          /*PIN-27*/
+    {PINNAME_SDC2_DATA3, 21},       /*PIN-28*/
+    {PINNAME_SDC2_DATA2, -1},       /*PIN-29*/
+    {PINNAME_SDC2_DATA1, 4},       /*PIN-30*/
+    {PINNAME_SDC2_DATA0, -1},       /*PIN-31*/
+    {PINNAME_SDC2_CLK, -1},         /*PIN-32*/
+    {PINNAME_SDC2_CMD, -1},         /*PIN-33*/
+    {PINNAME_SPI_CS_N, -1},         /*PIN-37*/
+    {PINNAME_SPI_MOSI, -1},         /*PIN-38*/
+    {PINNAME_SPI_MISO, -1},         /*PIN-39*/
+    {PINNAME_SPI_CLK, -1},          /*PIN-40*/
+    {PINNAME_I2C_SCL, -1},          /*PIN-41*/
+    {PINNAME_I2C_SDA, -1},          /*PIN-42*/
+    {PINNAME_GPIO20, 20},           /*PIN-45*/
+    {PINNAME_STATUS, 13},           /*PIN-49*/
+    {PINNAME_NETLIGHT, 14},         /*PIN-51*/
+    {PINNAME_GPIO6, -1},            /*PIN-62*/
+    {PINNAME_DCD, -1},              /*PIN-63*/
+    {PINNAME_DTR, -1},              /*PIN-66*/
+    {PINNAME_MAIN_CTS, -1},         /*PIN-64*/
+    {PINNAME_MAIN_RTS, -1},         /*PIN-65*/
+    {PINNAME_MAIN_TXD, -1},         /*PIN-67*/
+    {PINNAME_MAIN_RXD, -1},         /*PIN-68*/
+    {PINNAME_RMII_RXD1, -1},        /*PIN-73*/
+    {PINNAME_RMII_RXCL, -1},        /*PIN-74*/
+    {PINNAME_RMII_CLK, 3},         /*PIN-75*/
+    {PINNAME_RMII_RXD0, 1},        /*PIN-76*/
+    {PINNAME_RMII_TXD0, -1},        /*PIN-77*/
+    {PINNAME_RMII_TXD1, -1},        /*PIN-78*/
+    {PINNAME_RMII_RXD2, -1},        /*PIN-79*/
+    {PINNAME_RMII_TXD2, -1},        /*PIN-80*/
+    {PINNAME_RMII_TX_CTRL, -1},     /*PIN-81*/
+    {PINNAME_RMII_RXD3, -1},        /*PIN-82*/
+    {PINNAME_RMII_TXCL, -1},        /*PIN-83*/
+    {PINNAME_RMII_TXD3, 5},        /*PIN-84*/
+    {PINNAME_WLAN_SLP_CLK, -1},    /*PIN-118*/
+    {PINNAME_RMII_RST, 20},        /*PIN-119*/
+    {PINNAME_RMII_INT, -1},        /*PIN-120*/
+    {PINNAME_RMII_MDIO, 17},       /*PIN-121*/
+    {PINNAME_RMII_MDC, 16},        /*PIN-122*/
+    {PINNAME_PRI_TDI, 117},        /*PIN-123*/
+    {PINNAME_WLAN_PER_EN, 24},     /*PIN-127*/
+    {PINNAME_WLAN_WAKE, 21},       /*PIN-135*/
+    {PINNAME_WLAN_EN, 22},         /*PIN-136*/
+    {PINNAME_GPIO8, -1},            /*PIN-139*/
+};
+#else
+static pin_gpio_mmap_s pin_gpio_mmap[] = {
+    {PINNAME_GPIO1, -1},            /*PIN-1*/
+    {PINNAME_GPIO2, -1},             /*PIN-2*/
+    {PINNAME_GPIO3, -1},             /*PIN-3*/
+    {PINNAME_GPIO4, -1},             /*PIN-4*/
+    {PINNAME_GPIO5, -1},             /*PIN-5*/
+    {PINNAME_NET_STATUS, -1},        /*PIN-6*/
+    {PINNAME_DBG_RXD, -1},          /*PIN-11*/
+    {PINNAME_DBG_TXD, -1},          /*PIN-12*/
+    {PINNAME_USIM_PRESENCE, 19},    /*PIN-13*/
+    {PINNAME_SD_INT_DET, -1},       /*PIN-23*/
+    {PINNAME_PCM_IN, 28},           /*PIN-24*/
+    {PINNAME_PCM_OUT, 27},          /*PIN-25*/
+    {PINNAME_PCM_SYNC, -1},         /*PIN-26*/
+    {PINNAME_PCM_CLK, -1},          /*PIN-27*/
+    {PINNAME_SDC2_DATA3, 21},       /*PIN-28*/
+    {PINNAME_SDC2_DATA2, -1},       /*PIN-29*/
+    {PINNAME_SDC2_DATA1, 4},       /*PIN-30*/
+    {PINNAME_SDC2_DATA0, -1},       /*PIN-31*/
+    {PINNAME_SDC2_CLK, -1},         /*PIN-32*/
+    {PINNAME_SDC2_CMD, -1},         /*PIN-33*/
+    {PINNAME_SPI_CS_N, -1},         /*PIN-37*/
+    {PINNAME_SPI_MOSI, -1},         /*PIN-38*/
+    {PINNAME_SPI_MISO, -1},         /*PIN-39*/
+    {PINNAME_SPI_CLK, -1},          /*PIN-40*/
+    {PINNAME_I2C_SCL, -1},          /*PIN-41*/
+    {PINNAME_I2C_SDA, -1},          /*PIN-42*/
+    {PINNAME_GPIO20, 20},           /*PIN-45*/
+    {PINNAME_STATUS, 13},           /*PIN-49*/
+    {PINNAME_NETLIGHT, 14},         /*PIN-51*/
+    {PINNAME_GPIO6, -1},            /*PIN-62*/
+    {PINNAME_DCD, -1},              /*PIN-63*/
+    {PINNAME_DTR, -1},              /*PIN-66*/
+    {PINNAME_MAIN_CTS, -1},         /*PIN-64*/
+    {PINNAME_MAIN_RTS, -1},         /*PIN-65*/
+    {PINNAME_MAIN_TXD, -1},         /*PIN-67*/
+    {PINNAME_MAIN_RXD, -1},         /*PIN-68*/
+    {PINNAME_RMII_RXD1, -1},        /*PIN-73*/
+    {PINNAME_RMII_RXCL, -1},        /*PIN-74*/
+    {PINNAME_RMII_CLK, 3},         /*PIN-75*/
+    {PINNAME_RMII_RXD0, 1},        /*PIN-76*/
+    {PINNAME_RMII_TXD0, -1},        /*PIN-77*/
+    {PINNAME_RMII_TXD1, -1},        /*PIN-78*/
+    {PINNAME_RMII_RXD2, -1},        /*PIN-79*/
+    {PINNAME_RMII_TXD2, -1},        /*PIN-80*/
+    {PINNAME_RMII_TX_CTRL, -1},     /*PIN-81*/
+    {PINNAME_RMII_RXD3, -1},        /*PIN-82*/
+    {PINNAME_RMII_TXCL, -1},        /*PIN-83*/
+    {PINNAME_RMII_TXD3, 5},        /*PIN-84*/
+    {PINNAME_WLAN_SLP_CLK, -1},    /*PIN-118*/
+    {PINNAME_RMII_RST, 20},        /*PIN-119*/
+    {PINNAME_RMII_INT, -1},        /*PIN-120*/
+    {PINNAME_RMII_MDIO, 17},       /*PIN-121*/
+    {PINNAME_RMII_MDC, 16},        /*PIN-122*/
+    {PINNAME_PRI_TDI, 117},        /*PIN-123*/
+    {PINNAME_WLAN_PER_EN, 24},     /*PIN-127*/
+    {PINNAME_WLAN_WAKE, 21},       /*PIN-135*/
+    {PINNAME_WLAN_EN, 22},         /*PIN-136*/
+    {PINNAME_GPIO8, -1},            /*PIN-139*/
+};
+
+#endif
+
+static int gpio_export(int gpio)
+{
+    int index=0;
+    int file=-1;
+    int result =-1;
+    char pin_index_buffer[5]= {0};
+
+    char buffer[50];
+    memset(buffer,0,50);
+    sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+    if(access(buffer , F_OK) == 0)
+    {
+        LOGD("%d has export.", gpio);
+        return 0;
+    }
+
+    file = open("/sys/class/gpio/export",O_WRONLY);
+    if(file == -1)
+    {
+        LOGE("Open gpio export file fail.");
+        return -1;
+    }
+
+    memset(pin_index_buffer,0,5);
+    sprintf(pin_index_buffer,"%d", gpio);
+    result = write(file,pin_index_buffer,strlen(pin_index_buffer));
+    if(result < 0)
+    {
+        LOGE("Gpio[%d] export fail.", gpio);
+        close(file);
+        return -1;
+    }
+    close(file);
+
+    return 0;
+}
+
+static int gpio_unexport(int gpio)
+{
+    int index=0;
+    int file=-1;
+    int result =-1;
+    char pin_index_buffer[5]= {0};
+    char buffer[50];
+    memset(buffer,0,50);
+    sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+    if(access(buffer , F_OK) == -1)
+    {
+        LOGD("%d not export.", gpio);
+        return 0;
+    }
+
+    file = open("/sys/class/gpio/unexport",O_WRONLY);
+    if(file == -1)
+    {
+        LOGE("Open gpio unexport file fail.");
+        return -1;
+    }
+
+    memset(pin_index_buffer,0,5);
+    sprintf(pin_index_buffer,"%d", gpio);
+    result=write(file,pin_index_buffer,strlen(pin_index_buffer));
+    if(result < 0)
+    {
+        close(file);
+        LOGE("Gpio[%d] unexport fail.", gpio);
+        return -1;
+    }
+    close(file);
+
+    return 0;
+}
+
+static int gpio_direct_get(int gpio, char *value, int value_size)
+{
+    char buffer[50]= {0};
+    int file =-1;
+    int result =-1;
+
+    memset(buffer,0,50);
+    sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+    file = open(buffer, O_RDONLY);
+    if(file == -1)
+    {
+        LOGE("Open gpio[%d] direct fail.", gpio);
+        return -1;
+    }
+
+    memset(value, 0x0, value_size);
+    result = read(file,value,value_size);
+    if(result <= 0)
+    {
+        LOGE("Get gpio[%d] direct fail.", gpio);
+        close(file);
+        return -1;
+    }
+    close(file);
+
+    return 0;
+}
+
+
+static int gpio_direct_set(int gpio, char *value)
+{
+    char buffer[50]= {0};
+    int file =-1;
+    int result =-1;
+
+    memset(buffer,0,50);
+    sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+    file = open(buffer, O_WRONLY);
+    if(file == -1)
+    {
+        LOGE("Open gpio[%d] direct fail.", gpio);
+        return -1;
+    }
+
+    result = write(file,value,strlen(value));
+    if(result != strlen(value))
+    {
+        LOGE("Set gpio[%d] direct fail.", gpio);
+        close(file);
+        return -1;
+    }
+    close(file);
+
+    return 0;
+}
+
+static int gpio_value_get(int gpio)
+{
+    char buffer[50];
+    char path[10];
+    int file =-1;
+    int result =-1;
+    int value;
+
+    memset(path,0,50);
+    memset(buffer,0,10);
+    sprintf(path,"/sys/class/gpio/gpio%d/value", gpio);
+    file = open(path,O_RDONLY);
+    if(file == -1)
+    {
+        LOGE("Open gpio[%d] fail.", gpio);
+        return -1;
+    }
+    result = read(file,buffer,5);
+    if(result <= 0)
+    {
+        LOGE("Get gpio[%d] value fail", gpio);
+        close(file);
+        return -1;
+    }
+    close(file);
+    value = atoi(buffer);
+    return value;
+}
+
+static int gpio_value_set(int gpio, int value)
+{
+    char buffer[50]= {0};
+    int file =-1;
+    int result =-1;
+
+    memset(buffer,0,50);
+    sprintf(buffer,"/sys/class/gpio/gpio%d/value", gpio);
+    file = open(buffer,O_WRONLY);
+    if(file == -1)
+    {
+        LOGE("Open gpio[%d] value fail.", gpio);
+        return -1;
+    }
+    if(value == 0) {
+        result = write(file,"0",1);
+    } else {
+        result = write(file,"1",1);
+    }
+    if(result != 1)
+    {
+        LOGE("Set gpio[%d] value fail.", gpio);
+        close(file);
+        return -1;
+    }
+    close(file);
+
+    return 0;
+}
+
+static int pin_2_gpio(Enum_PinName       pin_name)
+{
+#if 0
+    switch(pin_name){
+        case PINNAME_USIM_PRESENCE:    /*PIN-13*/
+            return 19;
+        case PINNAME_PCM_IN:           /*PIN-24*/
+            return 28;
+        case PINNAME_PCM_OUT:          /*PIN-25*/
+            return 27;
+        case PINNAME_RMII_CLK:         /*PIN-75*/
+            return 3;
+        case PINNAME_RMII_RXD0:        /*PIN-76*/
+            return 1;
+        case PINNAME_RMII_RST:          /*PIN-119*/
+            return 20;
+        case PINNAME_RMII_MDIO:         /*PIN-121*/
+            return 17;
+        case PINNAME_RMII_MDC:          /*PIN-122*/
+            return 16;
+        case PINNAME_WLAN_PER_EN:       /*PIN-127*/
+            return 24;
+        case PINNAME_WLAN_WAKE:         /*PIN-135*/
+            return 21;
+        case PINNAME_WLAN_EN:           /*PIN-136*/
+            return 22;
+
+        // Unknown PIN.
+        case PINNAME_GPIO1:             /*PIN-1*/
+        case PINNAME_GPIO2:             /*PIN-2*/
+        case PINNAME_GPIO3:             /*PIN-3*/
+        case PINNAME_GPIO4:             /*PIN-4*/
+        case PINNAME_GPIO5:             /*PIN-5*/
+        case PINNAME_NET_STATUS:        /*PIN-6*/
+        case PINNAME_DBG_RXD:           /*PIN-11*/
+        case PINNAME_DBG_TXD:          /*PIN-12*/
+        case PINNAME_SD_INT_DET:       /*PIN-23*/
+        case PINNAME_PCM_SYNC:         /*PIN-26*/
+        case PINNAME_PCM_CLK:          /*PIN-27*/
+        case PINNAME_SDC2_DATA3:       /*PIN-28*/
+        case PINNAME_SDC2_DATA2:       /*PIN-29*/
+        case PINNAME_SDC2_DATA1:       /*PIN-30*/
+        case PINNAME_SDC2_DATA0:       /*PIN-31*/
+        case PINNAME_SDC2_CLK:         /*PIN-32*/
+        case PINNAME_SDC2_CMD:         /*PIN-33*/
+        case PINNAME_SPI_CS_N:         /*PIN-37*/
+        case PINNAME_SPI_MOSI:         /*PIN-38*/
+        case PINNAME_SPI_MISO:         /*PIN-39*/
+        case PINNAME_SPI_CLK:          /*PIN-40*/
+        case PINNAME_I2C_SCL:          /*PIN-41*/
+        case PINNAME_I2C_SDA:          /*PIN-42*/
+        case PINNAME_GPIO6:            /*PIN-62*/
+        case PINNAME_DCD:              /*PIN-63*/
+        case PINNAME_DTR:              /*PIN-66*/
+        case PINNAME_MAIN_CTS:         /*PIN-64*/
+        case PINNAME_MAIN_RTS:         /*PIN-65*/
+        case PINNAME_MAIN_TXD:         /*PIN-67*/
+        case PINNAME_MAIN_RXD:         /*PIN-68*/
+        case PINNAME_RMII_RXD1:        /*PIN-73*/
+        case PINNAME_RMII_RXCL:        /*PIN-74*/
+        case PINNAME_RMII_TXD0:        /*PIN-77*/
+        case PINNAME_RMII_TXD1:        /*PIN-78*/
+        case PINNAME_RMII_RXD2:        /*PIN-79*/
+        case PINNAME_RMII_TXD2:        /*PIN-80*/
+        case PINNAME_RMII_TX_CTRL:     /*PIN-81*/
+        case PINNAME_RMII_RXD3:        /*PIN-82*/
+        case PINNAME_RMII_TXCL:        /*PIN-83*/
+        case PINNAME_RMII_TXD3:        /*PIN-84*/
+        case PINNAME_WLAN_SLP_CLK:      /*PIN-118*/
+        case PINNAME_RMII_INT:          /*PIN-120*/
+        case PINNAME_GPIO8:             /*PIN-139*/
+        default:
+            LOGE("Unknown PIN : %d", pin_name);
+            return -1;
+    }
+#else
+    int i = 0;
+    while(i < ARRAY_SIZE(pin_gpio_mmap)) {
+        if(pin_name == pin_gpio_mmap[i].pin) {
+            return pin_gpio_mmap[i].gpio;
+        }
+        i++;
+    }
+
+    LOGE("No found PIN : %d", pin_name);
+    return -1;
+#endif
+}
+
+
+/*****************************************************************
+* Function:     Ql_GPIO_Init
+*
+* Description:
+*               This function enables the GPIO function of the specified pin,
+*               and initialize the configurations, including direction,
+*               level and pull selection.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+*               dir:
+*                   The initial direction of GPIO, one value of Enum_PinDirection.
+*               level:
+*                   The initial level of GPIO, one value of Enum_PinLevel.
+*               pull_sel:
+*                   Pull selection, one value of Enum_PinPullSel.
+* Return:
+*               RES_OK, this function succeeds.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               RES_IO_ERR, the function failed
+*               other place. For example this GPIO has been using as EINT.
+*****************************************************************/
+int Ql_GPIO_Init(Enum_PinName       pin_name,
+                 Enum_PinDirection  dir,
+                 Enum_PinLevel      level,
+                 Enum_PinPullSel    pull_sel
+                 )
+{
+    int gpio = pin_2_gpio(pin_name);
+    if(gpio == -1) {
+        return RES_IO_ERROR;
+    }
+    LOGD("PIN-%d => GPIO-%d", pin_name, gpio);
+
+    if(gpio_export(gpio))
+    {
+        LOGE("gpio_export() fail.");
+        return RES_IO_ERROR;
+    }
+
+    if(gpio_direct_set(gpio, dir == PINDIRECTION_IN ? "in" : "out"))
+    {
+        LOGE("gpio_direct_set() fail.");
+        return RES_IO_ERROR;
+    }
+
+    if(dir == PINDIRECTION_OUT){
+        if(gpio_value_set(gpio, level))
+        {
+            LOGE("gpio_value_set() fail.");
+            return RES_IO_ERROR;
+        }
+    }
+    // No support pull mode now.
+
+    return RES_OK;
+}
+
+/*****************************************************************
+* Function:     Ql_GPIO_Base_Init
+*
+* Description:
+*               This function enables the GPIO function of the specified pin.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+*
+* Return:
+*               RES_OK, this function succeeds.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               RES_IO_ERR, the function failed
+*****************************************************************/
+int Ql_GPIO_Base_Init(Enum_PinName pin_name );
+
+/*****************************************************************
+* Function:     Ql_GPIO_SetLevel
+*
+* Description:
+*               This function sets the level of the specified GPIO.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+*               level:
+*                   The initial level of GPIO, one value of Enum_PinLevel.
+* Return:
+*               RES_OK, this function succeeds.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               RES_IO_ERR, the function failed
+*               other place. For example this GPIO has been using as EINT.
+*****************************************************************/
+int Ql_GPIO_SetLevel(Enum_PinName pin_name, Enum_PinLevel level)
+{
+    int gpio = pin_2_gpio(pin_name);
+    if(gpio == -1) {
+        return RES_IO_ERROR;
+    }
+    LOGD("PIN-%d => GPIO-%d", pin_name, gpio);
+
+    if(gpio_value_set(gpio, level)) {
+        LOGE("gpio_value_set() fail.");
+        return RES_IO_ERROR;
+    } else {
+        return RES_OK;
+    }
+}
+
+/*****************************************************************
+* Function:     Ql_GPIO_GetLevel
+*
+* Description:
+*               This function gets the level of the specified GPIO.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+* Return:
+*               The level value of the specified GPIO, which is
+*               nonnegative integer.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*****************************************************************/
+int Ql_GPIO_GetLevel(Enum_PinName pin_name)
+{
+    int gpio = pin_2_gpio(pin_name);
+    if(gpio == -1) {
+        return RES_IO_ERROR;
+    }
+    LOGD("PIN-%d => GPIO-%d", pin_name, gpio);
+
+    return gpio_value_get(gpio);
+}
+
+/*****************************************************************
+* Function:     Ql_GPIO_SetDirection
+*
+* Description:
+*               This function sets the direction of the specified GPIO.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+*               dir:
+*                   The initial direction of GPIO, one value of Enum_PinDirection.
+* Return:
+*               RES_OK, this function succeeds.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               RES_IO_ERR, the function failed
+*               other place. For example this GPIO has been using as EINT.
+*****************************************************************/
+int Ql_GPIO_SetDirection(Enum_PinName pin_name, Enum_PinDirection dir)
+{
+    int gpio = pin_2_gpio(pin_name);
+    if(gpio == -1) {
+        return RES_IO_ERROR;
+    }
+    LOGD("PIN-%d => GPIO-%d", pin_name, gpio);
+
+    if(gpio_direct_set(gpio, dir == PINDIRECTION_IN ? "in" : "out")) {
+        LOGE("gpio_direct_set() fail.");
+        return RES_IO_ERROR;
+    } else {
+        return RES_OK;
+    }
+}
+
+/*****************************************************************
+* Function:     Ql_GPIO_GetDirection
+*
+* Description:
+*               This function gets the direction of the specified GPIO.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+* Return:
+*               0  INPUT
+*               1  OUTPUT
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               other place. For example this GPIO has been using as EINT.
+*****************************************************************/
+int Ql_GPIO_GetDirection(Enum_PinName pin_name)
+{
+    char buff[10];
+    int gpio = pin_2_gpio(pin_name);
+    if(gpio == -1) {
+        return RES_IO_ERROR;
+    }
+    LOGD("PIN-%d => GPIO-%d", pin_name, gpio);
+
+    if(gpio_direct_get(gpio, buff, 10)) {
+        LOGE("gpio_direct_get() fail.");
+        return RES_IO_NOT_SUPPORT;
+    } else {
+        if(strncmp(buff, "in",2) == 0) {
+            return PINDIRECTION_IN;
+        } else if(strncmp(buff, "out",3) == 0) {
+            return PINDIRECTION_OUT;
+        } else {
+            return RES_IO_NOT_SUPPORT;
+        }
+    }
+}
+
+/*****************************************************************
+* Function:     Ql_GPIO_SetPullSelection
+*
+* Description:
+*               This function sets the pull selection of the specified GPIO.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+*               Enum_PinPullSel:
+*                   Pull selection, one value of Enum_PinPullSel.
+* Return:
+*               RES_OK, this function succeeds.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               RES_IO_ERR, the function failed
+*               other place. For example this GPIO has been using as EINT.
+*****************************************************************/
+int Ql_GPIO_SetPullSelection(Enum_PinName pin_name, Enum_PinPullSel pull_sel);
+
+/*****************************************************************
+* Function:     ql_gpio_get_pull_selection
+*
+* Description:
+*               This function gets the pull selection of the specified GPIO.
+*
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+* Return:
+*               0<<13   no pull
+*               5<<13   pull down
+*               6<<13   pull up
+*****************************************************************/
+int Ql_GPIO_GetPullSelection(Enum_PinName pin_name);
+
+
+/*****************************************************************
+* Function:     Ql_GPIO_Uninit
+*
+* Description:
+*               This function releases the specified GPIO that was
+*               initialized by calling Ql_GPIO_Init() previously.
+*               After releasing, the GPIO can be used for other purpose.
+* Parameters:
+*               pin_name:
+*                   Pin name, one value of Enum_PinName.
+* Return:
+*               RES_OK, this function succeeds.
+*               RES_IO_NOT_SUPPORT, the input GPIO is invalid.
+*               RES_IO_ERR, the function failed
+*               other place. For example this GPIO has been using as EINT.
+*****************************************************************/
+int Ql_GPIO_Uninit(Enum_PinName pin_name)
+{
+    int gpio = pin_2_gpio(pin_name);
+    if(gpio == -1) {
+        return RES_IO_ERROR;
+    }
+    LOGD("PIN-%d => GPIO-%d", pin_name, gpio);
+
+    if(gpio_unexport(gpio))
+    {
+        LOGE("gpio_unexport() fail.");
+        return RES_IO_ERROR;
+    }
+
+    return RES_OK;
+}
+
+//------------------------------------------------------------------------------
+/*
+* Function:     Ql_EINT_Enable
+*
+* Description:
+*               Set the interrupt sense mode, and enable interrupt.
+*
+* Parameters:
+*               eint_pin_name:
+*                   EINT pin name, one value of Enum_PinName that has
+*                   the interrupt function.
+*
+*               eint_type:
+*                   Interrupt type, level-triggered or edge-triggered.
+*                   Now, only edge-triggered interrupt is supported.
+*
+*               eint_callback:
+*                   call back function
+*
+* Return:
+*               RES_OK, this function succeeds.
+*               else failed to execute the function.
+*/
+//------------------------------------------------------------------------------
+int Ql_EINT_Enable(Enum_PinName eint_pin_name, Enum_EintType eint_type, Ql_EINT_Callback eint_callback);
+
+
+//------------------------------------------------------------------------------
+/*
+* Function:     Ql_EINT_Disable
+*
+* Description:
+*               Disable the interrupt sense.
+*
+* Parameters:
+*               eint_pin_name:
+*                   EINT pin name, one value of Enum_PinName that has
+*                   the interrupt function.
+*
+* Return:
+*               RES_OK, this function succeeds.
+*               else failed to execute the function.
+*/
+//------------------------------------------------------------------------------
+int Ql_EINT_Disable(Enum_PinName eint_pin_name);
+
diff --git a/mbtk/libql_lib_v2/src/ql_i2c.c b/mbtk/libql_lib_v2/src/ql_i2c.c
new file mode 100755
index 0000000..8b8c6a0
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_i2c.c
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <linux/types.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "mbtk_log.h"
+#include "ql/ql_i2c.h"
+
+int Ql_I2C_Init(char *dev_name)
+{
+    int fd = open(dev_name, O_RDWR);
+    if(fd <= 0) {
+        LOGE("open (%s) fail:errno - %d", dev_name, errno);
+        return -1;
+    }
+    return fd;
+}
+
+
+int Ql_I2C_Read(int fd, unsigned short slaveAddr, unsigned char ofstAddr,  unsigned char* ptrBuff, unsigned short length)
+{
+    uint8_t outbuf[1];
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[2];
+
+    outbuf[0] = ofstAddr;
+    messages[0].addr = slaveAddr;
+    messages[0].flags = 0;
+    messages[0].len = sizeof(outbuf);
+    messages[0].buf = outbuf;
+
+    /* The data will get returned in this structure */
+    messages[1].addr = slaveAddr;
+    messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
+    messages[1].len = length;
+    messages[1].buf = ptrBuff;
+
+    /* Send the request to the kernel and get the result back */
+    packets.msgs = messages;
+    packets.nmsgs = 2;
+    if(ioctl(fd, I2C_RDWR, &packets) < 0)
+    {
+        LOGE("Error: Unable to send data");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int Ql_I2C_Write(int fd, unsigned short slaveAddr, unsigned char ofstAddr,  unsigned char* ptrData, unsigned short length)
+{
+    uint8_t *outbuf = NULL;
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[1];
+
+    outbuf = malloc(length + 1);
+    if (!outbuf) {
+        printf("Error: No memory for buffer\n");
+        return -1;
+    }
+
+    outbuf[0] = ofstAddr;
+    memcpy(outbuf + 1, ptrData, length);
+
+    messages[0].addr = slaveAddr;
+    messages[0].flags = 0;
+    messages[0].len = length + 1;
+    messages[0].buf = outbuf;
+
+    /* Transfer the i2c packets to the kernel and verify it worked */
+    packets.msgs = messages;
+    packets.nmsgs = 1;
+    if(ioctl(fd, I2C_RDWR, &packets) < 0)
+    {
+        printf("Error: Unable to send data");
+        free(outbuf);
+        return -1;
+    }
+
+    free(outbuf);
+
+    return 0;
+}
+
+
+int Ql_I2C_Deinit(int fd)
+{
+    if (fd <= 0)
+        return -1;
+
+    close(fd);
+    return 0;
+}
+
+#if 0
+int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
+{
+	int file, len;
+
+	len = snprintf(filename, size, "/dev/i2c/%d", i2cbus);
+	if (len >= (int)size) {
+		fprintf(stderr, "%s: path truncated\n", filename);
+		return -EOVERFLOW;
+	}
+	file = open(filename, O_RDWR);
+
+	if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
+		len = snprintf(filename, size, "/dev/i2c-%d", i2cbus);
+		if (len >= (int)size) {
+			fprintf(stderr, "%s: path truncated\n", filename);
+			return -EOVERFLOW;
+		}
+		file = open(filename, O_RDWR);
+	}
+	...
+	return file;
+}
+
+static int i2c_read_bytes(int fd, uint8_t slave_addr, uint8_t reg_addr, uint8_t *values, uint8_t len)
+{
+    uint8_t outbuf[1];
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[2];
+
+    outbuf[0] = reg_addr;
+    messages[0].addr = slave_addr;
+    messages[0].flags = 0;
+    messages[0].len = sizeof(outbuf);
+    messages[0].buf = outbuf;
+
+    /* The data will get returned in this structure */
+    messages[1].addr = slave_addr;
+    messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
+    messages[1].len = len;
+    messages[1].buf = values;
+
+    /* Send the request to the kernel and get the result back */
+    packets.msgs = messages;
+    packets.nmsgs = 2;
+    if(ioctl(fd, I2C_RDWR, &packets) < 0)
+    {
+        printf("Error: Unable to send data");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int i2c_write_bytes(int fd, uint8_t slave_addr, uint8_t reg_addr, uint8_t *values, uint8_t len)
+{
+    uint8_t *outbuf = NULL;
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[1];
+
+    outbuf = malloc(len + 1);
+    if (!outbuf) {
+        printf("Error: No memory for buffer\n");
+        return -1;
+    }
+
+    outbuf[0] = reg_addr;
+    memcpy(outbuf + 1, values, len);
+
+    messages[0].addr = slave_addr;
+    messages[0].flags = 0;
+    messages[0].len = len + 1;
+    messages[0].buf = outbuf;
+
+    /* Transfer the i2c packets to the kernel and verify it worked */
+    packets.msgs = messages;
+    packets.nmsgs = 1;
+    if(ioctl(fd, I2C_RDWR, &packets) < 0)
+    {
+        printf("Error: Unable to send data");
+        free(outbuf);
+        return -1;
+    }
+
+    free(outbuf);
+
+    return 0;
+}
+
+
+int set_slave_addr(int file, int address, int force)
+{
+	/* With force, let the user read from/write to the registers
+	   even when a driver is also running */
+	if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
+		fprintf(stderr,
+			"Error: Could not set address to 0x%02x: %s\n",
+			address, strerror(errno));
+		return -errno;
+	}
+
+	return 0;
+}
+
+
+int main(void)
+{
+	int fd = -1;
+        char send_data[64] = {0};
+	send_data[0] = 0x55;
+	send_data[1] = 0x00;
+	send_data[2] = 0x84;
+    	fd= open_i2c_dev(0, "i2c_test", 5, 0);
+	i2c_write_bytes(fd, 0x12, 0x10,send_data, 3)
+}
+#endif
diff --git a/mbtk/libql_lib_v2/src/ql_quec_nw.c b/mbtk/libql_lib_v2/src/ql_quec_nw.c
new file mode 100755
index 0000000..51598e9
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_quec_nw.c
@@ -0,0 +1,945 @@
+#include "ql/ql_nw.h"
+#include "mbtk_type.h"
+#include "mbtk_info_api.h"
+
+extern mbtk_info_handle_t* ql_info_handle;
+extern int ql_info_handle_num;
+static bool inited = FALSE;
+
+#define SIGNAL_STRENGTH_INVALID_1 99
+#define SIGNAL_STRENGTH_INVALID_2 255
+
+
+typedef struct
+{
+    uint8 *operator_l;
+    uint8 *operator_s;
+    uint32 mcc_mnc;
+} operator_mcc_mnc_t;
+
+typedef struct
+{
+    QL_NW_EventHandlerFunc_t handlerPtr;
+    void* contextPtr;
+} ql_cust_cb_func;
+
+static ql_cust_cb_func ql_func_cb_handle;
+
+static int roaming_pref = 1;  // Open roaming for default.
+
+static operator_mcc_mnc_t operator_mcc_mnc [] =
+{
+    {"China Mobile","CMCC",46000},
+    {"China Unicom","CU",46001},
+    {"China Mobile","CMCC",46002},
+    {"China Telecom","CT",46003},
+    {"China Mobile","CMCC",46004},
+    {"China Telecom","CT",46005},
+    {"China Unicom","CU",46006},
+    {"China Mobile","CMCC",46007},
+    {"China Mobile","CMCC",46008},
+    {"China Unicom","CU",46009},
+    {"China Telecom","CT",46011}
+};
+
+typedef enum {
+    RADIO_TECH_3GPP = 1, /* 3GPP Technologies - GSM, WCDMA */
+    RADIO_TECH_3GPP2 = 2 /* 3GPP2 Technologies - CDMA */
+} RIL_RadioTechnologyFamily;
+
+void ql_nw_state_change_cb(const void* data, int data_len)
+{
+    ///mbtk_net_info_t *reg = (mbtk_net_info_t *)data;
+    uint8 *net_data = NULL;
+
+    net_data = (uint8*)data;
+    /*
+    uint8 data[3];
+    data[0] = (uint8)MBTK_NET_CS_STATE;
+
+    net_data[0] = *(uint8 *)(data);                                 //MBTK_NET_PS_STATE
+    net_data[1] = *(uint8 *)(data + sizeof(uint8));                 //mbtk_net_reg_state_enum state Reg State
+    net_data[2] = *(uint8 *)(data + sizeof(uint8) + sizeof(uint8)); //act
+    */
+    if(roaming_pref == 0)
+    {
+        mbtk_modem_info_t info;
+        if(*net_data == 5)
+        {
+            info.fun=4;
+            //ql_netw_status_cb(5);
+        }
+        else
+            info.fun=1;
+        info.rst=0;
+        //mbtk_set_modem_fun(ql_info_handle, &info);
+    }
+
+    if(ql_func_cb_handle.handlerPtr != NULL)
+    {
+        ql_func_cb_handle.handlerPtr(QL_NW_IND_DATA_REG_EVENT_FLAG,&(net_data[2]), sizeof(&(net_data[2])), NULL);
+    }
+}
+
+QL_NW_ERROR_CODE ql_nw_init()
+{
+    if(!inited && ql_info_handle == NULL)
+    {
+        ql_info_handle = mbtk_info_handle_get();
+        if(ql_info_handle)
+        {
+            ql_info_handle_num++;
+            inited = TRUE;
+            return QL_NW_SUCCESS;
+        } else {
+            LOGE("mbtk_info_handle_get() fail.");
+            return QL_NW_GENERIC_FAILURE;
+        }
+    } else {
+        if(!inited) {
+            ql_info_handle_num++;
+            inited = TRUE;
+        }
+        return QL_NW_SUCCESS;
+    }
+}
+
+QL_NW_ERROR_CODE ql_nw_release()
+{
+    if(ql_info_handle)
+    {
+        LOGD("ql_info_handle_num = %d", ql_info_handle_num);
+        if(ql_info_handle_num == 1) { // 最后一个引用,可释放。
+            int ret = mbtk_info_handle_free(&ql_info_handle);
+            if(ret) {
+                LOGE("mbtk_info_handle_free() fail.");
+                return QL_NW_GENERIC_FAILURE;
+            }
+            else
+            {
+                ql_info_handle_num = 0;
+                ql_info_handle = NULL;
+                return QL_NW_SUCCESS;
+            }
+        } else {
+            ql_info_handle_num--;
+            return QL_NW_SUCCESS;
+        }
+    }
+    else
+    {
+        LOGE("NW handle not inited.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+}
+
+static uint8 net_pre_change(bool mbtk_2_ql,int net_mode)
+{
+    uint8 mbtk_net_pre = 0xFF;
+
+    /*
+    QL_NW_PREF_NET_TYPE_GSM_WCDMA = 0,                      //4
+    QL_NW_PREF_NET_TYPE_GSM_ONLY = 1,                       //0
+    QL_NW_PREF_NET_TYPE_WCDMA = 2,                          //1
+    QL_NW_PREF_NET_TYPE_GSM_WCDMA_AUTO = 3,                 //2
+    QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA = 9,                  //12
+    QL_NW_PREF_NET_TYPE_LTE_ONLY = 11,                      //5
+    QL_NW_PREF_NET_TYPE_LTE_WCDMA = 12,                     //9
+    QL_NW_PREF_NET_TYPE_LTE_GSM_GSM_PREF = 13,              //7
+    QL_NW_PREF_NET_TYPE_LTE_GSM_LTE_PREF = 14,              //8
+    QL_NW_PREF_NET_TYPE_LTE_GSM = 15,                       //6
+    QL_NW_PREF_NET_TYPE_LTE_WCDMA_WCDMA_PREF = 16,          //10
+    QL_NW_PREF_NET_TYPE_LTE_WCDMA_LTE_PREF = 17,            //11
+    QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_GSM_PREF = 19,        //13
+    QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_WCDMA_PREF = 20,      //14
+    QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_LTE_PREF = 21,        //15
+    */
+    /*
+    0 : GSM only
+    1 : UMTS only
+    2 : GSM/UMTS(auto)
+    3 : GSM/UMTS(GSM preferred)
+    4 : GSM/UMTS(UMTS preferred)
+    5 : LTE only
+    6 : GSM/LTE(auto)
+    7 : GSM/LTE(GSM preferred)
+    8 : GSM/LTE(LTE preferred)
+    9 : UMTS/LTE(auto)
+    10 : UMTS/LTE(UMTS preferred)
+    11 : UMTS/LTE(LTE preferred)
+    12 : GSM/UMTS/LTE(auto)
+    13 : GSM/UMTS/LTE(GSM preferred)
+    14 : GSM/UMTS/LTE(UMTS preferred)
+    15 : GSM/UMTS/LTE(LTE preferred)
+    */
+
+    if(mbtk_2_ql) {
+        switch(net_mode)
+        {
+            case MBTK_NET_PREF_GSM_UMTS_UMTS_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_GSM_WCDMA;
+                break;
+            case MBTK_NET_PREF_GSM_ONLY:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_GSM_ONLY;
+                break;
+            case MBTK_NET_PREF_UMTS_ONLY:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_WCDMA;
+                break;
+            case MBTK_NET_PREF_GSM_UMTS_AUTO:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_GSM_WCDMA_AUTO;
+                break;
+            case MBTK_NET_PREF_GSM_UMTS_LTE_AUTO:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA;
+                break;
+            case MBTK_NET_PREF_LTE_ONLY:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_ONLY;
+                break;
+            case MBTK_NET_PREF_UMTS_LTE_AUTO:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_WCDMA;
+                break;
+            case MBTK_NET_PREF_GSM_LTE_GSM_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM_GSM_PREF;
+                break;
+            case MBTK_NET_PREF_GSM_LTE_LTE_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM_LTE_PREF;
+                break;
+            case MBTK_NET_PREF_GSM_LTE_AUTO:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM;
+                break;
+            case MBTK_NET_PREF_UMTS_LTE_UMTS_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_WCDMA_WCDMA_PREF;
+                break;
+            case MBTK_NET_PREF_UMTS_LTE_LTE_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_WCDMA_LTE_PREF;
+                break;
+            case MBTK_NET_PREF_GSM_UMTS_LTE_GSM_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_GSM_PREF;
+                break;
+            case MBTK_NET_PREF_GSM_UMTS_LTE_UMTS_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_WCDMA_PREF;
+                break;
+            case MBTK_NET_PREF_GSM_UMTS_LTE_LTE_PREF:
+                mbtk_net_pre = QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_LTE_PREF;
+                break;
+            default:
+                mbtk_net_pre = 0xFF;
+                break;
+        }
+    } else {
+        switch(net_mode)
+        {
+            case QL_NW_PREF_NET_TYPE_GSM_WCDMA:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_UMTS_UMTS_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_GSM_ONLY:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_ONLY;
+                break;
+            case QL_NW_PREF_NET_TYPE_WCDMA:
+                mbtk_net_pre = MBTK_NET_PREF_UMTS_ONLY;
+                break;
+            case QL_NW_PREF_NET_TYPE_GSM_WCDMA_AUTO:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_UMTS_AUTO;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_UMTS_LTE_AUTO;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_ONLY:
+                mbtk_net_pre = MBTK_NET_PREF_LTE_ONLY;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_WCDMA:
+                mbtk_net_pre = MBTK_NET_PREF_UMTS_LTE_AUTO;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM_GSM_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_LTE_GSM_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM_LTE_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_LTE_LTE_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_LTE_AUTO;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_WCDMA_WCDMA_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_UMTS_LTE_UMTS_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_WCDMA_LTE_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_UMTS_LTE_LTE_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_GSM_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_UMTS_LTE_GSM_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_WCDMA_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_UMTS_LTE_UMTS_PREF;
+                break;
+            case QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_LTE_PREF:
+                mbtk_net_pre = MBTK_NET_PREF_GSM_UMTS_LTE_LTE_PREF;
+                break;
+            default:
+                mbtk_net_pre = 0xFF;
+                break;
+        }
+    }
+    return mbtk_net_pre;
+}
+
+QL_NW_ERROR_CODE ql_nw_set_config(QL_NW_CONFIG_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+
+	if(pt_info->preferred_nw_mode < QL_NW_PREF_NET_TYPE_GSM_WCDMA || pt_info->preferred_nw_mode > QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_LTE_PREF)
+	{
+        LOGE("Unknown preferred_nw_mode(%d) error.", pt_info->preferred_nw_mode);
+		return QL_NW_GENERIC_FAILURE;
+	}
+
+    roaming_pref = pt_info->roaming_pref;
+
+    mbtk_band_info_t band;
+    memset(&band, 0, sizeof(mbtk_band_info_t));
+    band.net_pref = net_pre_change(FALSE, pt_info->preferred_nw_mode);
+    if(band.net_pref == 0xFF)
+    {
+        LOGE("net_pre_change() fail.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    if(mbtk_current_band_set(ql_info_handle, &band)) {
+        return QL_NW_GENERIC_FAILURE;
+    } else {
+        return QL_NW_SUCCESS;
+    }
+}
+
+QL_NW_ERROR_CODE ql_nw_get_config(QL_NW_CONFIG_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    pt_info->roaming_pref = roaming_pref;
+    mbtk_band_info_t band;
+    if(mbtk_current_band_get(ql_info_handle, &band)) {
+        return QL_NW_GENERIC_FAILURE;
+    } else {
+        pt_info->preferred_nw_mode = (QL_NW_PREFERRED_NETWORK_TYPE)net_pre_change(TRUE, band.net_pref);
+        return QL_NW_SUCCESS;
+    }
+}
+
+QL_NW_ERROR_CODE ql_nw_get_nitz_time_info(QL_NW_NITZ_TIME_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    memset(pt_info, 0x0, sizeof(QL_NW_NITZ_TIME_INFO_T));
+    char time_str[100]={0};
+    ///printf("mbtk_net_time_get begin\n");
+    int err = mbtk_net_time_get(ql_info_handle, time_str);
+    if(err) {
+        LOGE("mbtk_net_time_get() fail.");
+        return QL_NW_GENERIC_FAILURE;
+    } else {
+        memset(pt_info->nitz_time,0,32);
+        memcpy(pt_info->nitz_time,time_str,strlen(time_str));
+        if(mbtk_get_abs_time(time_str, &(pt_info->abs_time))) {
+            LOGE("mbtk_get_abs_time() fail.");
+            return QL_NW_GENERIC_FAILURE;
+        }
+
+        pt_info->leap_sec = 0;
+
+        return QL_NW_SUCCESS;
+    }
+}
+
+//--------------------------------------------------------------------------------------
+QL_NW_ERROR_CODE ql_nw_event_register(unsigned int bitmask)
+{
+    /*
+    NW_IND_VOICE_REG_EVENT_IND_FLAG 语音拨号注册事件
+    NW_IND_DATA_REG_EVENT_IND_FLAG (1 << 1) 数据拨号注册事件
+    NW_IND_SIGNAL_STRENGTH_EVENT_IND_FLAG (1 << 2) 信号强度事件
+    NW_IND_NITZ_TIME_UPDATE_EVENT_IND_FLAG (1 << 3) 网络时间更新事件
+    */
+    if(bitmask == QL_NW_IND_VOICE_REG_EVENT_FLAG)
+        {}
+    if(bitmask == QL_NW_IND_DATA_REG_EVENT_FLAG)
+        {}
+    if(bitmask == QL_NW_IND_SIGNAL_STRENGTH_EVENT_FLAG)
+        {}
+    if(bitmask == QL_NW_IND_NITZ_TIME_UPDATE_EVENT_FLAG)
+        {}
+    return QL_NW_SUCCESS;
+}
+//--------------------------------------------------------------------------------------
+
+QL_NW_ERROR_CODE ql_nw_get_operator_name(QL_NW_OPERATOR_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    char OperatorFN[128];
+    char OperatorSH[128];
+    char MccMnc[128];
+    mbtk_net_info_t net;
+    if(!mbtk_net_sel_mode_get(ql_info_handle, &net) && net.plmn > 0)
+    {
+        // printf("Net : %d, %d, %d\n", net.net_sel_mode, net.net_type, net.plmn);
+        int i = 0;
+        while(i < ARRAY_SIZE(operator_mcc_mnc))
+        {
+            if(operator_mcc_mnc[i].mcc_mnc == net.plmn)
+                break;
+            i++;
+        }
+
+        if(i == ARRAY_SIZE(operator_mcc_mnc))   // No found mcc&mnc
+        {
+            strcpy(OperatorFN, "UNKNOWN");
+            strcpy(OperatorSH, "UNKNOWN");
+            sprintf(MccMnc, "%d", net.plmn);
+        }
+        else
+        {
+            strcpy(OperatorFN, operator_mcc_mnc[i].operator_l);
+            strcpy(OperatorSH, operator_mcc_mnc[i].operator_s);
+            sprintf(MccMnc, "%d", operator_mcc_mnc[i].mcc_mnc);
+        }
+        memset(pt_info->long_eons,0,128);
+        memcpy(pt_info->long_eons,operator_mcc_mnc[i].operator_l,strlen(operator_mcc_mnc[i].operator_l));
+        memset(pt_info->short_eons,0,128);
+        memcpy(pt_info->short_eons,operator_mcc_mnc[i].operator_s,strlen(operator_mcc_mnc[i].operator_s));
+        memset(pt_info->mcc,0,4);
+        memset(pt_info->mnc,0,4);
+        sprintf(pt_info->mcc, "%d", (operator_mcc_mnc[i].mcc_mnc)/100);
+        if(0 == operator_mcc_mnc[i].mcc_mnc % 100)
+        {
+            strcpy(pt_info->mnc, "00");   
+        }
+        else
+        {
+            sprintf(pt_info->mnc, "%d", (operator_mcc_mnc[i].mcc_mnc)%100);
+        }
+        //pt_info->act;
+        return QL_NW_SUCCESS;
+    }
+
+    return QL_NW_GENERIC_FAILURE;
+}
+
+QL_NW_ERROR_CODE ql_nw_perform_scan(QL_NW_SCAN_RESULT_LIST_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+	list_node_t* net_list = NULL;
+    int ret = mbtk_available_net_get(ql_info_handle, &net_list);
+    if(ret != 0)
+    {
+        LOGE("mbtk_available_net_get fail.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    else
+    {
+        memset(pt_info, 0x0, sizeof(QL_NW_SCAN_RESULT_LIST_INFO_T));
+        mbtk_net_info_t* net = NULL;
+		list_first(net_list);
+        int i=0;
+        while ((net = (mbtk_net_info_t*) list_next(net_list)))
+        {
+            //printf("Net : %d, %d, %d, %d\n", net->net_sel_mode, net->net_type, net->net_state, net->plmn);
+            if(net->net_state == 8)
+                pt_info->entry[i].status = QL_NW_ACCESS_TECH_E_UTRAN_CA;
+            else if(net->net_state == 0xff)
+                pt_info->entry[i].status = QL_NW_ACCESS_TECH_NONE;
+            else
+                pt_info->entry[i].status = net->net_state;
+
+            int j = 0;
+            while(j < ARRAY_SIZE(operator_mcc_mnc))
+            {
+                if(operator_mcc_mnc[j].mcc_mnc == net->plmn)
+                    break;
+                j++;
+            }
+            if(j == ARRAY_SIZE(operator_mcc_mnc))   // No found mcc&mnc
+            {
+                strcpy(pt_info->entry[i].operator_name.long_eons, "UNKNOWN");
+                strcpy(pt_info->entry[i].operator_name.short_eons, "UNKNOWN");
+                sprintf(pt_info->entry[i].operator_name.mcc, "%d", (net->plmn)/100);
+                sprintf(pt_info->entry[i].operator_name.mnc, "%d", (net->plmn)%100);
+            }
+            else
+            {
+                strcpy(pt_info->entry[i].operator_name.long_eons, operator_mcc_mnc[j].operator_l);
+                strcpy(pt_info->entry[i].operator_name.short_eons, operator_mcc_mnc[j].operator_s);
+                sprintf(pt_info->entry[i].operator_name.mcc, "%d", (net->plmn)/100);
+                sprintf(pt_info->entry[i].operator_name.mnc, "%d", (net->plmn)%100);
+            }
+            pt_info->entry[i].operator_name ;
+            pt_info->entry[i].act = net->net_type;
+            i++;
+            if(i > 40)
+                break;
+        }
+        pt_info->entry_len = i;
+        list_free(net_list);
+        return QL_NW_SUCCESS;
+    }
+}
+
+#if 0
+static int ql_query_registration_state(const char *type, int* regState,int *imsRegState,int * LAC, int *CID,int *netType,int * radioTechFam,int *netRejected)
+{
+    if(ql_info_handle == NULL || str_empty(type) || regState == NULL || imsRegState == NULL
+        || LAC == NULL || CID == NULL || netType == NULL || radioTechFam == NULL || netRejected == NULL)
+    {
+        return -1;
+    }
+    mbtk_net_reg_info_t reg;
+    int err = mbtk_net_reg_get(ql_info_handle, &reg);
+    if(err) {
+        *netRejected = err;
+        return -1;
+    } else {
+        //printf("REG : %d, %d, %d, %04x, %08o\n", reg.state, reg.type, reg.ims_reg, reg.lac, reg.ci);
+        // Voice/Data/IMS
+        if(strcmp("VOICE", type) == 0) {
+            *regState = reg.call_state;
+        } else if(strcmp("DATA", type) == 0) {
+            *regState = reg.data_state;
+        } else if(strcmp("IMS", type) == 0) {
+            *imsRegState = reg.ims_state;
+        } else {
+            return -1;
+        }
+
+        if(reg.call_state != MBTK_NET_REG_STATE_NON || reg.data_state != MBTK_NET_REG_STATE_NON || reg.ims_state != MBTK_NET_REG_STATE_NON) {
+            sprintf(LAC, "%04x", reg.lac);
+            sprintf(CID, "%08o", reg.ci);
+            *netType = reg.type;
+            *radioTechFam = RADIO_TECH_3GPP;
+        }
+        return 0;
+    }
+
+}
+#endif
+
+QL_NW_ERROR_CODE ql_nw_get_reg_status(QL_NW_REG_STATUS_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    /*VOICE/DATA/IMS*/
+    mbtk_net_reg_info_t reg;
+    int err = mbtk_net_reg_get(ql_info_handle, &reg);
+    if(err) {
+        LOGE("mbtk_net_reg_get fail.");
+        return QL_NW_GENERIC_FAILURE;
+    } else {
+        memset(pt_info, 0x0, sizeof(QL_NW_REG_STATUS_INFO_T));
+        pt_info->data_reg.state = (QL_NW_REG_STATE)reg.data_state;
+        pt_info->data_reg.lac = reg.lac;
+        pt_info->data_reg.cid = reg.ci;
+        pt_info->voice_reg.state = (QL_NW_REG_STATE)reg.call_state;
+        pt_info->voice_reg.lac = reg.lac;
+        pt_info->voice_reg.cid = reg.ci;
+        switch(reg.type)
+        {
+            case MBTK_RADIO_TECH_GSM:
+            case MBTK_RADIO_TECH_GSM_COMPACT:
+            case MBTK_RADIO_TECH_GSM_EGPRS:
+            case MBTK_RADIO_TECH_UTRAN_HSPA:
+            {
+                pt_info->data_reg.rat = QL_NW_RADIO_TECH_GPRS;
+                pt_info->voice_reg.rat = QL_NW_RADIO_TECH_GSM;
+                break;
+            }
+            case MBTK_RADIO_TECH_UTRAN:
+            case MBTK_RADIO_TECH_UTRAN_HSDPA:
+            case MBTK_RADIO_TECH_UTRAN_HSUPA:
+            case MBTK_RADIO_TECH_UTRAN_HSDPA_HSUPA:
+            {
+                pt_info->data_reg.rat = QL_NW_RADIO_TECH_UMTS;
+                pt_info->voice_reg.rat = QL_NW_RADIO_TECH_UMTS;
+                break;
+            }
+            case MBTK_RADIO_TECH_E_UTRAN:
+            {
+                pt_info->data_reg.rat = QL_NW_RADIO_TECH_LTE;
+                pt_info->voice_reg.rat = QL_NW_RADIO_TECH_LTE;
+                break;
+            }
+            default:
+            {
+                pt_info->data_reg.rat = QL_NW_RADIO_TECH_UNKNOWN;
+                pt_info->voice_reg.rat = QL_NW_RADIO_TECH_UNKNOWN;
+                break;
+            }
+        }
+    }
+
+    return 0;
+
+#if 0
+    int ret = ql_query_registration_state("VOICE", &(pt_info->voice_reg.state), &imsRegState, &(pt_info->voice_reg.lac), &(pt_info->voice_reg.cid), &netType, &(pt_info->voice_reg.rejectCause), &netRejected);
+    if(ret != 0)
+        err = QL_NW_GENERIC_FAILURE;
+    else
+        err = QL_NW_SUCCESS;
+    ret = ql_query_registration_state("DATA", &(pt_info->data_reg.state), &imsRegState, &(pt_info->data_reg.lac), &(pt_info->data_reg.cid), &netType, &(pt_info->data_reg.rejectCause), &netRejected);
+    if(ret != 0)
+        err =  QL_NW_GENERIC_FAILURE;
+    else
+        err = QL_NW_SUCCESS;
+
+    if(err == QL_NW_SUCCESS)
+    {
+        if(netType < 0 || netType > 8)
+            pt_info->data_reg.rat = QL_NW_ACCESS_TECH_NONE;
+        else
+            pt_info->data_reg.rat = netType;
+    }
+    return err;
+#endif
+}
+
+QL_NW_ERROR_CODE ql_nw_set_selection(QL_NW_SELECTION_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+
+    mbtk_net_info_t net;
+    net.net_type = 0xFF;
+    char mccmnc[10];
+    if(pt_info->nw_selection_mode == 0)
+    {
+        net.net_sel_mode = 0;
+        net.plmn = 0;
+    }
+    else if(pt_info->nw_selection_mode == 1 && !str_empty(pt_info->mnc) && !str_empty(pt_info->mcc))
+    {
+        net.net_sel_mode = 1;
+        memset(mccmnc, 0, 10);
+        //memcpy(mccmnc, pt_info->mcc, 3);
+        //memcpy(mccmnc + 3, pt_info->mnc, 3);
+        sprintf(mccmnc,"%s%s",pt_info->mcc,pt_info->mnc);
+        net.plmn = (uint32)atoi(mccmnc);
+        if(pt_info->act < QL_NW_ACCESS_TECH_GSM || pt_info->act > QL_NW_ACCESS_TECH_UTRAN_HSPAP)
+            net.net_type = 0xff;
+        else
+            net.net_type = pt_info->act;
+    }
+    else
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    //printf("mccmnc = %s\n",mccmnc);
+    //printf("net.plmn = %d\n",net.plmn);
+    int ret = mbtk_net_sel_mode_set(ql_info_handle, &net);
+    if(ret == 0)
+    {
+        return QL_NW_SUCCESS;
+    }
+    else
+    {
+        printf("mbtk_net_sel_mode_set error: %d\n",ret );
+        return QL_NW_GENERIC_FAILURE;
+    }
+}
+
+QL_NW_ERROR_CODE ql_nw_get_selection(QL_NW_SELECTION_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    char OperatorFN[128];
+    char OperatorSH[128];
+    char MccMnc[128];
+    mbtk_net_info_t net;
+    if(!mbtk_net_sel_mode_get(ql_info_handle, &net) && net.plmn > 0)
+    {
+        memset(pt_info, 0x0, sizeof(QL_NW_SELECTION_INFO_T));
+        // printf("Net : %d, %d, %d\n", net.net_sel_mode, net.net_type, net.plmn);
+        int i = 0;
+        while(i < ARRAY_SIZE(operator_mcc_mnc))
+        {
+            if(operator_mcc_mnc[i].mcc_mnc == net.plmn)
+                break;
+            i++;
+        }
+        if(i == ARRAY_SIZE(operator_mcc_mnc))   // No found mcc&mnc
+        {
+            strcpy(OperatorFN, "UNKNOWN");
+            strcpy(OperatorSH, "UNKNOWN");
+            sprintf(MccMnc, "%d", net.plmn);
+        }
+        else
+        {
+            strcpy(OperatorFN, operator_mcc_mnc[i].operator_l);
+            strcpy(OperatorSH, operator_mcc_mnc[i].operator_s);
+            sprintf(MccMnc, "%d", operator_mcc_mnc[i].mcc_mnc);
+
+            sprintf(pt_info->mcc,"%d",operator_mcc_mnc[i].mcc_mnc/100);
+            sprintf(pt_info->mnc,"%d",operator_mcc_mnc[i].mcc_mnc%100);
+
+        }
+        pt_info->nw_selection_mode = net.net_sel_mode;
+
+        pt_info->act = net.net_type;
+        return QL_NW_SUCCESS;
+    }
+
+    return QL_NW_GENERIC_FAILURE;
+
+}
+
+QL_NW_ERROR_CODE ql_nw_get_signal_strength(QL_NW_SIGNAL_STRENGTH_INFO_T *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+
+    int ret;
+    mbtk_signal_info_t signal;
+    ret = mbtk_net_signal_get(ql_info_handle, &signal);
+    if(ret != 0) {
+        LOGE("mbtk_net_signal_get fail.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    else
+    {
+        int rssi = 0;
+        if(SIGNAL_STRENGTH_INVALID_1 == signal.rssi)
+        {
+            rssi = SIGNAL_STRENGTH_INVALID_1;
+        }
+        else
+        {
+            rssi = 2 * signal.rssi - 113;
+        }
+        if(signal.type == MBTK_RADIO_TECH_GSM)              //GSM
+        {
+            pt_info->GW_SignalStrength.bitErrorRate = signal.ber;
+            pt_info->GW_SignalStrength.ecio = signal.ecno;
+            pt_info->GW_SignalStrength.rscp = signal.rscp;
+            pt_info->GW_SignalStrength.rssi = rssi;
+            
+            pt_info->LTE_SignalStrength.rsrp = SIGNAL_STRENGTH_INVALID_1;
+            pt_info->LTE_SignalStrength.rsrq = SIGNAL_STRENGTH_INVALID_1;
+            pt_info->LTE_SignalStrength.rssnr = SIGNAL_STRENGTH_INVALID_2;
+            pt_info->LTE_SignalStrength.rssi = SIGNAL_STRENGTH_INVALID_1;
+        }
+        else if(signal.type == MBTK_RADIO_TECH_E_UTRAN)     //LTE
+        {
+            pt_info->LTE_SignalStrength.cqi = SIGNAL_STRENGTH_INVALID_1;
+            pt_info->LTE_SignalStrength.rsrp = signal.rsrp;
+            pt_info->LTE_SignalStrength.rsrq = signal.rsrq;
+            pt_info->LTE_SignalStrength.rssnr = signal.ecno;
+            pt_info->LTE_SignalStrength.rssi = rssi;
+
+            pt_info->GW_SignalStrength.bitErrorRate = SIGNAL_STRENGTH_INVALID_1;
+            pt_info->GW_SignalStrength.ecio = SIGNAL_STRENGTH_INVALID_2;
+            pt_info->GW_SignalStrength.rscp = SIGNAL_STRENGTH_INVALID_2;
+            pt_info->GW_SignalStrength.rssi = SIGNAL_STRENGTH_INVALID_1;
+        }
+        else
+        {
+            return QL_NW_GENERIC_FAILURE;
+        }
+        LOGI("ql_GW_SignalStrength: %d , %d, %d, %d", pt_info->GW_SignalStrength.rssi, 
+            pt_info->GW_SignalStrength.bitErrorRate, pt_info->GW_SignalStrength.rscp, pt_info->GW_SignalStrength.ecio);
+        LOGI("ql_LTE_SignalStrength: %d , %d, %d, %d", pt_info->LTE_SignalStrength.rssi, 
+            pt_info->LTE_SignalStrength.rsrp, pt_info->LTE_SignalStrength.rsrq, pt_info->LTE_SignalStrength.rssnr, pt_info->LTE_SignalStrength.cqi);
+        return QL_NW_SUCCESS;
+    }
+}
+
+QL_NW_ERROR_CODE ql_nw_get_cell_info(QL_NW_CELL_INFO_T *pt_info)
+{
+    list_node_t* cell_list = NULL;
+    mbtk_cell_type_enum type;
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+
+    memset(pt_info, 0, sizeof(QL_NW_CELL_INFO_T));
+    int err = mbtk_cell_get(ql_info_handle, &type, &cell_list);
+    if(err || cell_list == NULL) {
+        LOGE("mbtk_cell_get fail.");
+        return QL_NW_GENERIC_FAILURE;
+    } else {
+        list_first(cell_list);
+        mbtk_cell_info_t* cell = (mbtk_cell_info_t*) list_next(cell_list);
+        if(cell) { // Current server cell.
+            switch(type)
+            {
+                case MBTK_CELL_TYPE_GSM:
+                {
+                    LOGD("GSM : lac=%d, ci=%d, arfcn=%d, bsic=%d", cell->value1, cell->value2, cell->value3, cell->value4);
+                    pt_info->gsm_info[0].lac = cell->value1;
+                    pt_info->gsm_info[0].cid = cell->value2;
+                    pt_info->gsm_info[0].arfcn = cell->value3;
+                    pt_info->gsm_info[0].bsic = cell->value4;
+                    pt_info->gsm_info[0].mcc = cell->value5;
+                    pt_info->gsm_info[0].mnc = cell->value6;
+                    pt_info->gsm_info[0].flag = 0;
+                    pt_info->gsm_info_num++;
+                    pt_info->gsm_info_valid = 1;
+                }
+                    break;
+                case MBTK_CELL_TYPE_UMTS:
+                {
+                    LOGD("UMTS : lac=%d, ci=%d, arfcn=%d", cell->value1, cell->value2, cell->value3);
+                    pt_info->umts_info[0].lac = cell->value1;
+                    pt_info->umts_info[0].cid = cell->value2;
+                    pt_info->umts_info[0].uarfcn = cell->value3;
+                    pt_info->umts_info[0].mcc = cell->value4;
+                    pt_info->umts_info[0].mnc = cell->value5;
+                    pt_info->umts_info[0].psc = cell->value6;
+                    pt_info->umts_info[0].flag = 0;
+                    pt_info->umts_info_num++;
+                    pt_info->umts_info_valid = 1;
+                }
+                    break;
+                case MBTK_CELL_TYPE_LTE:
+                {
+                    LOGD("LTE : tac=%d, PCI=%d, dlEuarfcn=%d, ulEuarfcn=%d, band=%d", cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+                    pt_info->lte_info[0].tac = cell->value1;
+                    pt_info->lte_info[0].pci = cell->value2;
+                    pt_info->lte_info[0].earfcn = cell->value3;
+                    pt_info->lte_info[0].cid = cell->value8;
+                    pt_info->lte_info[0].mcc = cell->value6;
+                    pt_info->lte_info[0].mnc = cell->value7;
+                    pt_info->lte_info[0].flag = 0;
+                    pt_info->lte_info_num++;
+                    pt_info->lte_info_valid = 1;
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+        while ((cell = (mbtk_cell_info_t*) list_next(cell_list)))
+        {
+            switch(type)
+            {
+                case MBTK_CELL_TYPE_GSM:
+                {
+                    LOGD("CELL : %d, %d, %d, %d, %d", cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+                    pt_info->gsm_info[pt_info->gsm_info_num].lac = cell->value1;
+                    pt_info->gsm_info[pt_info->gsm_info_num].cid = cell->value2;
+                    pt_info->gsm_info[pt_info->gsm_info_num].arfcn = cell->value3;
+                    pt_info->gsm_info[pt_info->gsm_info_num].bsic = cell->value4;
+                    pt_info->gsm_info[pt_info->gsm_info_num].flag = 1;
+                    pt_info->gsm_info_num++;
+                    pt_info->gsm_info_valid = 1;
+                }
+                    break;
+                case MBTK_CELL_TYPE_UMTS:
+                {
+                    LOGD("CELL : lac=%d, ci=%d, arfcn=%d", cell->value1, cell->value2, cell->value3);
+                    pt_info->umts_info[pt_info->umts_info_num].lac = cell->value1;
+                    pt_info->umts_info[pt_info->umts_info_num].cid = cell->value2;
+                    pt_info->umts_info[pt_info->umts_info_num].uarfcn = cell->value3;
+                    pt_info->umts_info[pt_info->umts_info_num].flag = 1;
+                    pt_info->umts_info_num++;
+                    pt_info->umts_info_valid = 1;
+                }
+                    break;
+                case MBTK_CELL_TYPE_LTE:
+                {
+                    LOGD("CELL : phyCellId=%d, euArfcn=%d, rsrp=%d, rsrq=%d", cell->value1, cell->value2, cell->value3, cell->value4);
+                    pt_info->lte_info[pt_info->lte_info_num].cid = cell->value1;
+                    pt_info->lte_info[pt_info->lte_info_num].earfcn = cell->value2;
+                    pt_info->lte_info[pt_info->lte_info_num].tac = cell->value3;
+                    pt_info->lte_info[pt_info->lte_info_num].pci = cell->value4;
+                    pt_info->lte_info[pt_info->lte_info_num].flag = 1;
+                    pt_info->lte_info_num++;
+                    pt_info->lte_info_valid = 1;
+                }
+                    break;
+                default:
+                    break;
+            }
+        }
+        list_free(cell_list);
+    }
+
+    LOGD("get_cell_success: %d, %d, %d.",pt_info->gsm_info_valid, pt_info->umts_info_valid, pt_info->lte_info_valid);
+    return QL_NW_SUCCESS;
+}
+
+QL_NW_ERROR_CODE ql_nw_add_event_handler(QL_NW_EventHandlerFunc_t handlerPtr,void* contextPtr)
+{
+    if(ql_info_handle == NULL || handlerPtr == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    mbtk_net_state_change_cb_reg(ql_info_handle, ql_nw_state_change_cb);
+    ql_func_cb_handle.handlerPtr = handlerPtr;
+    ql_func_cb_handle.contextPtr = contextPtr;
+    return QL_NW_SUCCESS;
+}
+
+QL_NW_ERROR_CODE ql_nw_get_volte_state(VOLTE_STATE *state)
+{
+    int ret;
+    if(ql_info_handle == NULL || state == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    ret = mbtk_volte_state_get(ql_info_handle, &(state->reg_state));
+    if(ret != 0)
+        return QL_NW_GENERIC_FAILURE;
+    else
+        return QL_NW_SUCCESS;
+}
+
+QL_NW_ERROR_CODE ql_nw_csq_get_signal_strength(QL_NW_CSQ_SIGNAL_STRENGTH_INFO_T *pt_info)
+{
+    int ret;
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_NW_GENERIC_FAILURE;
+    }
+    mbtk_signal_info_t signal;
+    ret = mbtk_net_signal_get(ql_info_handle, &signal);
+    if(ret != 0)
+        return QL_NW_GENERIC_FAILURE;
+    else
+    {
+        pt_info->rssi = (signal.rssi * 2 - 113);
+        pt_info->bitErrorRate = signal.ber;
+        LOGD("pt_info->rssi = %d  pt_info->bitErrorRate = %d",pt_info->rssi,pt_info->bitErrorRate);
+        return QL_NW_SUCCESS;
+    }
+}
+
+//*********************************************************************************
+
diff --git a/mbtk/libql_lib_v2/src/ql_quec_sim.c b/mbtk/libql_lib_v2/src/ql_quec_sim.c
new file mode 100755
index 0000000..edcef9a
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_quec_sim.c
@@ -0,0 +1,406 @@
+#include "ql/ql_sim.h"
+#include "mbtk_type.h"
+#include "mbtk_info_api.h"
+
+extern mbtk_info_handle_t* ql_info_handle;
+extern int ql_info_handle_num;
+static bool inited = FALSE;
+
+QL_SIM_CardStatusIndMsgHandlerFunc_t handlerPtr_cb = NULL;
+
+typedef struct
+{
+    uint8 *operator_l;
+    uint8 *operator_s;
+    uint32 mcc_mnc;
+} operator_mcc_mnc_t;
+
+static operator_mcc_mnc_t operator_mcc_mnc[] =
+{
+    {"China Mobile","CMCC",46000},
+    {"China Unicom","CU",46001},
+    {"China Mobile","CMCC",46002},
+    {"China Telecom","CT",46003},
+    {"China Mobile","CMCC",46004},
+    {"China Telecom","CT",46005},
+    {"China Unicom","CU",46006},
+    {"China Mobile","CMCC",46007},
+    {"China Mobile","CMCC",46008},
+    {"China Unicom","CU",46009},
+    {"China Telecom","CT",46011}
+};
+
+void ql_sim_state_change_cb(const void* data, int data_len)
+{
+    if(handlerPtr_cb != NULL)
+    {
+        //QL_SIM_NFY_MSG_ID msg_id, void *pv_data, int pv_data_len, void *contextPtr
+        //handlerPtr_cb(net_data[2]);
+    }
+    mbtk_sim_card_info *info = NULL;
+    info = (mbtk_sim_card_info*)data;
+
+    QL_SIM_CARD_STATUS_INFO sim_card_info = {0};
+    sim_card_info.card_state = info->sim;
+    sim_card_info.card_type = info->sim_card_type;
+    /*
+        sim_client_handle_type  h_sim,
+        E_QL_SIM_NFY_MSG_ID_T   e_msg_id,
+        void                    *pv_data,
+        void                    *contextPtr
+    */
+    handlerPtr_cb(QL_SIM_CARD_STATUS_UPDATE_EVENT, &sim_card_info, sizeof(QL_SIM_CARD_STATUS_INFO), NULL);
+}
+
+QL_SIM_ERROR_CODE ql_sim_init()
+{
+    if(!inited && ql_info_handle == NULL)
+    {
+        ql_info_handle = mbtk_info_handle_get();
+        if(ql_info_handle)
+        {
+            ql_info_handle_num++;
+            inited = TRUE;
+            return QL_SIM_SUCCESS;
+        } else {
+            LOGE("mbtk_info_handle_get() fail.");
+            return QL_SIM_GENERIC_FAILURE;
+        }
+    } else {
+        if(!inited) {
+            ql_info_handle_num++;
+            inited = TRUE;
+        }
+        return QL_SIM_SUCCESS;
+    }
+}
+
+
+QL_SIM_ERROR_CODE ql_sim_release()
+{
+    if(ql_info_handle)
+    {
+        LOGD("ql_info_handle_num = %d", ql_info_handle_num);
+        if(ql_info_handle_num == 1) { // 最后一个引用,可释放。
+            int ret = mbtk_info_handle_free(&ql_info_handle);
+            if(ret) {
+                LOGE("mbtk_info_handle_free() fail.");
+                return QL_SIM_GENERIC_FAILURE;
+            }
+            else
+            {
+                ql_info_handle_num = 0;
+                ql_info_handle = NULL;
+                return QL_SIM_SUCCESS;
+            }
+        } else {
+            ql_info_handle_num--;
+            return QL_SIM_SUCCESS;
+        }
+    }
+    else
+    {
+        LOGE("Sim handle not inited.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+}
+
+
+QL_SIM_ERROR_CODE ql_sim_get_imsi(uint8_t *imsi, size_t imsiLen)
+{
+    if(ql_info_handle == NULL || imsi == NULL || imsiLen <= 0)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    memset(imsi,0,imsiLen);
+    int err = mbtk_imsi_get(ql_info_handle, imsi);
+    if(err) {
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_get_iccid(uint8_t *iccid, size_t iccidLen)
+{
+    if(ql_info_handle == NULL || iccid == NULL || iccidLen <= 0)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    memset(iccid, 0, iccidLen);
+    int err = mbtk_iccid_get(ql_info_handle, iccid);
+    if(err) {
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_get_phonenumber(uint8_t *phone_num, size_t phoneLen)
+{
+    if(ql_info_handle == NULL || phone_num == NULL || phoneLen <= 0)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    memset(phone_num, 0, phoneLen);
+    int err = mbtk_phone_number_get(ql_info_handle, phone_num);
+    if(err) {
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_get_operator_plmn_list(QL_SIM_PREFERRED_OPERATOR_LIST *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+
+    mbtk_plmn_info plmn;
+    int err = mbtk_get_plmn_list(ql_info_handle, &plmn);
+    if(err) {
+        LOGE("mbtk_get_plmn_list file : %d",err);
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        memset(pt_info, 0x0, sizeof(QL_SIM_PREFERRED_OPERATOR_LIST));
+        pt_info->preferred_operator_list_num = plmn.count;
+        int list_count;
+        for(list_count = 0; list_count < plmn.count; list_count++)
+        {
+            if(plmn.mbtk_plmn_name[list_count].format == 2)    //number
+            {
+                uint32 plmn_name = (uint32)atoi(plmn.mbtk_plmn_name[list_count].plmn_name);
+                sprintf(pt_info->preferred_operator_list[list_count].mcc,"%d",plmn_name/100);
+                sprintf(pt_info->preferred_operator_list[list_count].mnc,"%02d",plmn_name%100);
+            }
+            else if(plmn.mbtk_plmn_name[list_count].format == 0)
+            {
+                int i = 0;
+                while(i < ARRAY_SIZE(operator_mcc_mnc))
+                {
+                    if(!strcmp(operator_mcc_mnc[i].operator_l,plmn.mbtk_plmn_name))
+                        break;
+                    i++;
+                }
+
+                if(i == ARRAY_SIZE(operator_mcc_mnc))   // No found mcc&mnc
+                {
+                    memcpy(pt_info->preferred_operator_list[list_count].mcc,0,3);
+                    memcpy(pt_info->preferred_operator_list[list_count].mnc,0,3);
+                }
+                else
+                {
+                    sprintf(pt_info->preferred_operator_list[list_count].mcc, "%d", (operator_mcc_mnc[i].mcc_mnc)/100);
+                    sprintf(pt_info->preferred_operator_list[list_count].mnc, "%d", (operator_mcc_mnc[i].mcc_mnc)%100);
+                }
+            }
+            else
+            {
+                int i = 0;
+                while(i < ARRAY_SIZE(operator_mcc_mnc))
+                {
+                    if(!strcmp(operator_mcc_mnc[i].operator_s,plmn.mbtk_plmn_name))
+                        break;
+                    i++;
+                }
+
+                if(i == ARRAY_SIZE(operator_mcc_mnc))   // No found mcc&mnc
+                {
+                    memcpy(pt_info->preferred_operator_list[list_count].mcc,0,3);
+                    memcpy(pt_info->preferred_operator_list[list_count].mnc,0,3);
+                }
+                else
+                {
+                    sprintf(pt_info->preferred_operator_list[list_count].mcc, "%d", (operator_mcc_mnc[i].mcc_mnc)/100);
+                    sprintf(pt_info->preferred_operator_list[list_count].mnc, "%d", (operator_mcc_mnc[i].mcc_mnc)%100);
+                }
+            }
+        }
+        int i;
+        for (i=0;i<pt_info->preferred_operator_list_num;i++)
+        {
+            LOGD("pt_info->preferred_operator_list[%d].mcc=%s",i, pt_info->preferred_operator_list[i].mcc);
+            LOGD("pt_info->preferred_operator_list[%d].mnc=%s",i, pt_info->preferred_operator_list[i].mnc);
+        }
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_verify_pin(QL_SIM_VERIFY_PIN_INFO *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+
+    int err = mbtk_verify_pin(ql_info_handle, pt_info->pin_value);
+    if(err) {
+        LOGE("mbtk_verify_pin fail : %d",err);
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_change_pin(QL_SIM_CHANGE_PIN_INFO *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    mbtk_change_pin_info pin_info = {0};
+    memcpy(pin_info.old_pin_value, pt_info->old_pin_value, strlen(pt_info->old_pin_value));
+    memcpy(pin_info.new_pin_value, pt_info->new_pin_value, strlen(pt_info->new_pin_value));
+    int err = mbtk_change_pin(ql_info_handle, &pin_info);
+    if(err) {
+        LOGE("mbtk_change_pin fail : %d",err);
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_unblock_pin(QL_SIM_UNBLOCK_PIN_INFO *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    mbtk_unlock_pin_info puk_pin_info = {0};
+    memcpy(puk_pin_info.pin_value, pt_info->new_pin_value, strlen(pt_info->new_pin_value));
+    memcpy(puk_pin_info.puk_value, pt_info->puk_value, strlen(pt_info->puk_value));
+    int err = mbtk_unlock_pin(ql_info_handle, &puk_pin_info);
+    if(err) {
+        LOGE("mbtk_unlock_pin fail : %d",err);
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_enable_pin(QL_SIM_VERIFY_PIN_INFO *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    mbtk_enable_pin_info pin_info = {0};
+    memcpy(pin_info.pin_value, pt_info->pin_value, strlen(pt_info->pin_value));
+    pin_info.enable = 1;
+    int err = mbtk_enable_pin(ql_info_handle, &pin_info);
+    if(err) {
+        LOGE("mbtk_enable_pin fail : %d",err);
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_disable_pin(QL_SIM_VERIFY_PIN_INFO *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("ARG error.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    mbtk_enable_pin_info pin_info = {0};
+    memcpy(pin_info.pin_value, pt_info->pin_value, strlen(pt_info->pin_value));
+    pin_info.enable = 0;
+    int err = mbtk_enable_pin(ql_info_handle, &pin_info);
+    if(err) {
+        LOGE("ql_sim_disable_pin fail : %d",err);
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        return QL_SIM_SUCCESS;
+    }
+}
+
+QL_SIM_ERROR_CODE ql_sim_get_card_status(QL_SIM_CARD_STATUS_INFO *pt_info)
+{
+    if(ql_info_handle == NULL || pt_info == NULL)
+    {
+        LOGE("sim not init.");
+        return QL_SIM_GENERIC_FAILURE;
+    }
+
+    mbtk_sim_state_enum sim;
+    mbtk_sim_card_type_enum sim_card_type;
+    mbtk_pin_puk_last_times ql_last_times = {0};
+    int err = mbtk_sim_state_get(ql_info_handle, &sim);
+    LOGD("mbtk_sim_state_get - %d");
+    if(err) {
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        memset(pt_info, 0x0, sizeof(QL_SIM_CARD_STATUS_INFO));
+        pt_info->card_state = sim;
+        switch (sim)
+        {
+            case 0:                     //ABSENT
+                pt_info->card_state = QL_SIM_STAT_NOT_INSERTED;
+                break;
+            case 1:                     //NOT READY
+                pt_info->card_state = QL_SIM_STAT_UNKNOWN;
+                break;
+            case 2:                     //READY
+                pt_info->card_state = QL_SIM_STAT_READY;
+                break;
+            case 3:                     //SIM PIN
+                pt_info->card_state = QL_SIM_STAT_SIM_PIN;
+                break;
+            case 4:                     //SIM PUK
+                pt_info->card_state = QL_SIM_STAT_SIM_PUK;
+                break;
+            case 5:                     //NETWORK
+                pt_info->card_state = QL_SIM_STAT_UNKNOWN;
+                break;
+            default:
+                pt_info->card_state = QL_SIM_STAT_UNKNOWN;
+                break;
+        }
+    }
+    err = mbtk_sim_card_type_get(ql_info_handle, &sim_card_type);
+    LOGD("mbtk_sim_card_type_get - %d", err);
+    if(err) {
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        if(sim_card_type == 0 || sim_card_type == 2)
+            pt_info->card_type = QL_SIM_CARD_TYPE_ICC;
+        else if(sim_card_type == 1 || sim_card_type == 3)
+            pt_info->card_type = QL_SIM_CARD_TYPE_UICC;
+        else
+            pt_info->card_type = QL_SIM_CARD_TYPE_UNKNOWN;
+    }
+    err = mbtk_pin_last_num_get(ql_info_handle, &ql_last_times);
+    LOGD("mbtk_pin_last_num_get - %d", err);
+    if(err) {
+        return QL_SIM_GENERIC_FAILURE;
+    } else {
+        pt_info->card_pin_info.pin1_num_retries = ql_last_times.p1_retry;
+        pt_info->card_pin_info.pin2_num_retries = ql_last_times.p2_retry;
+        pt_info->card_pin_info.puk1_num_retries = ql_last_times.puk1_retry;
+        pt_info->card_pin_info.puk2_num_retries = ql_last_times.puk2_retry;
+    }
+    return QL_SIM_SUCCESS;
+}
+
+QL_SIM_ERROR_CODE ql_sim_add_event_handler(QL_SIM_CardStatusIndMsgHandlerFunc_t handlerPtr, void* contextPtr)
+{
+    if(ql_info_handle == NULL || handlerPtr == NULL)
+    {
+        return QL_SIM_GENERIC_FAILURE;
+    }
+    handlerPtr_cb = handlerPtr;
+    mbtk_sim_state_change_cb_reg(ql_info_handle, ql_sim_state_change_cb);
+    return QL_SIM_SUCCESS;
+}
+
diff --git a/mbtk/libql_lib_v2/src/ql_sleep_wakelock.c b/mbtk/libql_lib_v2/src/ql_sleep_wakelock.c
new file mode 100755
index 0000000..03f356c
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_sleep_wakelock.c
@@ -0,0 +1,161 @@
+/*
+*
+* Data : 2023/03/28 16:00:28
+* Author : Hanzhiyu
+*
+*/
+#include "ql/ql_sleep_wakelock.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stddef.h>
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+
+typedef struct
+{
+    int fd;
+    char name[128];
+} lock_name;
+
+lock_name ql_lock_name[512]={0};
+static bool autosleep_enable = FALSE;
+
+extern int Ql_Autosleep_Enable(char enable)
+{
+    if(enable == 1)
+    {
+        if(!access("/sys/power/autosleep", W_OK))
+        {
+            system("echo mem > /sys/power/autosleep");
+            autosleep_enable = TRUE;
+            return 0;
+        }
+        else
+        {
+            LOGE("/sys/power/autosleep can not write.");
+            return -1;
+        }
+    }
+    else
+    {
+        if(!access("/sys/power/autosleep", W_OK))
+        {
+            system("echo off > /sys/power/autosleep");
+            autosleep_enable = FALSE;
+            return 0;
+        }
+        else
+        {
+            LOGE("/sys/power/autosleep can not write.");
+            return -1;
+        }
+    }
+}
+
+extern int Ql_SLP_WakeLock_Create(const char *name, size_t len)
+{
+    if(!autosleep_enable) {
+        LOGE("Autosleep not enable.");
+        return -1;
+    }
+
+    if(name != NULL && len < 127)
+    {
+        int i;
+        for(i=0;i<512;i++)
+        {
+            if(ql_lock_name[i].fd == 0)
+                break;
+        }
+        memcpy(ql_lock_name[i].name, name, strlen(name)+1);
+        ql_lock_name[i].fd = i;
+        return ql_lock_name[i].fd;
+    }
+    else
+        return -1;
+}
+
+extern int Ql_SLP_WakeLock_Lock(int fd)
+{
+    if(!autosleep_enable) {
+        LOGE("Autosleep not enable.");
+        return -1;
+    }
+
+    int i;
+    for(i=0;i<512;i++)
+    {
+        if(ql_lock_name[i].fd == fd)
+            break;
+    }
+    if(i == 512)
+        return -1;
+
+    if(!access("/sys/power/wake_lock", W_OK))
+    {
+        char cmd[128]={0};
+        sprintf(cmd, "echo %s > /sys/power/wake_lock", ql_lock_name[i].name);
+        system(cmd);
+        return 0;
+    }
+    else
+    {
+        printf("/sys/power/wake_lock can not write.");
+        return -1;
+    }
+}
+
+extern int Ql_SLP_WakeLock_Unlock(int fd)
+{
+    if(!autosleep_enable) {
+        LOGE("Autosleep not enable.");
+        return -1;
+    }
+
+    int i;
+    for(i=0;i<512;i++)
+    {
+        if(ql_lock_name[i].fd == fd)
+            break;
+    }
+    if(i == 512)
+        return -1;
+
+    if(!access("/sys/power/wake_unlock", W_OK))
+    {
+        char cmd[128]={0};
+        sprintf(cmd, "echo %s > /sys/power/wake_unlock", ql_lock_name[i].name);
+        system(cmd);
+        return 0;
+    }
+    else
+    {
+        printf("/sys/power/wake_unlock can not write.");
+        return -1;
+    }
+
+}
+
+extern int Ql_SLP_WakeLock_Destroy(int fd)
+{
+    if(!autosleep_enable) {
+        LOGE("Autosleep not enable.");
+        return -1;
+    }
+
+    int i;
+    for(i=0;i<512;i++)
+    {
+        if(ql_lock_name[i].fd == fd)
+        break;
+    }
+    if(i == 512)
+        return -1;
+    else
+    {
+        ql_lock_name[i].fd = 0;
+        memset(ql_lock_name[i].name, 0, 128);
+        return 0;
+    }
+}
+
diff --git a/mbtk/libql_lib_v2/src/ql_sms.c b/mbtk/libql_lib_v2/src/ql_sms.c
new file mode 100755
index 0000000..cbad623
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_sms.c
@@ -0,0 +1,493 @@
+//#include "lynq/lynq_sms_api.h"

+#include "mbtk_info_api.h"

+#include "mbtk_pdu_sms.h"

+#include "ql/ql_sms.h"

+

+

+#include <stdio.h>

+#include <stdlib.h>

+

+

+#define TELEPHONE_NUM_MAX 16

+#define MSM_NUMBER_MAX 1024+1

+#define RES_NUM_MIN 128

+

+#define DSC_to_msg(DSC) (DSC == 0 ? "Bit7" : (DSC == 1 ? "Bit8" : "UCS2"))

+

+static mbtk_info_handle_t* info_handle = NULL;

+static char center_address[15] = {0};

+

+

+// 编码后短信

+

+#if 0

+struct PDUS {

+    unsigned int count;

+    char **PDU;

+};

+#endif

+

+void lynq_sms_state_change_cb(const void* data, int data_len)

+{

+	LOGV("sms_state_change_cb()----------start\n");

+	uint8 *ptr = (uint8*)data;

+		printf("3sms_state_change_cb() : %s\n", ptr);

+

+	struct SMS_Struct s = PDUDecoding(ptr);

+	printf("服务中心地址: %s\n", s.SCA);

+	printf("发送方地址: %s\n", s.OA);

+	printf("服务中心时间戳: %s\n", s.SCTS);

+	printf("消息内容: %s\n", s.UD);

+	printf("数据编码方案: %s\n", DSC_to_msg(s.DCS));

+}

+

+

+QL_SMS_ERROR_CODE ql_sms_init()

+{

+    if(info_handle == NULL)

+    {

+        info_handle = mbtk_info_handle_get();

+        if(info_handle)

+        {

+			printf("creat info_handle is success\n");

+        }

+		else{

+			printf("creat info_handle is fail\n");

+			return QL_SMS_GENERIC_FAILURE;

+		}

+    }

+

+    return QL_SMS_SUCCESS;

+}

+

+

+QL_SMS_ERROR_CODE ql_sms_release()

+{

+    int ret = QL_SMS_SUCCESS;

+    if(info_handle)

+    {

+        ret = mbtk_info_handle_free(&info_handle);

+    }

+    else

+    {

+        ret = QL_SMS_GENERIC_FAILURE;

+    }

+

+    return ret;

+}

+

+

+/*

+*AT+CMGS="10086", CMGS TEST 				  // Send a SMS

+> CMGS TEST

++CMGS: 17

+OK

+*/

+/*

+int charset: send sms mode

+	 0:pdu, 1:text

+

+*/

+//当state 设置为 0(pdu)模式时,telephony_num应该设置为pud 数据大小的长度;msg:为pud 数据

+

+QL_SMS_ERROR_CODE ql_sms_send_pdu_msg(uint8_t *phone_num,uint8_t *data,int sms_type)

+{

+    if(info_handle == NULL || phone_num == NULL || data == NULL)

+    {

+        return -1;

+    }

+

+    char cmgs[MSM_NUMBER_MAX] = {0};

+    char resp[RES_NUM_MIN] = {0};

+    char pdu_data[512] = {0};

+    char phone_lenth[10] = {0};

+    char *p = pdu_data;

+    int mode = 0;

+    int err = 0;

+    int i = 0;

+    

+    if(strlen(data) > 512 || strlen(data) == 0 || strlen(phone_num) == 0)

+    {

+        printf("strlen(telephony_num):%d\n", strlen(phone_num));

+        printf("strlen(msg):%d\n", strlen(data));

+        return -1;

+    }

+

+    memset(center_address, 0, sizeof(center_address));

+    memcpy(center_address, "+8613800280500", strlen("+8613800280500"));

+

+    printf("phone_num:%s\n", phone_num);

+    printf("center_address:%s\n", center_address);

+    printf("data:%s\n", data);

+

+

+    mode = 0;   // PDU

+

+    char* pdu = NULL;

+        char* smsc = SCAEncoding(center_address);

+    struct PDUS *pdus = PDUEncoding(center_address,phone_num, data, NULL);

+

+    for (i = 0; i < pdus->count; i++) {

+         printf("第 %d 条:\n", i + 1);

+         printf("%s\n", pdus->PDU[i]);

+        pdu = pdus->PDU[i];

+    }

+

+    sprintf(p, "%s",smsc);

+    printf("pdu_data:%s\n", pdu_data);

+    sprintf(p+strlen(p), "%s", pdu);

+    printf("pdu_data:%s\n",pdu_data);

+

+

+    err = mbtk_sms_cmgf_set(info_handle, mode);

+    if(err) {

+       printf("cmgf set error : %d\n", err);

+    } else {

+       printf("cmgf set success\n");

+    }

+

+    sprintf(cmgs,"%d,%s",strlen(pdu_data), pdu_data);

+    printf("cmgs:%s\n", cmgs);

+

+    memset(resp, 0, sizeof(resp));

+

+    err = mbtk_sms_cmgs_set(info_handle, cmgs, resp);

+    if(err) {

+        printf("Error : %d\n", err);

+        return -1;

+    } else {

+        printf("cmgs set success . resp:%s\n", resp);

+    }

+

+    return 0;

+

+}

+QL_SMS_ERROR_CODE ql_sms_send_text_msg(uint8_t *phone_num,uint8_t *data,int sms_type)

+{

+    if(info_handle == NULL || phone_num == NULL || data == NULL)

+    {

+        return -1;

+    }

+

+    char cmgs[MSM_NUMBER_MAX] = {0};

+    char resp[RES_NUM_MIN] = {0};

+    int mode = 0;

+    int err = 0;

+    if(strlen(data) > 512 || strlen(data) == 0 || strlen(phone_num) == 0)

+    {

+        printf("strlen(telephony_num):%d\n", strlen(phone_num));

+        printf("strlen(msg):%d\n", strlen(data));

+        return -1;

+    }

+

+    mode = 1;   // text

+

+    err = mbtk_sms_cmgf_set(info_handle, mode);

+    if(err) {

+       printf("cmgf set error : %d\n", err);

+    } else {

+       printf("cmgf set success\n");

+    }

+

+    sprintf(cmgs,"%s,%s",phone_num, data);

+    printf("cmgs:%s\n", cmgs);

+

+/*  char *ptr = strstr(cmd, "cmgs,");      //CMGS="10086",hf

+    if(ptr != NULL)

+    {

+        ptr = strstr(cmd, ",");

+        ptr++;

+        memset(cmgs, 0, sizeof(cmgs));

+        memcpy(cmgs, ptr, strlen(ptr));

+        printf("1cmgs:%s, strlen(cmgs):%d\n", cmgs, strlen(cmgs));

+    }

+*/

+

+    memset(resp, 0, sizeof(resp));

+

+    err = mbtk_sms_cmgs_set(info_handle, cmgs, resp);

+    if(err) {

+        printf("Error : %d\n", err);

+        return -1;

+    } else {

+        printf("cmgs set success . resp:%s\n", resp);

+    }

+

+    return 0;

+

+}

+

+

+QL_SMS_ERROR_CODE ql_sms_add_event_handler(QL_SMS_StatusIndMsgHandlerFunc_t handlerPtr, void* contextPtr)

+{

+    if(info_handle == NULL)

+    {

+        return QL_SMS_GENERIC_FAILURE;

+    }

+

+	int ret = mbtk_sms_cnmi_set(info_handle);

+	if(ret)

+	{

+		printf("set cnmi fail\n");

+		return QL_SMS_GENERIC_FAILURE;

+	}

+

+	mbtk_sms_state_change_cb_reg(info_handle, lynq_sms_state_change_cb);

+	return QL_SMS_SUCCESS;

+}

+

+

+/*

+	AT+CMGD=<index>[,<delflag>]

+

+	Deletes message based on index

+	node:

+		index is -1, delete all message

+		delflag set 4

+*/

+

+QL_SMS_ERROR_CODE ql_sms_delete_msg(size_t index)

+{

+    char cmgd[128] = {0};

+    int err = 0;

+

+    if(index == -1)		//delete all

+    {

+    	memcpy(cmgd, ",4", strlen(",4"));

+    }

+    else

+    {

+    	sprintf(cmgd,"%d",index);

+    }

+

+    printf("cmgd:%s\n", cmgd);

+

+    err = mbtk_sms_cmgd_set(info_handle, cmgd);

+    if(err) {

+    	printf("lynq_delete_sms Error : %d\n", err);

+    	return -1;

+    } else {

+    	printf("lynq_delete_sms set success\n");

+    }

+

+    return 0;

+

+}

+

+

+QL_SMS_ERROR_CODE ql_search_sms_text_message(int index, recvmessage* payload)

+{

+    if(info_handle == NULL)

+    {

+        return -1;

+    }

+

+    char cmgs[MSM_NUMBER_MAX] = {0};

+    int mode = 1;   // text

+    int err = 0;

+    char *data = "ALL";

+

+    err = mbtk_sms_cmgf_set(info_handle, mode);

+    if(err) {

+       printf("cmgf set error : %d\n", err);

+    } else {

+       printf("cmgf set success\n");

+    }

+

+

+    char cmgl[128] = {0};

+    char resp[1024+1] ={0};

+    sprintf(cmgl,"%d,%s", index, data);

+/*

+    char *ptr = strstr(cmd, "cmgl,");  //  AT+CMGL[=<stat>]

+    if(ptr != NULL)

+    {

+        ptr = strstr(cmd, ",");

+        ptr++;

+        memset(cmgl, 0, sizeof(cmgl));

+        memcpy(cmgl, ptr, strlen(ptr));

+        printf("0cmgl:%s\n", cmgl);

+    }

+*/

+    memset(resp, 0, sizeof(resp));

+    err = mbtk_sms_cmgl_set(info_handle, cmgl, resp);

+    if(err) {

+        printf("lynq_list_sms Error : %d\n", err);

+        return -1;

+    } else {

+        printf("cmgl set success, reg:%s\n",resp);

+    }

+

+    return 0;

+

+}

+QL_SMS_ERROR_CODE ql_search_sms_pdu_message(int index, recvmessage* payload)

+{

+    if(info_handle == NULL)

+    {

+        return -1;

+    }

+

+    char cmgs[MSM_NUMBER_MAX] = {0};

+    int mode = 0;   // pud

+    int err = 0;

+    char *data = "ALL";

+

+

+    err = mbtk_sms_cmgf_set(info_handle, mode);

+    if(err) {

+       printf("cmgf set error : %d\n", err);

+    } else {

+       printf("cmgf set success\n");

+    }

+

+

+    char cmgl[128] = {0};

+    char resp[1024+1] ={0};

+    sprintf(cmgl,"%d,%s", index, data);

+/*

+    char *ptr = strstr(cmd, "cmgl,");  //  AT+CMGL[=<stat>]

+    if(ptr != NULL)

+    {

+        ptr = strstr(cmd, ",");

+        ptr++;

+        memset(cmgl, 0, sizeof(cmgl));

+        memcpy(cmgl, ptr, strlen(ptr));

+        printf("0cmgl:%s\n", cmgl);

+    }

+*/

+    memset(resp, 0, sizeof(resp));

+    err = mbtk_sms_cmgl_set(info_handle, cmgl, resp);

+    if(err) {

+        printf("lynq_list_sms Error : %d\n", err);

+        return -1;

+    } else {

+        printf("cmgl set success, reg:%s\n",resp);

+    }

+

+    return 0;

+

+}

+

+

+/*

+function: lynq_list_sms

+stat:0:pud, 1:text

+index: 0, list index;

+	  > 0,

+

+*/

+QL_SMS_ERROR_CODE ql_sms_list_sms(int stat, int index, char *data)

+{

+    if(info_handle == NULL)

+    {

+        return -1;

+    }

+

+	char cmgs[MSM_NUMBER_MAX] = {0};

+	int mode = 0;

+	int err = 0;

+

+	if(stat)	// text

+	{

+		mode = 1;

+	}

+

+	err = mbtk_sms_cmgf_set(info_handle, mode);

+	if(err) {

+	   printf("cmgf set error : %d\n", err);

+	} else {

+	   printf("cmgf set success\n");

+	}

+

+

+	char cmgl[128] = {0};

+	char resp[1024+1] ={0};

+	sprintf(cmgl,"%d,%s", index, data);

+/*

+	char *ptr = strstr(cmd, "cmgl,");  //  AT+CMGL[=<stat>]

+	if(ptr != NULL)

+	{

+		ptr = strstr(cmd, ",");

+		ptr++;

+		memset(cmgl, 0, sizeof(cmgl));

+		memcpy(cmgl, ptr, strlen(ptr));

+		printf("0cmgl:%s\n", cmgl);

+	}

+*/

+	memset(resp, 0, sizeof(resp));

+	err = mbtk_sms_cmgl_set(info_handle, cmgl, resp);

+	if(err) {

+		printf("lynq_list_sms Error : %d\n", err);

+		return -1;

+	} else {

+	    printf("cmgl set success, reg:%s\n",resp);

+	}

+

+	return 0;

+}

+

+

+

+int ql_sms_query_sms_storage_status(void)

+{

+	char mem[128] = {0};

+	int err = mbtk_sms_cpms_get(info_handle, mem);

+    if(err) {

+        printf("cpms query is fail Error : %d\n", err);

+		return -1;

+    } else {

+        printf("cpms query is success : %s\n", mem);

+    }

+

+	return 0;

+}

+

+QL_SMS_ERROR_CODE ql_sms_get_sms_center_address(uint8_t *sms_center_addree)

+{

+	char csca[128] = {0};

+	if(info_handle == NULL || sms_center_addree == NULL)

+    {

+		return QL_SMS_GENERIC_FAILURE;

+	}

+

+	int err = mbtk_sms_csca_get(info_handle, sms_center_addree);

+	if(err) {

+		printf("lynq_get_smsc_address Error : %d\n", err);

+		return QL_GET_RESPONSE_ERROR;

+	} else {

+		printf("lynq_get_smsc_address success\n");

+	}

+

+	return 0;

+}

+

+

+QL_SMS_ERROR_CODE ql_sms_set_sms_center_address(unsigned char *destNum)

+{

+    printf("1destNum:%s\n", destNum);

+    memset(center_address, 0, sizeof(center_address));

+        memcpy(center_address, destNum, strlen(destNum));

+	if(info_handle == NULL || destNum == NULL)

+	{

+		return -1;

+	}

+

+	int err = mbtk_sms_csca_set(info_handle, destNum);

+	if(err) {

+		printf("Error : %d\n", err);

+		return err;

+	} else {

+    //    memset(center_address, 0, sizeof(center_address));

+    //    memcpy(center_address, destNum, strlen(destNum));

+        printf("destNum:%s\n", destNum);

+		printf("lynq_set_smsc_address success\n");

+	}

+	return 0;

+

+}

+

+

+

+

+

diff --git a/mbtk/libql_lib_v2/src/ql_spi.c b/mbtk/libql_lib_v2/src/ql_spi.c
new file mode 100755
index 0000000..4fc5d9f
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_spi.c
@@ -0,0 +1,342 @@
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+#include <errno.h>
+
+#include "ql/ql_spi.h"
+#include "mbtk_log.h"
+
+#if 0
+static const char *device = "/dev/spidev1.0\0";
+static uint8_t mode = 3; /* SPI通信使用全双工,设置CPOL=0,CPHA=0。 */
+static uint8_t bits = 8; /* 8bits读写,MSB first。*/
+static uint32_t speed = 100 * 1000;/* 设置0.5M传输速度 */
+static uint16_t delay = 500;
+
+int SPI_Transfer(const uint8_t *TxBuf, uint8_t *RxBuf, int len)
+{
+    int ret;
+    int fd = g_SPI_Fd;
+
+
+    struct spi_ioc_transfer tr ;
+    memset(&tr,0x00,sizeof(tr));
+    tr.tx_buf = (unsigned long) TxBuf,
+    tr.rx_buf = (unsigned long) RxBuf,
+    tr.len =len,
+    tr.delay_usecs = delay;
+    tr.speed_hz=speed;
+    tr.bits_per_word=bits;
+    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+    if (ret < 1)
+    {
+        printf("can't send spi message");
+    }
+   else
+   {
+        //printf("Send spi message OK %d\n",RxBuf[0]);
+   }
+   return 1;
+}
+
+/**
+* 功 能:关闭SPI模块
+*/
+int SPI_Close(void)
+{
+    int fd = g_SPI_Fd;
+
+
+    if (fd == 0) /* SPI是否已经打开*/
+    return 0;
+    close(fd);
+    g_SPI_Fd = 0;
+
+
+    return 0;
+}
+
+int SPI_Write(uint8_t *TxBuf, int len)
+{
+    int ret;
+    int fd = g_SPI_Fd;
+
+    printf("fd : %d\n",fd);
+    ret = write(fd, TxBuf, len);
+    if (ret < 0)
+    printf("SPI Write errorn");
+
+    return ret;
+}
+
+int SPI_Open(void)
+{
+    int fd;
+    int ret = 0;
+
+	printf("open spi dev:%s \r\n", device);
+    fd = open(device, O_RDWR);
+    if (fd < 0)
+	{
+        	printf("can't open device \n");
+		return -1;
+	}
+    else
+        printf("SPI - Open Succeed. Start Init SPI...n\n");
+
+    /*
+    * spi mode
+    */
+    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+    if (ret == -1)
+    printf("can't set spi mode\n");
+
+
+    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+    if (ret == -1)
+    printf("can't get spi mode\n");
+
+
+    /*
+    * bits per word
+    */
+    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
+    if (ret == -1)
+      printf("can't set bits per word\n");
+
+
+    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
+    if (ret == -1)
+      printf("can't get bits per word\n");
+
+
+    /*
+    * max speed hz
+    */
+    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+    if (ret == -1)
+    printf("can't set max speed hz\n");
+
+
+    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
+    if (ret == -1)
+        printf("can't get max speed hz\n");
+
+    g_SPI_Fd=fd;
+    return ret;
+}
+#endif
+
+/**
+ * Function:  Ql_SPI_Init
+ * Description: spi init
+ * Parameters:  dev_name---device name
+ *              mode---spi mode
+ *              bits---spi per word
+ *              speed---spi transfer clock
+ * Return: spi fd
+ **/
+int Ql_SPI_Init(const char *dev_name, SPI_MODE mode, unsigned char bits, SPI_SPEED speed)
+{
+    int fd;
+    int ret = 0;
+
+	LOGD("open spi dev:%s.", dev_name);
+    fd = open(dev_name, O_RDWR);
+    if (fd < 0)
+	{
+        LOGE("can't open device, errno - %d", errno);
+        return -1;
+	}
+    else
+        LOGD("SPI - Open Succeed. Start Init SPI...");
+
+    /*
+    * spi mode
+    */
+    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+    if (ret == -1) {
+        LOGE("can't set spi mode");
+        goto error;
+    }
+
+#if 0
+    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+    if (ret == -1) {
+        LOGE("can't get spi mode");
+        goto error;
+    }
+#endif
+
+    /*
+    * bits per word
+    */
+    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
+    if (ret == -1) {
+        LOGE("can't set bits per word");
+        goto error;
+    }
+
+#if 0
+    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
+    if (ret == -1) {
+        LOGE("can't get bits per word");
+        goto error;
+    }
+#endif
+
+    /*
+    * max speed hz
+    */
+    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+    if (ret == -1) {
+        LOGE("can't set max speed hz");
+        goto error;
+    }
+
+#if 0
+    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
+    if (ret == -1) {
+        LOGE("can't get max speed hz");
+        goto error;
+    }
+#endif
+
+    return fd;
+error:
+    if(fd > 0)
+    {
+        close(fd);
+    }
+    return -1;
+}
+
+/**
+ * Function: Ql_SPI_DeInit
+ * Description: spi deinit
+ * Parameters: fd---spi fd
+ * Return:
+ */
+int Ql_SPI_DeInit(int fd)
+{
+    if (fd <= 0)
+        return -1;
+
+    close(fd);
+    return 0;
+}
+
+/**
+ * Function: Ql_SPI_Write_Read
+ * Description: spi write read function
+ * Parameters: fd---spi fd
+ *              w_buf---write buffer
+ *              r_buf---read buffer
+ *              len---spi transfer length
+ * Return: 0---transfer success
+ *          other---failed
+ **/
+int Ql_SPI_Write_Read(int fd, unsigned char *w_buf, unsigned char *r_buf, unsigned int len)
+{
+    int ret;
+    struct spi_ioc_transfer tr ;
+    memset(&tr,0x00,sizeof(tr));
+    tr.tx_buf = (unsigned long) w_buf,
+    tr.rx_buf = (unsigned long) r_buf,
+    tr.len =len,
+    tr.delay_usecs = 500;
+    //tr.speed_hz=speed;
+    //tr.bits_per_word=bits;
+    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+    if (ret < 1)
+    {
+        LOGE("can't send spi message");
+        return -1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+
+#if 0
+int main(int argc, char *argv[])
+{
+
+	char send_data[64] = {0};
+	char read_data[64] = {0};
+	char crc = 0;
+	int i = 0;
+	int j = 0;
+
+    system("echo PB6 > /sys/kernel/debug/sunxi_pinctrl/sunxi_pin");
+    system("echo PB6 1 > /sys/kernel/debug/sunxi_pinctrl/function");
+    system("echo PB6 0 > /sys/kernel/debug/sunxi_pinctrl/data");
+
+	/* spi 初始化程序 */
+	SPI_Open();
+
+	send_data[0] = 0x55;
+	send_data[1] = 0x00;
+	send_data[2] = 0x84;
+	send_data[3] = 0x00;
+	send_data[4] = 0x08;
+	send_data[5] = 0x00;
+	send_data[6] = 0x00;
+
+	crc = send_data[1];
+	for (i = 2; i < 7; i++)
+	{
+		crc ^= send_data[i];
+	}
+	crc = ~crc;
+
+	send_data[7] = crc;
+
+	printf("send data:");
+	for (i = 0; i < 8; i++)
+	{
+		printf("%#x, ", send_data[i]);
+	}
+	printf("\n");
+
+	/* spi 发送数据 */
+	SPI_Transfer(send_data,read_data,8);
+
+	printf("read data:");
+	for (j = 0; j < 20; j++)
+	{
+		printf("%#x, ", read_data[j]);
+	}
+
+	usleep(10000);
+
+
+	memset(read_data, 0, sizeof(read_data));
+	memset(send_data, 0, sizeof(send_data));
+
+	/* spi 读取数据 */
+	SPI_Transfer(send_data,read_data,16);
+
+	printf("read data:");
+	for (j = 0; j < 20; j++)
+	{
+		printf("%#x, ", read_data[j]);
+	}
+
+	return 0;
+}
+#endif
diff --git a/mbtk/libql_lib_v2/src/ql_uart.c b/mbtk/libql_lib_v2/src/ql_uart.c
new file mode 100755
index 0000000..ca6f779
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_uart.c
@@ -0,0 +1,432 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "mbtk_log.h"
+#include "ql/ql_uart.h"
+
+int Ql_UART_Open(const char* port, Enum_BaudRate baudrate, Enum_FlowCtrl flowctrl)
+{
+    int fd;
+    if((fd = open(port, O_RDWR | O_NOCTTY)) < 0)
+    {
+        LOGE("open %s failed - %d", port, errno);
+        return -1;
+    }
+
+    LOGD("Open %s success.", port);
+
+    /* set newtio */
+    struct termios newtio;
+    memset(&newtio, 0, sizeof(newtio));
+    if (tcflush(fd, TCIOFLUSH) < 0) {
+        LOGE("Could not flush uart port");
+        return -1;
+    }
+
+    newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
+    newtio.c_cc[VMIN]      = 0;   /* blocking read until 5 chars received */
+
+    if(flowctrl == FC_RTSCTS) {
+        newtio.c_cflag |= CRTSCTS;
+    } else if(flowctrl == FC_XONXOFF) {
+        newtio.c_cflag |= (IXON | IXOFF);
+    } else {
+        // newtio.c_cflag |= CRTSCTS;
+    }
+        /* c_iflag 输入模式 */
+    newtio.c_iflag &= ~(ICRNL |  INLCR);
+    newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
+
+    // /* c_lflag 本地模式 */
+    newtio.c_cflag &= ~ INPCK;
+    newtio.c_cflag |= (CLOCAL |  CREAD);
+
+    // /* c_lflag 本地模式 */
+    newtio.c_lflag &= ~(ICANON | ECHO | ECHOE |  ISIG);
+    /* c_oflag 输出模式 */
+    newtio.c_oflag &= ~ OPOST;
+    newtio.c_oflag &= ~(ONLCR | OCRNL);
+
+    /* c_cflag 控制模式 */
+    newtio.c_cflag &= ~ CSIZE;
+    newtio.c_cflag |=  CS8;
+    newtio.c_cflag &= ~ CSTOPB;
+    newtio.c_cflag &= ~ PARENB;
+
+    switch(baudrate)
+    {
+        case B_300:
+            cfsetospeed(&newtio, B300);
+            cfsetispeed(&newtio, B300);
+            break;
+        case B_600:
+            cfsetospeed(&newtio, B600);
+            cfsetispeed(&newtio, B600);
+            break;
+        case B_1200:
+            cfsetospeed(&newtio, B1200);
+            cfsetispeed(&newtio, B1200);
+            break;
+        case B_2400:
+            cfsetospeed(&newtio, B2400);
+            cfsetispeed(&newtio, B2400);
+            break;
+        case B_4800:
+            cfsetospeed(&newtio, B4800);
+            cfsetispeed(&newtio, B4800);
+            break;
+        case B_9600:
+            cfsetospeed(&newtio, B9600);
+            cfsetispeed(&newtio, B9600);
+            break;
+        case B_19200:
+            cfsetospeed(&newtio, B19200);
+            cfsetispeed(&newtio, B19200);
+            break;
+        case B_38400:
+            cfsetospeed(&newtio, B38400);
+            cfsetispeed(&newtio, B38400);
+            break;
+        case B_57600:
+            cfsetospeed(&newtio, B57600);
+            cfsetispeed(&newtio, B57600);
+            break;
+        case B_115200:
+            cfsetospeed(&newtio, B115200);
+            cfsetispeed(&newtio, B115200);
+            break;
+        case B_230400:
+            cfsetospeed(&newtio, B230400);
+            cfsetispeed(&newtio, B230400);
+            break;
+        case B_460800:
+            cfsetospeed(&newtio, B460800);
+            cfsetispeed(&newtio, B460800);
+            break;
+        case B_921600:
+            cfsetospeed(&newtio, B921600);
+            cfsetispeed(&newtio, B921600);
+            break;
+        case B_3000000:
+            cfsetospeed(&newtio, B3000000);
+            cfsetispeed(&newtio, B3000000);
+            break;
+        case B_4000000:
+            cfsetospeed(&newtio, B4000000);
+            cfsetispeed(&newtio, B4000000);
+            break;
+        default:
+            cfsetospeed(&newtio, B115200);
+            cfsetispeed(&newtio, B115200);
+            break;
+    }
+
+    if (tcsetattr(fd, TCSANOW, &newtio) < 0) {
+        LOGE("Can't set port setting");
+        return -1;
+    }
+    /* Blocking behavior */
+    fcntl(fd, F_SETFL, 0);
+
+    return fd;
+}
+
+int Ql_UART_Read(int fd, char* buf, unsigned int buf_len)
+{
+    return read(fd, buf, buf_len);
+}
+
+
+int Ql_UART_Write(int fd, const char* buf, unsigned int buf_len)
+{
+    return write(fd, buf, buf_len);
+}
+
+
+int Ql_UART_SetDCB(int fd, ST_UARTDCB *dcb)
+{
+    struct termios newtio;
+    memset(&newtio, 0, sizeof(newtio));
+
+    if(tcgetattr(fd, &newtio) != 0)
+    {
+        LOGE("Serial port configuration backup errno");
+        return -1;
+    }
+
+    switch(dcb->baudrate)
+    {
+        case B_300:
+            cfsetospeed(&newtio, B300);
+            cfsetispeed(&newtio, B300);
+            break;
+        case B_600:
+            cfsetospeed(&newtio, B600);
+            cfsetispeed(&newtio, B600);
+            break;
+        case B_1200:
+            cfsetospeed(&newtio, B1200);
+            cfsetispeed(&newtio, B1200);
+            break;
+        case B_2400:
+            cfsetospeed(&newtio, B2400);
+            cfsetispeed(&newtio, B2400);
+            break;
+        case B_4800:
+            cfsetospeed(&newtio, B4800);
+            cfsetispeed(&newtio, B4800);
+            break;
+        case B_9600:
+            cfsetospeed(&newtio, B9600);
+            cfsetispeed(&newtio, B9600);
+            break;
+        case B_19200:
+            cfsetospeed(&newtio, B19200);
+            cfsetispeed(&newtio, B19200);
+            break;
+        case B_38400:
+            cfsetospeed(&newtio, B38400);
+            cfsetispeed(&newtio, B38400);
+            break;
+        case B_57600:
+            cfsetospeed(&newtio, B57600);
+            cfsetispeed(&newtio, B57600);
+            break;
+        case B_115200:
+            cfsetospeed(&newtio, B115200);
+            cfsetispeed(&newtio, B115200);
+            break;
+        case B_230400:
+            cfsetospeed(&newtio, B230400);
+            cfsetispeed(&newtio, B230400);
+            break;
+        case B_460800:
+            cfsetospeed(&newtio, B460800);
+            cfsetispeed(&newtio, B460800);
+            break;
+        case B_921600:
+            cfsetospeed(&newtio, B921600);
+            cfsetispeed(&newtio, B921600);
+            break;
+        case B_3000000:
+            cfsetospeed(&newtio, B3000000);
+            cfsetispeed(&newtio, B3000000);
+            break;
+        case B_4000000:
+            cfsetospeed(&newtio, B4000000);
+            cfsetispeed(&newtio, B4000000);
+            break;
+        default:
+            LOGD("No set speed.");
+            break;
+    }
+
+    switch(dcb->databit)
+    {
+        case DB_CS5:
+            newtio.c_cflag &= ~CSIZE;
+            newtio.c_cflag |= CS5;
+            break;
+        case DB_CS6:
+            newtio.c_cflag &= ~CSIZE;
+            newtio.c_cflag |= CS6;
+            break;
+        case DB_CS7:
+            newtio.c_cflag &= ~CSIZE;
+            newtio.c_cflag |= CS7;
+            break;
+        case DB_CS8:
+            newtio.c_cflag &= ~CSIZE;
+            newtio.c_cflag |= CS8;
+            break;
+        default:
+            LOGD("No set databit.");
+            break;
+    }
+
+    if(dcb->stopbit == SB_2) {
+        newtio.c_cflag |= CSTOPB;
+    } else {
+        newtio.c_cflag &= ~CSTOPB;
+    }
+
+    switch (dcb->parity)
+    {
+        case PB_ODD:// 奇校验
+            newtio.c_cflag |= PARENB;
+            newtio.c_cflag |= PARODD;
+            break;
+        case PB_EVEN:// 偶校验
+            newtio.c_cflag |= PARENB;
+            newtio.c_cflag &= ~PARODD;
+            break;
+        case PB_NONE:// 无奇偶校验
+            newtio.c_cflag &= ~PARENB;
+            break;
+        default:
+            LOGD("No set parity.");
+            break;
+    }
+
+    switch (dcb->flowctrl)
+    {
+        case FC_RTSCTS:
+            newtio.c_cflag |= CRTSCTS;
+            tcflush(fd, TCIFLUSH);
+            break;
+        case FC_XONXOFF:
+            newtio.c_iflag |= (IXON | IXOFF);
+            tcflush(fd, TCIFLUSH);
+            break;
+        case FC_NONE:
+            newtio.c_cflag &= ~CRTSCTS;
+            newtio.c_iflag &= ~(IXON | IXOFF);
+            tcflush(fd, TCIFLUSH);
+            break;
+        default:
+            LOGD("No set flow ctrl.");
+            break;
+    }
+
+    if(tcsetattr(fd, TCSANOW, &newtio) != 0)
+    {
+        LOGE("Serial port configuration backup errno");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int Ql_UART_GetDCB(int fd, ST_UARTDCB *dcb)
+{
+    struct termios newtio;
+    memset(&newtio, 0, sizeof(newtio));
+
+    if(tcgetattr(fd, &newtio) != 0)
+    {
+        LOGE("Serial port configuration backup errno");
+        return -1;
+    }
+
+    switch(cfgetispeed(&newtio))
+    {
+        case B300:
+            dcb->baudrate = B_300;
+            break;
+        case B600:
+            dcb->baudrate = B_600;
+            break;
+        case B1200:
+            dcb->baudrate = B_1200;
+            break;
+        case B2400:
+            dcb->baudrate = B_2400;
+            break;
+        case B4800:
+            dcb->baudrate = B_4800;
+            break;
+        case B9600:
+            dcb->baudrate = B_9600;
+            break;
+        case B19200:
+            dcb->baudrate = B_19200;
+            break;
+        case B38400:
+            dcb->baudrate = B_38400;
+            break;
+        case B57600:
+            dcb->baudrate = B_57600;
+            break;
+        case B115200:
+            dcb->baudrate = B_115200;
+            break;
+        case B230400:
+            dcb->baudrate = B_230400;
+            break;
+        case B460800:
+            dcb->baudrate = B_460800;
+            break;
+        case B921600:
+            dcb->baudrate = B_921600;
+            break;
+        case B3000000:
+            dcb->baudrate = B_3000000;
+            break;
+        case B4000000:
+            dcb->baudrate = B_4000000;
+            break;
+        default:
+            dcb->baudrate = B_115200;
+            break;
+    }
+
+    switch(newtio.c_cflag & CSIZE)
+    {
+        case CS5:
+            dcb->databit = DB_CS5;
+            break;
+        case CS6:
+            dcb->databit = DB_CS6;
+            break;
+        case CS7:
+            dcb->databit = DB_CS7;
+            break;
+        case CS8:
+            dcb->databit = DB_CS8;
+            break;
+        default:
+            dcb->databit = DB_CS8;
+            break;
+    }
+
+    if(newtio.c_cflag & CSTOPB) {
+        dcb->stopbit = SB_2;
+    } else {
+        dcb->stopbit = SB_1;
+    }
+
+    if(newtio.c_cflag & PARENB) { // 启用了奇偶校验
+        if(newtio.c_cflag & PARODD) {
+            dcb->parity = PB_ODD; // 奇校验
+        } else {
+            dcb->parity = PB_EVEN; // 偶校验
+        }
+    } else {
+        dcb->parity = PB_NONE;
+    }
+
+    if(newtio.c_cflag & CRTSCTS) {
+        dcb->flowctrl = FC_RTSCTS;
+    } else if(newtio.c_iflag & (IXON | IXOFF) == (IXON | IXOFF)){
+        dcb->flowctrl = FC_XONXOFF;
+    } else {
+        dcb->flowctrl = FC_NONE;
+    }
+
+    return 0;
+}
+
+
+int Ql_UART_IoCtl(int fd, unsigned int cmd, void* pValue)
+{
+    return 0;
+}
+
+
+int Ql_UART_Close(int fd)
+{
+    if (fd <= 0)
+        return -1;
+
+    close(fd);
+    return 0;
+}
+
diff --git a/mbtk/libql_lib_v2/src/ql_voice.c b/mbtk/libql_lib_v2/src/ql_voice.c
new file mode 100755
index 0000000..9df4053
--- /dev/null
+++ b/mbtk/libql_lib_v2/src/ql_voice.c
@@ -0,0 +1,229 @@
+#include "mbtk_type.h"
+#include "ql/ql_at.h"
+#include "ql/ql_vcall.h"
+#include "ql/ql_mcm_call.h"
+#include "ql/ql_voice.h"
+
+typedef struct
+{
+    int  cmdIdx;
+    char *funcName;
+} st_api_test_case;
+
+//for server test
+st_api_test_case at_api_testcases[] =
+{
+    {0,   "print_help"},
+    {1,   "QL_Voice_Call_Ecall"},
+    {2,   "QL_Voice_Call_Ecall_HangUp"},
+
+    {-1,    NULL}
+};
+
+
+voice_client_handle_type h_voice = 0;
+
+
+void print_help(void)
+{
+    int i;
+
+    printf("Supported test cases:\n");
+    for(i = 0; ; i++)
+    {
+        if(at_api_testcases[i].cmdIdx == -1)
+        {
+            break;
+        }
+        printf("%d:\t%s\n", at_api_testcases[i].cmdIdx, at_api_testcases[i].funcName);
+    }
+}
+
+static void ql_voice_call_ind_func(unsigned int ind_id,
+                                   void* ind_data,
+                                   uint32_t ind_data_len)
+{
+    if(NULL == ind_data)
+    {
+        return;
+    }
+
+    switch(ind_id)
+    {
+        case E_QL_MCM_VOICE_CALL_IND:
+        {
+            if(ind_data_len != sizeof(ql_mcm_voice_call_ind))
+            {
+                break;
+            }
+
+            ql_mcm_voice_call_ind *pVoiceCallInd = (ql_mcm_voice_call_ind*)ind_data;
+
+            char *call_state[] = {"INCOMING", "DIALING", "ALERTING", "ACTIVE", "HOLDING", "END", "WAITING"};
+
+            int i = 0;
+            for(i = 0; i < pVoiceCallInd->calls_len; i++)
+            {
+                printf("######### Call id=%d, PhoneNum:%s, event=%s!  ######\n",
+                            pVoiceCallInd->calls[i].call_id, pVoiceCallInd->calls[i].number, call_state[pVoiceCallInd->calls[i].state]);
+            }
+
+            break;
+        }
+
+        case E_QL_MCM_VOICE_ECALL_STATUE_IND:
+        {
+            if(ind_data_len != sizeof(ql_mcm_voice_ecall_status_ind))
+            {
+                break;
+            }
+
+            ql_mcm_voice_ecall_status_ind *pEcallStatusInd
+                                           = (ql_mcm_voice_ecall_status_ind*)ind_data;
+
+            if (pEcallStatusInd->ecall_msd_tx_status_valid)
+            {
+                if (pEcallStatusInd->ecall_msd_tx_status == E_QL_MCM_VOICE_ECALL_MSD_TRANSMISSION_STATUS_SUCCESS)
+                {
+                    printf("========== Ecall status  call_id =%d ,   ecall msd tx success.\r\n", pEcallStatusInd->call_id);
+                }
+                else
+                {
+                    printf("========== Ecall status  call_id =%d ,   ecall msd tx failure.\r\n",  pEcallStatusInd->call_id);
+                }
+            }
+            else
+            {
+                printf("========== Ecall status  call_id =%d  \r\n", pEcallStatusInd->call_id);
+            }
+
+            break;
+        }
+
+        case E_QL_MCM_VOICE_UNKOWN_IND:
+        default:
+            break;
+    }
+}
+
+//"\t1 call init\n"
+QL_VOICE_ERROR_CODE ql_voice_call_init()
+{
+    int ret = 0;
+    ret = QL_Voice_Call_Client_Init(&h_voice);
+    if(ret < 0)
+    {
+        printf("QL_Voice_Call_Client_Init FAIL. ret:%d\n",ret);
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+    else{
+        printf("QL_Voice_Call_Client_Init ret = %d, with h_voice=%d\n", ret, h_voice);
+    }
+
+    return ret;
+}
+
+//"\t9 call deinit\n"
+QL_VOICE_ERROR_CODE ql_voice_call_release()
+{
+    int ret = 0;
+    ret = QL_Voice_Call_Client_Deinit(h_voice);
+    if(ret)
+    {
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+    
+    return ret;
+}
+
+//\t2 call register handle\n"
+QL_VOICE_ERROR_CODE ql_voice_call_event_register(QL_VOICE_EventHandlerFunc_t handlerPtr, void* contextPtr)
+{
+    int ret = 0;
+    ret = QL_Voice_Call_AddCommonStateHandler(h_voice, (QL_VoiceCall_CommonStateHandlerFunc_t)ql_voice_call_ind_func);
+    if(ret < 0)
+    {
+        printf("QL_Voice_Call_AddCommonStateHandler FAIL.       ret:%d\n",ret);
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+    
+    return ret;
+}
+
+/*
+    Phone call.
+     -call_num   : dst phone number
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_start(char* call_num)
+{
+    int ret = 0;
+
+    ret = QL_Voice_Call_Start(h_voice, 0, call_num, NULL);
+    if(ret)
+    {
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+    return ret;
+}
+
+
+/*
+    Put through.
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_answer()
+{
+    int ret = 0;
+    ret = QL_Voice_Call_Answer(h_voice, 0);
+    if(ret)
+    {
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+    return ret;
+}
+QL_VOICE_ERROR_CODE ql_voice_auto_answer(int seconds)
+{
+    int ret = 0;
+
+    ret = QL_Voice_Call_SetAutoAnswer(h_voice, E_QL_MCM_VOICE_AUTO_ANSWER_ENABLE, 6000);
+    if(ret)
+    {
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+    return ret;
+}
+
+/*
+    Hang up.
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_end()
+{
+    int ret = 0;
+    ret = QL_Voice_Call_End(h_voice, 0);
+    if(ret)
+    {
+        ret = QL_VOICE_GENERIC_FAILURE;
+    }
+
+    return ret;
+}
+
+
+/* hold the voice */
+QL_VOICE_ERROR_CODE ql_voice_call_hold()
+{
+    int ret = 0;
+    QL_Voice_Call_Hold(h_voice);
+
+    return ret;
+}
+
+/* unhold the voice */
+QL_VOICE_ERROR_CODE ql_voice_call_unhold()
+{
+    int ret = 0;
+
+    QL_Voice_Call_UnHold(h_voice);
+
+    return ret;
+}
+