Add toolchain and mbtk source

Change-Id: Ie12546301367ea59240bf23d5e184ad7e36e40b3
diff --git a/mbtk/Make.defines b/mbtk/Make.defines
new file mode 100755
index 0000000..a2629c4
--- /dev/null
+++ b/mbtk/Make.defines
@@ -0,0 +1,65 @@
+# Common make definitions, customized for each platform

+

+# Definitions required in all program directories to compile and link

+# C programs using gcc.

+

+# static / shared

+BUILD_LIB_TYPE = shared

+# gcc-4.9 / gcc-8.4

+BUILD_PLATFORM = gcc-4.9

+OUT_DIR = $(ROOT)/out

+BUILD_ROOT = $(ROOT)/mbtk

+BUILD_TOOLCHAIN_DIR = $(ROOT)/toolchain/$(BUILD_PLATFORM)

+LOCAL_PATH=.

+

+ifeq ($(BUILD_PLATFORM), gcc-4.9)

+CC=$(BUILD_TOOLCHAIN_DIR)/bin/arm-openwrt-linux-uclibcgnueabi-gcc

+AR=$(BUILD_TOOLCHAIN_DIR)/bin/arm-openwrt-linux-uclibcgnueabi-ar

+else ifeq ($(BUILD_PLATFORM), gcc-8.4)

+CC=$(BUILD_TOOLCHAIN_DIR)/bin/arm-openwrt-linux-gcc

+AR=$(BUILD_TOOLCHAIN_DIR)/bin/arm-openwrt-linux-ar

+else

+CC=gcc

+AR=ar

+endif

+

+MAKE=make

+

+$(info BUILD_LIB_TYPE=$(BUILD_LIB_TYPE))

+$(info BUILD_PLATFORM=$(BUILD_PLATFORM))

+$(info ROOT=$(ROOT))

+$(info CC=$(CC))

+$(info AR=$(AR))

+

+CFLAGS= --sysroot=$(BUILD_TOOLCHAIN_DIR) -Os -pipe -march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -fno-caller-saves -fhonour-copts -Wno-error=unused-but-set-variable -mfloat-abi=hard -fno-exceptions -Wno-multichar -ffunction-sections -fdata-sections -funwind-tables -Wa,--noexecstack -fno-short-enums -no-canonical-prefixes -fno-canonical-system-headers -mfpu=neon -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -mthumb-interwork -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith  -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -mthumb -fomit-frame-pointer -fno-strict-aliasing -Werror=format-security -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -ffunction-sections -Wl,--gc-sections -Wl,--no-undefined

+

+AWK=awk

+

+#CFLAGS += -Wno-error=format-truncation -Wno-error=format-overflow= -Wno-error=stringop-overread -Wno-error=deprecated-declarations

+

+INC_DIR = \

+	-I$(LOCAL_PATH)/inc \

+	-I$(BUILD_ROOT)/include \

+	-I$(BUILD_ROOT)/include/mbtk \

+	-I$(BUILD_ROOT)/include/lynq \

+	-I$(BUILD_ROOT)/include/mqtt \

+	-I$(BUILD_ROOT)/include/ql

+

+# -DCONFIG_AB_SYSTEM

+DEFINE = \

+	-DMBTK_SUPPORT \

+	-DMARVELL_EXTENDED \

+	-DPXA1826_AUDIO \

+	-D__USE_GNU \

+	-DNOT_DROPPED_FLAGS_TEST \

+	-DNDEBUG \

+	-UDEBUG \

+	-D_FORTIFY_SOURCE=2

+

+LIB_DIR = \

+	-L$(OUT_DIR)/lib

+

+LIBS = -lpthread -lstdc++

+

+# Common temp files to delete from each directory.

+TEMPFILES=core core.* *.o temp.* *.out

diff --git a/mbtk/Makefile b/mbtk/Makefile
new file mode 100755
index 0000000..d6ed12d
--- /dev/null
+++ b/mbtk/Makefile
@@ -0,0 +1,19 @@
+ROOT = $(shell pwd)/..
+include Make.defines
+
+DIRS = mbtk_lib mbtk_mqtt lynq_lib ql_lib mbtk_adbd mbtk_logd mbtk_ril test
+
+all:
+	@echo $(ROOT)
+	@echo $(CC)
+	@echo $(OUT_DIR)
+	@for i in $(DIRS); do \
+		(cd $$i && echo "making $$i" && $(MAKE) ) || exit 1; \
+	done
+	@echo "Success"
+
+clean:
+	@for i in $(DIRS); do \
+		(cd $$i && echo "Cleaning $$i" && $(MAKE) clean) || exit 1; \
+	done
+	rm -rf $(OUT_DIR)
\ No newline at end of file
diff --git a/mbtk/include/lynq/lynq_audio_api.h b/mbtk/include/lynq/lynq_audio_api.h
new file mode 100755
index 0000000..6e709dc
--- /dev/null
+++ b/mbtk/include/lynq/lynq_audio_api.h
@@ -0,0 +1,41 @@
+/*
+*
+* Data : 2022/10/27 17:26:46
+* Author : LuoJian
+*/
+#ifndef _LYNQ_AUDIO_API_H
+#define _LYNQ_AUDIO_API_H
+#include "mbtk_audio.h"
+
+//播放音频文件
+int lynq_media_play_audio(const char *path);
+
+//停止播放音频文件
+void lynq_media_stop_audio(void);
+
+//录制音频文件
+int lynq_media_rec_audio(const char *path);
+
+//停止录制音频文件
+void lynq_media_rec_stop_audio(void);
+
+//获取功放音量
+//volume (0~100)
+int lynq_get_spk_volume(int* volume);
+
+//设置功放音量。
+int lynq_set_spk_volume(const int volume);
+
+//获取麦克风音量
+int lynq_get_mic_volume(int* volume);
+
+//设置麦克风音量
+int lynq_set_mic_volume(const int volume);
+
+
+int lynq_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb);
+
+int lynq_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio);
+
+#endif /* _LYNQ_AUDIO_API_H */
+
diff --git a/mbtk/include/lynq/lynq_call_api.h b/mbtk/include/lynq/lynq_call_api.h
new file mode 100755
index 0000000..bdb9ffe
--- /dev/null
+++ b/mbtk/include/lynq/lynq_call_api.h
@@ -0,0 +1,72 @@
+/*
+*
+* Data : 2022/11/07 16:57:28
+* Author : HanZhiyu
+*/
+#include "mbtk_audio.h"
+
+typedef enum {
+    LYNQ_CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
+    LYNQ_CALL_FAIL_NORMAL = 16,
+    LYNQ_CALL_FAIL_BUSY = 17,
+    LYNQ_CALL_FAIL_CONGESTION = 34,
+    LYNQ_CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
+    LYNQ_CALL_FAIL_LYNQ_CALL_BARRED = 240,
+    LYNQ_CALL_FAIL_FDN_BLOCKED = 241,
+    LYNQ_CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
+    LYNQ_CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
+    LYNQ_CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244, /* STK LYNQ_CALL Control */
+    LYNQ_CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
+    LYNQ_CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
+    LYNQ_CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000,
+    LYNQ_CALL_FAIL_CDMA_DROP = 1001,
+    LYNQ_CALL_FAIL_CDMA_INTERCEPT = 1002,
+    LYNQ_CALL_FAIL_CDMA_REORDER = 1003,
+    LYNQ_CALL_FAIL_CDMA_SO_REJECT = 1004,
+    LYNQ_CALL_FAIL_CDMA_RETRY_ORDER = 1005,
+    LYNQ_CALL_FAIL_CDMA_ACCESS_FAILURE = 1006,
+    LYNQ_CALL_FAIL_CDMA_PREEMPTED = 1007,
+    LYNQ_CALL_FAIL_CDMA_NOT_EMERGENCY = 1008, /* For non-emergency number dialed
+                                            during emergency callback mode */
+    LYNQ_CALL_FAIL_CDMA_ACCESS_BLOCKED = 1009, /* CDMA network access probes blocked */
+    LYNQ_CALL_FAIL_ERROR_UNSPECIFIED = 0xffff
+} lynq_last_call_fail_cause_t;
+
+typedef enum{
+    AUDIO_MODE_CODEC = 0,     /* Codec */
+    AUDIO_MODE_RTP = 1,      /* RTP */
+}LYNQ_Audio_Mode;
+
+typedef enum{
+    RTP_CLIENT = 0,     /*客户端,从远端拉文件到本地播放*/
+RTP_SERVER =1,     /*服务器端,推文件到远端播放*/
+RTP_MODE_MAX
+}LYNQ_Rtp_Mode;
+
+typedef enum{
+    LYNQ_CALL_ACTIVE,
+    LYNQ_CALL_HOLDING,
+    LYNQ_CALL_DIALING,
+    LYNQ_CALL_ALERTING,
+    LYNQ_CALL_INCOMING,
+    LYNQ_CALL_WAITING,
+    LYNQ_CALL_OFFERING,
+}LYNQ_Call_State;
+
+int lynq_init_call(int uToken);
+int lynq_deinit_call(void);
+int lynq_call(int *handle, char addr[]);
+int lynq_call_answer();
+int lynq_call_hungup_all();
+int lynq_call_hungup(int *handle);
+int lynq_hangup_waiting_or_background(void);
+int lynq_switch_waiting_or_holding_and_active(void);
+int lynq_hangup_foreground_resume_background(void);
+int lynq_wait_incoming_call(void *incoming_call_cb);
+int lynq_get_mute_mic (int *status);
+int lynq_set_mute_mic(const int enable);
+int lynq_set_DTMF(const char callnum);
+int lynq_get_current_call_state(int *handle,int *call_state,int*toa,int *direction,char addr[]);
+//void lynq_audio_volume_cb(int volume);
+int lynq_set_speech_volume(const int volume);
+int lynq_get_speech_volume(int * volume);
diff --git a/mbtk/include/lynq/lynq_ecall_api.h b/mbtk/include/lynq/lynq_ecall_api.h
new file mode 100755
index 0000000..58b6e41
--- /dev/null
+++ b/mbtk/include/lynq/lynq_ecall_api.h
@@ -0,0 +1,71 @@
+#ifndef LYNQ_ECALL_H
+#define LYNQ_ECALL_H
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+
+typedef uint32 ecall_handle_type;
+
+typedef enum{
+    LYNQ_ECALL_SET_NUMBER = 0,     /* Set Number */
+    LYNQ_ECALL_SET_URI = 1,      /* Set Uri */
+}LYNQ_ECall_Set_Type;
+
+typedef enum{
+    LYNQ_EMER_CAT_MANUAL_ECALL = 0,      /* Manual Emergency eCall */
+    LYNQ_EMER_CAT_AUTO_ECALL = 1,     /*  Automatic Emergency eCall */
+}LYNQ_ECall_Category;
+
+typedef enum{
+    LYNQ_ECALL_TEST = 0,     /* Test eCall */
+    LYNQ_ECALL_EMERGENCY = 1,      /* Emergency eCall */
+    LYNQ_ECALL_RECONFIG = 2,     /*  Reconfiguration eCall */
+    LYNQ_ECALL_VAR_MAX,
+}LYNQ_ECall_Variant;
+
+typedef enum{
+    LYNQ_ECALL_SENDING_START = 1,
+    LYNQ_ECALL_SENDING_MSD = 2,
+    LYNQ_ECALL_LLACK_RECEIVED = 3,
+    LYNQ_ECALL_ALACK_POSITIVE_RECEIVED = 4,
+    LYNQ_ECALL_ALACK_CLEARDOWN_RECEIVED = 5,
+    LYNQ_ECALL_ACTIVE = 11,
+    LYNQ_ECALL_DISCONNECTED = 12,
+    LYNQ_ECALL_IMS_ACTIVE = 13,
+    LYNQ_ECALL_IMS_DISCONNECTED = 14,
+    LYNQ_ECALL_ABNORMAL_HANGUP=15,
+    LYNQ_ECALL_IMS_MSD_ACK = 20,
+    LYNQ_ECALL_IMS_UPDATE_MSD = 21,
+    LYNQ_ECALL_IMS_IN_BAND_TRANSFER = 22,
+    LYNQ_ECALL_IMS_MSD_NACK = 23,
+    LYNQ_ECALL_IMS_SRVCC = 24,
+    LYNQ_ECALL_ONLY_DEREGISTRATION = 31,
+    LYNQ_ECALL_MAY_DEREGISTER = 32,
+    LYNQ_ECALL_PSAP_CALLBACK_START = 40,
+    LYNQ_ECALL_PSAP_CALLBACK_IMS_UPDATE_MSD = 41,
+    LYNQ_ECALL_T2_TIMER_OUT = 9000,
+    LYNQ_ECALL_T5_TIMER_OUT = 9001,
+    LYNQ_ECALL_T6_TIMER_OUT = 9002,
+    LYNQ_ECALL_T7_TIMER_OUT = 9003,
+    LYNQ_ECALL_REDIAL_TIMER_OUT = 9004,
+    LYNQ_ECALL_AUTO_ANS_TIMER_OUT = 9005,
+    LYNQ_ECALL_AUTO_ANS_IMS_TIMER_OUT = 9006,
+    LYNQ_ECALL_UNSPECIFIED = 0xffff,
+}LYNQ_ECall_Indication;
+
+int lynq_ecall_init(ecall_handle_type *handle);
+int lynq_ecall_deinit(ecall_handle_type handle);
+int lynq_set_test_num(LYNQ_ECall_Set_Type type, const char *test_num, int test_num_length);
+int lynq_set_reconf_num(LYNQ_ECall_Set_Type type, const char *reconf_num, int reconf_num_length);
+int lynq_fast_ecall(int* handle,
+                    LYNQ_ECall_Category lynq_ecall_cat,
+                    LYNQ_ECall_Variant lynq_ecall_variant,
+                    const char *addr, int addr_length,
+                    const unsigned char *msd_data, int msd_length);
+int lynq_make_ecall(int* handle, LYNQ_ECall_Variant type);
+int lynq_set_msd(int* handle, const unsigned char *msd_data, int msd_length);
+int lynq_set_ivs(int enable);
+int lynq_ivs_push_msd();
+int lynq_wait_ecall_indication(int* handle, LYNQ_ECall_Indication *eCall_Indication);
+int lynq_ecall_hungup(int handle);
+
+#endif
diff --git a/mbtk/include/lynq/lynq_gnss.h b/mbtk/include/lynq/lynq_gnss.h
new file mode 100755
index 0000000..679039b
--- /dev/null
+++ b/mbtk/include/lynq/lynq_gnss.h
@@ -0,0 +1,121 @@
+#ifndef __MBTK_LYNQ_GNSS_H__
+#define __MBTK_LYNQ_GNSS_H__
+
+typedef enum
+{
+    E_LYNQ_LOC_MSG_ID_STATUS_INFO = 0,
+    E_LYNQ_LOC_MSG_ID_LOCATION_INFO,
+    E_LYNQ_LOC_MSG_ID_SV_INFO,
+    E_LYNQ_LOC_MSG_ID_NMEA_INFO,
+    E_LYNQ_LOC_MSG_ID_CAPABILITIES_INFO,
+    E_LYNQ_LOC_MSG_ID_AGPS_STATUS,
+    E_LYNQ_LOC_MSG_ID_NI_NOTIFICATION,
+    E_LYNQ_LOC_MSG_ID_XTRA_REPORT_SERVER,
+}E_LYNQ_LOC_MSG_ID_T;
+
+#define LYNQ_LOC_NMEA_MAX_LENGTH  255                 /**  NMEA string maximum length. */
+typedef struct
+{
+    int64_t     timestamp;                          /**<   System Timestamp, marked for when got the nmea data */
+    int         length;                             /**<   NMEA string length. */
+    char        nmea[LYNQ_LOC_NMEA_MAX_LENGTH + 1];   /**<   NMEA string.*/
+}LYNQ_LOC_NMEA_INFO_T;  /* Message */
+
+/* callback function register to lynq_gnss_rx_ind_msg_handler
+   e_msg_id: which kind of msg can be received depend on the bit_mask set in QL_LOC_Set_Indications;
+   pv_data: depend on the e_msg_id type.
+*/
+typedef void (*lynq_gnss_rx_ind_msg_handler_t)
+(
+    uint32  h_loc,
+    E_LYNQ_LOC_MSG_ID_T   e_msg_id,
+    void                    *pv_data,
+    void                    *contextPtr
+);
+
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_init(void);
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_deinit(void);
+
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_callback_reg(lynq_gnss_rx_ind_msg_handler_t handlerPtr);
+
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_start(void);
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_stop(void);
+
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_agps_dataconnopen(void);
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_dev_reset(void);
+
+/**
+ * @brief      function description
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int lynq_gnss_enable_glonass(void);
+
+#endif
diff --git a/mbtk/include/lynq/lynq_net_api.h b/mbtk/include/lynq/lynq_net_api.h
new file mode 100755
index 0000000..30f8837
--- /dev/null
+++ b/mbtk/include/lynq/lynq_net_api.h
@@ -0,0 +1,167 @@
+/*
+*
+* Data : 2022/10/21 16:00:28
+* Author : LiuBin
+*/
+#ifndef _LYNQ_NET_API_H
+#define _LYNQ_NET_API_H
+#include "mbtk_info_api.h"
+
+typedef enum {
+    RADIO_TECH_3GPP = 1, /* 3GPP Technologies - GSM, WCDMA */
+    RADIO_TECH_3GPP2 = 2 /* 3GPP2 Technologies - CDMA */
+} RIL_RadioTechnologyFamily;
+
+typedef struct
+{
+    int rssi;   // 0: 113 dBm or less
+                // 1: 111 dBm
+                // 2...30: 109 dBm...53 dBm
+                // 31: 51 dBm or greater
+                // 99: not known or not detectable
+    int ber;  // 0...7 as RXQUAL values in the table in 3GPP TS 45.008 [20] subclause 8.2.4
+                // 99 not known or not detectable
+    int gsm_sig_valid;
+    int rxlev;// 0:rssi < -110 dBm
+                // 1: -110 dBm <= rssi < -109 dBm
+                // 2: -109 dBm <= rssi < -108 dBm
+                // ......
+                // 61: -50 dBm <= rssi < -49 dBm
+                // 62: -49 dBm <= rssi < -48 dBm
+                // 63: -48 dBm <= rssi
+                // 99: not known or not detectable
+    int umts_sig_valid;
+    int rscp; // 0: rscp < -120 dBm
+                // 1: -120 dBm <= rscp < -119 dBm
+                // 2: -119 dBm <= rscp < -118 dBm
+                // ......
+                // 94: -27 dBm <= rscp < -26 dBm
+                // 95: -26 dBm <= rscp < -25 dBm
+                // 96: - 25 dBm <= rscp
+                // 255: not known or not detectable
+    int ecno; // 0: Ec/Io < -24 dB
+                // 1: -24 dB <= Ec/Io < -23.5 dB
+                // 2: -23.5 dB <= Ec/Io < -23 dB
+                // ......
+                // 47: -1 dB <= Ec/Io < -0.5 dB
+                // 48: -0.5 dB <= Ec/Io < 0 dB
+                // 49: 0 dB <= Ec/Io
+                // 255: not known or not detectable
+    int lte_sig_valid;
+    int rsrq; // 0: rsrq < -19.5 dB
+                // 1: -19.5 dB <= rsrq < -19 dB
+                // 2: -19 dB <= rsrq < -18.5 dB
+                // ......
+                // 32: -4 dB <= rsrq < -3.5 dB
+                // 33: -3.5 dB <= rsrq < -3 dB
+                // 34: -3 dB <= rsrq
+                // 255: not known or not detectable
+    int rsrp; // 0: rsrp < -140 dBm
+                // 1: -140 dBm <= rsrp < -139 dBm
+                // 2: -139 dBm <= rsrp < -138 dBm
+                // ......
+                // 95: -46 dBm <= rsrp < -45 dBm
+                // 96: -45 dBm <= rsrp < -44 dBm
+                // 97: -44 dBm <= rsrp
+                // 255: not known or not detectable
+} signalStrength_t;
+
+typedef enum {
+    ZONE_NUM_SOC = 0,
+    ZONE_NUM_RF
+} ZONE_NUM;
+
+int lynq_network_init(int uToken);
+
+int lynq_network_deinit(void);
+
+int lynq_get_version(char buf[]);
+
+int lynq_get_imei(char buf[]);
+
+int lynq_get_sn(char buf[]);
+
+int lynq_shutdown(char options[]);
+
+int lynq_time_set(mbtk_time_type_enum time_type, char* time_str);
+
+int lynq_get_zone_tmp(ZONE_NUM num, int *temp);
+
+int lynq_get_sim_status(int *card_status);
+
+int lynq_get_imsi(char buf[]);
+
+int lynq_get_iccid(char buf[]);
+
+int lynq_query_phone_number(char buf[]);
+
+int lynq_sim_power (int mode);
+
+int lynq_query_operater(char *OperatorFN,char *OperatorSH,char *MccMnc);
+
+int lynq_query_network_selection_mode (int *netselMode);
+
+int lynq_set_network_selection_mode(const char *mode, const char* mccmnc);
+
+int lynq_query_available_network(list_node_t** net_list);
+
+int lynq_query_registration_state(const char *type, int* regState,int *imsRegState,char * LAC,char *CID,int *netType,int * radioTechFam,int *netRejected);
+
+int lynq_query_prefferred_networktype (int *preNetType);
+
+int lynq_set_prefferred_networktype (const int preNetType);
+
+int lynq_set_band_mode(int gsm_band, int umts_band, int tdlte_band, int fddlte_band);
+
+int lynq_query_available_bandmode (int *gsm_band, int *umts_band, int *tdlte_band, int *fddlte_band);
+
+int lynq_radio_on (const int data);
+
+int lynq_query_radio_tech (int* radioTech);
+
+int lynq_solicited_signal_strength (signalStrength_t *solSigStren);
+
+int lynq_set_ims (const int ims_mode);
+
+int lynq_init_cell(void);
+
+int lynq_deinit_cell(void);
+
+int lynq_query_cell_info(int *type, list_node_t **cell_list);
+
+void lynq_set_cell_info(char *mem);
+
+/*
+* Set specific APN informations.
+*
+* cid : 2-7
+*/
+int lynq_apn_set(int cid, mbtk_ip_type_enum ip_type, const void* apn_name,
+                    const void *user_name, const void *user_pass, const void *auth);
+
+/*
+* Get current all APN informations.
+*/
+int lynq_apn_get(int *apn_num, mbtk_apn_info_t apns[]);
+
+/*
+* Start data call.
+*/
+int lynq_data_call_start(int cid, int timeout);
+
+/*
+* Stop data call.
+*/
+int lynq_data_call_stop(int cid, int timeout);
+
+/*
+* Query data call state.
+*/
+int lynq_data_call_query(int cid, mbtk_ipv4_info_t *ipv4, mbtk_ipv6_info_t *ipv6);
+
+/*
+*Get native ip and free port
+*/
+int lynq_get_ip_and_port(char *ipBuf_out,int *port,int iptype);
+
+#endif /* _LYNQ_NET_API_H */
diff --git a/mbtk/include/lynq/lynq_sms_api.h b/mbtk/include/lynq/lynq_sms_api.h
new file mode 100755
index 0000000..cedf230
--- /dev/null
+++ b/mbtk/include/lynq/lynq_sms_api.h
@@ -0,0 +1,73 @@
+#ifndef LYNQ_SMS_QPI_H

+#define LYNQ_SMS_QPI_H

+/*

+*

+* Data : 2022/11/29 

+* Author : LuoJian

+*/

+

+#include "mbtk_type.h"

+

+#define TELEPHONE_NUM_MAX 16

+#define MSM_NUMBER_MAX 1024+1

+#define RES_NUM_MIN 128

+

+

+enum EnumDCS {

+    BIT7 = 0,            // GSM ×Ö·û¼¯

+    BIT8 = 1,            // ASCII×Ö·û¼¯

+    UCS2 = 2             // Unicode ×Ö·û¼¯

+};

+

+struct PDUUDH {

+    unsigned int count;    // ÐÅÏ¢ÔªËØÊý¾Ý×Ö½ÚÊý

+    char IEI;           // ÐÅÏ¢ÔªËØ±êʶ

+    char *IED;          // ÐÅÏ¢ÔªËØÊý¾Ý

+};

+

+// Óû§Êý¾ÝÍ·

+struct UDHS {

+    int count;

+    struct PDUUDH *UDH;

+};

+

+struct SMS_Struct {

+    char *SCA;         // ·þÎñÖÐÐĵØÖ·

+    char *OA;          // ·¢ËÍ·½µØÖ·

+    char *SCTS;        // ·þÎñÖÐÐÄʱ¼ä´Á

+    struct UDHS *UDH;     // Óû§Êý¾ÝÍ·

+    char *UD;          // Óû§Êý¾Ý

+

+    bool RP;              // Ó¦´ð·¾¶

+    bool UDHI;            // Óû§Êý¾ÝÍ·±êʶ

+    bool SRI;             // ״̬±¨¸æÖ¸Ê¾

+    bool MMS;             // ¸ü¶àÐÅÏ¢·¢ËÍ

+    int MTI;              // ÐÅÏ¢ÀàÐÍָʾ

+

+    char PID;          // PID ЭÒé±êʶ

+

+    enum EnumDCS DCS;      // Êý¾Ý±àÂë·½°¸

+    bool TC;              // Îı¾Ñ¹Ëõָʾ 0£º δѹËõ 1£ºÑ¹Ëõ

+    int MC;               // ÏûÏ¢ÀàÐÍ -1£º ÎÞ 1£ºÒƶ¯Éè±¸ÌØ¶¨ÀàÐÍ 2£ºSIMÌØ¶¨ÀàÐÍ 3£ºÖÕ¶ËÉè±¸ÌØ¶¨ÀàÐÍ

+

+};

+

+extern struct SMS_Struct PDUDecoding(const char *data);

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

+

+

+

+int lynq_init_sms(int uToken);

+int lynq_deinit_sms(void);

+int lynq_delete_sms(int index);

+int lynq_wait_receive_new_sms(int *handle);

+int lynq_send_sms(char *telephony_num, int state, char *msg);

+int lynq_list_sms(int stat, int index, char *data);

+int lynq_query_sms_storage_status(void);

+

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

+

+int lynq_get_smsc_address(char *serviceNumber);

+int lynq_set_smsc_address(const char* service_num);

+

+#endif

diff --git a/mbtk/include/mbtk/mbtk_adc.h b/mbtk/include/mbtk/mbtk_adc.h
new file mode 100755
index 0000000..b0b0b5e
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_adc.h
@@ -0,0 +1,42 @@
+/*
+    MBTK ADC interface define.
+*/
+/******************************************************************************
+
+                   EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2023/4/3      b.liu    Initial version
+
+******************************************************************************/
+#ifndef __MBTK_ADC_H__
+#define __MBTK_ADC_H__
+
+/*
+* MBTK ADC define.
+*/
+typedef enum {
+    MBTK_ADC0 = 0,  /* ADC 0 */
+    MBTK_ADC1       /* ADC 1 */
+} mbtk_adc_enum;
+
+
+/*===========================================================================
+FUNCTION mbtk_adc_get
+
+DESCRIPTION:
+  Get ADC's value.
+
+PARAMETERS:
+  adc [IN]: ADC path, refer to mbtk_adc_enum.
+
+RETURN VALUE:
+  int : ADC value.
+
+===========================================================================*/
+int mbtk_adc_get(mbtk_adc_enum adc);
+
+
+#endif /* __MBTK_ADC_H__ */
+
diff --git a/mbtk/include/mbtk/mbtk_at.h b/mbtk/include/mbtk/mbtk_at.h
new file mode 100755
index 0000000..e73414d
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_at.h
@@ -0,0 +1,64 @@
+/*
+    MBTK AT header file.
+*/
+/******************************************************************************
+
+                          EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2023/4/6      b.liu    Initial version
+
+******************************************************************************/
+#ifndef __MBTK_AT__
+#define __MBTK_AT__
+
+/*===========================================================================
+FUNCTION mbtk_at_init
+
+DESCRIPTION:
+  Initial MBTK AT.
+
+PARAMETERS:
+  None.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_at_init();
+
+
+/*===========================================================================
+FUNCTION mbtk_at_deinit
+
+DESCRIPTION:
+  Deinitial MBTK AT.
+
+PARAMETERS:
+  None.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_at_deinit();
+
+/*===========================================================================
+FUNCTION mbtk_at_send
+
+DESCRIPTION:
+  Send AT command.
+
+PARAMETERS:
+  cmd [IN]: AT command.
+  rsp [OUT]: AT command response.
+  rsp_len[IN] : AT command response buffer size.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_at_send(char* cmd, char* rsp, int rsp_len);
+
+#endif /* __MBTK_AT__ */
diff --git a/mbtk/include/mbtk/mbtk_audio.h b/mbtk/include/mbtk/mbtk_audio.h
new file mode 100755
index 0000000..bdc54ee
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_audio.h
@@ -0,0 +1,208 @@
+/**
+ *   \file mbtk_audio_alsa.h
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   Audio API definition.
+ *
+ *   \Author:  wangjinshu <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2020.04.05
+ */
+
+#ifndef __MBTK_AUDIO_ALSA_H__
+#define __MBTK_AUDIO_ALSA_H__
+#include <pthread.h>
+#include "mbtk_type.h"
+
+typedef void* mbtk_audio_handle;
+typedef void(*mbtk_audio_record_cb_func)(int result, char* databuf, unsigned int len); //callback function get recording data
+typedef int(*mbtk_dtmf_cb)(char result);
+typedef int(*mbtk_volume_cb)(int result);
+typedef uint32 mbtk_audio_client_handle_type;
+
+/*
+* Audio device enum.
+*/
+typedef enum {
+    MBTK_AUTIO_TYPE_OUT = 0, /* Audio play device. */
+    MBTK_AUTIO_TYPE_IN /* Audio record device. */
+} mbtk_audio_dev_enum;
+
+/*
+* Audio running state..
+*/
+typedef enum {
+    AUDIO_NONE = -1,
+    AUDIO_STOP = 0,
+    AUDIO_OPEN = 1,
+    AUDIO_RUNNING = 2,
+    AUDIO_PAUSE = 3,
+    AUDIO_RESUME = 4
+} mbtk_audio_state_enum;
+
+
+/****************************************************************************
+*  Audio function
+***************************************************************************/
+/*===========================================================================
+FUNCTION mbtk_audio_open
+
+DESCRIPTION:
+  Initial MBTK audio interface.
+
+PARAMETERS:
+  dev [IN]: Audio device, refer for mbtk_audio_dev_enum.
+  channel [IN]: Audio channel number.
+  rate [IN]: Audio bite rate.
+  usrData [IN]: Additional data, usually specified as NULL.
+
+RETURN VALUE:
+  mbtk_audio_handle : Return audio handle if success, NULL for failure.
+
+===========================================================================*/
+mbtk_audio_handle mbtk_audio_open(mbtk_audio_dev_enum dev, int channels, int rate, void* usrData);
+
+
+/*===========================================================================
+FUNCTION mbtk_audio_play_stream
+
+DESCRIPTION:
+  Play audio stream.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+  pdata [IN]: Audio stream data.
+  len [IN]: Audio stream data length.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_play_stream(mbtk_audio_handle dev_hdl, const void* pdata, int len);
+
+
+/*===========================================================================
+FUNCTION mbtk_audio_play_file
+
+DESCRIPTION:
+  Play audio file.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+  file_fd [IN]: File descriptor to play.
+  offset [IN]: File offset.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_play_file(mbtk_audio_handle dev_hdl, int file_fd, int offset);
+
+
+/*===========================================================================
+FUNCTION mbtk_audio_record
+
+DESCRIPTION:
+  Start audio record.This function will call cb_func in the new thread to return record data.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+  cb_func [IN]: Audio record callback function.
+  cb_date [IN]: Audio record additional data,usually specified as NULL.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_record(mbtk_audio_handle dev_hdl, mbtk_audio_record_cb_func cb_func, void* cb_date);
+int mbtk_audio_play_waitend(void* hdl);
+
+/*===========================================================================
+FUNCTION mbtk_audio_pause
+
+DESCRIPTION:
+  Audio play pause.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_pause(mbtk_audio_handle dev_hdl);
+
+
+/*===========================================================================
+FUNCTION mbtk_audio_resume
+
+DESCRIPTION:
+  Audio play resume.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_resume(void* dev_hdl);
+int mbtk_audio_prepare(void* dev_hdl);
+/*===========================================================================
+FUNCTION mbtk_audio_state_get
+
+DESCRIPTION:
+  Get audio play state.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+
+RETURN VALUE:
+  mbtk_audio_state_enum : Return audio state,refer to mbtk_audio_state_enum.
+
+===========================================================================*/
+mbtk_audio_state_enum mbtk_audio_state_get(void *hdl);
+
+
+/*===========================================================================
+FUNCTION mbtk_audio_stop
+
+DESCRIPTION:
+  Stop audio play.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_stop(void* dev_hdl);
+
+
+/*===========================================================================
+FUNCTION mbtk_audio_resume
+
+DESCRIPTION:
+  Close audio handle.
+
+PARAMETERS:
+  dev_hdl [IN]: Audio handle, get by call mbtk_audio_open.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_audio_close(void* dev_hdl);
+
+
+int mbtk_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_dtmf, mbtk_dtmf_cb cb);
+int mbtk_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_dtmf);
+void mbtk_audio_ubus_volume_set(unsigned int volume);
+void mbtk_audio_ubus_volume_get(mbtk_volume_cb cb);
+int mbtk_audio_dsp_set(int type, int gain);
+
+int mbtk_audio_mp3_to_wav(const char *wavpath, char *mp3path);
+int mbtk_audio_mp3_to_play(char *mp3path, int hdl, int sample_rate);
+#endif /*__MBTK_AUDIO_ALSA_H__*/
diff --git a/mbtk/include/mbtk/mbtk_coap.h b/mbtk/include/mbtk/mbtk_coap.h
new file mode 100755
index 0000000..23827b6
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_coap.h
@@ -0,0 +1,228 @@
+/*************************************************************

+Description:

+    L620 Coap support Header file.

+Author:

+    LuoJian

+Date:

+    2018/9/16 4:26:36

+*************************************************************/

+#ifndef FEATURE_MBTK_ECOAP

+#define FEATURE_MBTK_ECOAP

+#include <ctype.h>

+#include <stdbool.h>

+

+#include "mbtk_coap_api.h"

+

+/*************************************************************

+    Constants and Macros

+*************************************************************/

+#define MBTK_COAP_DTLS_SUPPORT

+

+#define MBTK_ECOAP_NEW_MAX 128

+#define MBTK_ECOAP_OPTION_LEN 512

+#define MBTK_ECOAP_DATA_MAX 1024

+

+

+/*************************************************************

+    Definitions:enum,struct,union,class

+*************************************************************/

+

+#define MBTK_ECOAP_ERR_SUCCESS  0                 /* No error */

+#define	MBTK_ECOAP_ERR_NO_OPEN 300               /* 300 coap service is not opened. */

+#define	MBTK_ECOAP_ERR_IS_OPENED 301                /* 301 coap service is opened.*/

+#define	MBTK_ECOAP_ERR_NO_READY 302              /* 302 coap host and port not set */

+#define	MBTK_ECOAP_ERR_NET 303                   /* 303 DNS error. */

+#define	MBTK_ECOAP_ERR_SOCK_CANNOT_RST 304       /* 304 Socket can not reset. */

+#define	MBTK_ECOAP_ERR_MSG_ID 305                /* 305 Message ID error. */

+#define	MBTK_ECOAP_ERR_PAYLOAD_LENGTH 306        /* 306 Payload length error. */

+#define	MBTK_ECOAP_ERR_OPTION 307                /* 307 Potion set error. */

+#define	MBTK_ECOAP_ERR_TASK_IS_RUNING 308        /* 308 Task is runing. */

+#define	MBTK_ECOAP_ERR_UNKNOWN 350           /* 350 Unknown coap error */

+

+

+

+

+typedef enum

+{

+    MBTK_ECOAP_BLOCK_16,

+    MBTK_ECOAP_BLOCK_32,

+    MBTK_ECOAP_BLOCK_64,

+    MBTK_ECOAP_BLOCK_128,

+    MBTK_ECOAP_BLOCK_256,

+    MBTK_ECOAP_BLOCK_512,

+    MBTK_ECOAP_BLOCK_1024

+} mbtk_ecoap_option_block_e;

+

+typedef enum {

+	MBTK_ECOAP_SIG_START,

+	MBTK_ECOAP_SIG_STOP,

+    MBTK_ECOAP_SIG_SEND,

+    MBTK_ECOAP_SIG_RECV,

+    MBTK_ECOAP_SIG_DISCONNING

+} mbtk_ecoap_base_sig_enum;

+

+typedef enum

+{

+    MBTK_ECOAP_STATE_NON,

+    MBTK_ECOAP_STATE_CLOSING,

+    MBTK_ECOAP_STATE_OPENED,

+    MBTK_ECOAP_STATE_READY

+} mbtk_ecoap_state_e;

+

+typedef struct

+{

+    mbtk_ecoap_option_block_e size;

+    int number;

+    uint8 more_flag;

+} mbtk_ecoap_option_block_s;

+

+typedef struct mbtk_ecoap_option

+{

+    mbtk_coap_option_type type;

+

+    union

+    {

+        mbtk_ecoap_option_block_s opt_block;

+        mbtk_content_format_type opt_content_format;

+        uint8 opt_str[128];

+        int opt_int;

+    } opt;

+

+    struct mbtk_ecoap_option *next;

+} mbtk_ecoap_option_s;

+

+typedef struct mbtk_ecoap_option_2{

+	int optlen;

+	uint8 optVal[512+1];

+}mbtk_ecoap_opt_2;

+

+typedef struct mbtk_ecoap_option_3{

+	int optlen;

+	char optVal[512+1];

+}mbtk_ecoap_opt_3;

+

+typedef struct

+{

+    uint8 version;

+    mbtk_coap_type type;

+    mbtk_coap_code_type code;

+    int message_id;

+

+    uint8 token[8];

+    uint8 token_len;

+

+    uint8 send_count;

+

+    mbtk_ecoap_opt_2 option;

+

+    uint8 *payload;

+    int payload_len;

+}mbtk_ecoap_package_ver;

+

+

+typedef struct mbtk_ecoap_package

+{

+    uint8 send_count;

+

+    uint8 version;

+    mbtk_coap_type type;

+    mbtk_coap_code_type code;

+

+    uint8 token[8];

+    uint8 token_len;

+

+    int message_id;

+

+    mbtk_ecoap_option_s *options;

+

+    uint8 *payload;

+    int payload_len;

+

+    struct mbtk_ecoap_package *next;

+} mbtk_ecoap_package_s;

+

+typedef struct

+{

+    uint8 host[32];

+    int port;

+	int socket;

+#ifdef MBTK_COAP_DTLS_SUPPORT

+    int is_dtls;

+#endif

+    int message_id;

+} mbtk_ecoap_net_s;

+

+

+/*************************************************************

+    Extern variables

+*************************************************************/

+

+

+/*************************************************************

+    Public Function Declaration

+*************************************************************/

+int mbtk_coap_ecoapnew_exec_cmd

+(

+    char *ip_addr,

+    int port,

+    bool is_support_ssl, 

+    bool ingnore_cert

+);

+

+int mbtk_coap_ecoaprxmod_exec_cmd

+(

+	int mode

+);

+

+int mbtk_coap_ecoappr_exec_cmd

+(

+	int format

+);

+

+

+int mbtk_coap_ecoaprxget_exec_cmd

+(

+    int len

+);

+

+int mbtk_coap_ecoapver_exec_cmd

+(

+    int version

+);

+

+int mbtk_coap_ecoaptype_exec_cmd

+(

+    mbtk_coap_type type

+);

+

+int mbtk_coap_ecoapcode_exec_cmd

+(

+    mbtk_coap_code_type code

+);

+

+int mbtk_coap_ecoaptoken_exec_cmd

+(

+    char *token_buf, int len

+);

+

+int mbtk_coap_ecoapmsgid_exec_cmd

+(

+    int msg_id

+);

+

+int mbtk_coap_ecoapopt_exec_cmd

+(

+    char *value_buf, int buf_len

+);

+

+int mbtk_coap_ecoapsend_exec_cmd

+(

+    int message_id, int data_len, char *data

+);

+

+int mbtk_coap_ecoapdel_exec_cmd( int del_id );

+

+int mbtk_coap_ecoapnmi_exec_cmd( void );

+

+

+#endif /* _MBTK_COAP_L620_H */

diff --git a/mbtk/include/mbtk/mbtk_coap_api.h b/mbtk/include/mbtk/mbtk_coap_api.h
new file mode 100755
index 0000000..ac1b699
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_coap_api.h
@@ -0,0 +1,223 @@
+#ifndef MBTK_COAP_API_H

+#define MBTK_COAP_API_H

+

+#include "mbtk_type.h"

+

+// CoAP message types. Note, values only work as enum.

+typedef enum

+{

+    COAP_CONFIRMABLE=0x00,

+    COAP_NON_CONFIRMABLE=0x10,

+    COAP_ACKNOWLEDGEMENT=0x20,

+    COAP_RESET=0x30

+} mbtk_coap_type;

+

+// CoAP response codes.

+typedef enum

+{

+    COAP_EMPTY=0x00,

+    COAP_GET,

+    COAP_POST,

+    COAP_PUT,

+    COAP_DELETE,

+    COAP_LASTMETHOD=0x1F,

+    COAP_CREATED=0x41,

+    COAP_DELETED,

+    COAP_VALID,

+    COAP_CHANGED,

+    COAP_CONTENT,

+    COAP_CONTINUE=0x5F,

+    COAP_BAD_REQUEST=0x80,

+    COAP_UNAUTHORIZED,

+    COAP_BAD_OPTION,

+    COAP_FORBIDDEN,

+    COAP_NOT_FOUND,

+    COAP_METHOD_NOT_ALLOWED,

+    COAP_NOT_ACCEPTABLE,

+    COAP_PRECONDITION_FAILED=0x8C,

+    COAP_REQUEST_ENTITY_TOO_LARGE=0x8D,

+    COAP_UNSUPPORTED_CONTENT_FORMAT=0x8F,

+    COAP_INTERNAL_SERVER_ERROR=0xA0,

+    COAP_NOT_IMPLEMENTED,

+    COAP_BAD_GATEWAY,

+    COAP_SERVICE_UNAVAILABLE,

+    COAP_GATEWAY_TIMEOUT,

+    COAP_PROXYING_NOT_SUPPORTED,

+    COAP_UNDEFINED_CODE=0xFF

+} mbtk_coap_code_type;

+

+/// CoAP option numbers.

+typedef enum

+{

+    COAP_OPTION_NON=0,

+    COAP_OPTION_IF_MATCH=1,

+    COAP_OPTION_URI_HOST=3,

+    COAP_OPTION_ETAG,

+    COAP_OPTION_IF_NONE_MATCH,

+    COAP_OPTION_OBSERVE,

+    COAP_OPTION_URI_PORT,

+    COAP_OPTION_LOCATION_PATH,

+    COAP_OPTION_URI_PATH=11,

+    COAP_OPTION_CONTENT_FORMAT,

+    COAP_OPTION_MAX_AGE=14,

+    COAP_OPTION_URI_QUERY,

+    COAP_OPTION_ACCEPT=17,

+    COAP_OPTION_LOCATION_QUERY=20,

+    COAP_OPTION_BLOCK2=23,

+    COAP_OPTION_BLOCK1=27,

+    COAP_OPTION_SIZE2,

+    COAP_OPTION_PROXY_URI=35,

+    COAP_OPTION_PROXY_SCHEME=39,

+    COAP_OPTION_SIZE1=60

+} mbtk_coap_option_type;

+

+/// CoAP content-formats.

+typedef enum

+{

+    COAP_CONTENT_FORMAT_NON = -1,

+    COAP_CONTENT_FORMAT_TEXT_PLAIN = 0,

+    COAP_CONTENT_FORMAT_APP_LINK  = 40,

+    COAP_CONTENT_FORMAT_APP_XML,

+    COAP_CONTENT_FORMAT_APP_OCTET,

+    COAP_CONTENT_FORMAT_APP_EXI   = 47,

+    COAP_CONTENT_FORMAT_APP_JSON  = 50

+} mbtk_content_format_type;

+

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+extern void coapReleaseCoapPUD();

+extern int coapReset();

+extern int coapValidate();

+

+// version

+extern int coapSetVersion(uint8_t version);

+extern uint8_t coapGetVersion();

+

+// message type

+extern void coapSetType(mbtk_coap_type type);

+extern mbtk_coap_type coapGetType();

+

+// tokens

+extern int coapCoapsetTokenLength(uint8_t tokenLength);

+extern int coapGetTokenLength();

+extern uint8_t* coapGetTokenPointer();

+extern int coapSetToken(uint8_t *token, uint8_t tokenLength);

+

+// message code

+extern void coapSetCode(mbtk_coap_code_type code);

+extern mbtk_coap_code_type coapGetCode();

+extern mbtk_coap_code_type coapHttpStatusToCode(int httpStatus);

+

+// message ID

+extern int coapSetMessageID(uint16_t messageID);

+extern uint16_t coapGetMessageID();

+

+// options

+extern int coapAddOption(uint16_t optionNumber, uint16_t optionLength, uint8_t *optionValue);

+// gets a list of all options

+//extern CoapOption* getOptions();

+extern int coapGetNumOptions();

+// shorthand helpers

+extern int coapSetURI(char *uri);

+extern int coapsetURI(char *uri, int urilen);

+extern int coapGetURI(char *dst, int dstlen, int *outLen);

+extern int coapAddURIQuery(char *query);

+

+// content format helper

+extern int coapSetContentFormat(mbtk_content_format_type format);

+

+// payload

+extern uint8_t* coapMallocPayload(int bytes);

+extern int coapSetPayload(uint8_t *value, int len);

+extern uint8_t* coapGetPayloadPointer();

+extern int coapGetPayloadLength();

+extern uint8_t* coapGetPayloadCopy();

+

+// pdu

+extern int coapGetPDULength();

+extern uint8_t* coapGetPDUPointer();

+extern void coapSetPDULength(int len);

+extern int mbtk_coap_get_pdu_Length();

+

+extern void coapDeleteRecv();

+extern int coapCreateRecv(uint8_t *pdu, int pduLength);

+extern void coapPrintHuman(char * outBuffer) ;

+extern const char* coapPrintHumanByIndex(int index);

+extern const char* coapPrintHexByIndex(int index);

+extern void coapGetOptionValueById(uint16_t optionNumber, uint16_t * optionValueLength, uint8_t * optionValuePointer);

+extern uint16_t coapGetRecvMessageID();

+extern mbtk_coap_type coapGetRecvType();

+extern mbtk_coap_code_type coapGetRecvCode();

+extern int coapGetRecvTokenLength();

+extern uint8_t* coapGetRecvTokenPointer();

+extern int coapGetRecvPayloadLength();

+extern uint8_t* coapGetRecvPayloadPointer();

+uint8_t coapGetRecvVersion();

+

+// Return If-Match length,or 0 if fail.

+extern uint16_t coapGetRecvOptionIfMatch(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Uri-Host length,or 0 if fail.

+extern uint16_t coapGetRecvOptionUriHost(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return ETag length,or 0 if fail.

+extern uint16_t coapGetRecvOptionETag(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return If-None-Match length,or 0 if fail.

+extern uint16_t coapGetRecvOptionIfNoneMatch(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Location-Path length,or 0 if fail.

+extern uint16_t coapGetRecvOptionLocationPath(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Location-Query length,or 0 if fail.

+extern uint16_t coapGetRecvOptionLocationQuery(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Proxy-Uri length,or 0 if fail.

+extern uint16_t coapGetRecvOptionProxyUri(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Proxy-Scheme length,or 0 if fail.

+extern uint16_t coapGetRecvOptionProxyScheme(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Uri-Path length,or 0 if fail.

+extern uint16_t coapGetRecvOptionUriPath(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return Uri-Query length,or 0 if fail.

+extern uint16_t coapGetRecvOptionUriQuery(uint16_t *optionValueLength, uint8_t *optionValuePointer);

+

+// Return 1 if get Observe success,or 0 if fail.

+extern uint16_t coapGetRecvOptionObserve(uint16_t *observe);

+

+// Return 1 if get Max-Age success,or 0 if fail.

+extern uint16_t coapGetRecvOptionMaxAge(uint16_t *max_age);

+

+// Return 1 if get Uri-Port success,or 0 if fail.

+extern uint16_t coapGetRecvOptionUriPort(uint16_t *uri_port);

+

+// Return 1 if get Size2 success,or 0 if fail.

+extern uint16_t coapGetRecvOptionSize2(uint16_t *size2);

+

+// Return 1 if get Size1 success,or 0 if fail.

+extern uint16_t coapGetRecvOptionSize1(uint16_t *size1);

+

+// Return 1 if get Block2 success,or 0 if fail.

+extern uint16_t coapGetRecvOptionBlock2(uint32_t *number,uint8_t *more_flag,uint8_t *size);

+

+// Return 1 if get Block1 success,or 0 if fail.

+extern uint16_t coapGetRecvOptionBlock1(uint32_t *number,uint8_t *more_flag,uint8_t *size);

+

+// Return 1 if get Content-Format success,or 0 if fail.

+extern uint16_t coapGetRecvOptionContentFormat(mbtk_content_format_type *type);

+

+// Return 1 if get Accept success,or 0 if fail.

+extern uint16_t coapGetRecvOptionAccept(mbtk_content_format_type *type);

+

+extern int coapHasOption(uint16_t optionNumber );

+extern int coapPrintRecvPayload(char *out);

+#ifdef __cplusplus

+}

+#endif

+

+#endif

diff --git a/mbtk/include/mbtk/mbtk_device_info.h b/mbtk/include/mbtk/mbtk_device_info.h
new file mode 100755
index 0000000..c5e5bce
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_device_info.h
@@ -0,0 +1,18 @@
+/*
+* MBTK Device Information Define Header.
+*
+* Author : lb
+* Date   : 2021/11/5 17:40:29
+*
+*/
+#ifndef MBTK_DEVICES_INFO_H
+#define MBTK_DEVICES_INFO_H
+
+#define MBTK_DEVICES_MANUFACTURER "LYNQ"
+
+#define MBTK_DEVICES_MODEL "LYNQ_L508TLC"
+
+#define MBTK_DEVICES_REVISION "L508TLCv02.02b06.00"
+
+
+#endif /* MBTK_DEVICES_INFO_H */
diff --git a/mbtk/include/mbtk/mbtk_dhcp.h b/mbtk/include/mbtk/mbtk_dhcp.h
new file mode 100755
index 0000000..8553d43
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_dhcp.h
@@ -0,0 +1,104 @@
+/*
+* MBTK DHCP Header.
+*
+* Author : lb
+* Date   : 2021/8/20 13:38:03
+*
+*/
+#ifndef _MBTK_DHCP_H
+#define _MBTK_DHCP_H
+#include <netinet/in.h>
+
+#include "mbtk_type.h"
+
+#define PORT_BOOTP_SERVER 67
+#define PORT_BOOTP_CLIENT 68
+#define OP_BOOTREQUEST 1
+#define OP_BOOTREPLY   2
+#define FLAGS_BROADCAST 0x8000
+#define HTYPE_ETHER    1
+#define DHCP_MSG_FIXED_SIZE 236
+
+/* first four bytes of options are a cookie to indicate that
+** the payload are DHCP options as opposed to some other BOOTP
+** extension.
+*/
+#define OPT_COOKIE1          0x63
+#define OPT_COOKIE2          0x82
+#define OPT_COOKIE3          0x53
+#define OPT_COOKIE4          0x63
+
+/* BOOTP/DHCP options - see RFC 2132 */
+#define OPT_PAD              0
+
+#define OPT_SUBNET_MASK      1     /* 4 <ipaddr> */
+#define OPT_TIME_OFFSET      2     /* 4 <seconds> */
+#define OPT_GATEWAY          3     /* 4*n <ipaddr> * n */
+#define OPT_DNS              6     /* 4*n <ipaddr> * n */
+#define OPT_DOMAIN_NAME      15    /* n <domainnamestring> */
+#define OPT_BROADCAST_ADDR   28    /* 4 <ipaddr> */
+
+#define OPT_REQUESTED_IP     50    /* 4 <ipaddr> */
+#define OPT_LEASE_TIME       51    /* 4 <seconds> */
+#define OPT_MESSAGE_TYPE     53    /* 1 <msgtype> */
+#define OPT_SERVER_ID        54    /* 4 <ipaddr> */
+#define OPT_PARAMETER_LIST   55    /* n <optcode> * n */
+#define OPT_MESSAGE          56    /* n <errorstring> */
+#define OPT_CLASS_ID         60    /* n <opaque> */
+#define OPT_CLIENT_ID        61    /* n <opaque> */
+#define OPT_END              255
+
+/* DHCP message types */
+#define DHCPDISCOVER         1
+#define DHCPOFFER            2
+#define DHCPREQUEST          3
+#define DHCPDECLINE          4
+#define DHCPACK              5
+#define DHCPNAK              6
+#define DHCPRELEASE          7
+#define DHCPINFORM           8
+
+typedef unsigned long long msecs_t;
+
+typedef struct {
+    uint8_t op;           /* BOOTREQUEST / BOOTREPLY    */
+    uint8_t htype;        /* hw addr type               */
+    uint8_t hlen;         /* hw addr len                */
+    uint8_t hops;         /* client set to 0            */
+
+    uint32_t xid;         /* transaction id             */
+
+    uint16_t secs;        /* seconds since start of acq */
+    uint16_t flags;
+
+    uint32_t ciaddr;      /* client IP addr             */
+    uint32_t yiaddr;      /* your (client) IP addr      */
+    uint32_t siaddr;      /* ip addr of next server     */
+                          /* (DHCPOFFER and DHCPACK)    */
+    uint32_t giaddr;      /* relay agent IP addr        */
+
+    uint8_t chaddr[16];  /* client hw addr             */
+    char sname[64];      /* asciiz server hostname     */
+    char file[128];      /* asciiz boot file name      */
+
+    uint8_t options[1024];  /* optional parameters        */
+} dhcp_msg;
+
+typedef struct {
+    uint32_t type;
+
+    uint32_t ipaddr;
+    uint32_t gateway;
+    uint32_t prefixLength;
+
+    uint32_t dns1;
+    uint32_t dns2;
+
+    uint32_t serveraddr;
+    uint32_t lease;
+} dhcp_info;
+
+int mbtk_do_dhcp(const char *name);
+
+#endif /* _MBTK_DHCP_H */
+
diff --git a/mbtk/include/mbtk/mbtk_file.h b/mbtk/include/mbtk/mbtk_file.h
new file mode 100755
index 0000000..6d17fa1
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_file.h
@@ -0,0 +1,72 @@
+/*
+*
+*
+* Author : lb
+* Date   : 2022/3/4 16:44:14
+*
+*/
+#ifndef _MBTK_FILE_H
+#define _MBTK_FILE_H
+#include "mbtk_type.h"
+
+#ifdef MBTK_PLATFORM_LINUX
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#ifdef MBTK_PLATFORM_QCOMM
+#include "fs_public.h"
+#include "ds_profile.h"
+#include "dsati.h"
+#include "dsat_v.h"
+#include "rex.h"
+#include <stringl/stringl.h>
+#include "mbtk_9205_prod.h"
+#include "mbtk_socket_api.h"
+#endif
+
+#include "mbtk_log.h"
+
+// Return TRUE if file exist,FLASE or not.
+bool file_exist(const char *path);
+
+/*
+ * Return file descriptor if open file success, return -1 or not.
+ *
+ * flag : File open flag.
+ *  O_RDONLY 以只读方式打开文件
+ *  O_WRONLY 以只写方式打开文件
+ *  O_RDWR 以可读写方式打开文件
+ *      上述三种旗标是互斥
+ *
+ *  O_CREAT 若欲打开的文件不存在则自动建立该文件。
+ *  O_EXCL 如果 O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则
+ *      建立该文件,否则将导致打开文件错误。此外,若 O_CREAT 与 O_EXCL 同时设置,
+ *      并且欲打开的文件为符号连接,则会打开文件失败。
+ *  O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。
+ *  O_TRUNC 若文件存在并且以可写的方式打开时,此旗标会令文件长度清为 0,而原来存于该文件的资料也会消失。
+ *  O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
+ *  O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
+ *  O_NDELAY 同 O_NONBLOCK。
+ *  O_SYNC 以同步的方式打开文件。
+ *  O_NOFOLLOW 如果参数 pathname 所指的文件为一符号连接,则会令打开文件失败。
+ *  O_DIRECTORY 如果参数 pathname 所指的文件并非为一目录,则会令打开文件失败
+ */
+int file_open(const char *path, int flag);
+
+// Return file size,or -1 if get file size fail.
+int file_length(int fd);
+
+// Read data of specified length.
+int file_read(int fd, void *buf, int nbyte);
+
+// Write data of specified length.
+int file_write(int fd, void *buf, int nbyte);
+
+// Close file.
+int file_close(int fd);
+
+#endif /* _MBTK_FILE_H */
diff --git a/mbtk/include/mbtk/mbtk_ftp.h b/mbtk/include/mbtk/mbtk_ftp.h
new file mode 100755
index 0000000..0eb0a25
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_ftp.h
@@ -0,0 +1,216 @@
+/*************************************************************
+ Description:
+ MBTK FTP Protocol Head File.
+ Author:
+ LiuBin
+ Date:
+ 2020/10/28 11:49:19
+ *************************************************************/
+#ifndef _MBTK_FTP_H
+#define _MBTK_FTP_H
+
+#include "mbtk_file.h"
+#include "mbtk_sock.h"
+/*************************************************************
+ Constants and Macros
+ *************************************************************/
+#define MBTK_FTP_IP_MAX 50
+#define MBTK_FTP_FILE_NAME_MAX 50
+#define FTP_SERVICE_PORT_DEF 21
+#define FTP_SERVER_USER_NAME_MAX 30
+#define FTP_SERVER_USER_PASS_MAX FTP_SERVER_USER_NAME_MAX
+
+/*************************************************************
+ Definitions:enum,struct,union,class
+ *************************************************************/
+typedef enum
+{
+    FTP_STATE_NON,
+    FTP_STATE_CONNECTING,
+    FTP_STATE_CONNECTED, /* FTP connected. */
+    FTP_STATE_READY, /* FTP logn in success. */
+    FTP_STATE_CMD_PROCESS
+} mbtk_ftp_state_enum;
+
+typedef enum
+{
+    FTP_CMD_CONN, FTP_CMD_PORT,       // Active mode(IPV4).
+    FTP_CMD_EPRT,       // Active mode(IPV6).
+    FTP_CMD_PASV,       // Passive mode(IPV4).
+    FTP_CMD_EPSV,       // Passive mode(IPV6).
+    FTP_CMD_LIST,       // List files in current directory.
+    FTP_CMD_NLST,       // List files in current directory.
+    FTP_CMD_PWD,        // Get current directory.
+    FTP_CMD_CWD,        // Set current directory.
+    FTP_CMD_MKD,        // Create directory.
+    FTP_CMD_RMD,        // Remove directory.
+    FTP_CMD_STAT,       // Get service status.
+    FTP_CMD_TYPE,       // Set data type[A-Ascii,E-EBCDIC,I-Binary].
+    FTP_CMD_SIZE,       // Get file size.
+    FTP_CMD_DELE,       // Delete file.
+    FTP_CMD_MDTM,       // Get file modify time.
+    FTP_CMD_PUT,       // Update file.
+    FTP_CMD_GET,       // Download file.
+    FTP_CMD_QUIT
+} mbtk_ftp_cmd_enum;
+
+typedef enum
+{
+    FTP_ERR_SUCCESS,
+    FTP_ERR_PARAM_SET,
+    FTP_ERR_CLI_FULL,
+    FTP_ERR_NET_CONN,
+    FTP_ERR_LOGIN_DENIED,
+    FTP_ERR_NET_READ,
+    FTP_ERR_NET_WRITE,
+    FTP_ERR_NET_CLOSE,
+    FTP_ERR_NET_TIMEOUT,
+    FTP_ERR_FILE_NO_FOUND,
+    FTP_ERR_FILE_EXIST,
+    FTP_ERR_DATA_SOCK_BUSY,
+    FTP_ERR_EFS_FILE,
+    FTP_ERR_UNKNOWN
+} mbtk_ftp_error_enum;
+
+typedef enum
+{
+    FTP_MODE_PASSIVE, FTP_MODE_ACTION
+} mbtk_ftp_mode_enum;
+
+typedef enum
+{
+    FTP_DATA_TYPE_A,    // Ascii
+    FTP_DATA_TYPE_E,    // EBCDIC
+    FTP_DATA_TYPE_I     // Binary
+} mbtk_ftp_data_type_enum;
+
+typedef enum
+{
+    FTP_SOCK_CTRL = 0,
+    FTP_SOCK_DATA,
+    FTP_SOCK_MAX
+} mbtk_ftp_sock_type_enum;
+
+typedef int mbtk_ftp_handle;
+typedef void (*mbtk_data_cb_func)(void *data, uint32 data_len);
+
+typedef struct
+{
+    sint16 fd;
+    uint8 host[MBTK_FTP_IP_MAX + 1];
+    uint16 port;
+} mbtk_ftp_sock_s;
+
+typedef struct
+{
+    int fd;
+    uint8 remote_name[MBTK_FTP_FILE_NAME_MAX * 2 + 1];
+    uint8 local_name[MBTK_FTP_FILE_NAME_MAX * 2 + 1];
+    uint8 modify_time[20];
+    mbtk_data_cb_func data_cb;
+    bool is_download;
+    uint32 size_count;
+    uint32 size_send;
+} mbtk_ftp_file_trans_info_s;
+
+typedef struct
+{
+    uint8 name[FTP_SERVER_USER_NAME_MAX + 1];
+    uint8 pass[FTP_SERVER_USER_PASS_MAX + 1];
+} mbtk_ftp_user_info_s;
+
+typedef enum
+{
+    FTP_AUTH_TYPE_NON,
+    FTP_AUTH_TYPE_IMPLICIT,
+    FTP_AUTH_TYPE_EXPLICIT_SSL,
+    FTP_AUTH_TYPE_EXPLICIT_TLS
+} mbtk_ftp_auth_type_enum;
+
+typedef struct
+{
+    mbtk_ftp_handle handle; // 1 - 5
+    mbtk_ftp_auth_type_enum auth_type;
+//    bool ssl_enable;
+//    bool is_ipv6;
+//    bool use_cert;
+    bool is_trans;      // Is download or update.
+    bool is_data_sock_busy;      // Data socket is busy.
+    //bool should_reconn; // Should reconnect.
+
+    mbtk_ftp_user_info_s user;
+    mbtk_ftp_state_enum state;
+    //mbtk_ftp_sock_s ctrl_sock;
+    mbtk_ftp_file_trans_info_s file_trans;
+    //sint16 data_sock_fd;
+    mbtk_ftp_mode_enum data_mode;
+    mbtk_net_info_s net_info;
+    mbtk_sock_info_s sock_info[FTP_SOCK_MAX];
+    mbtk_init_info ftp_ssl_info;
+    mbtk_init_info ftp_ssl_info_data;
+    mbtk_sock_handle ftp_ssl_handle;
+    mbtk_sock_handle ftp_ssl_handle_data;
+    mbtk_sock_info *ftp_sock_ssl_info;
+    mbtk_sock_info *ftp_sock_ssl_info_data;
+    mbtk_sock_session session;
+    mbtk_sock_session session_data;
+
+} mbtk_ftp_info_s;
+
+typedef struct mbtk_ftp_dir_info
+{
+    uint8 name[MBTK_FTP_FILE_NAME_MAX + 1];
+    bool is_file;
+    uint32 size;    // Directory is 0
+
+    struct mbtk_ftp_dir_info *next;
+    void (*ftp_ls_cb_typedef)(void *file_list_cb);
+} mbtk_ftp_file_info_s;
+
+/*************************************************************
+ Extern variables
+ *************************************************************/
+mbtk_ftp_handle mbtk_ftp_init(const void* host, uint16 port, mbtk_ftp_auth_type_enum auth_type,
+                              bool is_ipv6, bool use_cert);
+mbtk_ftp_error_enum mbtk_ftp_reconfig(mbtk_ftp_handle handle,const void* host, uint16 port, mbtk_ftp_auth_type_enum auth_type,
+                                      bool is_ipv6, bool use_cert);
+mbtk_ftp_error_enum mbtk_ftp_deinit(mbtk_ftp_handle handle);
+mbtk_ftp_error_enum mbtk_ftp_quit(mbtk_ftp_handle handle);
+mbtk_ftp_info_s* mbtk_ftp_info_get(mbtk_ftp_handle handle);
+mbtk_ftp_error_enum mbtk_ftp_login(mbtk_ftp_handle handle, void *user,
+                                   void *pass);
+mbtk_ftp_error_enum mbtk_ftp_net_close(mbtk_ftp_handle handle);
+mbtk_ftp_error_enum mbtk_ftp_pwd(mbtk_ftp_handle handle, void *path);
+mbtk_ftp_error_enum mbtk_ftp_cd(mbtk_ftp_handle handle, void *path);
+mbtk_ftp_error_enum mbtk_ftp_dir_ls(mbtk_ftp_handle handle,
+                                    mbtk_ftp_file_info_s *list_head);
+uint32 mbtk_ftp_file_size(mbtk_ftp_handle handle, void *path);
+mbtk_ftp_error_enum mbtk_ftp_file_del(mbtk_ftp_handle handle, void *path);
+mbtk_ftp_error_enum mbtk_ftp_dir_mkdir(mbtk_ftp_handle handle, void *path);
+mbtk_ftp_error_enum mbtk_ftp_dir_rmdir(mbtk_ftp_handle handle, void *path);
+mbtk_ftp_error_enum mbtk_ftp_mode_set(mbtk_ftp_handle handle,
+                                      mbtk_ftp_mode_enum mode);
+mbtk_ftp_error_enum mbtk_ftp_data_type_set(mbtk_ftp_handle handle,
+        mbtk_ftp_data_type_enum data_type);
+uint32 mbtk_ftp_download_start(mbtk_ftp_handle handle, void *remote_path,
+                               void *local_path, mbtk_data_cb_func data_cb);
+uint32 mbtk_ftp_download_continue(mbtk_ftp_handle handle);
+int mbtk_ftp_upload_start(mbtk_ftp_handle handle, const void *remote_path,
+                          const void *local_path, uint32 size_byte);
+int mbtk_ftp_upload_send(mbtk_ftp_handle handle, const void *data,uint16 data_len);
+mbtk_ftp_error_enum mbtk_ftp_trans_reset(mbtk_ftp_handle handle);
+mbtk_ftp_handle mbtk_ftp_upload_end(mbtk_ftp_handle handle);
+
+#ifdef MBTK_PLATFORM_QCOMM
+int mbtk_ftp_task_handle_set(mbtk_ftp_handle handle,sint15 task_handle);
+mbtk_ftp_error_enum mbtk_ftp_get_ip_and_port(char *ipBuf_out,
+                                    int *port,int iptype);
+
+#endif
+
+/*************************************************************
+ Public Function Declaration
+ *************************************************************/
+
+#endif /* _MBTK_FTP_H */
+
diff --git a/mbtk/include/mbtk/mbtk_gnss.h b/mbtk/include/mbtk/mbtk_gnss.h
new file mode 100755
index 0000000..027eb48
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_gnss.h
@@ -0,0 +1,64 @@
+/**
+ *   \file mbtk_gnss_internal.h
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-17
+ */
+
+#ifndef __MBTK_GNSS_H__
+#define __MBTK_GNSS_H__
+
+#define MOPEN_GNSS_NMEA_MAX_LENGTH  255                 /**  NMEA string maximum length. */
+
+typedef uint32 mbtk_gnss_client_handle;
+
+typedef void (*mbtk_gnss_handler_func_t)
+(
+    mbtk_gnss_client_handle  h_loc,
+    int   e_msg_id,
+    void                    *pv_data,
+    void                    *context_ptr
+);
+
+struct mbtk_gnss_location_info_t
+{
+    uint32_t    size;                   /**<   Set to the size of mcm_gps_location_t. */
+    int flags; /**<   Contains GPS location flags bits. */
+    int position_source;  /**<   Provider indicator for HYBRID or GPS. */
+    double      latitude;               /**<   Latitude in degrees. */
+    double      longitude;              /**<   Longitude in degrees. */
+    double      altitude;               /**<   Altitude in meters above the WGS 84 reference ellipsoid. */
+    float       speed;                  /**<   Speed in meters per second. */
+    float       bearing;                /**<   Heading in degrees. */
+    float       accuracy;               /**<   Expected accuracy in meters. */
+    int64_t     timestamp;              /**<   Timestamp for the location fix in UTC million-second base.  */
+    int32_t     is_indoor;              /**<   Location is indoors. */
+    float       floor_number;           /**<   Indicates the floor number. */
+};
+
+typedef struct
+{
+    int64_t     timestamp;                          /**<   System Timestamp, marked for when got the nmea data */
+    int         length;                             /**<   NMEA string length. */
+    char        nmea[MOPEN_GNSS_NMEA_MAX_LENGTH + 1];   /**<   NMEA string.*/
+} mbtk_gnss_nmea_info_t;  /* Message */
+
+int mbtk_gnss_client_init(uint32 *ph_gnss);
+int mbtk_gnss_client_deinit(uint32 h_gnss);
+int mbtk_gnss_add_rx_msg_handler(uint32 h_gnss, mbtk_gnss_handler_func_t handler_ptr);
+int mbtk_gnss_set_mode(uint32 h_gnss, int mode);
+int mbtk_gnss_set_system_config(uint32 h_gnss, int mode);
+int mbtk_gnss_set_nema_config(uint32 h_gnss, int mode);
+int mbtk_gnss_download_tle(void);
+int mbtk_gnss_injects_aidpos(uint32 h_gnss);
+int mbtk_gnss_firmware_update(void);
+int mbtk_gnss_dev_reset(uint32 h_gnss, int type, int mode);
+int mbtk_gnss_print_version(uint32 h_gnss);
+
+
+int mbtk_at_gnss_start_ttff(int type, int timeout_sec, int count);
+
+#endif
diff --git a/mbtk/include/mbtk/mbtk_http.h b/mbtk/include/mbtk/mbtk_http.h
new file mode 100755
index 0000000..70ade42
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_http.h
@@ -0,0 +1,364 @@
+/*************************************************************
+Description:
+    MBTK HTTP Header file.
+Author:
+    LiuBin
+Date:
+    2020/4/29 17:25:55
+*************************************************************/
+#ifndef _MBTK_HTTP_2_H
+#define _MBTK_HTTP_2_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include "mbtk_type.h"
+#include "mbtk_sock2.h"
+
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+#define MBTK_HTTP_URI_MAX 512
+#define MBTK_HTTP_HOST_MAX 50
+#define MBTK_HTTP_URL_MAX (MBTK_HTTP_URI_MAX + MBTK_HTTP_HOST_MAX)
+#define MBTK_HTTP_PORT_DEF 80
+#define MBTK_HTTPS_PORT_DEF 443
+#define HTTP_HANDLE_MAX 3
+#define HTTP_SESSION_MAX 5
+#define HTTP_REQUEST_HEADER_MAX 30
+#define HTTP_RESPONSE_HEADER_MAX 30
+#define HTTP_CONTENT_LEN_MAX 1024
+#define HTTP_MSG_LEN_MAX 1024
+
+#define HTTP_IPC_MSG_PATH "/dev"
+#define HTTP_IPC_MSG_ID 'H'
+
+/*************************************************************
+    Definitions:enum,struct,union,class
+*************************************************************/
+typedef enum {
+    HTTP_VERSION_1_0 = 0,
+    HTTP_VERSION_1_1,
+    HTTP_VERSION_2,
+    HTTP_VERSION_3
+} mbtk_http_version_enum;
+
+typedef enum {
+    HTTP_OPTION_HEAD = 0,
+    HTTP_OPTION_GET,
+    HTTP_OPTION_POST,
+    HTTP_OPTION_PUT,
+    HTTP_OPTION_DELETE,
+    HTTP_OPTION_OPTIONS,
+    HTTP_OPTION_TRACE,
+    HTTP_OPTION_CONNECT,
+    HTTP_OPTION_LINK,
+    HTTP_OPTION_UNLINK
+} mbtk_http_option_enum;
+
+#if 0
+typedef enum {
+    HTTP_HEADER_GENERAL = 0,
+    HTTP_HEADER_REQUEST,
+    HTTP_HEADER_RESPONSE,
+    HTTP_HEADER_ENTITY,
+    HTTP_HEADER_OTHERS
+} mbtk_http_header_type_e;
+
+typedef enum {
+    // General field start.
+    HTTP_HEADER_INDEX_CACHE_CONTROL = 0,
+    HTTP_HEADER_INDEX_CONNECTION,
+    HTTP_HEADER_INDEX_DATE,
+    HTTP_HEADER_INDEX_PRAGMA,
+    HTTP_HEADER_INDEX_TRAILER,
+    HTTP_HEADER_INDEX_TRANSFER_ENCODING,
+    HTTP_HEADER_INDEX_UPGRADE,
+    HTTP_HEADER_INDEX_VIA,
+    HTTP_HEADER_INDEX_WARNING,
+    // General field end.
+    // Request field start.
+    HTTP_HEADER_INDEX_ACCEPT,
+    HTTP_HEADER_INDEX_ACCEPT_CHARSET,
+    HTTP_HEADER_INDEX_ACCEPT_ENCODING,
+    HTTP_HEADER_INDEX_ACCEPT_LANGUAGE,
+    HTTP_HEADER_INDEX_AUTHORIZATION,
+    HTTP_HEADER_INDEX_EXPECT,
+    HTTP_HEADER_INDEX_FROM,
+    HTTP_HEADER_INDEX_HOST,
+    HTTP_HEADER_INDEX_IF_MATCH,
+    HTTP_HEADER_INDEX_IF_MODIFIED_SINCE,
+    HTTP_HEADER_INDEX_IF_NONE_MATCH,
+    HTTP_HEADER_INDEX_IF_RANGE,
+    HTTP_HEADER_INDEX_IF_UNMODIFIED_SINCE,
+    HTTP_HEADER_INDEX_MAX_FORWARDS,
+    HTTP_HEADER_INDEX_PROXY_AUTHORIZATION,
+    HTTP_HEADER_INDEX_RANGE,
+    HTTP_HEADER_INDEX_REFERER,
+    HTTP_HEADER_INDEX_TE,
+    HTTP_HEADER_INDEX_USER_AGENT,
+    // Request field end.
+    // Response field start.
+    HTTP_HEADER_INDEX_ACCEPT_RANGES,
+    HTTP_HEADER_INDEX_AGE,
+    HTTP_HEADER_INDEX_ETAG,
+    HTTP_HEADER_INDEX_LOCATION,
+    HTTP_HEADER_INDEX_PROXY_AUTHENTICATE,
+    HTTP_HEADER_INDEX_RETRY_AFTER,
+    HTTP_HEADER_INDEX_SERVER,
+    HTTP_HEADER_INDEX_VARY,
+    HTTP_HEADER_INDEX_WWW_AUTHENTICATE,
+    // Response field end.
+    // Entity field start.
+    HTTP_HEADER_INDEX_ALLOW,
+    HTTP_HEADER_INDEX_CONTENT_ENCODING,
+    HTTP_HEADER_INDEX_CONTENT_LANGUAGE,
+    HTTP_HEADER_INDEX_CONTENT_LENGTH,
+    HTTP_HEADER_INDEX_CONTENT_LOCATION,
+    HTTP_HEADER_INDEX_CONTENT_MD5,
+    HTTP_HEADER_INDEX_CONTENT_RANGE,
+    HTTP_HEADER_INDEX_CONTENT_TYPE,
+    HTTP_HEADER_INDEX_EXPIRES,
+    HTTP_HEADER_INDEX_LAST_MODIFIED,
+    // Entity field end.
+    // Other field start.
+    HTTP_HEADER_INDEX_SET_COOKIE,
+    HTTP_HEADER_INDEX_COOKIE,
+    HTTP_HEADER_INDEX_X_FRAME_OPTIONS,
+    HTTP_HEADER_INDEX_X_XSS_PROTECTION,
+    HTTP_HEADER_INDEX_DNT,
+    HTTP_HEADER_INDEX_P3P
+    // Other field end.
+} mbtk_http_header_index_e;
+#endif
+
+typedef enum {
+    HTTP_SESSION_STATE_NON = 0,
+    HTTP_SESSION_STATE_CONN,
+    HTTP_SESSION_STATE_WRITE_HEADER,
+    HTTP_SESSION_STATE_WRITE_CONTENT,
+    HTTP_SESSION_STATE_WRITE_END,
+    HTTP_SESSION_STATE_READ_HEADER,
+    HTTP_SESSION_STATE_READ_CONTENT,
+    HTTP_SESSION_STATE_READ_END
+} http_session_state_e;
+
+typedef enum {
+    MBTK_HTTP_STATE_CODE_200 = 200,
+    MBTK_HTTP_STATE_CODE_204 = 204,
+    MBTK_HTTP_STATE_CODE_206 = 206,
+    MBTK_HTTP_STATE_CODE_301 = 301,
+    MBTK_HTTP_STATE_CODE_302 = 302,
+    MBTK_HTTP_STATE_CODE_303 = 303,
+    MBTK_HTTP_STATE_CODE_304 = 304,
+    MBTK_HTTP_STATE_CODE_307 = 307,
+    MBTK_HTTP_STATE_CODE_400 = 400,
+    MBTK_HTTP_STATE_CODE_401 = 401,
+    MBTK_HTTP_STATE_CODE_403 = 403,
+    MBTK_HTTP_STATE_CODE_404 = 404,
+    MBTK_HTTP_STATE_CODE_500 = 500,
+    MBTK_HTTP_STATE_CODE_503 = 503
+} mbtk_http_state_code_e;
+
+typedef enum {
+    MBTK_HTTP_DATA_NON = 0,
+    MBTK_HTTP_DATA_HEADER,
+    MBTK_HTTP_DATA_CONTENT,
+    MBTK_HTTP_DATA_COMPLETE
+} mbtk_http_data_type_enum;
+
+typedef void (*mbtk_http_data_callback_func)(
+    int session_id, mbtk_http_data_type_enum type,
+    void *data,int data_len);
+
+typedef struct mbtk_http_header {
+    char name[30];
+    char *value;
+} mbtk_http_header_t;
+
+typedef struct {
+    int header_cnt;
+    mbtk_http_header_t *req_h[HTTP_REQUEST_HEADER_MAX];
+
+    int content_len;    // Post content lenght
+    int content_len_send; // Post content lenght for send.
+    char *content;
+} mbtk_http_session_req_t;
+
+typedef struct {
+    int state_code;
+    mbtk_http_version_enum version;
+
+    int content_length;
+    bool is_chunked;
+    int header_cnt;
+    mbtk_http_header_t *rsp_h[HTTP_RESPONSE_HEADER_MAX];
+} mbtk_http_session_rsp_t;
+
+typedef struct mbtk_http_session{
+    int handle_id;
+    int id;
+    int sock_fd;
+    FILE *sock_file;
+    http_session_state_e state;
+    char host[MBTK_HTTP_HOST_MAX + 1];
+    mbtk_http_option_enum option;
+    mbtk_http_version_enum version;
+    char uri[MBTK_HTTP_URI_MAX + 1];
+    int port;
+    bool is_ssl;
+
+    mbtk_http_session_req_t req;
+    mbtk_http_session_rsp_t rsp;
+} mbtk_http_session_t;
+
+typedef struct mbtk_http_handle{
+    int id;
+    bool show_rsp_header;
+    mbtk_http_data_callback_func data_cb;
+
+    int session_cnt;
+    mbtk_http_session_t *session[HTTP_SESSION_MAX];
+} mbtk_http_handle_t;
+
+#if 0
+typedef enum {
+    HTTP_MSG_SESSION_CREATE_REQ,
+    HTTP_MSG_SESSION_CREATE_RSP,
+    HTTP_MSG_SESSION_FREE_REQ,
+    HTTP_MSG_SESSION_FREE_RSP,
+    HTTP_MSG_SESSION_URL_SET_REQ,
+    HTTP_MSG_SESSION_URL_SET_RSP,
+    HTTP_MSG_SESSION_HEAD_SET_REQ,
+    HTTP_MSG_SESSION_HEAD_SET_RSP,
+    HTTP_MSG_SESSION_CONTENT_SET_REQ,
+    HTTP_MSG_SESSION_CONTENT_SET_RSP,
+    HTTP_MSG_SESSION_ACTION_REQ,
+    HTTP_MSG_SESSION_ACTION_RSP,
+    HTTP_MSG_SESSION_CONTENT_SEND_REQ,
+    HTTP_MSG_SESSION_CONTENT_SEND_RSP
+} mbtk_http_msg_type_enum;
+#endif
+
+typedef enum {
+    HTTP_MSG_SESSION_CREATE,
+    HTTP_MSG_SESSION_FREE,
+    HTTP_MSG_SESSION_HEAD_SET,
+    HTTP_MSG_SESSION_CONTENT_SET,
+    HTTP_MSG_SESSION_ACTION,
+    HTTP_MSG_SESSION_CONTENT_SEND,
+    HTTP_MSG_HANDLE_EXIT
+} mbtk_http_msg_type_enum;
+
+typedef enum {
+    MBTK_HTTP_ERR_SUCCESS,
+    MBTK_HTTP_ERR_UNKNOWN
+} mbtk_http_err_enum;
+
+typedef struct {
+    mbtk_http_msg_type_enum type;
+    int int_arg1;
+    int int_arg2;
+    char str_small[30];
+    char str_large[HTTP_MSG_LEN_MAX];
+} mbtk_http_msg_req_t;
+
+typedef struct {
+    mbtk_http_msg_type_enum type;
+    mbtk_http_err_enum err;
+
+    mbtk_http_data_type_enum data_type;
+    int buff_len;
+    char buff[HTTP_MSG_LEN_MAX];
+} mbtk_http_msg_rsp_t;
+
+/*************************************************************
+    Extern variables
+*************************************************************/
+#if 0
+const mbtk_http_header_field_t mbtk_http_headers[] = {
+    {HTTP_HEADER_INDEX_CACHE_CONTROL, HTTP_HEADER_GENERAL,"Cache-Control"},
+    {HTTP_HEADER_INDEX_CONNECTION, HTTP_HEADER_GENERAL,"Connection"},
+    {HTTP_HEADER_INDEX_DATE, HTTP_HEADER_GENERAL,"Date"},
+    {HTTP_HEADER_INDEX_PRAGMA, HTTP_HEADER_GENERAL,"Pragma"},
+    {HTTP_HEADER_INDEX_TRAILER, HTTP_HEADER_GENERAL,"Trailer"},
+    {HTTP_HEADER_INDEX_TRANSFER_ENCODING, HTTP_HEADER_GENERAL,"Transfer-Encoding"},
+    {HTTP_HEADER_INDEX_UPGRADE, HTTP_HEADER_GENERAL,"Upgrade"},
+    {HTTP_HEADER_INDEX_VIA, HTTP_HEADER_GENERAL,"Via"},
+    {HTTP_HEADER_INDEX_WARNING, HTTP_HEADER_GENERAL,"Warning"},
+    {HTTP_HEADER_INDEX_ACCEPT, HTTP_HEADER_REQUEST,"Accept"},
+    {HTTP_HEADER_INDEX_ACCEPT_CHARSET, HTTP_HEADER_REQUEST,"Accept-Charset"},
+    {HTTP_HEADER_INDEX_ACCEPT_ENCODING, HTTP_HEADER_REQUEST,"Accept-Encoding"},
+    {HTTP_HEADER_INDEX_ACCEPT_LANGUAGE, HTTP_HEADER_REQUEST,"Accept-Language"},
+    {HTTP_HEADER_INDEX_AUTHORIZATION, HTTP_HEADER_REQUEST,"Authorization"},
+    {HTTP_HEADER_INDEX_EXPECT, HTTP_HEADER_REQUEST,"Expect"},
+    {HTTP_HEADER_INDEX_FROM, HTTP_HEADER_REQUEST,"From"},
+    {HTTP_HEADER_INDEX_HOST, HTTP_HEADER_REQUEST,"Host"},
+    {HTTP_HEADER_INDEX_IF_MATCH, HTTP_HEADER_REQUEST,"If-Match"},
+    {HTTP_HEADER_INDEX_IF_MODIFIED_SINCE, HTTP_HEADER_REQUEST,"If-Modified-Since"},
+    {HTTP_HEADER_INDEX_IF_NONE_MATCH, HTTP_HEADER_REQUEST,"If-None-Match"},
+    {HTTP_HEADER_INDEX_IF_RANGE, HTTP_HEADER_REQUEST,"If-Range"},
+    {HTTP_HEADER_INDEX_IF_UNMODIFIED_SINCE, HTTP_HEADER_REQUEST,"If-Unmodified-Since"},
+    {HTTP_HEADER_INDEX_MAX_FORWARDS, HTTP_HEADER_REQUEST,"Max-Forwards"},
+    {HTTP_HEADER_INDEX_PROXY_AUTHORIZATION, HTTP_HEADER_REQUEST,"Proxy-Authorization"},
+    {HTTP_HEADER_INDEX_RANGE, HTTP_HEADER_REQUEST,"Range"},
+    {HTTP_HEADER_INDEX_REFERER, HTTP_HEADER_REQUEST,"Referer"},
+    {HTTP_HEADER_INDEX_TE, HTTP_HEADER_REQUEST,"TE"},
+    {HTTP_HEADER_INDEX_USER_AGENT, HTTP_HEADER_REQUEST,"User-Agent"},
+    {HTTP_HEADER_INDEX_ACCEPT_RANGES, HTTP_HEADER_RESPONSE,"Accept-Ranges"},
+    {HTTP_HEADER_INDEX_AGE, HTTP_HEADER_RESPONSE,"Age"},
+    {HTTP_HEADER_INDEX_ETAG, HTTP_HEADER_RESPONSE,"ETag"},
+    {HTTP_HEADER_INDEX_LOCATION, HTTP_HEADER_RESPONSE,"Location"},
+    {HTTP_HEADER_INDEX_PROXY_AUTHENTICATE, HTTP_HEADER_RESPONSE,"Proxy-Authenticate"},
+    {HTTP_HEADER_INDEX_RETRY_AFTER, HTTP_HEADER_RESPONSE,"Retry-After"},
+    {HTTP_HEADER_INDEX_SERVER, HTTP_HEADER_RESPONSE,"Server"},
+    {HTTP_HEADER_INDEX_VARY, HTTP_HEADER_RESPONSE,"Vary"},
+    {HTTP_HEADER_INDEX_WWW_AUTHENTICATE, HTTP_HEADER_RESPONSE,"WWW-Authenticate"},
+    {HTTP_HEADER_INDEX_ALLOW, HTTP_HEADER_ENTITY,"Allow"},
+    {HTTP_HEADER_INDEX_CONTENT_ENCODING, HTTP_HEADER_ENTITY,"Content-Encoding"},
+    {HTTP_HEADER_INDEX_CONTENT_LANGUAGE, HTTP_HEADER_ENTITY,"Content-Language"},
+    {HTTP_HEADER_INDEX_CONTENT_LENGTH, HTTP_HEADER_ENTITY,"Content-Length"},
+    {HTTP_HEADER_INDEX_CONTENT_LOCATION, HTTP_HEADER_ENTITY,"Content-Location"},
+    {HTTP_HEADER_INDEX_CONTENT_MD5, HTTP_HEADER_ENTITY,"Content-MD5"},
+    {HTTP_HEADER_INDEX_CONTENT_RANGE, HTTP_HEADER_ENTITY,"Content-Range"},
+    {HTTP_HEADER_INDEX_CONTENT_TYPE, HTTP_HEADER_ENTITY,"Content-Type"},
+    {HTTP_HEADER_INDEX_EXPIRES, HTTP_HEADER_ENTITY,"Expires"},
+    {HTTP_HEADER_INDEX_LAST_MODIFIED, HTTP_HEADER_ENTITY,"Last-Modified"},
+    {HTTP_HEADER_INDEX_SET_COOKIE, HTTP_HEADER_OTHERS,"Set-Cookie"},
+    {HTTP_HEADER_INDEX_COOKIE, HTTP_HEADER_OTHERS,"Cookie"},
+    {HTTP_HEADER_INDEX_X_FRAME_OPTIONS, HTTP_HEADER_OTHERS,"X-Frame-Options"},
+    {HTTP_HEADER_INDEX_X_XSS_PROTECTION, HTTP_HEADER_OTHERS,"X-XSS-Protection"},
+    {HTTP_HEADER_INDEX_DNT, HTTP_HEADER_OTHERS,"DNT"},
+    {HTTP_HEADER_INDEX_P3P, HTTP_HEADER_OTHERS,"P3P"}
+};
+#endif
+/*************************************************************
+    Public Function Declaration
+*************************************************************/
+int mbtk_http_handle_get(bool show_rsp_header,mbtk_http_data_callback_func data_cb);
+int mbtk_http_handle_free(int handle_id);
+int mbtk_http_session_create(int handle_id, mbtk_http_option_enum option,
+        mbtk_http_version_enum version);
+int mbtk_http_session_option_reset(int handle_id, int session_id, mbtk_http_option_enum option);
+int mbtk_http_session_free(int handle_id,int session_id);
+int mbtk_http_session_url_set(int handle_id,int session_id,void *url);
+int mbtk_http_session_head_add(int handle_id,int session_id,
+        char *name, char *value);
+int mbtk_http_session_content_set(int handle_id,int session_id,
+        char *content,uint32 content_len);
+int mbtk_http_session_start(int handle_id,int session_id);
+int mbtk_http_session_content_send(int handle_id,int session_id,
+        char *data,int data_len);
+const mbtk_http_session_t* mbtk_http_session_get(int handle_id,int session_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MBTK_HTTP_2_H */
+
+
diff --git a/mbtk/include/mbtk/mbtk_ifc.h b/mbtk/include/mbtk/mbtk_ifc.h
new file mode 100755
index 0000000..a839aea
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_ifc.h
@@ -0,0 +1,38 @@
+/*
+* MBTK Network Interface Control Header.
+*
+* Author : lb
+* Date   : 2021/8/20 13:18:00
+*
+*/
+#ifndef _MBTK_IFC_H
+#define _MBTK_IFC_H
+#include <netinet/in.h>
+
+int mbtk_ifc_open(void);
+int mbtk_ifc_close(void);
+int mbtk_ifc_up(const char *name);
+int mbtk_ifc_down(const char *name);
+int mbtk_ifc_set_addr(const char *name, in_addr_t addr, in_addr_t netmask);
+int mbtk_ifc_get_addr(const char *name, void *addr);
+int mbtk_ifc_get_hwaddr(const char *name, void *ptr);
+int mbtk_ifc_get_ifindex(const char *name, int *if_indexp);
+int mbtk_ifc_ip_config(const char *ifname, const char *ipv4, const char *mask, const char *gateway);
+int mbtk_ifc_set_netmask(const char *ifname, const char *netmask);
+
+int mbtk_ifc_configure1(const char *ifname,
+                        in_addr_t address,
+                        uint32_t prefixLength,
+                        in_addr_t gateway,
+                        in_addr_t netmask);
+
+int mbtk_ifc_configure2(const char *ifname,
+                        const char *ipv4,
+                        uint32_t prefixLength,
+                        const char *gateway,
+                        const char *netmask);
+
+int mbtk_ipv6_config(const char *ifname, const char *ipv6, uint32_t prefixLength);
+
+#endif /* _MBTK_IFC_H */
+
diff --git a/mbtk/include/mbtk/mbtk_info_api.h b/mbtk/include/mbtk/mbtk_info_api.h
new file mode 100755
index 0000000..8a70c66
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_info_api.h
@@ -0,0 +1,768 @@
+/*
+*
+* Data : 2022/10/20 11:24:09
+* Author : LiuBin
+*/
+#ifndef _MBTK_INFO_API_H
+#define _MBTK_INFO_API_H
+#include <netinet/in.h>
+
+#include "mbtk_type.h"
+#include "mbtk_list.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+
+#ifndef UNUSED
+#define UNUSED(a)    (void)(a)
+#endif
+
+// LOG_DEBUG_LEVEL 7
+#define LOG LOGI
+
+#define CELL_NUM_MAX 50
+#define APN_STR_MAX 128
+// 2 - 7
+#define MBTK_APN_CID_MIN 2
+#define MBTK_APN_CID_MAX 7
+#define MBTK_DATA_CALL_TIMEOUT_DEFAULT 10  // 10s
+
+typedef void (*mbtk_info_callback_func)(const void* data, int data_len);
+
+typedef enum {
+    MBTK_TIME_TYPE_CELL = 0,
+    MBTK_TIME_TYPE_NTP,
+    MBTK_TIME_TYPE_USER
+} mbtk_time_type_enum;
+
+typedef enum {
+    MBTK_ACTIVE,
+    MBTK_HELD,
+    MBTK_DIALING,
+    MBTK_ALERTING,
+    MBTK_INCOMING,
+    MBTK_WAITING,
+    MBTK_OFFERING,
+} mbtk_call_stat_enum;
+
+/*
+    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)
+*/
+typedef enum
+{
+    MBTK_NET_PREF_GSM_ONLY = 0,
+    MBTK_NET_PREF_UMTS_ONLY,
+    MBTK_NET_PREF_GSM_UMTS_AUTO,
+    MBTK_NET_PREF_GSM_UMTS_GSM_PREF,
+    MBTK_NET_PREF_GSM_UMTS_UMTS_PREF,
+    MBTK_NET_PREF_LTE_ONLY,
+    MBTK_NET_PREF_GSM_LTE_AUTO,
+    MBTK_NET_PREF_GSM_LTE_GSM_PREF,
+    MBTK_NET_PREF_GSM_LTE_LTE_PREF,
+    MBTK_NET_PREF_UMTS_LTE_AUTO,
+    MBTK_NET_PREF_UMTS_LTE_UMTS_PREF,
+    MBTK_NET_PREF_UMTS_LTE_LTE_PREF,
+    MBTK_NET_PREF_GSM_UMTS_LTE_AUTO,
+    MBTK_NET_PREF_GSM_UMTS_LTE_GSM_PREF,
+    MBTK_NET_PREF_GSM_UMTS_LTE_UMTS_PREF,
+    MBTK_NET_PREF_GSM_UMTS_LTE_LTE_PREF
+} mbtk_net_pref_enum;
+
+typedef enum
+{
+    MBTK_CELL_TYPE_GSM = 0,
+    MBTK_CELL_TYPE_UMTS,
+    MBTK_CELL_TYPE_LTE
+} mbtk_cell_type_enum;
+
+typedef struct
+{
+    int client_fd;
+    pthread_t read_thread_id;
+    int exit_fd[2];
+    bool is_waitting;
+    pthread_cond_t cond;
+    pthread_mutex_t mutex;
+
+    // Temp response data.
+    uint16 info_err;
+    uint16 data_len;
+    void *data;
+
+    //mbtk wyq for server_ready_status add start
+    char server_ready_status;
+    //mbtk wyq for server_ready_status add end
+
+    mbtk_info_callback_func net_state_cb;
+    mbtk_info_callback_func call_state_cb;
+    mbtk_info_callback_func sms_state_cb;
+    mbtk_info_callback_func radio_state_cb;
+    mbtk_info_callback_func sim_state_cb;
+    mbtk_info_callback_func pdp_state_cb;
+} mbtk_info_handle_t;
+
+typedef struct
+{
+    /*
+    0: automatic
+    1: manual
+    */
+    uint8 net_sel_mode;
+    /*
+    0: GSM
+    1: GSM Compact
+    2: UTRAN
+    3: GSM w/EGPRS
+    4: UTRAN w/HSDPA
+    5: UTRAN w/HSUPA
+    6: UTRAN w/HSDPA and HSUPA
+    7: E-UTRAN
+    8: UTRAN HSPA+
+    0xFF: Unused
+    */
+    uint8 net_type;
+    //uint8 plmn[10]; // 46000
+    /*
+    0: unknown
+    1: available
+    2: current
+    3: forbidden
+    */
+    uint8 net_state;
+    uint32 plmn;
+} __attribute__((packed)) mbtk_net_info_t;
+
+typedef struct
+{
+    uint8 net_pref;     // mbtk_net_pref_enum
+    uint16 gsm_band;    // mbtk_gsm_band_enum
+    uint16 umts_band;   // mbtk_umts_band_enum
+    uint32 tdlte_band;  // mbtk_tdlte_band_enum
+    uint32 fddlte_band; // mbtk_fddlte_band_enum
+} __attribute__((packed)) mbtk_band_info_t;
+
+typedef struct
+{
+    uint8 type; // mbtk_radio_technology_enum
+    uint8 rssi; // 0: 113 dBm or less
+                // 1: 111 dBm
+                // 2��30: 109��53 dBm
+                // 31: 51 dBm or greater
+                // 99: not known or not detectable
+    uint8 rxlev;// 0:rssi < -110 dBm
+                // 1: -110 dBm �� rssi < -109 dBm
+                // 2: -109 dBm �� rssi < -108 dBm
+                // ......
+                // 61: -50 dBm �� rssi < -49 dBm
+                // 62: -49 dBm �� rssi < -48 dBm
+                // 63: -48 dBm �� rssi
+                // 99: not known or not detectable
+    uint8 ber;  // 0...7 as RXQUAL values in the table in 3GPP TS 45.008 [20] subclause 8.2.4
+                // 99 not known or not detectable
+    uint8 rscp; // 0: rscp < -120 dBm
+                // 1: -120 dBm �� rscp < -119 dBm
+                // 2: -119 dBm �� rscp < -118 dBm
+                // ......
+                // 94: -27 dBm �� rscp < -26 dBm
+                // 95: -26 dBm �� rscp < -25 dBm
+                // 96: - 25 dBm �� rscp
+                // 255: not known or not detectable
+    uint8 ecno; // 0: Ec/Io < -24 dB
+                // 1: -24 dB �� Ec/Io < -23.5 dB
+                // 2: -23.5 dB �� Ec/Io < -23 dB
+                // ......
+                // 47: -1 dB �� Ec/Io < -0.5 dB
+                // 48: -0.5 dB �� Ec/Io < 0 dB
+                // 49: 0 dB �� Ec/Io
+                // 255: not known or not detectable
+    uint8 rsrq; // 0: rsrq < -19.5 dB
+                // 1: -19.5 dB �� rsrq < -19 dB
+                // 2: -19 dB �� rsrq < -18.5 dB
+                // ......
+                // 32: -4 dB �� rsrq < -3.5 dB
+                // 33: -3.5 dB �� rsrq < -3 dB
+                // 34: -3 dB �� rsrq
+                // 255: not known or not detectable
+    uint8 rsrp; // 0: rsrp < -140 dBm
+                // 1: -140 dBm �� rsrp < -139 dBm
+                // 2: -139 dBm �� rsrp < -138 dBm
+                // ......
+                // 95: -46 dBm �� rsrp < -45 dBm
+                // 96: -45 dBm �� rsrp < -44 dBm
+                // 97: -44 dBm �� rsrp
+                // 255: not known or not detectable
+} __attribute__((packed)) mbtk_signal_info_t;
+
+typedef struct
+{
+    uint8 call_state;// mbtk_net_reg_state_enum
+    uint8 data_state;// mbtk_net_reg_state_enum
+    uint8 ims_state;// mbtk_net_reg_state_enum
+    uint8 type; // mbtk_radio_technology_enum
+    uint16 lac;
+    uint32 ci;
+} __attribute__((packed)) mbtk_net_reg_info_t;
+
+typedef struct
+{
+    uint8 call_wait;
+    uint8 dir1;
+    uint8 dir;
+    uint8 state;
+    uint8 mode;
+    uint8 mpty;
+    char phone_number[100];
+    uint8 type;
+    uint8 pas;
+    uint8 disconnected_id;
+} __attribute__((packed)) mbtk_call_info_t;
+
+typedef struct
+{
+    char character;
+    uint32 duration;
+} __attribute__((packed)) mbtk_call_dtmf_info_t;
+
+typedef enum {
+    MBTK_SIM_ABSENT = 0,
+    MBTK_SIM_NOT_READY = 1,
+    MBTK_SIM_READY = 2,
+    MBTK_SIM_PIN = 3,
+    MBTK_SIM_PUK = 4,
+    MBTK_SIM_NETWORK_PERSONALIZATION = 5
+} mbtk_sim_state_enum;
+
+typedef enum {
+    MBTK_IP_TYPE_IP,
+    MBTK_IP_TYPE_IPV6,
+    MBTK_IP_TYPE_IPV4V6,
+    MBTK_IP_TYPE_PPP
+} mbtk_ip_type_enum;
+
+typedef enum
+{
+    MBTK_NET_TYPE_UNKNOWN,
+    MBTK_NET_TYPE_GSM,
+    MBTK_NET_TYPE_UMTS,
+    MBTK_NET_TYPE_LTE
+} mbtk_net_type_enum;
+
+typedef enum {
+    MBTK_CLCC = 1,
+    MBTK_CPAS,
+    MBTK_DISCONNECTED,
+} mbtk_call_enum;
+
+typedef struct
+{
+    // LTE server cell: tac, PCI, dlEuarfcn, ulEuarfcn, band
+    // LTE cell: phyCellId,euArfcn,rsrp,rsrq
+    // WCDMA server cell: lac, ci, arfcn
+    // WCDMA cell: lac, ci, arfcn
+    // GSM server cell: lac, ci, arfcn, bsic
+    // GSM cell:
+    uint32 value1;
+    uint32 value2;
+    uint32 value3;
+    uint32 value4;
+    uint32 value5;
+	uint32 value6;
+    uint32 value7;
+    uint32 value8;
+    uint32 value9;
+    uint32 value10;
+} __attribute__((packed)) mbtk_cell_info_t;
+
+typedef enum {
+    MBTK_CALL_RADY,                 //MT allows commands from TA/TE
+    MBTK_CALL_UNAVAILABLE,          //MT does not allow commands from TA/TE
+    MBTK_CALL_UNKNOWN,              //MT is not guaranteed to respond to instructions
+    MBTK_CALL_RINGING,              //MT is ready for commands from TA/TE, but the ringer is active
+    MBTK_CALL_PROGRESS,             //MT is ready for commands from TA/TE, but a call is in progress
+    MBTK_CALL_ASLEEP,               //MT is unable to process commands from TA/TE because it is in a low functionality state
+    MBTK_CALL_ACTIVE,
+} mbtk_call_pas_enum;
+
+typedef enum {
+    MBTK_RADIO_STATE_UNKNOWN,
+    MBTK_RADIO_STATE_ON,
+    MBTK_RADIO_STATE_OFF
+} mbtk_radio_state_enum;
+
+typedef enum {
+    MBTK_DATA_CALL_STOP = 0,    // Stop data call.
+    MBTK_DATA_CALL_START,       // Start data call.
+    MBTK_DATA_CALL_STATE        // Get data call state
+} mbtk_data_call_type_enum;
+
+/*
+0: not registered, MT is not currently searching a new operator to register to
+1: registered, home network
+2: not registered, but MT is currently searching a new operator to register to
+3: registration denied
+4: unknown
+5: registered, roaming
+6: registered, home network, SMS-only (applicable only when AcT is E-UTRAN)
+7: registered, roaming, SMS-only (applicable only when AcT is E-UTRAN)
+8: attached for emergency bearer services only (not applicable)
+9: registered for ��CSFB not preferred��,home network(applicable only when AcT is E-UTRAN)
+10: registered for ��CSFB not preferred��,roaming(applicable only when AcT is E-UTRAN)
+11: only emergency services are available
+*/
+typedef enum
+{
+    MBTK_NET_REG_STATE_NON = 0,
+    MBTK_NET_REG_STATE_HOME,
+    MBTK_NET_REG_STATE_SEARCHING,
+    MBTK_NET_REG_STATE_DENIED,
+    MBTK_NET_REG_STATE_UNKNOWN,
+    MBTK_NET_REG_STATE_ROAMING,
+    MBTK_NET_REG_STATE_SMS_ONLY,
+    MBTK_NET_REG_STATE_ROAMING_SMS,
+    MBTK_NET_REG_STATE_ATTACHED_EMERGENCY,
+    MBTK_NET_REG_STATE_CSFB_HOME,
+    MBTK_NET_REG_STATE_CSFB_ROAMING,
+    MBTK_NET_REG_STATE_EMERGENCY_ONLY
+} mbtk_net_reg_state_enum;
+
+typedef struct {
+    int cid; // 2 - 7
+    mbtk_ip_type_enum ip_type; // mbtk_ip_type_enum
+    uint8 apn[APN_STR_MAX];
+    uint8 user[APN_STR_MAX];
+    uint8 pass[APN_STR_MAX];
+    uint8 auth[APN_STR_MAX];
+} mbtk_apn_info_t;
+
+typedef struct {
+    bool valid;
+    uint32 IPAddr;
+    uint32 PrimaryDNS;
+    uint32 SecondaryDNS;
+    uint32 GateWay;
+    uint32 NetMask;
+} __attribute__((packed)) mbtk_ipv4_info_t;
+
+typedef struct {
+    bool valid;
+    uint32 IPV6Addr[4];
+    uint32 PrimaryDNS[4];
+    uint32 SecondaryDNS[4];
+    uint32 GateWay[4];
+    uint32 NetMask[4];
+} __attribute__((packed)) mbtk_ipv6_info_t;
+
+typedef enum
+{
+    MBTK_DEV_MODEM_MIN_FUN,                                   //Modem 最小功能
+    MBTK_DEV_MODEM_FULL_FUN,                                  //Modem 全功能
+    MBTK_DEV_MODEM_DISABLE_RECEIVE_RF_CIRCUITS = 3,           //Modem 禁用射频接收电路
+    MBTK_DEV_MODEM_DISABLE_TRANSMIT_AND_RECEIVE_RF_CIRCUITS,  //Modem禁用射频发射和接收电路
+    MBTK_DEV_MODEM_DISABLE_SIM,                               //Modem 禁用(U)SIM 卡
+    MBTK_DEV_MODEM_TURN_OFF_FULL_SECONDARY_RECEIVE,           //Modem 完全禁用辅助接收
+}MBTK_DEV_MODEM_FUNCTION;
+
+/*
+0: GSM
+1: GSM Compact
+2: UTRAN
+3: GSM w/EGPRS
+4: UTRAN w/HSDPA
+5: UTRAN w/HSUPA
+6: UTRAN w/HSDPA and HSUPA
+7: E-UTRAN
+8: UTRAN HSPA+
+*/
+typedef enum {
+    MBTK_RADIO_TECH_GSM = 0,
+    MBTK_RADIO_TECH_GSM_COMPACT,
+    MBTK_RADIO_TECH_UTRAN,
+    MBTK_RADIO_TECH_GSM_EGPRS,
+    MBTK_RADIO_TECH_UTRAN_HSDPA,
+    MBTK_RADIO_TECH_UTRAN_HSUPA,
+    MBTK_RADIO_TECH_UTRAN_HSDPA_HSUPA,
+    MBTK_RADIO_TECH_E_UTRAN,      // LTE
+    MBTK_RADIO_TECH_UTRAN_HSPA
+} mbtk_radio_technology_enum;
+
+typedef struct
+{
+    MBTK_DEV_MODEM_FUNCTION fun;
+    int rst;
+} mbtk_modem_info_t;
+
+typedef enum {
+    MBTK_SIM = 0,
+    MBTK_USIM = 1,
+    MBTK_TEST_SIM = 2,
+    MBTK_TEST_USIM = 3,
+    MBTK_UNKNOWN = 4,
+} mbtk_sim_card_type_enum;
+
+typedef struct
+{
+    uint8_t p1_retry;
+    uint8_t p2_retry;
+    uint8_t puk1_retry;
+    uint8_t puk2_retry;
+} mbtk_pin_puk_last_times;
+
+typedef struct
+{
+    uint8_t format;
+    char plmn_name[16];
+}MBTK_SIM_PLMN_INFO_C;  //string type
+
+
+typedef struct
+{
+    uint8_t count;
+    uint8_t format;
+    MBTK_SIM_PLMN_INFO_C mbtk_plmn_name[24];
+} mbtk_plmn_info;
+
+typedef struct
+{
+ uint8_t old_pin_value[16];
+ uint8_t new_pin_value[16];
+} mbtk_change_pin_info;
+
+typedef struct
+{
+ uint8_t pin_value[16];
+ uint8_t puk_value[16];
+} mbtk_unlock_pin_info;
+
+typedef struct
+{
+ uint8_t pin_value[16];
+ uint8_t enable;
+} mbtk_enable_pin_info;
+
+typedef struct
+{
+    int sim;
+    int sim_card_type;
+    mbtk_pin_puk_last_times ql_last_times;
+} mbtk_sim_card_info;
+
+mbtk_info_handle_t* mbtk_info_handle_get();
+
+int mbtk_info_handle_free(mbtk_info_handle_t** handle);
+
+/*
+* Get platform version.
+*/
+int mbtk_version_get(mbtk_info_handle_t* handle, void *version);
+
+/*
+* Get platform model.
+*/
+int mbtk_model_get(mbtk_info_handle_t* handle, void *model);
+
+/*
+* Get platform IMEI.
+*/
+int mbtk_imei_get(mbtk_info_handle_t* handle, void *imei);
+
+/*
+* Get platform SN.
+*/
+int mbtk_sn_get(mbtk_info_handle_t* handle, void *sn);
+
+/*
+* Get platform MEID.
+*/
+int mbtk_meid_get(mbtk_info_handle_t* handle, void *meid);
+
+/*
+* Return VoLTE state.
+*/
+int mbtk_volte_state_get(mbtk_info_handle_t* handle, int *volte_state);
+
+/*
+* Return modem state.
+*/
+int mbtk_get_modem_fun(mbtk_info_handle_t* handle, int* fun);
+
+/*
+* Set modem state.
+*/
+int mbtk_set_modem_fun(mbtk_info_handle_t* handle, mbtk_modem_info_t *info);
+
+
+/*
+* Set VoLTE state.
+*
+* volte_state:
+* 0 : Close VoLTE.
+* 1 : Open VoLTE.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_volte_state_set(mbtk_info_handle_t* handle, int volte_state);
+
+/*
+* Get platform IMSI.
+*/
+int mbtk_imsi_get(mbtk_info_handle_t* handle, void *imsi);
+
+/*
+* Get platform ICCID.
+*/
+int mbtk_iccid_get(mbtk_info_handle_t* handle, void *iccid);
+
+/*
+* Get current phone number.
+*/
+int mbtk_phone_number_get(mbtk_info_handle_t* handle, void *phone_number);
+
+/*
+* Get available network.
+*/
+int mbtk_available_net_get(mbtk_info_handle_t* handle, list_node_t **net_list);
+
+/*
+* Set network select mode. (+COPS=...)
+*/
+int mbtk_net_sel_mode_set(mbtk_info_handle_t* handle, const mbtk_net_info_t *net);
+
+/*
+* Get network select mode. (+COPS?)
+*/
+int mbtk_net_sel_mode_get(mbtk_info_handle_t* handle, mbtk_net_info_t *net);
+
+/*
+* Get platform support bands.
+*/
+int mbtk_support_band_get(mbtk_info_handle_t* handle, mbtk_band_info_t *band);
+
+/*
+* Get platform current bands.
+*/
+int mbtk_current_band_get(mbtk_info_handle_t* handle, mbtk_band_info_t *band);
+
+/*
+* Set platform current bands.
+*/
+int mbtk_current_band_set(mbtk_info_handle_t* handle, const mbtk_band_info_t *band);
+
+/*
+* Get current cell infomation.
+*/
+int mbtk_cell_get(mbtk_info_handle_t* handle, mbtk_cell_type_enum *type, list_node_t **cell_list);
+
+/*
+* Set AT*CELL.
+*/
+int mbtk_cell_set(mbtk_info_handle_t* handle, char * info, char* response);
+
+/*
+* Get current APN informations.
+*/
+int mbtk_apn_get(mbtk_info_handle_t* handle, int *apn_num, mbtk_apn_info_t apns[]);
+
+/*
+* Set current APN informations.
+*/
+int mbtk_apn_set(mbtk_info_handle_t* handle, int cid, mbtk_ip_type_enum ip_type, const void* apn_name,
+                    const void *user_name, const void *user_pass, const void *auth);
+
+/*
+* Start data call.
+*/
+int mbtk_data_call_start(mbtk_info_handle_t* handle, int cid, int auto_conn_interval, bool boot_conn, int timeout);
+
+/*
+* Stop data call.
+*/
+int mbtk_data_call_stop(mbtk_info_handle_t* handle, int cid, int timeout);
+
+/*
+* Get data call state.
+*/
+int mbtk_data_call_state_get(mbtk_info_handle_t* handle, int cid, mbtk_ipv4_info_t *ipv4, mbtk_ipv6_info_t *ipv6);
+
+/*
+* Get current network signal.
+*/
+int mbtk_net_signal_get(mbtk_info_handle_t* handle, mbtk_signal_info_t *signal);
+
+/*
+* Get current network register information.
+*/
+int mbtk_net_reg_get(mbtk_info_handle_t* handle, mbtk_net_reg_info_t *reg);
+
+/*
+* Get radio state.
+*/
+int mbtk_radio_state_get(mbtk_info_handle_t* handle, int *radio_state);
+
+/*
+* Set radio state.
+*/
+int mbtk_radio_state_set(mbtk_info_handle_t* handle, int radio_state);
+
+/*
+* Get sim state.
+*/
+int mbtk_sim_state_get(mbtk_info_handle_t* handle, mbtk_sim_state_enum *sim_state);
+
+/*
+* Get sim card type.
+*/
+int mbtk_sim_card_type_get(mbtk_info_handle_t* handle, mbtk_sim_card_type_enum *sim_card_type);
+
+/*
+* Get PIN’s number of remaining retry
+*/
+int mbtk_pin_last_num_get(mbtk_info_handle_t* handle, mbtk_pin_puk_last_times *last_times);
+
+/*
+* Get plmn list
+*/
+int mbtk_get_plmn_list(mbtk_info_handle_t* handle, mbtk_plmn_info *pin);
+
+/*
+* Get system temperature.
+*
+* type[IN]:
+*   0: Soc temperature.
+*   1: RF temperature.
+* temp[OUT]:
+*   temperature in celsius.
+*/
+int mbtk_temp_get(mbtk_info_handle_t* handle, int type, int* temp);
+
+/*
+* Set sim power state.
+* power:
+* 0: Sim power off.
+* 1: Sim power on.
+*/
+int mbtk_sim_power_set(int power);
+
+/*
+*enable PIN
+*/
+int mbtk_enable_pin(mbtk_info_handle_t* handle, mbtk_enable_pin_info *pin);
+
+/*
+*Verify PIN
+*/
+int mbtk_verify_pin(mbtk_info_handle_t* handle, char *pin);
+
+/*
+*change PIN
+*/
+int mbtk_change_pin(mbtk_info_handle_t* handle, mbtk_change_pin_info *pin);
+
+/*
+*unlock PIN
+*/
+int mbtk_unlock_pin(mbtk_info_handle_t* handle, mbtk_unlock_pin_info *pin);
+
+
+/*
+* System power.
+* type:
+* 0: Reboot system.
+* 1: Poweroff system.
+* 2: Halt system.
+*/
+int mbtk_system_reboot(int type);
+
+/*
+* Get time type.
+*/
+int mbtk_time_get(mbtk_info_handle_t* handle, int *time_type);
+
+/*
+* Get net time.
+*/
+int mbtk_net_time_get(mbtk_info_handle_t* handle, char* time_str);
+
+/*
+* Absolute time conversion
+*/
+int mbtk_get_abs_time(char *time_str, time_t *time_out);
+
+/*
+* Set time.
+*
+* time_type:
+* 0: Cell time
+* 1: NTP time
+* 2: User time
+* time_str: "YYYY-MM-DD HH:MM:SS"
+*/
+int mbtk_time_set(mbtk_info_handle_t* handle, mbtk_time_type_enum time_type, char* time_str);
+
+//call a phone number
+int mbtk_call_start(mbtk_info_handle_t* handle, char* phone_number);
+//answer a call
+int mbtk_call_answer(mbtk_info_handle_t* handle);
+//hang up all call
+int mbtk_call_hang(mbtk_info_handle_t* handle);
+//hang up a call
+int mbtk_a_call_hang(mbtk_info_handle_t* handle, int phone_id);
+//hang up waiting or background call
+int mbtk_waiting_or_background_call_hang(mbtk_info_handle_t* handle);
+//hang up foreground resume background call
+int mbtk_foreground_resume_background_call_hang(mbtk_info_handle_t* handle);
+//get call infomation
+int mbtk_call_reg_get(mbtk_info_handle_t* handle, mbtk_call_info_t *reg);
+//set call mute
+int mbtk_mute_state_set(mbtk_info_handle_t* handle, int mute_state);
+//get mute state
+int mbtk_mute_state_get(mbtk_info_handle_t* handle, int *mute_state);
+//set dtmf character
+int mbtk_dtmf_send(mbtk_info_handle_t* handle, mbtk_call_dtmf_info_t *dtmf_character);
+
+/*
+* Set pdp state change callback function.
+*/
+int mbtk_pdp_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb);
+
+/*
+* Set network state change callback function.
+*/
+int mbtk_net_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb);
+
+/*
+* Set call state change callback function.
+*/
+int mbtk_call_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb);
+
+/*
+* Set sms state change callback function.
+*/
+int mbtk_sms_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb);
+
+/*
+* Set radio state change callback function.
+*/
+int mbtk_radio_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb);
+
+/*
+* Set sim state change callback function.
+*/
+int mbtk_sim_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb);
+
+int mbtk_sms_cnmi_set(mbtk_info_handle_t* handle);
+
+#endif /* _MBTK_INFO_API_H */
diff --git a/mbtk/include/mbtk/mbtk_list.h b/mbtk/include/mbtk/mbtk_list.h
new file mode 100755
index 0000000..bab5bb3
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_list.h
@@ -0,0 +1,63 @@
+/*
+ * mbtk_list.h
+ *
+ *  Created on: Aug 18, 2020
+ *      Author: lb
+ */
+
+#ifndef MBTK_LIST_H_
+#define MBTK_LIST_H_
+#include "mbtk_type.h"
+
+typedef struct list_arraynode
+{
+    void *data;
+    struct list_arraynode *next;
+} list_arraynode_t;
+
+typedef struct list_treenode
+{
+    list_arraynode_t *data;
+    int count;
+    struct list_treenode *left;
+    struct list_treenode *right;
+} list_treenode_t;
+
+typedef int (*list_sort_func)(void *data1, void *data2);
+typedef void (*list_free_func)(void *data);
+
+typedef struct list_node
+{
+    uint32 size;
+    list_sort_func sort_func;
+    list_free_func free_func;
+
+    uint32 cur_index;
+    list_arraynode_t *cur_array_data;
+
+    list_arraynode_t array_data;
+    list_treenode_t tree_data;
+} list_node_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+list_node_t* list_create(list_free_func free_func);
+uint32 list_size(list_node_t *list);
+void list_add(list_node_t *list, void *data);
+void list_add_unique(list_node_t *list, void *data, uint32 len);
+void* list_remove(list_node_t *list, void *data);
+void* list_get(list_node_t *list, uint32 index);
+void* list_remove_by_content(list_node_t *list, void *data, uint32 data_len);
+void list_first(list_node_t *list);
+void* list_next(list_node_t *list);
+void list_sort(list_node_t *list, list_sort_func sort_func);
+void list_free(list_node_t *list);
+void list_clear(list_node_t *list);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBTK_LIST_H_ */
+
diff --git a/mbtk/include/mbtk/mbtk_log.h b/mbtk/include/mbtk/mbtk_log.h
new file mode 100755
index 0000000..4f82533
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_log.h
@@ -0,0 +1,136 @@
+#ifndef MBTK_LOG_INCLUDE
+#define MBTK_LOG_INCLUDE
+#include <string.h>
+
+#ifndef MBTK_ANDROID_LOG
+//#define MBTK_ANDROID_LOG
+#endif
+
+#ifdef MBTK_ANDROID_LOG
+
+#ifndef LOG_TAG
+#define LOG_TAG "mbtk_log"
+#endif
+
+// Print ALOGV log.
+#ifndef LOG_NDEBUG
+//#define LOG_NDEBUG 0
+#endif
+
+#include <cutils/log.h>
+
+#define LOGV(fmt, arg...) ALOGV("Line-%d: " fmt,__LINE__,##arg)
+#define LOGI(fmt, arg...) ALOGI("Line-%d: " fmt,__LINE__,##arg)
+#define LOGD(fmt, arg...) ALOGD("Line-%d: " fmt,__LINE__,##arg)
+#define LOGW(fmt, arg...) ALOGW("Line-%d: " fmt,__LINE__,##arg)
+#define LOGE(fmt, arg...) ALOGE("Line-%d: " fmt,__LINE__,##arg)
+
+#else /* MBTK_ANDROID_LOG */
+
+//#include <log.h>
+#include <stdio.h>
+
+#ifndef UNUSED
+#define UNUSED(a)    (void)(a)
+#endif
+
+//#include "pxa_dbg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void mbtk_log(int level, const char *format, ...);
+void mbtk_log_init(char *path, char *tag);
+void log_hex(const char *tag, const void *data, int data_len);
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef LOG_ERR_LEVEL
+#define LOG_ERR_LEVEL  3      /* error conditions */
+#endif
+#ifndef LOG_WARN_LEVEL
+#define LOG_WARN_LEVEL 4   /* warning conditions */
+#endif
+#ifndef LOG_INFO_LEVEL
+#define LOG_INFO_LEVEL 6      /* informational */
+#endif
+#ifndef LOG_DEBUG_LEVEL
+#define LOG_DEBUG_LEVEL 7     /* debug-level messages */
+#endif
+#ifndef LOG_VERBOSE_LEVEL
+#define LOG_VERBOSE_LEVEL 8
+#endif
+
+#define LOGV(fmt, args ...) \
+    do{ \
+        char *file_ptr_1001 = __FILE__; \
+        char *ptr_1001 = file_ptr_1001 + strlen(file_ptr_1001) - 1;   \
+        char line_1001[10] = {0}; \
+        sprintf(line_1001, "%d", __LINE__); \
+        while(ptr_1001 >= file_ptr_1001 && *ptr_1001){ \
+            if(*ptr_1001 == '/') \
+                 break; \
+            ptr_1001--; \
+        } \
+        mbtk_log(LOG_VERBOSE_LEVEL, "%s#%s: " fmt, ptr_1001 + 1, line_1001, ##args); \
+    } while(0)
+
+#define LOGI(fmt, args...) \
+    do{ \
+        char *file_ptr_1001 = __FILE__; \
+        char *ptr_1001 = file_ptr_1001 + strlen(file_ptr_1001) - 1;   \
+        char line_1001[10] = {0}; \
+        sprintf(line_1001, "%d", __LINE__); \
+        while(ptr_1001 >= file_ptr_1001 && *ptr_1001){ \
+            if(*ptr_1001 == '/') \
+                 break; \
+            ptr_1001--; \
+        } \
+        mbtk_log(LOG_INFO_LEVEL, "%s#%s: " fmt, ptr_1001 + 1, line_1001, ##args); \
+    } while(0)
+
+#define LOGD(fmt, args...) \
+    do{ \
+        char *file_ptr_1001 = __FILE__; \
+        char *ptr_1001 = file_ptr_1001 + strlen(file_ptr_1001) - 1;   \
+        char line_1001[10] = {0}; \
+        sprintf(line_1001, "%d", __LINE__); \
+        while(ptr_1001 >= file_ptr_1001 && *ptr_1001){ \
+            if(*ptr_1001 == '/') \
+                 break; \
+            ptr_1001--; \
+        } \
+        mbtk_log(LOG_DEBUG_LEVEL, "%s#%s: " fmt "\n", ptr_1001 + 1, line_1001, ##args); \
+    } while(0)
+
+#define LOGW(fmt, args...) \
+    do{ \
+        char *file_ptr_1001 = __FILE__; \
+        char *ptr_1001 = file_ptr_1001 + strlen(file_ptr_1001) - 1;   \
+        char line_1001[10] = {0}; \
+        sprintf(line_1001, "%d", __LINE__); \
+        while(ptr_1001 >= file_ptr_1001 && *ptr_1001){ \
+            if(*ptr_1001 == '/') \
+                 break; \
+            ptr_1001--; \
+        } \
+        mbtk_log(LOG_WARN_LEVEL, "%s#%s: " fmt, ptr_1001 + 1, line_1001, ##args); \
+    } while(0)
+
+#define LOGE(fmt, args...) \
+    do{ \
+		char *file_ptr_1001 = __FILE__; \
+        char *ptr_1001 = file_ptr_1001 + strlen(file_ptr_1001) - 1;   \
+        char line_1001[10] = {0}; \
+        sprintf(line_1001, "%d", __LINE__); \
+        while(ptr_1001 >= file_ptr_1001 && *ptr_1001){ \
+            if(*ptr_1001 == '/') \
+                 break; \
+            ptr_1001--; \
+        } \
+        mbtk_log(LOG_ERR_LEVEL, "%s#%s: " fmt, ptr_1001 + 1, line_1001, ##args); \
+    } while(0)
+#endif
+
+#endif /* MBTK_LOG_INCLUDE */
diff --git a/mbtk/include/mbtk/mbtk_map.h b/mbtk/include/mbtk/mbtk_map.h
new file mode 100755
index 0000000..d0ed1d2
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_map.h
@@ -0,0 +1,44 @@
+/*
+ * mbtk_map.h
+ *
+ *  Created on: Aug 18, 2020
+ *      Author: lb
+ */
+
+#ifndef MBTK_MAP_H_
+#define MBTK_MAP_H_
+#include "mbtk_type.h"
+
+typedef void (*map_free_func)(void *data);
+
+typedef struct map_data
+{
+    char *key;
+    void *value;
+    struct map_data *next;
+} map_data_t;
+
+typedef struct
+{
+    uint32 size;
+    uint32 capacity;
+    uint32 cur_index;
+    map_data_t *cur_data;
+    map_free_func free_func;
+
+    map_data_t **map_array;
+} map_node_t;
+
+map_node_t* map_create(uint32 capacity, map_free_func free_func);
+uint32 map_size(map_node_t* map);
+uint32 map_hash(const char* key, uint32 capacity);
+void map_put(map_node_t* map, const char* key, void* value);
+void* map_get(map_node_t* map, char* key);
+void* map_remove(map_node_t* map, char* key);
+void map_first(map_node_t *map);
+void* map_next(map_node_t *map);
+void map_clear(map_node_t* map);
+void map_free(map_node_t* map);
+
+#endif /* MBTK_MAP_H_ */
+
diff --git a/mbtk/include/mbtk/mbtk_mqtt.h b/mbtk/include/mbtk/mbtk_mqtt.h
new file mode 100755
index 0000000..02c54e1
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_mqtt.h
@@ -0,0 +1,107 @@
+#ifndef MBTK_MQTT_H
+#define MBTK_MQTT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mqtt/MQTTClient.h"
+#include "mqtt/MQTTLinux.h"
+enum  iot_ctrl_status_t
+{
+	IOT_STATUS_LOGIN,
+	IOT_STATUS_CONNECT,
+	IOT_STATUS_DROP,
+};
+typedef void  (*pMessageArrived_Fun)(void*,int len);
+
+#define MQTT_TOPIC_SIZE     (128)		//订阅和发布主题长度
+#define MQTT_BUF_SIZE       (8 * 1024) 	//接收后发送缓冲区大小
+#define MQTT_CONFIG_SIZE    256
+#define MBTK_IMQTT_USER_NAME_LEN   (100)
+#define MBTK_IMQTT_CLIENT_ID_LEN   (160)
+#define MBTK_IMQTT_PASSWORD_LEN    (160)
+#define MBTK_ITOPIC_PATH_MAX_LEN (MBTK_IMQTT_CLIENT_ID_LEN+40) //160+40
+
+#define MQTT_HOST "***.***.***.***"		//ip地址
+#define MQTT_PORT 61613					//端口号
+#define MQTT_USER "admin"				//用户名
+#define MQTT_PASS "password"			//密码
+#define MQTT_CLIENT_ID "17849359"		//客户端标识
+
+typedef struct {
+    Network* network;
+    Client Client;
+    char sub_topic[MQTT_TOPIC_SIZE];		//存放订阅主题
+    char pub_topic[MQTT_TOPIC_SIZE];		//存放发布主题
+    char mqtt_buffer[MQTT_BUF_SIZE];		//发送缓冲区
+    char mqtt_read_buffer[MQTT_BUF_SIZE];	//接收缓冲区
+
+    unsigned char willFlag;
+    MQTTPacket_willOptions will;
+    char will_topic[MQTT_TOPIC_SIZE];		//存放遗嘱主题
+
+    pMessageArrived_Fun DataArrived_Cb;
+
+    char mqtt_host[MQTT_CONFIG_SIZE] ;
+    char mqtt_client_id[MQTT_CONFIG_SIZE];
+    char mqtt_user[MQTT_CONFIG_SIZE];
+    char mqtt_pass[MQTT_CONFIG_SIZE];
+    int mqtt_port;
+    int keepAliveInterval;
+    int mqtt_version;
+}Cloud_MQTT_t;
+
+typedef struct{
+    enum iot_ctrl_status_t iotstatus;
+    char model[5];
+    char company[32];
+} iot_device_info_t;//主题结构体
+
+
+struct opts_struct {
+    char    *clientid;
+    int     nodelimiter;
+    char    *delimiter;
+    enum    QoS qos;
+    char    *username;
+    char    *password;
+    char    *host;
+    int     port;
+    int     showtopics;
+}; //结构体
+
+typedef struct mbtk_mqtt_device_session{
+    char product_key[MQTT_CONFIG_SIZE];
+    char product_secret[MQTT_CONFIG_SIZE];
+    char device_name[MQTT_CONFIG_SIZE];
+    char device_secret[MQTT_CONFIG_SIZE];
+    int host;
+    int port;
+} mbtk_mqtt_device_session_t;
+
+void mqtt_module_init(void);
+int mqtt_data_write(char *pbuf, int len, char retain);
+
+void iot_mqtt_init(Cloud_MQTT_t *piot_mqtt,char *host,int port ,char *clientid,char *user,char *pass,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb);
+int mqtt_will_msg_set(Cloud_MQTT_t *piot_mqtt, char *pbuf, int len);
+int mqtt_device_connect(Cloud_MQTT_t *piot_mqtt);
+int mqtt_device_disconnect(Cloud_MQTT_t *piot_mqtt);
+int mbtk_aliyun_mqtt_one_type_one_secret_unregin_device_connect(Cloud_MQTT_t *piot_mqtt);
+void mbtk_aliyun_mqtt_one_type_one_secret_unregin_set_info_init(Cloud_MQTT_t *piot_mqtt,mbtk_mqtt_device_session_t *device,int keepAliveInterval,int version,pMessageArrived_Fun mqtt_data_rx_cb);
+int mbtk_aliyun_mqtt_one_type_one_secret_unregin_get_regin_info(char *clientId, char *deviceToken);
+void iot_aliyun_mqtt_one_type_one_secret_unregin_connect_init(Cloud_MQTT_t *piot_mqtt,mbtk_mqtt_device_session_t *device, char *clientId, char *deviceToken,
+         int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb);
+void mqtt_data_rx_cb(void *pbuf, int len);
+void *cloud_mqtt_thread(void *arg);
+int mbtk_MQTTSubscribe(Client* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler);
+int mbtk_MQTTUnsubscribe(Client* c, const char* topicFilter);
+int mbtk_MQTTPublish(char *pbuf, int len, char retain,Client* c,const char* pub_topic,enum QoS qos,char dup);
+#define mDEBUG(fmt, ...)  printf("%s[%s](%d):" fmt,__FILE__,__FUNCTION__,__LINE__,##__VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/mbtk/include/mbtk/mbtk_net_control.h b/mbtk/include/mbtk/mbtk_net_control.h
new file mode 100755
index 0000000..bc886f8
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_net_control.h
@@ -0,0 +1,48 @@
+/*************************************************************
+Description:
+    Header file for network control.
+Author:
+    LiuBin
+Date:
+    2019/7/24 17:18:43
+*************************************************************/
+#ifndef _MBTK_NET_CONTROL_H
+#define _MBTK_NET_CONTROL_H
+#include "mbtk_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+
+
+/*************************************************************
+    Definitions:enum,struct,union,class
+*************************************************************/
+typedef enum {
+    MBTK_NET_STATE_OFF,     /* Network off */
+    MBTK_NET_STATE_CONN,     /* Network connected */
+    MBTK_NET_STATE_CONN_2G,  // 2
+    MBTK_NET_STATE_CONN_3G,  // 3
+    MBTK_NET_STATE_CONN_4G,  // 4
+    MBTK_NET_STATE_CONN_UNKNOWN
+} mbtk_net_state_t;
+
+/*************************************************************
+    Extern variables
+*************************************************************/
+
+
+/*************************************************************
+    Public Function Declaration
+*************************************************************/
+mbtk_net_state_t mbtk_net_state_get();
+int mbtk_net_enable(bool enable);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* _MBTK_NET_CONTROL_H */
diff --git a/mbtk/include/mbtk/mbtk_ntp.h b/mbtk/include/mbtk/mbtk_ntp.h
new file mode 100755
index 0000000..1b3b926
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_ntp.h
@@ -0,0 +1,39 @@
+#ifndef __MBTK_NTP_H__
+#define __MBTK_NTP_H__
+
+
+/*****************************************************************
+* Function:     mbtk_at_systime
+*
+* Description:  
+*               This function is used to get the time from ntp server "cn.pool.ntp.org"
+*
+* Parameters:
+*               null
+*
+* Return:
+*               time_t is success
+*               0 is fail
+*****************************************************************/
+int mbtk_at_systime(void);
+
+/*****************************************************************
+* Function:     mbtk_ntp_server_set
+*
+* Description:  
+*               This function is used to set the ip address and port of NTP server.
+*               return the time obtained from ntp.
+*
+* Parameters:
+*               server_ip  : NTP server
+*
+*		        port : ntp port
+*
+* Return:
+*               time_t is success
+*               0 is fail
+*****************************************************************/
+time_t mbtk_ntp_server_set(const char* server_ip, const char * port);
+
+
+#endif
\ No newline at end of file
diff --git a/mbtk/include/mbtk/mbtk_queue.h b/mbtk/include/mbtk/mbtk_queue.h
new file mode 100755
index 0000000..9119355
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_queue.h
@@ -0,0 +1,71 @@
+/*************************************************************
+Description:
+    mbtk_queue.h
+    Used to define mobiletek standard queue interfaces
+Author:
+    YangDagang
+Date:
+    2019-7-13
+*************************************************************/
+#ifndef __MBTK_QUEUE_H__
+#define __MBTK_QUEUE_H__
+
+#include "mbtk_type.h"
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+#define MBTK_QUEUE_MAX_NUM 500
+#define task_mutex pthread_mutex_t
+
+/*************************************************************
+    Definitions:enum,struct,union
+*************************************************************/
+
+typedef struct{
+    task_mutex crit_sect; //User-defined data type
+} mbtk_mutex;
+
+typedef struct node
+{
+    void *payload;
+    int count;          //only used to count for internal
+    mbtk_mutex mutex;   //only used to count for internal
+    struct node *front;
+    struct node *rear;
+} mbtk_queue_node_t;
+
+/*************************************************************
+    Variables:local,extern
+*************************************************************/
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Extern Function Declaration
+*************************************************************/
+extern void mbtk_mutex_init(mbtk_mutex *mutex);
+extern void mbtk_mutex_deinit(mbtk_mutex *mutex);
+extern void mbtk_mutex_lock(mbtk_mutex *mutex);
+extern void mbtk_mutex_unlock(mbtk_mutex *mutex);
+
+extern void mbtk_queue_init(mbtk_queue_node_t *queue);
+extern int mbtk_queue_put(mbtk_queue_node_t *queue,void *payload);
+extern void* mbtk_queue_get(mbtk_queue_node_t *queue);
+extern int mbtk_queue_insert(mbtk_queue_node_t *queue,void *payload);
+extern bool mbtk_queue_empty(mbtk_queue_node_t *queue);
+extern bool mbtk_queue_is_full(mbtk_queue_node_t *queue);
+extern void mbtk_queue_deinit(mbtk_queue_node_t *queue);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __MBTK_QUEUE_H__ */
diff --git a/mbtk/include/mbtk/mbtk_sock.h b/mbtk/include/mbtk/mbtk_sock.h
new file mode 100755
index 0000000..5179336
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_sock.h
@@ -0,0 +1,101 @@
+
+/*
+*
+*
+* Author : lb
+* Date   : 2022/3/5 15:33:37
+*
+*/
+#ifndef _MBTK_SOCK_H
+#define _MBTK_SOCK_H
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+
+#include "mbtk_type.h"
+#include "mbtk_sock2.h"
+
+
+#define MBTK_BUFF_SIZE 2048
+
+typedef struct
+{
+    union
+    {
+        struct sockaddr_in6 dst_sock_addr6;
+        struct sockaddr_in serverSockAddr;
+    }addr;
+    uint16 ip_version;
+    uint16 addr_len;
+} mbtk_ipv4v6_addr;
+
+typedef enum
+{
+    MBTK_ADDR_IPV4,
+    MBTK_ADDR_IPV6,
+    MBTK_ADDR_IPV4V6
+} mbtk_addr_family_e;
+
+typedef enum
+{
+    MBTK_SOCK_TCP_COM = 0,
+    MBTK_SOCK_UDP_COM
+} mbtk_sock_type_e;
+
+
+typedef struct
+{
+    int16 net_id;
+#ifdef MBTK_PLATFORM_QCOMM
+    sint15 app6_id;
+    sint15 task_handle;
+    uint32 ip_filter;
+    //ds_policy_info_type policy_info;    // No use
+#endif
+    bool keep_alive;
+    uint32 recv_buff_size;
+} mbtk_net_info_s;
+
+typedef struct
+{
+    int fd;
+    char host[50];
+    int port;
+    bool is_ssl;
+    bool use_cert;
+    mbtk_sock_type_e sock_type;
+    mbtk_addr_family_e addr_family;
+    mbtk_buffer_t read_buff;
+
+    mbtk_ipv4v6_addr addr;
+    uint16 temp;    // Must add (addr.addr_len should be uint32)
+} mbtk_sock_info_s;
+
+int sock_net_open(mbtk_net_info_s *net_info, mbtk_addr_family_e addr_family);
+
+int sock_open(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err);
+
+int sock_addr_set(mbtk_net_info_s *net_info,mbtk_sock_info_s *sock_info,void *host, uint32 port);
+
+int sock_bind(int sockfd, bool is_ipv6, uint16 port);
+
+int sock_read(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err);
+
+int sock_read_async(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err);
+
+int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err);
+
+int sock_write(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout, int *err);
+
+int sock_recv(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout);
+
+int sock_sendto(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout);
+
+int sock_close(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err);
+
+int sock_net_close(mbtk_net_info_s *net_info, uint32 timeout, int *err);
+
+#endif /* _MBTK_SOCK_H */
diff --git a/mbtk/include/mbtk/mbtk_sock2.h b/mbtk/include/mbtk/mbtk_sock2.h
new file mode 100755
index 0000000..fbd8a0d
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_sock2.h
@@ -0,0 +1,169 @@
+/*************************************************************
+Description:
+    mbtk_sock.h
+    Used to define mobiletek sockets interfaces
+Author:
+    YangDagang
+Date:
+    2019-1-30
+*************************************************************/
+#ifndef __MBTK_SOCK2_H__
+#define __MBTK_SOCK2_H__
+
+#include "mbtk_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MBTK_SOCK_EVENT_READ 0x01
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+typedef int mbtk_sock_handle;
+typedef int mbtk_sock_session;
+
+/*************************************************************
+    Definitions:enum,struct,union
+*************************************************************/
+typedef enum
+{
+    /*common error code (-99 ~ 0)*/
+    MBTK_SOCK_SUCCESS = 0,
+    MBTK_SOCK_ERROR = -1,
+    MBTK_SOCK_EMEMORY = -2,
+    MBTK_SOCK_EARG = -3, /* Invalid buffer or argument */
+    MBTK_SOCK_EDNS = -4, /* DNS error */
+    MBTK_SOCK_ETIMEOUT = -5, /* Timeout */
+    /*socket error code */
+    MBTK_SOCK_EEOF = 0, /* end of file */
+    MBTK_SOCK_EBADF = 100, /* Invalid socket descriptor */
+    MBTK_SOCK_EFAULT= 101,   /* Invalid buffer or argument */
+    MBTK_SOCK_EWOULDBLOCK = 102, /* Operation would block */
+    MBTK_SOCK_EAFNOSUPPORT = 103, /* Address family not supported */
+    MBTK_SOCK_EPROTOTYPE = 104, /* Wrong protocol for socket type */
+    MBTK_SOCK_ESOCKNOSUPPORT = 105, /* Socket parameter not supported */
+    MBTK_SOCK_EPROTONOSUPPORT = 106, /* Socket parameter not supported */
+    MBTK_SOCK_EMFILE = 107, /* No more sockets available for opening */
+    MBTK_SOCK_EOPNOTSUPP = 108, /* Operation not supported */
+    MBTK_SOCK_ETIMEDOUT = 116, /* Connection attempt timed out */
+    MBTK_SOCK_ECONNRESET = 117, /* Connection reset */
+    MBTK_SOCK_ECONNABORTED = 118, /* Connection aborted */
+    MBTK_SOCK_EPIPE = 119,   /* Broken pipe */
+    MBTK_SOCK_ENETDOWN = 120, /* Network subsystem unavailable */
+    MBTK_SOCK_ENETNONET = 202, /* network subsystem unavailable */
+    /*unkonw error code (-1000 ~ ...)*/
+    MBTK_SOCK_EUNKONW = -1000     /*unkonw error*/
+}mbtk_sock_errno;
+
+typedef enum
+{
+    MBTK_SOCK_TCP = 0,
+    MBTK_SOCK_UDP
+} mbtk_sock_type;
+
+typedef enum
+{
+    MBTK_NET_LINUX = 0, // Default for Linux socket.
+    MBTK_NET_QUAL,      // Qcomm modem socket.
+    MBTK_NET_MAX
+} mbtk_net_type;
+
+typedef void (*mbtk_net_cb_func)(mbtk_sock_handle handle, int state);
+typedef void (*mbtk_sock_cb_func)(mbtk_sock_handle handle, mbtk_sock_session sock_fd, int event);
+
+//Used to provide external and to transmit information
+typedef struct
+{
+    mbtk_sock_type type; // socket type:TCP or UDP
+    bool is_support_ssl; //is suppoert ssl
+    bool ingnore_cert; //is ingnore certificate
+    char address[256]; //server address
+    int port; //server port
+    int ftp_ssl_support;
+} mbtk_sock_info;
+
+typedef struct
+{
+    mbtk_net_type net_type;
+    mbtk_net_cb_func net_cb;
+    mbtk_sock_cb_func sock_cb;
+} mbtk_init_info;
+
+#define DFL_SERVER_NAME         "asr"
+#define DFL_SERVER_ADDR         NULL
+#define DFL_SERVER_PORT         4433
+#define DFL_REQUEST_PAGE        "/"
+#define DFL_REQUEST_SIZE        -1
+#define DFL_DEBUG_LEVEL         0
+#define DFL_NBIO                0
+#define DFL_CA_FILE             "/ca.crt"
+#define DFL_CA_PATH             "/ca.crt"
+#define DFL_CRT_FILE            "/client.crt"
+#define DFL_KEY_FILE            "/client.key"
+#define DFL_PSK                 ""
+#define DFL_PSK_IDENTITY        "Client_identity"
+#define DFL_FORCE_CIPHER        0
+#define DFL_RENEGOTIATION       SSL_RENEGOTIATION_DISABLED
+#define DFL_ALLOW_LEGACY        SSL_LEGACY_NO_RENEGOTIATION
+#define DFL_RENEGOTIATE         0
+#define DFL_EXCHANGES           1
+#define DFL_MIN_VERSION         SSL_MINOR_VERSION_3
+#define DFL_MAX_VERSION         SSL_MINOR_VERSION_3
+#define DFL_AUTH_MODE           SSL_VERIFY_REQUIRED
+#define DFL_MFL_CODE            SSL_MAX_FRAG_LEN_NONE
+#define DFL_TRUNC_HMAC          0
+#define DFL_RECONNECT           0
+#define DFL_RECO_DELAY          0
+#define DFL_TICKETS             SSL_SESSION_TICKETS_ENABLED
+#define DFL_ALPN_STRING         NULL
+
+/*************************************************************
+    Variables:local,extern
+*************************************************************/
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Extern Function Declaration
+*************************************************************/
+extern mbtk_sock_handle mbtk_sock_init(mbtk_init_info *info);
+extern mbtk_sock_session mbtk_sock_open(mbtk_sock_handle handle,mbtk_sock_info *info,
+                unsigned int timeout,
+                int *mbtk_errno);
+extern int mbtk_sock_write(mbtk_sock_handle handle,mbtk_sock_session session,
+                void *buffer,
+                unsigned int buf_len,
+                unsigned int timeout,
+                int *mbtk_errno);
+extern int mbtk_sock_read(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len,
+            unsigned int timeout,
+            int *mbtk_errno);
+extern int mbtk_sock_read_async(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len);
+extern int mbtk_sock_close(mbtk_sock_handle handle,mbtk_sock_session session,
+            unsigned int timeout,
+            int *mbtk_errno);
+extern int mbtk_sock_deinit(mbtk_sock_handle handle);
+
+extern int mbtk_ssl_init_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd);
+extern int mbtk_ssl_close_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd);
+extern int mbtk_sock_readline(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len,
+            unsigned int timeout,
+            int *mbtk_errno,
+            int *read_line_count,
+            char *buf_ptr);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __MBTK_SOCK2_H__ */
diff --git a/mbtk/include/mbtk/mbtk_str.h b/mbtk/include/mbtk/mbtk_str.h
new file mode 100755
index 0000000..c74127d
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_str.h
@@ -0,0 +1,125 @@
+#ifndef MBTK_STR_INCLUDE
+#define MBTK_STR_INCLUDE
+
+#include "mbtk_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+* Converts all of the characters in this String to lower.
+*
+* Parameters:
+*   src - The string should be converted.
+*   dest  - The lowercase string.
+*   len - The length of result string.Must be "strlen(src) + 1"
+* Returns:
+*   The string, converted to lowercase,or NULL for fail.
+*/
+void*
+str_tolower
+(
+    const void *src,
+    void *dest,
+    size_t len
+);
+
+/*
+* Converts all of the characters in this String to upper case.
+*
+* Parameters:
+*   src - The string should be converted.
+*   dest  - The uppercase string.
+*   len - The length of result string.Must be "strlen(str_ptr) + 1"
+* Returns:
+*   The string, converted to uppercase.or NULL for fail.
+*/
+void*
+str_toupper
+(
+    const void *src,
+    void *dest,
+    size_t len
+);
+
+/*
+* Remove the head and tail spaces.
+*/
+void*
+str_trim
+(
+    const void* str,
+    void *result,
+    size_t len
+);
+
+/*
+* Returns true if and only if this string contains the specified sequence of char values.
+*
+* Parameters:
+*   str   -   The substring to search from.
+*   sub_str - The substring to search for.
+* Returns:
+*   True if str contains sub_str, false otherwise.
+*/
+bool
+str_contains
+(
+    const void* str,
+    const void* sub_str
+);
+
+/*
+* Returns the index within this string of the first occurrence of the specified substring.
+* If no such substring, then -1 is returned.
+*
+* Parameters:
+*   str   -   The substring to search from.
+*   sub_str - The substring to search for.
+* Returns:
+*   The index of the first occurrence of the specified substring,
+*   or -1 if there is no such occurrence.
+*/
+ssize_t
+str_indexof
+(
+    const void* str,
+    const void* sub_str
+);
+
+/*
+* Returns a new string that is a substring of this string. The substring begins
+* at the specified beginIndex and extends to the character at index endIndex - 1.
+* Thus the length of the substring is endIndex-beginIndex.
+*
+* Examples:
+*   "hamburger".substring(4, 8) returns "urge"
+*   "smiles".substring(1, 5) returns "mile"
+*
+* Parameters:
+*   begin_index     The beginning index, inclusive.
+*   end_index       The ending index, exclusive.
+* Returns:
+*   The specified substring or NULL.
+*/
+void*
+str_substring
+(
+    const void* str,
+    size_t begin_index,
+    size_t end_index,
+    void *sub_str,
+    size_t len
+);
+
+bool str_startwith(const char* str, const void* prefix);
+
+void* strstr_hex(char *haystack,int haystack_len,
+                    const char *needle,int needle_len);
+
+bool str_empty(const void *str);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif /* MBTK_STR_INCLUDE */
diff --git a/mbtk/include/mbtk/mbtk_task.h b/mbtk/include/mbtk/mbtk_task.h
new file mode 100755
index 0000000..d0a0604
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_task.h
@@ -0,0 +1,79 @@
+/*************************************************************
+Description:
+    mbtk_task.h
+    Used to define mobiletek standard task or thread interfaces
+Author:
+    YangDagang
+Date:
+    2019-7-13
+*************************************************************/
+#ifndef __MBTK_TASK_H__
+#define __MBTK_TASK_H__
+
+#include "mbtk_queue.h"
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+typedef void* (*mbtk_task_cb_handle)(void *payload);
+typedef void (*mbtk_uart_printf_cb)(char* data,int data_len);
+
+
+/*************************************************************
+    Definitions:enum,struct,union
+*************************************************************/
+typedef struct
+{
+    unsigned int sig;
+    void* payload;
+} mbtk_signal_info;
+
+typedef struct
+{
+    void* task_id;
+    mbtk_task_cb_handle thread_run;
+    void* args;
+} mbtk_task_info;
+
+typedef struct
+{
+    mbtk_uart_printf_cb urc_prt;
+    mbtk_uart_printf_cb data_prt;
+} mbtk_reg_callback;
+
+typedef struct {
+    pthread_t thread_id;
+    pthread_cond_t cond;
+    mbtk_mutex mutex;
+    mbtk_queue_node_t queue;
+} mbtk_task_queue_info;
+
+
+/*************************************************************
+    Variables:local,extern
+*************************************************************/
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Extern Function Declaration
+*************************************************************/
+extern int mbtk_task_start(mbtk_task_info *task);
+extern int mbtk_task_queue_start(void *param,mbtk_task_cb_handle cb);
+extern void mbtk_task_queue_stop(void *param);
+extern int mbtk_signal_send(void *param,mbtk_signal_info* info);
+extern mbtk_signal_info *mbtk_signal_get(void *param);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __MBTK_TASK_H__ */
+
diff --git a/mbtk/include/mbtk/mbtk_type.h b/mbtk/include/mbtk/mbtk_type.h
new file mode 100755
index 0000000..f948ab9
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_type.h
@@ -0,0 +1,120 @@
+#ifndef MBTK_TYPE_INCLUDE
+#define MBTK_TYPE_INCLUDE
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifndef MBTK_PLATFORM_LINUX
+#define MBTK_PLATFORM_LINUX
+#endif
+
+#ifndef MBTK_PLATFORM_QCOMM
+//#define MBTK_PLATFORM_QCOMM
+#endif
+
+#define MBTK_SUCCESS 0
+#define MBTK_FAILE (-1)
+
+#ifndef UNUSED
+#define UNUSED(param) ((void) param)
+#define UNUSEDPARAM UNUSED
+#endif
+
+#ifndef TRUE
+#define TRUE   1   /* Boolean true value. */
+#endif
+
+#ifndef true
+#define true   1   /* Boolean true value. */
+#endif
+
+#ifndef FALSE
+#define FALSE  0   /* Boolean false value. */
+#endif
+
+#ifndef false
+#define false  0   /* Boolean false value. */
+#endif
+
+
+#ifndef NULL
+#define NULL  0
+#endif
+
+
+#ifndef null
+#define null  0
+#endif
+
+/**
+ * Compiler-digit : 16
+ * char : 1     (%c)
+ * char* : 2
+ * short int : 2
+ * int : 2      (%d)
+ * unsigned int : 2  (%u)
+ * float : 4    (%f)
+ * double : 8   (%f)
+ * long : 4
+ * unsigned long : 4
+ * long long : 8
+ * unsigned long long : 8
+ *
+ *
+ * Compiler-digit : 32
+ * char : 1
+ * char* : 4
+ * short int : 2
+ * int : 4
+ * unsigned int : 4
+ * float : 4
+ * double : 8
+ * long : 4
+ * unsigned long : 4
+ * long long : 8
+ * unsigned long long : 8
+ *
+ *
+ * Compiler-digit : 64
+ * char : 1
+ * char* : 8
+ * short int : 2
+ * int : 4
+ * unsigned int : 4
+ * float : 4
+ * double : 8
+ * long : 8
+ * unsigned long : 8
+ * long long : 8
+ * unsigned long long : 8
+ */
+typedef unsigned char boolean; /* Boolean value type. */
+// typedef unsigned char bool; /* Boolean value type. */
+typedef unsigned long long uint64; /* Unsigned 64 bit value */
+typedef unsigned long long uint64_t; /* Unsigned 64 bit value */
+typedef unsigned int uint32; /* Unsigned 32 bit value */
+typedef unsigned int uint32_t; /* Unsigned 32 bit value */
+typedef unsigned short uint16; /* Unsigned 16 bit value */
+typedef unsigned short uint16_t;
+typedef unsigned char uint8; /* Unsigned 8  bit value */
+typedef unsigned char uint8_t;
+typedef signed long long int64; /* Signed 64 bit value */
+typedef signed long long sint64; /* Signed 64 bit value */
+typedef signed int int32; /* Signed 32 bit value */
+typedef signed int sint32; /* Signed 32 bit value */
+typedef signed short int16; /* Signed 16 bit value */
+typedef signed short sint16; /* Signed 16 bit value */
+typedef signed char int8; /* Signed 8  bit value */
+typedef signed char sint8; /* Signed 8  bit value */
+typedef unsigned char byte; /* byte type */
+
+
+typedef struct
+{
+    char *buffer;
+    int size;
+    int size_max;
+} mbtk_buffer_t;
+
+
+#endif /* MBTK_TYPE_INCLUDE */
diff --git a/mbtk/include/mbtk/mbtk_utils.h b/mbtk/include/mbtk/mbtk_utils.h
new file mode 100755
index 0000000..5b2113d
--- /dev/null
+++ b/mbtk/include/mbtk/mbtk_utils.h
@@ -0,0 +1,97 @@
+/*************************************************************
+Description:
+    MBTK utils head file.
+Author:
+    LiuBin
+Date:
+    2019/7/24 20:08:03
+*************************************************************/
+#ifndef _MBTK_UTILS_H
+#define _MBTK_UTILS_H
+#include "mbtk_type.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+#define MBTK_CMDLINE_LEN  1024
+
+
+/*************************************************************
+    Definitions:enum,struct,union,class
+*************************************************************/
+typedef void (*mbtk_timer_alrm_func)(int signo);
+typedef void (*mbtk_cmd_cb_func)(char *buf,int buf_size);
+
+
+/*************************************************************
+    Extern variables
+*************************************************************/
+typedef enum {
+    MBTK_BYTEORDER_BIG,     // Gig Endian
+    MBTK_BYTEORDER_LITTLE,  // Little Endian
+    MBTK_BYTEORDER_UNKNOWN
+} mbtk_byteorder_enum;
+
+/*************************************************************
+    Public Function Declaration
+*************************************************************/
+bool mbtk_cmd_line
+(
+    const char *cmd,
+    char *buf,
+    int buf_size
+);
+
+bool mbtk_cmd_line_ex
+(
+    const char *cmd,
+    mbtk_cmd_cb_func cb
+);
+
+int mbtk_send_at(const void *at_req,void* at_rsp,int rsp_size,int timeout);
+
+/*
+* Set timer as microseconds.
+*/
+int mbtk_timer_set(mbtk_timer_alrm_func func,uint32 timeout_ms);
+
+/**
+* Clear current timer.
+*/
+int mbtk_timer_clear();
+
+int mbtk_get_kernel_cmdline(char *buf, int len);
+
+/** returns 1 if line starts with prefix, 0 if it does not */
+int strStartsWith(const char *line, const char *prefix);
+
+char* mbtk_time_text_get(char *buff, size_t buff_size);
+
+mbtk_byteorder_enum mbtk_byteorder_get();
+
+uint16 byte_2_uint16(const void *buff, bool big_endian);
+
+int uint16_2_byte(uint16 a, void *buff, bool big_endian);
+
+uint32 byte_2_uint32(const void *buff, bool big_endian);
+
+int uint32_2_byte(uint32 a, void *buff, bool big_endian);
+
+uint64 byte_2_uint64(const void *buff, bool big_endian);
+
+int uint64_2_byte(uint64 a, void *buff, bool big_endian);
+
+void* memdup(const void* data, int data_len);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* _MBTK_UTILS_H */
diff --git a/mbtk/include/mbtk_device_info.h b/mbtk/include/mbtk_device_info.h
new file mode 100755
index 0000000..2f178eb
--- /dev/null
+++ b/mbtk/include/mbtk_device_info.h
@@ -0,0 +1,17 @@
+/*
+* MBTK Device Information Define Header.
+*
+* Author : lb
+* Date   : 2021/11/5 17:40:29
+*
+*/
+#ifndef MBTK_DEVICES_INFO_H
+#define MBTK_DEVICES_INFO_H
+
+#define MBTK_DEVICES_MANUFACTURER "LYNQ"
+
+#define MBTK_DEVICES_MODEL "LYNQ_L508LEN"
+
+#define MBTK_DEVICES_REVISION "L508LENv03.05b01.00"
+
+#endif /* MBTK_DEVICES_INFO_H */
diff --git a/mbtk/include/mqtt/MQTTClient.h b/mbtk/include/mqtt/MQTTClient.h
new file mode 100755
index 0000000..890a11b
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTClient.h
@@ -0,0 +1,100 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#ifndef __MQTT_CLIENT_C_

+#define __MQTT_CLIENT_C_

+

+#include "MQTTPacket.h"

+#include "stdio.h"

+#include "MQTTLinux.h" 

+

+#define MAX_PACKET_ID 65535

+#define MAX_MESSAGE_HANDLERS 5

+#define MAX_FAIL_ALLOWED  2

+

+enum QoS { QOS0, QOS1, QOS2 };

+

+// all failure return codes must be negative

+enum returnCode {DISCONNECTED = -3,  BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };

+

+void NewTimer(Timer*);

+

+typedef struct MQTTMessage MQTTMessage;

+

+typedef struct MessageData MessageData;

+

+struct MQTTMessage

+{

+    enum QoS qos;

+    char retained;

+    char dup;

+    unsigned short id;

+    void *payload;

+    size_t payloadlen;

+};

+

+struct MessageData

+{

+    MQTTMessage* message;

+    MQTTString* topicName;

+};

+

+typedef struct {

+    char clientId[255];

+    char deviceToken[255];

+} regnwl_info_t;

+

+typedef void (*messageHandler)(MessageData*);

+

+typedef struct Client Client;

+

+int MQTTConnect (Client*, MQTTPacket_connectData*);

+int MQTTPublish (Client*, const char*, MQTTMessage*);

+int MQTTSubscribe (Client*, const char*, enum QoS, messageHandler);

+int MQTTUnsubscribe (Client*, const char*);

+int MQTTDisconnect (Client*,Network*);

+int MQTTYield (Client*, int);

+

+void setDefaultMessageHandler(Client*, messageHandler);

+

+void MQTTClient(Client*, Network*, unsigned int, unsigned char*, size_t, unsigned char*, size_t);

+

+struct Client {

+    unsigned int next_packetid;

+    unsigned int command_timeout_ms;

+    size_t buf_size, readbuf_size;

+    unsigned char *buf;  

+    unsigned char *readbuf; 

+    unsigned int keepAliveInterval;

+    char ping_outstanding;

+    int fail_count;

+    int isconnected;

+

+    struct MessageHandlers

+    {

+        const char* topicFilter;

+        void (*fp) (MessageData*);

+    } messageHandlers[MAX_MESSAGE_HANDLERS];      // Message handlers are indexed by subscription topic

+    

+    void (*defaultMessageHandler) (MessageData*);

+    

+    Network* ipstack;

+    Timer ping_timer;

+};

+

+#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}

+

+#endif

diff --git a/mbtk/include/mqtt/MQTTConnect.h b/mbtk/include/mqtt/MQTTConnect.h
new file mode 100755
index 0000000..d77f18c
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTConnect.h
@@ -0,0 +1,136 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTCONNECT_H_

+#define MQTTCONNECT_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+

+typedef union

+{

+	unsigned char all;	/**< all connect flags */

+#if defined(REVERSED)

+	struct

+	{

+		unsigned int username : 1;			/**< 3.1 user name */

+		unsigned int password : 1; 			/**< 3.1 password */

+		unsigned int willRetain : 1;		/**< will retain setting */

+		unsigned int willQoS : 2;				/**< will QoS value */

+		unsigned int will : 1;			    /**< will flag */

+		unsigned int cleansession : 1;	  /**< clean session flag */

+		unsigned int : 1;	  	          /**< unused */

+	} bits;

+#else

+	struct

+	{

+		unsigned int : 1;	     					/**< unused */

+		unsigned int cleansession : 1;	  /**< cleansession flag */

+		unsigned int will : 1;			    /**< will flag */

+		unsigned int willQoS : 2;				/**< will QoS value */

+		unsigned int willRetain : 1;		/**< will retain setting */

+		unsigned int password : 1; 			/**< 3.1 password */

+		unsigned int username : 1;			/**< 3.1 user name */

+	} bits;

+#endif

+} MQTTConnectFlags;	/**< connect flags byte */

+

+

+

+/**

+ * Defines the MQTT "Last Will and Testament" (LWT) settings for

+ * the connect packet.

+ */

+typedef struct

+{

+	/** The eyecatcher for this structure.  must be MQTW. */

+	char struct_id[4];

+	/** The version number of this structure.  Must be 0 */

+	int struct_version;

+	/** The LWT topic to which the LWT message will be published. */

+	MQTTString topicName;

+	/** The LWT payload. */

+	MQTTString message;

+	/**

+      * The retained flag for the LWT message (see MQTTAsync_message.retained).

+      */

+	unsigned char retained;

+	/**

+      * The quality of service setting for the LWT message (see

+      * MQTTAsync_message.qos and @ref qos).

+      */

+	char qos;

+} MQTTPacket_willOptions;

+

+

+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }

+

+

+typedef struct

+{

+	/** The eyecatcher for this structure.  must be MQTC. */

+	char struct_id[4];

+	/** The version number of this structure.  Must be 0 */

+	int struct_version;

+	/** Version of MQTT to be used.  3 = 3.1 4 = 3.1.1

+	  */

+	unsigned char MQTTVersion;

+	MQTTString clientID;

+	unsigned short keepAliveInterval;

+	unsigned char cleansession;

+	unsigned char willFlag;

+	MQTTPacket_willOptions will;

+	MQTTString username;

+	MQTTString password;

+} MQTTPacket_connectData;

+

+typedef union

+{

+	unsigned char all;	/**< all connack flags */

+#if defined(REVERSED)

+	struct

+	{

+		unsigned int sessionpresent : 1;    /**< session present flag */

+		unsigned int : 7;	  	          /**< unused */

+	} bits;

+#else

+	struct

+	{

+		unsigned int : 7;	     			/**< unused */

+		unsigned int sessionpresent : 1;    /**< session present flag */

+	} bits;

+#endif

+} MQTTConnackFlags;	/**< connack flags byte */

+

+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \

+		MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }

+

+DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);

+DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);

+DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);

+

+DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);

+DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);

+

+#endif /* MQTTCONNECT_H_ */

diff --git a/mbtk/include/mqtt/MQTTFormat.h b/mbtk/include/mqtt/MQTTFormat.h
new file mode 100755
index 0000000..f7bd0d1
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTFormat.h
@@ -0,0 +1,37 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#if !defined(MQTTFORMAT_H)

+#define MQTTFORMAT_H

+

+#include "StackTrace.h"

+#include "MQTTPacket.h"

+

+const char* MQTTPacket_getName(unsigned short packetid);

+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);

+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);

+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,

+		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);

+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);

+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,

+		MQTTString topicFilters[], int requestedQoSs[]);

+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);

+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[]);

+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);

+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);

+

+#endif

diff --git a/mbtk/include/mqtt/MQTTLinux.h b/mbtk/include/mqtt/MQTTLinux.h
new file mode 100755
index 0000000..6ca888a
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTLinux.h
@@ -0,0 +1,74 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#ifndef __MQTT_LINUX_

+#define __MQTT_LINUX_

+

+#include <sys/types.h>

+#include <sys/socket.h>

+#include <sys/param.h>

+#include <sys/time.h>

+#include <sys/select.h>

+#include <netinet/in.h>

+#include <netinet/tcp.h>

+#include <arpa/inet.h>

+#include <netdb.h>

+#include <stdio.h>

+#include <unistd.h>

+#include <errno.h>

+#include <fcntl.h>

+#include <stdbool.h>

+#include <stdlib.h>

+#include <string.h>

+#include <signal.h>

+

+// #include <openssl/ssl.h>

+// #include <openssl/err.h>

+//#include "DC_iot_port.h"

+

+typedef struct Timer Timer;

+

+struct Timer {

+	struct timeval end_time;

+};

+

+typedef struct Network Network;

+struct Network

+{

+	int my_socket;

+    bool is_support_ssl;

+    bool ingnore_cert;

+    int handle;

+	int (*mqttread) (Network*, unsigned char*, int, int);

+	int (*mqttwrite) (Network*, unsigned char*, int, int);

+	void (*disconnect) (Network*);

+};

+

+char expired(Timer*);

+void countdown_ms(Timer*, unsigned int);

+void countdown(Timer*, unsigned int);

+int left_ms(Timer*);

+

+void InitTimer(Timer*);

+

+int linux_read(Network*, unsigned char*, int, int);

+int linux_write(Network*, unsigned char*, int, int);

+void linux_disconnect(Network*);

+void NewNetwork(Network*);

+

+int ConnectNetwork(Network*, char*, int, bool ,bool );

+

+#endif
\ No newline at end of file
diff --git a/mbtk/include/mqtt/MQTTPacket.h b/mbtk/include/mqtt/MQTTPacket.h
new file mode 100755
index 0000000..f417929
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTPacket.h
@@ -0,0 +1,133 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTPACKET_H_

+#define MQTTPACKET_H_

+

+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */

+extern "C" {

+#endif

+

+#if defined(WIN32_DLL) || defined(WIN64_DLL)

+  #define DLLImport __declspec(dllimport)

+  #define DLLExport __declspec(dllexport)

+#elif defined(LINUX_SO)

+  #define DLLImport extern

+  #define DLLExport  __attribute__ ((visibility ("default")))

+#else

+  #define DLLImport

+  #define DLLExport  

+#endif

+

+enum errors

+{

+	MQTTPACKET_BUFFER_TOO_SHORT = -2,

+	MQTTPACKET_READ_ERROR = -1,

+	MQTTPACKET_READ_COMPLETE

+};

+

+enum msgTypes

+{

+	CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,

+	PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,

+	PINGREQ, PINGRESP, DISCONNECT

+};

+

+/**

+ * Bitfields for the MQTT header byte.

+ */

+typedef union

+{

+	unsigned char byte;	                /**< the whole byte */

+#if defined(REVERSED)

+	struct

+	{

+		unsigned int type : 4;			/**< message type nibble */

+		unsigned int dup : 1;				/**< DUP flag bit */

+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */

+		unsigned int retain : 1;		/**< retained flag bit */

+	} bits;

+#else

+	struct

+	{

+		unsigned int retain : 1;		/**< retained flag bit */

+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */

+		unsigned int dup : 1;				/**< DUP flag bit */

+		unsigned int type : 4;			/**< message type nibble */

+	} bits;

+#endif

+} MQTTHeader;

+

+typedef struct

+{

+	int len;

+	char* data;

+} MQTTLenString;

+

+typedef struct

+{

+	char* cstring;

+	MQTTLenString lenstring;

+} MQTTString;

+

+#define MQTTString_initializer {NULL, {0, NULL}}

+

+int MQTTstrlen(MQTTString mqttstring);

+

+#include "MQTTConnect.h"

+#include "MQTTPublish.h"

+#include "MQTTSubscribe.h"

+#include "MQTTUnsubscribe.h"

+#include "MQTTFormat.h"

+

+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);

+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);

+

+int MQTTPacket_len(int rem_len);

+int MQTTPacket_equals(MQTTString* a, char* b);

+

+int MQTTPacket_encode(unsigned char* buf, int length);

+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);

+int MQTTPacket_decodeBuf(unsigned char* buf, int* value);

+

+int readInt(unsigned char** pptr);

+char readChar(unsigned char** pptr);

+void writeChar(unsigned char** pptr, char c);

+void writeInt(unsigned char** pptr, int anInt);

+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);

+void writeCString(unsigned char** pptr, const char* string);

+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);

+

+DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));

+

+typedef struct {

+	int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */

+	void *sck;	/* pointer to whatever the system may use to identify the transport */

+	int multiplier;

+	int rem_len;

+	int len;

+	char state;

+}MQTTTransport;

+

+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);

+

+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */

+}

+#endif

+

+

+#endif /* MQTTPACKET_H_ */

diff --git a/mbtk/include/mqtt/MQTTPublish.h b/mbtk/include/mqtt/MQTTPublish.h
new file mode 100755
index 0000000..d62dddb
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTPublish.h
@@ -0,0 +1,38 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTPUBLISH_H_

+#define MQTTPUBLISH_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,

+		MQTTString topicName, unsigned char* payload, int payloadlen);

+

+DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,

+		unsigned char** payload, int* payloadlen, unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);

+DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);

+DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);

+

+#endif /* MQTTPUBLISH_H_ */

diff --git a/mbtk/include/mqtt/MQTTSubscribe.h b/mbtk/include/mqtt/MQTTSubscribe.h
new file mode 100755
index 0000000..383ca0d
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTSubscribe.h
@@ -0,0 +1,39 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTSUBSCRIBE_H_

+#define MQTTSUBSCRIBE_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[], int requestedQoSs[]);

+

+DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,

+		int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);

+

+DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);

+

+

+#endif /* MQTTSUBSCRIBE_H_ */

diff --git a/mbtk/include/mqtt/MQTTUnsubscribe.h b/mbtk/include/mqtt/MQTTUnsubscribe.h
new file mode 100755
index 0000000..1644ae5
--- /dev/null
+++ b/mbtk/include/mqtt/MQTTUnsubscribe.h
@@ -0,0 +1,38 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTUNSUBSCRIBE_H_

+#define MQTTUNSUBSCRIBE_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[]);

+

+DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],

+		unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);

+

+DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);

+

+#endif /* MQTTUNSUBSCRIBE_H_ */

diff --git a/mbtk/include/mqtt/StackTrace.h b/mbtk/include/mqtt/StackTrace.h
new file mode 100755
index 0000000..c65a2ef
--- /dev/null
+++ b/mbtk/include/mqtt/StackTrace.h
@@ -0,0 +1,78 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Ian Craggs - fix for bug #434081

+ *******************************************************************************/

+

+#ifndef STACKTRACE_H_

+#define STACKTRACE_H_

+

+#include <stdio.h>

+#define NOSTACKTRACE 1

+

+#if defined(NOSTACKTRACE)

+#define FUNC_ENTRY

+#define FUNC_ENTRY_NOLOG

+#define FUNC_ENTRY_MED

+#define FUNC_ENTRY_MAX

+#define FUNC_EXIT

+#define FUNC_EXIT_NOLOG

+#define FUNC_EXIT_MED

+#define FUNC_EXIT_MAX

+#define FUNC_EXIT_RC(x)

+#define FUNC_EXIT_MED_RC(x)

+#define FUNC_EXIT_MAX_RC(x)

+

+#else

+

+#if defined(WIN32)

+#define inline __inline

+#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)

+#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)

+#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)

+#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)

+#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)

+#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)

+#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)

+#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)

+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)

+#else

+#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)

+#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)

+#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)

+#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)

+#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)

+#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)

+#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)

+#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)

+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)

+

+void StackTrace_entry(const char* name, int line, int trace);

+void StackTrace_exit(const char* name, int line, void* return_value, int trace);

+

+void StackTrace_printStack(FILE* dest);

+char* StackTrace_get(unsigned long);

+

+#endif

+

+#endif

+

+

+

+

+#endif /* STACKTRACE_H_ */

diff --git a/mbtk/include/ql/DSI_ConnectManager.h b/mbtk/include/ql/DSI_ConnectManager.h
new file mode 100755
index 0000000..3a8029f
--- /dev/null
+++ b/mbtk/include/ql/DSI_ConnectManager.h
@@ -0,0 +1,259 @@
+/**  
+  @file
+  DSI_ConnectManager.h
+
+  @brief
+  This file provides the definitions for dsi, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+24/07/2019  Nebula.li      create
+=============================================================================*/
+
+#ifndef __DSI_CONNECTMANAGER_H__
+#define __DSI_CONNECTMANAGER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define QL_WAN_SUCCESS                      (0)
+#define QL_WAN_ERROR                        (-1)
+#define QL_INTERFACE_NAME_LEN               16
+#define QL_IPV4_MAX_ADDR_LEN                32
+#define QL_IPV6_MAX_ADDR_LEN                128
+
+
+/**
+ * used to check network status, when timeout, start data call again.
+*/
+#define QL_WAN_NETWORK_STATUS_MAX_TIMEOUT   (60)
+
+
+/**
+ * DSI event define
+ */ 
+typedef enum
+{
+  CONNECT_DISCON = 0x00,
+  CONNECT_CONSUCCESS,
+  CONNECT_CONNING,
+  CONNECT_REDIAL,
+  CONNECT_DIAL_IMMEDIATELY,
+  CONNECT_ROAM,
+  CONNECT_WAIT_NWCHANGE,
+  CONNECT_GET_GLOBALIP_ERR,
+  CONNECT_DEACTIVATED,
+  CONNECT_WAIT_PS_ATTACH,
+
+  FAIL_BASE_INDEX=0x10,
+  SIM_NOT_READY=FAIL_BASE_INDEX+0x01,
+  NW_NOT_READY=FAIL_BASE_INDEX+0x02,
+  PDP_OPERATOR_BARRED =FAIL_BASE_INDEX+0x08,               /* no retry */
+  PDP_INSUFFICIENT_RESOURCES =FAIL_BASE_INDEX+0x1A,
+  PDP_MISSING_UKNOWN_APN = FAIL_BASE_INDEX+0x1B,            /* no retry */
+  PDP_UNKNOWN_PDP_ADDRESS_TYPE = FAIL_BASE_INDEX+0x1C,      /* no retry */
+  PDP_USER_AUTHENTICATION = FAIL_BASE_INDEX+0x1D,           /* no retry */
+  PDP_ACTIVATION_REJECT_GGSN = FAIL_BASE_INDEX+0x1E,        /* no retry */
+  PDP_ACTIVATION_REJECT_UNSPECIFIED = FAIL_BASE_INDEX+0x1F,
+  PDP_SERVICE_OPTION_NOT_SUPPORTED = FAIL_BASE_INDEX+0x20,  /* no retry */
+  PDP_SERVICE_OPTION_NOT_SUBSCRIBED = FAIL_BASE_INDEX+0x21, /* no retry */
+  PDP_SERVICE_OPTION_OUT_OF_ORDER = FAIL_BASE_INDEX+0x22,
+  PDP_NSAPI_IN_USE = FAIL_BASE_INDEX+0x23,                  /* no retry */
+  PDP_REGULAR_DEACTIVATION = FAIL_BASE_INDEX+0x24,          /* possibly restart radio,
+                                                    based on framework config */
+  PDP_ONLY_IPV4_ALLOWED = FAIL_BASE_INDEX+0x32,             /* no retry */
+  PDP_ONLY_IPV6_ALLOWED = FAIL_BASE_INDEX+0x33,             /* no retry */
+  PDP_ONLY_SINGLE_BEARER_ALLOWED = FAIL_BASE_INDEX+0x34,
+  PDP_PROTOCOL_ERRORS   = FAIL_BASE_INDEX+0x6F,             /* no retry */
+
+  /* Not mentioned in the specification */
+  PDP_VOICE_REGISTRATION_FAIL = -1,
+  PDP_DATA_REGISTRATION_FAIL = -2,
+
+  /* reasons for data call drop - network/modem disconnect */
+  PDP_SIGNAL_LOST = -3,
+  PDP_PREF_RADIO_TECH_CHANGED = -4,/* preferred technology has changed, should retry
+                                            with parameters appropriate for new technology */
+  PDP_RADIO_POWER_OFF = -5,        /* data call was disconnected because radio was resetting,
+                                            powered off - no retry */
+  PDP_TETHERED_CALL_ACTIVE = -6,   /* data call was disconnected by modem because tethered
+                                            mode was up on same APN/data profile - no retry until
+                                            tethered call is off */
+	PDP_CID_EXIST_FAIL = -7,		  /* cid is exist already*/
+
+  PDP_NO_CCINET=-10,
+  PDP_DHCP_SERVER_ERR_PIPE=-11,
+
+  PDP_ERROR_UNSPECIFIED = 0xffff,  /* retry silently */
+  QL_DSI_EVT_MAX
+} QL_DSI_NET_EVT_T;
+
+#define SIM_REMOVED SIM_NOT_READY
+
+typedef struct
+{
+	char ip[QL_IPV4_MAX_ADDR_LEN];
+	char pri_dns[QL_IPV4_MAX_ADDR_LEN];
+	char sec_dns[QL_IPV4_MAX_ADDR_LEN];
+  char name[QL_INTERFACE_NAME_LEN];
+  char gateway[QL_IPV4_MAX_ADDR_LEN];
+}v4_address_status;
+
+typedef struct
+{
+	int state; //dial status
+	v4_address_status addr; //IPv4 address information
+}v4_info;
+
+typedef struct
+{
+	char ip[QL_IPV6_MAX_ADDR_LEN];
+	char pri_dns[QL_IPV6_MAX_ADDR_LEN];
+	char sec_dns[QL_IPV6_MAX_ADDR_LEN];
+  char name[QL_INTERFACE_NAME_LEN];
+  char gateway[QL_IPV6_MAX_ADDR_LEN];
+}v6_address_status;
+
+typedef struct
+{
+	int state; //dial status
+	v6_address_status addr; //IPv6 address information
+}v6_info;
+
+typedef struct
+{
+	int profile_idx;
+	int ip_type;
+	v4_info v4;
+	v6_info v6;
+}ql_data_call_info;
+
+/**
+ * DSI auth pref define
+*/
+typedef enum
+{
+  QL_DSI_AUTH_PREF_NULL = 0,
+  QL_DSI_AUTH_PREF_ONLY_PAP,
+  QL_DSI_AUTH_PREF_ONLY_CHAP,
+  //QL_DSI_AUTH_PREF_BOTH_PAP_CHAP
+} QL_DSI_AUTH_PREF_T;
+
+/** 
+ * callback function used in  ql_wan_start, when data call status changed, 
+ * Use callback functions for notifications, see enum QL_DSI_NET_EVT_T
+*/
+typedef void (*nw_status_cb)(int status);
+
+
+typedef void (*ex_conn_status_cb)(int cid,int iptype,int status,int cause);
+
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief data call init function, must call first.
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_wan_init();
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief data call release function, must call finally.
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_wan_release();
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief data call auto connect set, include auto status and interval(seconds).
+  @param[in] auto_status  When it is 0, the network cannot be automatically reconnected 
+                                after disconnection; when it is 1, it can be automatically reconnected
+  @param[in] interval_sec data call status check interval
+                                the max value is QL_WAN_NETWORK_STATUS_MAX_TIMEOUT
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_wan_set_autoconnect(int auto_status, int interval_sec);
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief start data call, must call ql_wan_init first.
+  @param[in] nw_cb this is a callback function, when data call status changed, Use callback 
+                   functions for notifications
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_wan_start(int profile_idx, int op, nw_status_cb nw_cb);
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief start data call, must call ql_wan_init first.
+  @param[in] nw_cb this is a callback function, when data call status changed, Use callback 
+                   functions for notifications
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_wan_start_ex(int profile_idx, int op, ex_conn_status_cb nw_cb);
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief data call stop function.
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_wan_stop(int profile_idx);
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief function to set apn.
+  @param[in] apn        apn name want to set
+  @param[in] username   user name of apn
+  @param[in] password   password of apn
+  @param[in] auth       auth type of apn, see enum QL_DSI_AUTH_PREF_T
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+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);
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief function to get first apn infomation.
+  @param[out] apn       apn name to return
+  @param[in ] apnLen    apn name buffer size
+  @param[out] userName  username of apn to return
+  @param[in ] userLen   username buffer size
+  @param[out] password  password to return
+  @param[in ] pwdLen    password buffer size 
+  @return if success return QL_WAN_SUCCESS, else return QL_WAN_ERROR
+  */
+/*-----------------------------------------------------------------------------------------------*/
+
+#define ql_wan_getapn(profile_idx,ip_type,apn,apnLen,userName,userLen,password,pwdLen,...)   __ql_wan_getapn(profile_idx,ip_type,apn,apnLen,userName,userLen,password,pwdLen,(NULL,##__VA_ARGS__))
+
+int __ql_wan_getapn(int profile_idx, int *ip_type, char *apn, int apnLen, char *userName, int userLen, char *password, int pwdLen,int* auth);
+int ql_get_data_call_info(int profile_idx, ql_data_call_info *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mbtk/include/ql/ql_adc.h b/mbtk/include/ql/ql_adc.h
new file mode 100755
index 0000000..a2c71df
--- /dev/null
+++ b/mbtk/include/ql/ql_adc.h
@@ -0,0 +1,47 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of Quectel Co., Ltd. 2019
+*
+*****************************************************************************/
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *   ql_adc.h 
+ *
+ * Project:
+ * --------
+ *   OpenLinux
+ *
+ * Description:
+ * ------------
+ *   ADC API defines.
+ *
+ *
+ *============================================================================
+ *             HISTORY
+ *----------------------------------------------------------------------------
+ * WHO            WHEN                WHAT
+ *----------------------------------------------------------------------------
+ * Carola.Zhang   20/11/2019		  Create.
+ ****************************************************************************/
+
+#ifndef __QL_ADC_H__
+#define __QL_ADC_H__
+
+typedef enum {
+    QADC_NONE = -1,
+    ADC0 = 0,
+    ADC1 = 1,
+    QADC_END
+}Enum_QADC;
+
+
+int ql_adc_show(Enum_QADC qadc);
+
+
+#endif
\ No newline at end of file
diff --git a/mbtk/include/ql/ql_at.h b/mbtk/include/ql/ql_at.h
new file mode 100755
index 0000000..9cd6e8f
--- /dev/null
+++ b/mbtk/include/ql/ql_at.h
@@ -0,0 +1,91 @@
+
+#ifndef __QL_AT_H__
+#define __QL_AT_H__
+
+//#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TRUE  1
+#define FALSE 0
+
+#define BUF_LEN     1024
+
+#define MAX_URC_EVENT_HANDLER_ARRAY_SIZE    10
+
+//typedef unsigned int size_t;
+typedef int URC_EVENT_HANDLE;
+typedef void (*ql_urc_event_handle_func_t)(const char* urc_content);
+
+typedef struct
+{
+    char*      urc_event;
+    ql_urc_event_handle_func_t    pfun;
+} st_urc_handle_node;
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Standard result codes.
+ *
+ * @note All error codes are negative integers. They allow functions with signed
+ *  integers to return non-negative values when successful or standard error codes on failure.
+ * @deprecated the result code LE_NOT_POSSIBLE is scheduled to be removed.
+ */
+//--------------------------------------------------------------------------------------------------
+typedef enum
+{
+    E_QL_OK                 = 0,    ///< Successful.
+    E_QL_NOT_FOUND          = -1,   ///< Referenced item does not exist or could not be found.
+    E_QL_NOT_POSSIBLE       = -2,   ///< @deprecated It is not possible to perform the requested action.
+    E_QL_OUT_OF_RANGE       = -3,   ///< An index or other value is out of range.
+    E_QL_NO_MEMORY          = -4,   ///< Insufficient memory is available.
+    E_QL_NOT_PERMITTED      = -5,   ///< Current user does not have permission to perform requested action.
+    E_QL_FAULT              = -6,   ///< Unspecified internal error.
+    E_QL_COMM_ERROR         = -7,   ///< Communications error.
+    E_QL_TIMEOUT            = -8,   ///< A time-out occurred.
+    E_QL_OVERFLOW           = -9,   ///< An overflow occurred or would have occurred.
+    E_QL_UNDERFLOW          = -10,  ///< An underflow occurred or would have occurred.
+    E_QL_WOULD_BLOCK        = -11,  ///< Would have blocked if non-blocking behaviour was not requested.
+    E_QL_DEADLOCK           = -12,  ///< Would have caused a deadlock.
+    E_QL_FORMAT_ERROR       = -13,  ///< Format error.
+    E_QL_DUPLICATE          = -14,  ///< Duplicate entry found or operation already performed.
+    E_QL_BAD_PARAMETER      = -15,  ///< Parameter is invalid.
+    E_QL_CLOSED             = -16,  ///< The resource is closed.
+    E_QL_BUSY               = -17,  ///< The resource is busy.
+    E_QL_UNSUPPORTED        = -18,  ///< The underlying resource does not support this operation.
+    E_QL_IO_ERROR           = -19,  ///< An IO operation failed.
+    E_QL_NOT_IMPLEMENTED    = -20,  ///< Unimplemented functionality.
+    E_QL_UNAVAILABLE        = -21,  ///< A transient or temporary loss of a service or resource.
+    E_QL_TERMINATED         = -22,  ///< The process, operation, data stream, session, etc. has stopped.
+}E_QL_RESULT;
+
+extern const char strDelimit[];
+
+extern st_urc_handle_node g_urc_handler[];
+
+/*
+    Specify the AT port name used for sending/receiving AT cmd.
+*/
+extern int QL_AT_PortInit(char *device_path);   
+
+extern void QL_AT_PortDeinit(void);
+
+/*
+    register the URC event call back, such as "+CMT: ;+CDS: ;+CBM: ;+CMTI: ;" seperated by ";" for sms.
+*/
+extern URC_EVENT_HANDLE register_urc_callback_func(const char* urc_event, ql_urc_event_handle_func_t pfun);
+
+/*
+    unregister the URC event call back.
+*/
+extern void unregister_urc_callback_func(URC_EVENT_HANDLE h_handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__QL_AT_H__
diff --git a/mbtk/include/ql/ql_atc.h b/mbtk/include/ql/ql_atc.h
new file mode 100755
index 0000000..4c8d8a8
--- /dev/null
+++ b/mbtk/include/ql/ql_atc.h
@@ -0,0 +1,63 @@
+/**

+  @file

+  ql_atc.h

+  @brief

+  send at command api

+

+*/

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

+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.

+  Quectel Wireless Solution Proprietary and Confidential.

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

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

+

+                        EDIT HISTORY FOR MODULE

+

+This section contains comments describing changes made to the module.

+Notice that changes are listed in reverse chronological order.

+

+

+WHEN        WHO            WHAT, WHERE, WHY

+----------  ------------   ----------------------------------------------------

+06/07/2022  Wayen.xu      create

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

+

+#ifndef QL_ATC_H

+#define QL_ATC_H

+

+/*******************************************************

+* @method: ql_atc_init

+* @Description: initialize environment variables.                

+* @param: void

+* @return: 

+         success: return 0

+         error: return !0

+********************************************************/

+int ql_atc_init();

+

+/*******************************************************

+* @method: ql_atc_release

+* @Description: release environment variables.                

+* @param: void

+* @return: 

+         success: return 0

+         error: return !0

+********************************************************/

+int ql_atc_release();

+

+/*******************************************************

+* @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);

+

+

+#endif

diff --git a/mbtk/include/ql/ql_audio.h b/mbtk/include/ql/ql_audio.h
new file mode 100755
index 0000000..68c2190
--- /dev/null
+++ b/mbtk/include/ql/ql_audio.h
@@ -0,0 +1,627 @@
+/**
+  @file
+  ql_audio.h
+
+  @brief
+  This file provides the definitions for audio & record, and declares the
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+07/06/2018  Stanley.yong   Revise the comments for API.
+19/04/2018  Zichar.zhang   Add Ql_Update_wav_size function.
+                           Add Ql_AudPlayer_OpenExt function.
+                           Add Ql_AudRecorder_OpenExt function.
+19/12/2016  Stanley.yong   Optimize the APIs, and add comments.
+13/12/2016  Running.qian   Implement newly-designed APIs.
+18/07/2016	Jun.wu         Create
+=============================================================================*/
+
+#ifndef __AUD_H__
+#define __AUD_H__
+
+//this two headers for alsa params setting
+// #include "asoundlib.h"
+//#include "alsa-intf/alsa_audio.h"
+
+#include "mbtk_type.h"
+
+#define QUEC_PCM_8K 8000
+#define QUEC_PCM_16K 16000
+#define QUEC_PCM_44k 44100
+#define QUEC_PCM_MONO 1
+#define QUEC_PCM_STEREO 2
+
+typedef enum {
+        AUD_UP_LINK = 0,
+        AUD_DOWN_LINK,
+} Enum_AudDlink;
+
+typedef enum {
+	AUD_PLAYER_ERROR = -1,
+	AUD_PLAYER_START = 0,
+	AUD_PLAYER_PAUSE,
+	AUD_PLAYER_RESUME,
+	AUD_PLAYER_NODATA,  //Buff no data and play tread will sleep
+    AUD_PLAYER_LESSDATA, //Buff has less data
+	AUD_PLAYER_FINISHED,
+} Enum_AudPlayer_State;
+
+typedef enum {
+	AUD_RECORDER_ERROR = -1,
+	AUD_RECORDER_START = 0,
+	AUD_RECORDER_PAUSE,
+	AUD_RECORDER_RESUME,
+	AUD_RECORDER_FINISHED,
+} Enum_AudRecorder_State;
+
+
+/****************************************************************************
+*  Audio Volume Level Definition
+***************************************************************************/
+typedef enum {
+	AUD_VOLUME_LEVEL1 = 0,
+	AUD_VOLUME_LEVEL2,
+	AUD_VOLUME_LEVEL3,
+	AUD_VOLUME_LEVEL4,
+	AUD_VOLUME_LEVEL5,
+	AUD_VOLUME_LEVEL_END
+}Enum_AudVolumeLevel;
+
+/****************************************************************************
+*  Audio Format
+***************************************************************************/
+typedef enum {
+	AUD_STREAM_FORMAT_MP3 = 0,
+	AUD_STREAM_FORMAT_AMR = 1,
+	AUD_STREAM_FORMAT_PCM = 2,
+	AUD_STREAM_FORMAT_END
+} Enum_AudStreamFormat;
+
+/****************************************************************************
+*  Audio Direct
+***************************************************************************/
+typedef enum {
+	AUD_LINK_REVERSE = 0,
+	AUD_LINK_FORWARD = 1,
+	AUD_LINK_BOTH = 2,
+	AUD_LINK_INVALID
+}Enum_AudStreamDirection;
+
+
+/*****************************************************************
+********************New Advanced Audio High API******************
+* ***************************************************************/
+struct wav_header {
+	uint32_t riff_id;
+	uint32_t riff_sz;
+	uint32_t riff_fmt;
+	uint32_t fmt_id;
+	uint32_t fmt_sz;
+	uint16_t audio_format;
+	uint16_t num_channels;
+	uint32_t sample_rate;
+	uint32_t byte_rate;       /* sample_rate * num_channels * bps / 8 */
+	uint16_t block_align;     /* num_channels * bps / 8 */
+	uint16_t bits_per_sample;
+	uint32_t data_id;
+	uint32_t data_sz;
+};
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT  0x20746d66
+#define ID_DATA 0x61746164
+#define FORMAT_PCM 1
+
+struct ST_MediaParams {
+	Enum_AudStreamFormat     format;
+	Enum_AudVolumeLevel      volume;
+	Enum_AudStreamDirection     direct;
+};
+
+
+//
+// Function:  _cb_onPlayer
+//
+// Description:
+//   This callback function handles the result of audio player.
+//
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+// @param result:
+//   the executing result for previous operation, such as Open, Play, Pause, Resume, Stop.
+//   see the definition of Enum_AudPlayer_State for the specific meaning.
+typedef int(*_cb_onPlayer)(int hdl, int result);
+//
+// Function:  _cb_onRecorder
+//
+// Description:
+//   This callback function handles the result of audio recorder.
+//   If result < 0, the recorder will stop the recording automatically.
+//
+// @param result:
+//   the executing result for previous operation, such as Open, StartRecord, Pause, Resume, Stop.
+//   see the definition of Enum_AudRecorder_State for the specific meaning.
+// @param pBuf:
+//   pointer to the output recording (PCM) data.
+// @param length:
+//   the length of the output recording (PCM) data.
+typedef int(*_cb_onRecorder)(int result, unsigned char* pBuf, unsigned int length);  //if result < 0 will stop record, else  continue record
+
+/*****************************************************************
+* 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);
+
+/*========================================================================
+  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);
+
+/*========================================================================
+  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);
+//
+// Function:  Ql_AudPlayer_Pause
+//
+// Description:
+//   Pause playing.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+int  Ql_AudPlayer_Pause(int hdl);
+//
+// Function:  Ql_AudPlayer_Resume
+//
+// Description:
+//   Resume playing.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+int  Ql_AudPlayer_Resume(int hdl);
+//
+// Function:  Ql_AudPlayer_Stop
+//
+// Description:
+//   Stop playing audio
+// hdl:
+//   Handle received from Ql_AudPlayer_Open().
+void Ql_AudPlayer_Stop(int hdl);
+//
+// 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);
+
+
+int Ql_AudPlayer_set_LessDataThreshold(int hdl, unsigned short threshSize);
+
+int Ql_AudPlayer_get_freeSpace(int hdl);
+
+
+/*****************************************************************
+* 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);
+//
+// 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);
+//
+// Function:  Ql_AudRecorder_Pause
+//
+// Description:
+//   Pause recording
+int  Ql_AudRecorder_Pause(void);
+//
+// Function:  Ql_AudRecorder_Resume
+//
+// Description:
+//   Resume recording
+int  Ql_AudRecorder_Resume(void);
+//
+// Function:  Ql_AudRecorder_Stop
+//
+// Description:
+//   Stop recording
+void Ql_AudRecorder_Stop(void);
+//
+// Function:  Ql_AudRecorder_Close
+//
+// Description:
+//   Close recorder, and free the resource
+void Ql_AudRecorder_Close(void);
+
+//
+// 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);
+
+
+//****************QL TONE API************************//
+struct Ql_TonePara {
+    unsigned int lowFreq;   //100-4000HZ
+    unsigned int highFreq;  //100-4000HZ
+    unsigned int volume;    //0 -1000
+    unsigned int duration;  // >0 ms
+};
+
+int Ql_AudTone_Open(char* device, _cb_onPlayer cb);//cb not support now
+int Ql_AudTone_Start(int hdl, struct Ql_TonePara *para);
+void Ql_AudTone_Stop(int hdl);
+void Ql_AudTone_Close(int hdl);
+
+
+//****************QL Codec API************************//
+struct Ql_ALC5616_DRCAGC {
+    unsigned short control1_mask;
+    unsigned short control1_value;
+    unsigned short control2_mask;
+    unsigned short control2_value;
+    unsigned short control3_mask;
+    unsigned short control3_value;
+};
+
+//
+// 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);
+
+//
+// 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);
+
+//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);
+
+/*
+ * describe : this function is use to close pcm handle
+ * paras    :
+ *        pcm : pcm handle to close
+ * return    :
+ */
+int quec_pcm_close(struct pcm *pcm );
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+//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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+
+//end grady
+
+/**
+ * @brief Set RX DSP Gain
+ * @details
+ *      Gain support [-36,12] dB
+ *
+ * @param gain
+ *      DSP gain
+ */
+
+int Ql_Rxgain_Set(int gain);
+
+/**
+ * @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);
+
+/*****************************************************************
+* 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);
+
+/*****************************************************************
+* 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);
+
+/*****************************************************************
+* Function:     Ql_Mp3_To_Wav
+*
+* Description:
+*               set mp3 file change to wav file.
+*
+* Parameters:
+*               wavpath  : wav path
+*
+*		        mp3path : mp3 path
+*
+* Return:
+*               0:  success
+*               -1: fail
+*****************************************************************/
+int Ql_Mp3_To_Wav(const char *wavpath, char *mp3path);
+
+
+/*****************************************************************
+* Function:     Ql_Mp3_To_Wav
+*
+* Description:
+*               flay mp3 file.
+*
+* Parameters:
+*               wavpath  : wav path
+*
+*		        hdl : Device handle
+*
+*               sample_rate : 0 for NB(8000) 1 for WB(16000)
+*
+* Return:
+*               0:  success
+*               -1: fail
+*****************************************************************/
+
+int Ql_Mp3_To_Play(char *mp3path, int hdl,int sample_rate);
+/*
+* Function:     uac enable
+*
+* Description:
+*               uac enable
+*
+* Parameters:
+*               none
+* Return:
+*               TURE or FALSE
+*/
+int ql_uac_enable(void);
+
+/*
+* Function:     uac disable
+*
+* Description:
+*               uac disable
+*
+* Parameters:
+*               none
+* Return:
+*               TURE or FALSE
+*/
+int ql_uac_disable(void);
+
+#endif //__AUD_H__
diff --git a/mbtk/include/ql/ql_cell_locator.h b/mbtk/include/ql/ql_cell_locator.h
new file mode 100755
index 0000000..4244f82
--- /dev/null
+++ b/mbtk/include/ql/ql_cell_locator.h
@@ -0,0 +1,116 @@
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @file ql_cell_locator.h
+  @brief Common API
+*/
+/*-----------------------------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------------------------------
+  Copyright (c) 2018 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+-------------------------------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------------------------------
+  EDIT HISTORY
+  This section contains comments describing changes made to the file.
+  Notice that changes are listed in reverse chronological order.
+  $Header: $
+  when       who          what, where, why
+  --------   ---          ----------------------------------------------------------
+  20190321   baron.qian  Created .
+-------------------------------------------------------------------------------------------------*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+#ifndef __QL_CELL_LOCATOR_H__
+#define __QL_CELL_LOCATOR_H__
+
+/**/
+#define LOCATOR_MAX_ADDRESS_SIZE (256)
+#define LOCATOR_MAX_ERR_MSG_SIZE (256)
+
+
+typedef enum {
+    Q_LOC_ADDR_UTF8 = 0,
+    Q_LOC_ADDR_GBK,
+    Q_LOC_ADDR_ASCII,
+    Q_LOC_ADDR_NUM,
+}QUECLOCATOR_CHARSET;
+
+typedef struct {
+    int err_code;
+    char err_msg[LOCATOR_MAX_ERR_MSG_SIZE];
+} ql_cell_err;
+
+typedef struct {
+    /*longtitude*/
+    double lon;
+    /*latitude*/
+    double lat;
+    /*accuracy*/
+    unsigned short accuracy;
+    /*address charset, not support yet*/
+    QUECLOCATOR_CHARSET charset;
+    /*address info, not support yet*/
+    unsigned char addrinfo[LOCATOR_MAX_ADDRESS_SIZE];
+    /*address length, not support yet*/
+    unsigned short addrlen;
+    /*result*/
+    ql_cell_err err;
+} ql_cell_resp;
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief cell locator init function, when you want to use cell locator, call this function first!
+  @return if success return 0, else return -1
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_cell_locator_init();
+
+
+int ql_cell_locator_release();
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @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);
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @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);
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @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);
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @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);
+
+
+#endif /* !__QL_CELL_LOCATOR_H__ */
+#ifdef __cplusplus
+} 
+#endif
diff --git a/mbtk/include/ql/ql_common.h b/mbtk/include/ql/ql_common.h
new file mode 100755
index 0000000..eef054d
--- /dev/null
+++ b/mbtk/include/ql/ql_common.h
@@ -0,0 +1,76 @@
+

+/**  

+  @file

+  ql_common.h

+

+  @brief

+  This file provides the definitions for common functions, and declares the 

+  common functions.

+

+*/

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

+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.

+  Quectel Wireless Solution Proprietary and Confidential.

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

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

+

+                        EDIT HISTORY FOR MODULE

+

+This section contains comments describing changes made to the module.

+Notice that changes are listed in reverse chronological order.

+

+

+WHEN        WHO            WHAT, WHERE, WHY

+----------  ------------   ----------------------------------------------------

+23/08/2019  Nebula.li      create

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

+

+#ifndef __QL_COMMON_H__

+#define __QL_COMMON_H__

+

+#include <sys/types.h>

+#include <unistd.h>

+#include <sys/syscall.h>

+

+#include <libubox/ustream.h>

+#include <libubox/blobmsg_json.h>

+#include <libubox/kvlist.h>

+#include "libubus.h"

+#include "uci_blob.h"

+#include "libubox/uloop.h"

+#include "rilutil.h"

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+void Ql_Powerdown(int mode);

+

+int ql_start_main_thread();

+int ql_exit_main_thread();

+int ql_ril_sync_request(unsigned int requestid, const void * data, int len,void* priv,void * cb,int timeout);

+int ql_ril_async_request(unsigned int requestid, const void * data, int len,void* priv,void * cb);

+int ql_ubus_sync_request(char *obj_name, char *method,struct blob_buf *blob_buf,void* priv,void *cb,int timeout);

+int ql_ubus_async_request(char *obj_name, char *method,struct blob_buf *blob_buf,void* priv,void *cb);

+int ql_ubus_subscribe_reg(char *subscriber_name, struct ubus_subscriber *event_obj);

+int ql_ubus_subscribe_remove(char *subscriber_name, struct ubus_subscriber *event_obj);

+

+int atcmd_get_line_num(char * result, int result_len);

+char * atcmd_get_line(char * result, int result_len,int index);

+int atcmd_get_para_num(char * line);

+void atcmd_get_para_value_str(char * line,int index, char *para_value);

+void ql_set_response(struct kvlist *result_list,int reqid, int resp_type, int ret, void *data, int data_len);

+int ql_get_response(struct kvlist *result_list,int reqid, int * resp_type, void *data);

+int kvlist_get_len(struct kvlist *kv, const void *data);

+

+int utf8_to_usc2(unsigned char *utf8_data,int utf8_data_len, unsigned int *usc2_data);

+int usc2_to_utf8(unsigned int *usc2_data, int usc2_data_len, unsigned char *utf8_data);

+

+int set_config_option(const char *package, const char *section, const char *option, const char *value);

+char *get_config_option(char *package, char *section, char *option);

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif
\ No newline at end of file
diff --git a/mbtk/include/ql/ql_dev.h b/mbtk/include/ql/ql_dev.h
new file mode 100755
index 0000000..04a6dd5
--- /dev/null
+++ b/mbtk/include/ql/ql_dev.h
@@ -0,0 +1,114 @@
+/**  
+  @file
+  ql_dev.h
+
+  @brief
+  This file provides the definitions for device, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+11/10/2019  Nebula.li      create
+=============================================================================*/
+
+#ifndef __QL_DEV_H__
+#define __QL_DEV_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum 
+{
+	QL_DEV_SUCCESS,
+	QL_DEV_GENERIC_FAILURE,
+ 	QL_DEV_RADIO_NOT_AVAILABLE,
+}QL_DEV_ERROR_CODE;
+
+typedef enum 
+{
+	QL_DEV_MODEM_MIN_FUN,
+	QL_DEV_MODEM_FULL_FUN,
+	QL_DEV_MODEM_DISABLE_RECEIVE_RF_CIRCUITS = 3,
+	QL_DEV_MODEM_DISABLE_TRANSMIT_AND_RECEIVE_RF_CIRCUITS,
+	QL_DEV_MODEM_DISABLE_SIM,
+	QL_DEV_MODEM_TURN_OFF_FULL_SECONDARY_RECEIVE,
+}QL_DEV_MODEM_FUNCTION;
+
+QL_DEV_ERROR_CODE ql_dev_init ();
+QL_DEV_ERROR_CODE ql_dev_release();
+
+/*
+    Get the IMEI string.
+     -imei      : input buffer
+*/
+QL_DEV_ERROR_CODE ql_dev_get_imei(char* imei);
+
+
+/*
+    Get the FirmwareVersion string.
+     -version   : input buffer
+*/
+QL_DEV_ERROR_CODE ql_dev_get_firmware_version(char* version);
+
+
+/*
+    Get the DeviceModel string.
+     -model     : input buffer
+*/
+QL_DEV_ERROR_CODE ql_dev_get_model(char* model);
+
+
+/*
+    Get the SN string.
+     -sn       : input buffer
+*/
+QL_DEV_ERROR_CODE ql_dev_get_sn(char* sn);
+
+/*
+    Set the modem function.
+     -function       :[in]   modem function
+     -rst    :[in]    if it is to reset modem before setting modem function. (0: not to reset; 1: reset)
+*/
+QL_DEV_ERROR_CODE ql_dev_set_modem_fun(QL_DEV_MODEM_FUNCTION function,int rst);
+
+/*
+    Get the modem function.
+     -function    :[out]  modem function
+*/
+QL_DEV_ERROR_CODE ql_dev_get_modem_fun(int *function);
+
+/*
+    Set the modem forbid urc.
+    forbid NETWORK  0x01
+    forbid SIM      0x02
+    forbid SMS      0x04
+    forbid CS CALL  0x08
+    forbid PS DATA  0x10
+     -bitmask       :[in]   modem forbid urc
+    Set bitmask to 31 before sleep and 1 after wake up 
+*/
+QL_DEV_ERROR_CODE ql_dev_forbidind(int bitmask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mbtk/include/ql/ql_fota.h b/mbtk/include/ql/ql_fota.h
new file mode 100755
index 0000000..fab1d48
--- /dev/null
+++ b/mbtk/include/ql/ql_fota.h
@@ -0,0 +1,95 @@
+/**  
+  @file
+  ql_fota.h
+
+  @brief
+  This file provides the definitions for device, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+08/11/2019  baron.qian      create
+=============================================================================*/
+#ifndef __QL_FOTA_H__
+#define __QL_FOTA_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    QUEC_FOTA_OK,           /*OK*/
+    QUEC_FOTA_FAILED        /*failed*/
+}QL_FOTA_STATUS;
+
+/*callback function define, used to get upgrade state and rate of process*/
+typedef int(*fota_callback)(int state, int percent);
+
+/*******************************************************************************
+* @brief fota initialize
+  @param 
+    
+    fota_callback: callback function
+  @return 
+        if success return 0, else return -1
+ *******************************************************************************/
+int ql_fota_init(fota_callback 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);
+
+
+/*******************************************************************************
+* @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);
+
+
+/*******************************************************************************
+* @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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //__QL_FOTA_H__
diff --git a/mbtk/include/ql/ql_gpio.h b/mbtk/include/ql/ql_gpio.h
new file mode 100755
index 0000000..74402e9
--- /dev/null
+++ b/mbtk/include/ql/ql_gpio.h
@@ -0,0 +1,376 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of Quectel Co., Ltd. 2019
+*
+*****************************************************************************/
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *   ql_gpio.h 
+ *
+ * Project:
+ * --------
+ *   OpenLinux
+ *
+ * Description:
+ * ------------
+ *   GPIO API defines.
+ *
+ *
+ *============================================================================
+ *             HISTORY
+ *----------------------------------------------------------------------------
+ * WHO            WHEN                WHAT
+ *----------------------------------------------------------------------------
+ * Carola.Zhang   16/07/2019		  Create.
+ ****************************************************************************/
+
+#ifndef __QL_GPIO_H__
+#define __QL_GPIO_H__
+
+typedef enum{
+    /*Invalid*/  PINNAME_BEGIN = -1,
+	/*PIN-1*/    PINNAME_GPIO1 = 1,
+	/*PIN-2*/    PINNAME_GPIO2 = 2,
+	/*PIN-3*/    PINNAME_GPIO3 = 3,
+	/*PIN-4*/    PINNAME_GPIO4 = 4,
+	/*PIN-5*/    PINNAME_GPIO5 = 5,
+    /*PIN-6*/    PINNAME_NET_STATUS = 6,
+    /*PIN-11*/   PINNAME_DBG_RXD = 11,
+    /*PIN-12*/   PINNAME_DBG_TXD = 12,
+    /*PIN-13*/   PINNAME_USIM_PRESENCE = 13,
+    /*PIN-23*/   PINNAME_SD_INT_DET = 23,
+    /*PIN-24*/   PINNAME_PCM_IN = 24,
+    /*PIN-25*/   PINNAME_PCM_OUT = 25,
+    /*PIN-26*/   PINNAME_PCM_SYNC = 26,
+    /*PIN-27*/   PINNAME_PCM_CLK = 27,
+    /*PIN-28*/   PINNAME_SDC2_DATA3 = 28,
+    /*PIN-29*/   PINNAME_SDC2_DATA2 = 29,
+    /*PIN-30*/   PINNAME_SDC2_DATA1 = 30,
+    /*PIN-31*/   PINNAME_SDC2_DATA0 = 31,
+    /*PIN-32*/   PINNAME_SDC2_CLK = 32,
+    /*PIN-33*/   PINNAME_SDC2_CMD = 33,
+    /*PIN-37*/   PINNAME_SPI_CS_N = 37,
+    /*PIN-38*/   PINNAME_SPI_MOSI = 38,
+    /*PIN-39*/   PINNAME_SPI_MISO = 39,
+    /*PIN-40*/   PINNAME_SPI_CLK = 40,
+    /*PIN-41*/   PINNAME_I2C_SCL = 41,
+    /*PIN-42*/   PINNAME_I2C_SDA = 42,
+    /*PIN-62*/   PINNAME_GPIO6 = 62,
+    /*PIN-63*/   PINNAME_DCD = 63,
+    /*PIN-66*/   PINNAME_DTR = 66,
+    /*PIN-64*/   PINNAME_MAIN_CTS = 64,
+    /*PIN-65*/   PINNAME_MAIN_RTS = 65,
+    /*PIN-67*/   PINNAME_MAIN_TXD = 67,
+    /*PIN-68*/   PINNAME_MAIN_RXD = 68,
+    /*PIN-73*/   PINNAME_RMII_RXD1 = 73,
+    /*PIN-74*/   PINNAME_RMII_RXCL = 74,
+    /*PIN-75*/   PINNAME_RMII_CLK = 75,
+    /*PIN-76*/   PINNAME_RMII_RXD0 = 76,
+    /*PIN-77*/   PINNAME_RMII_TXD0 = 77,
+    /*PIN-78*/   PINNAME_RMII_TXD1 = 78,
+    /*PIN-79*/   PINNAME_RMII_RXD2 = 79,
+    /*PIN-80*/   PINNAME_RMII_TXD2 = 80,
+    /*PIN-81*/   PINNAME_RMII_TX_CTRL = 81,
+    /*PIN-82*/   PINNAME_RMII_RXD3 = 82,
+    /*PIN-83*/   PINNAME_RMII_TXCL = 83,
+    /*PIN-84*/   PINNAME_RMII_TXD3 = 84,
+    /*PIN-118*/  PINNAME_WLAN_SLP_CLK = 118,
+    /*PIN-119*/  PINNAME_RMII_RST = 119,
+    /*PIN-120*/  PINNAME_RMII_INT = 120,
+    /*PIN-121*/  PINNAME_RMII_MDIO = 121,
+    /*PIN-122*/  PINNAME_RMII_MDC = 122,
+    /*PIN-127*/  PINNAME_WLAN_PER_EN = 127,
+    /*PIN-135*/  PINNAME_WLAN_WAKE = 135,
+    /*PIN-136*/  PINNAME_WLAN_EN = 136,
+    /*PIN-139*/  PINNAME_GPIO8 = 139,
+    PINNAME_END
+}Enum_PinName;
+
+/****************************************************************************
+ * Error Code Definition
+ ***************************************************************************/
+enum {
+        RES_OK = 0,
+        RES_BAD_PARAMETER  = -1,     ///< Parameter is invalid.
+        RES_IO_NOT_SUPPORT = -2,
+        RES_IO_ERROR = -3,
+        RES_NOT_IMPLEMENTED = -4
+};
+
+typedef enum{
+    PINDIRECTION_IN  = 0,
+    PINDIRECTION_OUT = 1
+}Enum_PinDirection;
+
+typedef enum{
+    PINLEVEL_LOW  = 0,
+    PINLEVEL_HIGH = 1
+}Enum_PinLevel;
+
+typedef enum{
+    PINPULLSEL_DISABLE  = (0<<13),    // Disable pull selection
+    PINPULLSEL_PULLDOWN = (5<<13),    // Pull-down 
+    PINPULLSEL_PULLUP   = (6<<13)     // Pull-up 
+}Enum_PinPullSel;
+
+/****************************************************************************
+ * GPIO Config Items
+ ***************************************************************************/
+typedef struct{
+    Enum_PinName           pin_name;
+    Enum_PinDirection      pinDirection;  
+    Enum_PinLevel          pinLevel;
+    Enum_PinPullSel       pinPullSel;
+}ST_GPIOConfig;
+
+//------------------------------------------------------------------------------
+/**
+ * The type of GPIO Edge Sensivity.
+ */
+//------------------------------------------------------------------------------
+typedef enum {
+    EINT_SENSE_NONE,       // pin is input, but no an interrupt pin.
+    EINT_SENSE_RISING,
+    EINT_SENSE_FALLING,
+    EINT_SENSE_BOTH
+}Enum_EintType;
+
+/*****************************************************************
+* 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
+                 );
+
+/*****************************************************************
+* 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);
+
+/*****************************************************************
+* 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);
+
+/*****************************************************************
+* 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);
+
+/*****************************************************************
+* 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);
+
+/*****************************************************************
+* 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);
+
+//------------------------------------------------------------------------------
+/*
+* Description:
+*     Definition for EINT callback function.
+* 
+* Parameters:
+*     PinName:
+*         EINT pin name, one value of Enum_PinName.
+*
+*     level:
+*         The EINT level value, one value of Enum_PinLevel. 
+*         0 or 1
+*/
+//------------------------------------------------------------------------------
+typedef void (*Ql_EINT_Callback)(Enum_PinName eint_pin_name, int level);
+
+//------------------------------------------------------------------------------
+/*
+* 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);
+
+#endif  // __QL_GPIO_H__
diff --git a/mbtk/include/ql/ql_i2c.h b/mbtk/include/ql/ql_i2c.h
new file mode 100755
index 0000000..52eb4c8
--- /dev/null
+++ b/mbtk/include/ql/ql_i2c.h
@@ -0,0 +1,41 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of Quectel Co., Ltd. 2019
+*
+*****************************************************************************/
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *   ql_i2c.h 
+ *
+ * Project:
+ * --------
+ *   OpenLinux
+ *
+ * Description:
+ * ------------
+ *   i2c API defines.
+ *
+ *
+ *============================================================================
+ *             HISTORY
+ *----------------------------------------------------------------------------
+ * WHO            WHEN                WHAT
+ *----------------------------------------------------------------------------
+ * Carola.Zhang   16/07/2019		  Create.
+ ****************************************************************************/
+#ifndef __QL_UART_H__
+#define __QL_UART_H__
+
+
+int Ql_I2C_Init(char *dev_name);
+int Ql_I2C_Read(int fd, unsigned short slaveAddr, unsigned char ofstAddr,  unsigned char* ptrBuff, unsigned short length);
+int Ql_I2C_Write(int fd, unsigned short slaveAddr, unsigned char ofstAddr,  unsigned char* ptrData, unsigned short length);
+int Ql_I2C_Deinit(int fd);
+
+#endif /* __QL_i2c_H__ */
\ No newline at end of file
diff --git a/mbtk/include/ql/ql_log.h b/mbtk/include/ql/ql_log.h
new file mode 100755
index 0000000..83940d1
--- /dev/null
+++ b/mbtk/include/ql/ql_log.h
@@ -0,0 +1,86 @@
+/**  
+  @file
+  DSI_ConnectManager.h
+
+  @brief
+  This file provides the definitions for quectel log api, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+24/07/2019  Nebula.li      create
+=============================================================================*/
+
+#ifndef _QL_LOG_H_
+#define _QL_LOG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+	QL_LOG_MIN = -1,
+	QL_LOG_EMERG_LEVEL=0,     /* system is unusable */
+	QL_LOG_INIT_LEVEL=0,      /* log init level */
+	QL_LOG_ALERT_LEVEL=1,     /* action must be taken immediately */
+	QL_LOG_CRIT_LEVEL=2,      /* critical conditions */
+	QL_LOG_ERR_LEVEL=3,      /* error conditions */
+	QL_LOG_WARN_LEVEL=4,   /* warning conditions */
+	QL_LOG_NOTICE_LEVEL=5,    /* normal but significant condition */
+	QL_LOG_INFO_LEVEL=6,      /* informational */
+	QL_LOG_DEBUG_LEVEL=7,     /* debug-level messages */
+	QL_LOG_MAX
+} QL_LOG_PRIORITY_E;
+
+#define QL_LOG_PRORIFY_VERIFY(prio) ((prio)>QL_LOG_MIN && (prio)<QL_LOG_MAX)
+
+typedef enum {
+    QL_LOG_ID_MIN = -1,
+   	QL_LOG_ID_MAIN = 0,
+    QL_LOG_ID_RADIO = 1,
+    QL_LOG_ID_EVENTS = 2,
+    QL_LOG_ID_SYSTEM = 3,
+    QL_LOG_ID_KMSG = 4,
+	QL_LOG_ID_STDOUT=5,
+    QL_LOG_ID_MAX
+} QL_LOG_ID_E;
+
+#define QL_LOG_ID_VERIFY(log_id)    ((log_id)>QL_LOG_ID_MIN && (log_id)<QL_LOG_ID_MAX)
+
+#define LOG_BUF_SIZE 2048
+
+#define QL_LOG_OPEN() ql_log_open()
+#define QL_LOG_CLOSE() ql_log_close()
+#define QL_LOG_SETPOS(log_id) ql_log_setpos(log_id)
+
+#define QL_LOG_DEBUG(fmt, ...) ql_log_print(QL_LOG_DEBUG_LEVEL,__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+#define QL_LOG_INFO(fmt, ...) ql_log_print(QL_LOG_INFO_LEVEL,__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+#define QL_LOG_WARN(fmt, ...) ql_log_print(QL_LOG_WARN_LEVEL,__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+#define QL_LOG_ERROR(fmt, ...) ql_log_print(QL_LOG_ERR_LEVEL,__FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+
+extern void ql_log_open();
+extern void ql_log_close();
+extern int ql_log_print(QL_LOG_PRIORITY_E prio,const char *func, int line,  const char *fmt, ...);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/mbtk/include/ql/ql_mcm.h b/mbtk/include/ql/ql_mcm.h
new file mode 100755
index 0000000..a5ae770
--- /dev/null
+++ b/mbtk/include/ql/ql_mcm.h
@@ -0,0 +1,165 @@
+#ifndef __QL_MCM_H__
+#define __QL_MCM_H__
+
+
+#define MCM_SERVICE_MAX             (17)
+
+#define MCM_SERVICE_DATA            0x01
+#define MCM_SERVICE_DM              0x02
+#define MCM_SERVICE_LOC             0x03
+#define MCM_SERVICE_MOBILEAP        0x04
+#define MCM_SERVICE_NW              0x05
+#define MCM_SERVICE_ATC             0x06
+#define MCM_SERVICE_SMS             0x07
+#define MCM_SERVICE_CLIENT          0x08
+#define MCM_SERVICE_SIM             0x0B
+#define MCM_SERVICE_VCALL           0x10
+
+
+#define SERVICE_REQUIRED            1
+#define SERVICE_NOT_REQUIRED        0
+
+#define MAGIC_MSG_ID_SERVICE_UP     0x87654321
+#define MAGIC_MSG_ID_SERVICE_DOWN   0x87654320
+
+typedef enum
+{
+    E_QL_SUCCESS                        = 0,    /**<  Success. */
+    E_QL_SUCCESS_CONDITIONAL_SUCCESS    = 1,    /**<  Conditional success. */
+    E_QL_ERROR_MCM_SERVICES_NOT_AVAILABLE = 2,  /**<  MCM services not available. */
+    E_QL_ERROR_GENERIC                  = 3,    /**<  Generic error. */
+    E_QL_ERROR_BADPARM                  = 4,    /**<  Bad parameter. */
+    E_QL_ERROR_MEMORY                   = 5,    /**<  Memory error. */
+    E_QL_ERROR_INVALID_STATE            = 6,    /**<  Invalid state. */
+    E_QL_ERROR_MALFORMED_MSG            = 7,    /**<  Malformed message. */
+    E_QL_ERROR_NO_MEMORY                = 8,    /**<  No memory. */
+    E_QL_ERROR_INTERNAL                 = 9,    /**<  Internal error. */
+    E_QL_ERROR_ABORTED                  = 10,   /**<  Action was aborted. */
+    E_QL_ERROR_CLIENT_IDS_EXHAUSTED     = 11,   /**<  Client IDs have been exhausted. */
+    E_QL_ERROR_UNABORTABLE_TRANSACTION  = 12,   /**<  Unabortable transaction. */
+    E_QL_ERROR_INVALID_CLIENT_ID        = 13,   /**<  Invalid client ID. */
+    E_QL_ERROR_NO_THRESHOLDS            = 14,   /**<  No thresholds. */
+    E_QL_ERROR_INVALID_HANDLE           = 15,   /**<  Invalid handle. */
+    E_QL_ERROR_INVALID_PROFILE          = 16,   /**<  Invalid profile. */
+    E_QL_ERROR_INVALID_PINID            = 17,   /**<  Invalid PIN ID. */
+    E_QL_ERROR_INCORRECT_PIN            = 18,   /**<  Incorrect PIN. */
+    E_QL_ERROR_NO_NETWORK_FOUND         = 19,   /**<  No network found. */
+    E_QL_ERROR_CALL_FAILED              = 20,   /**<  Call failed. */
+    E_QL_ERROR_OUT_OF_CALL              = 21,   /**<  Out of call. */
+    E_QL_ERROR_NOT_PROVISIONED          = 22,   /**<  Not provisioned. */
+    E_QL_ERROR_MISSING_ARG              = 23,   /**<  Missing argument. */
+    E_QL_ERROR_ARG_TOO_LONG             = 24,   /**<  Argument is too long. */
+    E_QL_ERROR_INVALID_TX_ID            = 25,   /**<  Invalid Tx ID. */
+    E_QL_ERROR_DEVICE_IN_USE            = 26,   /**<  Device is in use. */
+    E_QL_ERROR_OP_NETWORK_UNSUPPORTED   = 27,   /**<  OP network is not supported. */
+    E_QL_ERROR_OP_DEVICE_UNSUPPORTED    = 28,   /**<  OP device is not supported. */
+    E_QL_ERROR_NO_EFFECT                = 29,   /**<  No effect. */
+    E_QL_ERROR_NO_FREE_PROFILE          = 30,   /**<  No free profile. */
+    E_QL_ERROR_INVALID_PDP_TYPE         = 31,   /**<  Invalid PDP type. */
+    E_QL_ERROR_INVALID_TECH_PREF        = 32,   /**<  Invalid technical preference. */
+    E_QL_ERROR_INVALID_PROFILE_TYPE     = 33,   /**<  Invalid profile type. */
+    E_QL_ERROR_INVALID_SERVICE_TYPE     = 34,   /**<  Invalid service type. */
+    E_QL_ERROR_INVALID_REGISTER_ACTION  = 35,   /**<  Invalid register action. */
+    E_QL_ERROR_INVALID_PS_ATTACH_ACTION = 36,   /**<  Invalid PS attach action. */
+    E_QL_ERROR_AUTHENTICATION_FAILED    = 37,   /**<  Authentication failed. */
+    E_QL_ERROR_PIN_BLOCKED              = 38,   /**<  PIN is blocked. */
+    E_QL_ERROR_PIN_PERM_BLOCKED         = 39,   /**<  PIN is permanently blocked. */
+    E_QL_ERROR_SIM_NOT_INITIALIZED      = 40,   /**<  SIM is not initialized. */
+    E_QL_ERROR_MAX_QOS_REQUESTS_IN_USE  = 41,   /**<  Maximum QoS requests are in use. */
+    E_QL_ERROR_INCORRECT_FLOW_FILTER    = 42,   /**<  Incorrect flow filter. */
+    E_QL_ERROR_NETWORK_QOS_UNAWARE      = 43,   /**<  Network QoS is unaware. */
+    E_QL_ERROR_INVALID_ID               = 44,   /**<  Invalid ID. */
+    E_QL_ERROR_INVALID_QOS_ID           = 45,   /**<  Invalid QoS ID. */
+    E_QL_ERROR_REQUESTED_NUM_UNSUPPORTED= 46,   /**<  Requested number is not supported. */
+    E_QL_ERROR_INTERFACE_NOT_FOUND      = 47,   /**<  Interface was not found. */
+    E_QL_ERROR_FLOW_SUSPENDED           = 48,   /**<  Flow is suspended. */
+    E_QL_ERROR_INVALID_DATA_FORMAT      = 49,   /**<  Invalid data format. */
+    E_QL_ERROR_GENERAL                  = 50,   /**<  General error. */
+    E_QL_ERROR_UNKNOWN                  = 51,   /**<  Unknown error. */
+    E_QL_ERROR_INVALID_ARG              = 52,   /**<  Invalid argument. */
+    E_QL_ERROR_INVALID_INDEX            = 53,   /**<  Invalid index. */
+    E_QL_ERROR_NO_ENTRY                 = 54,   /**<  No entry. */
+    E_QL_ERROR_DEVICE_STORAGE_FULL      = 55,   /**<  Device storage is full. */
+    E_QL_ERROR_DEVICE_NOT_READY         = 56,   /**<  Device is not ready. */
+    E_QL_ERROR_NETWORK_NOT_READY        = 57,   /**<  Network is not ready. */
+    E_QL_ERROR_CAUSE_CODE               = 58,   /**<  Cause code error. */
+    E_QL_ERROR_MESSAGE_NOT_SENT         = 59,   /**<  Message was not sent. */
+    E_QL_ERROR_MESSAGE_DELIVERY_FAILURE = 60,   /**<  Message delivery failure. */
+    E_QL_ERROR_INVALID_MESSAGE_ID       = 61,   /**<  Invalid message ID. */
+    E_QL_ERROR_ENCODING                 = 62,   /**<  Encoding error. */
+    E_QL_ERROR_AUTHENTICATION_LOCK      = 63,   /**<  Authentication lock error. */
+    E_QL_ERROR_INVALID_TRANSITION       = 64,   /**<  Invalid transition. */
+    E_QL_ERROR_NOT_A_MCAST_IFACE        = 65,   /**<  Not an MCast interface. */
+    E_QL_ERROR_MAX_MCAST_REQUESTS_IN_USE= 66,   /**<  Maximum MCast requests are in use. */
+    E_QL_ERROR_INVALID_MCAST_HANDLE     = 67,   /**<  Invalid MCast handle. */
+    E_QL_ERROR_INVALID_IP_FAMILY_PREF   = 68,   /**<  Invalid IP family preference. */
+    E_QL_ERROR_SESSION_INACTIVE         = 69,   /**<  Session is inactive. */
+    E_QL_ERROR_SESSION_INVALID          = 70,   /**<  Session is invalid. */
+    E_QL_ERROR_SESSION_OWNERSHIP        = 71,   /**<  Session ownership error. */
+    E_QL_ERROR_INSUFFICIENT_RESOURCES   = 72,   /**<  Insufficient resources. */
+    E_QL_ERROR_DISABLED                 = 73,   /**<  Disabled. */
+    E_QL_ERROR_INVALID_OPERATION        = 74,   /**<  Invalid operation. */
+    E_QL_ERROR_INVALID_CMD              = 75,   /**<  Invalid command. */
+    E_QL_ERROR_TPDU_TYPE                = 76,   /**<  Transfer Protocol data unit type error. */
+    E_QL_ERROR_SMSC_ADDR                = 77,   /**<  Short message service center address error. */
+    E_QL_ERROR_INFO_UNAVAILABLE         = 78,   /**<  Information is not available. */
+    E_QL_ERROR_SEGMENT_TOO_LONG         = 79,   /**<  Segment is too long. */
+    E_QL_ERROR_SEGMENT_ORDER            = 80,   /**<  Segment order error. */
+    E_QL_ERROR_BUNDLING_NOT_SUPPORTED   = 81,   /**<  Bundling is not supported. */
+    E_QL_ERROR_OP_PARTIAL_FAILURE       = 82,   /**<  OP partial failure. */
+    E_QL_ERROR_POLICY_MISMATCH          = 83,   /**<  Policy mismatch. */
+    E_QL_ERROR_SIM_FILE_NOT_FOUND       = 84,   /**<  SIM file was not found. */
+    E_QL_ERROR_EXTENDED_INTERNAL        = 85,   /**<  Extended internal error. */
+    E_QL_ERROR_ACCESS_DENIED            = 86,   /**<  Access is denied. */
+    E_QL_ERROR_HARDWARE_RESTRICTED      = 87,   /**<  Hardware is restricted. */
+    E_QL_ERROR_ACK_NOT_SENT             = 88,   /**<  Acknowledgement was not sent. */
+    E_QL_ERROR_INJECT_TIMEOUT           = 89,   /**<  Inject timeout error. */
+    E_QL_ERROR_INCOMPATIBLE_STATE       = 90,   /**<  Incompatible state. */
+    E_QL_ERROR_FDN_RESTRICT             = 91,   /**<  Fixed dialing number restrict error. */
+    E_QL_ERROR_SUPS_FAILURE_CAUSE       = 92,   /**<  SUPS failure cause. */
+    E_QL_ERROR_NO_RADIO                 = 93,   /**<  No radio. */
+    E_QL_ERROR_NOT_SUPPORTED            = 94,   /**<  Not supported. */
+    E_QL_ERROR_NO_SUBSCRIPTION          = 95,   /**<  No subscription. */
+    E_QL_ERROR_CARD_CALL_CONTROL_FAILED = 96,   /**<  Card call control failed. */
+    E_QL_ERROR_NETWORK_ABORTED          = 97,   /**<  Network was aborted. */
+    E_QL_ERROR_MSG_BLOCKED              = 98,   /**<  Message was blocked. */
+    E_QL_ERROR_INVALID_SESSION_TYPE     = 99,   /**<  Invalid session type. */
+    E_QL_ERROR_INVALID_PB_TYPE          = 100,  /**<  Invalid phonebook type. */
+    E_QL_ERROR_NO_SIM                   = 101,  /**<  No SIM was found. */
+    E_QL_ERROR_PB_NOT_READY             = 102,  /**<  Phonebook not ready. */
+    E_QL_ERROR_PIN_RESTRICTION          = 103,  /**<  PIN restriction. */
+    E_QL_ERROR_PIN2_RESTRICTION         = 104,  /**<  PIN2 restriction. */
+    E_QL_ERROR_PUK_RESTRICTION          = 105,  /**<  PIN unlocking key restriction. */
+    E_QL_ERROR_PUK2_RESTRICTION         = 106,  /**<  PIN unlocking key2 restriction. */
+    E_QL_ERROR_PB_ACCESS_RESTRICTED     = 107,  /**<  Phonebook access is restricted. */
+    E_QL_ERROR_PB_DELETE_IN_PROG        = 108,  /**<  Phonebook delete is in progress. */
+    E_QL_ERROR_PB_TEXT_TOO_LONG         = 109,  /**<  Phonebook text is too long. */
+    E_QL_ERROR_PB_NUMBER_TOO_LONG       = 110,  /**<  Phonebook number is too long. */
+    E_QL_ERROR_PB_HIDDEN_KEY_RESTRICTION= 111,  /**<  Phonebook hidden key restriction. */
+    E_QL_ERROR_PB_NOT_AVAILABLE         = 112,  /**<  Phonebook is not available. */
+    E_QL_ERROR_DEVICE_MEMORY_ERROR      = 113,  /**<  Device memory error. */
+    E_QL_ERROR_SIM_PIN_BLOCKED          = 114,  /**<  SIM PIN is blocked. */
+    E_QL_ERROR_SIM_PIN_NOT_INITIALIZED  = 115,  /**<  SIM PIN is not initialized. */
+    E_QL_ERROR_SIM_INVALID_PIN          = 116,  /**<  SIM PIN is invalid. */
+    E_QL_ERROR_SIM_INVALID_PERSO_CK     = 117,  /**<  SIM invalid personalization CK. */
+    E_QL_ERROR_SIM_PERSO_BLOCKED        = 118,  /**<  SIM personalization blocked. */
+    E_QL_ERROR_SIM_PERSO_INVALID_DATA   = 119,  /**<  SIM personalization contains invalid data. */
+    E_QL_ERROR_SIM_ACCESS_DENIED        = 120,  /**<  SIM access is denied. */
+    E_QL_ERROR_SIM_INVALID_FILE_PATH    = 121,  /**<  SIM file path is invalid. */
+    E_QL_ERROR_SIM_SERVICE_NOT_SUPPORTED= 122,  /**<  SIM service is not supported. */
+    E_QL_ERROR_SIM_AUTH_FAIL            = 123,  /**<  SIM authorization failure. */
+    E_QL_ERROR_SIM_PIN_PERM_BLOCKED     = 124,  /**<  SIM PIN is permanently blocked. */
+}E_QL_ERROR_CODE_T;
+
+#if 0
+int QL_MCM_Client_Init( mcm_client_handle_type  *ph_mcm,
+                        int                     client_type,
+                        mcm_client_ind_cb       client_ind_cb,
+                        mcm_client_async_cb     client_async_cb);
+
+int QL_MCM_Client_Deinit(mcm_client_handle_type h_mcm,
+                         int                    client_type);
+#endif
+
+#endif // __QL_MCM_H__
+
diff --git a/mbtk/include/ql/ql_mcm_call.h b/mbtk/include/ql/ql_mcm_call.h
new file mode 100755
index 0000000..973fb47
--- /dev/null
+++ b/mbtk/include/ql/ql_mcm_call.h
@@ -0,0 +1,909 @@
+/**
+ *@file     ql_mcm_voice.h
+ *@date     2017-11-30
+ *@author
+ *@brief
+ */
+
+#ifndef __QL_MCM_VOICE_H__
+#define __QL_MCM_VOICE_H__
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "ql_vcall.h"
+
+#define QL_MCM_MAX_VOICE_CALLS                  8   /**  GSM provides up to 8 calls; 3GPP2 provides 2. */
+#define QL_MCM_MAX_PHONE_NUMBER                 82  /**  Maximum phone number length. */
+#define QL_MCM_MAX_UUS_DATA                     20  /**  Maximum user-to-user data. */
+#define QL_MCM_MAX_DTMF_LENGTH                  20  /**  Maximum DTMF length. */
+#define QL_MCM_MAX_USSD_LENGTH                  128 /**  Maximum USSD length. */
+#define QL_MCM_MAX_PASSWORD_LENGTH              4   /**  Maximum password length. */
+#define QL_MCM_MAX_CALL_FORWARDING_INFO         13  /**  Maximum call forwarding information. */
+#define QL_MCM_MAX_ECALL_MSD                    140 /**  Maximum size of the MSD sent to the network with an eCall */
+#define QL_MCM_MAX_ECALL_URC_EVENT_LENGTH       128 /**  Maximum size of the ecall urc event */
+
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_STATE_INCOMING      = 0x0000, /**< MT incoming; CC setup. */
+    E_QL_MCM_VOICE_CALL_STATE_DIALING       = 0x0001, /**< Dialing state. */
+    E_QL_MCM_VOICE_CALL_STATE_ALERTING      = 0x0002, /**< MT call waiting; MO alterting. */
+    E_QL_MCM_VOICE_CALL_STATE_ACTIVE        = 0x0003, /**< Call is active. */
+    E_QL_MCM_VOICE_CALL_STATE_HOLDING       = 0x0004, /**< Call is on hold. */
+    E_QL_MCM_VOICE_CALL_STATE_END           = 0x0005, /**< Call is disconnected. */
+    E_QL_MCM_VOICE_CALL_STATE_WAITING       = 0x0006, /**< Call is waiting. */
+} ql_mcm_voice_call_state_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_TECH_NONE                = 0, /**<  None. */
+    E_QL_MCM_VOICE_TECH_3GPP                = 1, /**<  3GPP. */
+    E_QL_MCM_VOICE_TECH_3GPP2               = 2, /**<  3GPP2. */
+} ql_mcm_voice_tech_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_NUMBER_UNKNOWN      = 0x0000,
+    E_QL_MCM_VOICE_CALL_NUMBER_ALLOWED      = 0x0001, /**<  Number allowed. */
+    E_QL_MCM_VOICE_CALL_NUMBER_RESTRICTED   = 0x0002, /**<  Number restricted. */
+    E_QL_MCM_VOICE_CALL_NUMBER_PAYPHONE     = 0x0003, /**<  Payhone number. */
+} ql_mcm_voice_call_number_presentation_type_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_MOBILE_ORIGINATED   = 0x0000, /**<  Mobile-originated. */
+    E_QL_MCM_VOICE_CALL_MOBILE_TERMINATED   = 0x0001, /**<  Mobile-terminated. */
+} ql_mcm_voice_call_direction_type_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_ANSWER,     //!<Answer the call.
+    E_QL_MCM_VOICE_CALL_END,        //!<Deprecated. Do not use.
+    E_QL_MCM_VOICE_CALL_HOLD,       //!<Hold the call.
+    E_QL_MCM_VOICE_CALL_UNHOLD,     //!<Release the call from hold.
+    E_QL_MCM_VOICE_CALL_CONFERENCE, //!<Conference call.
+    E_QL_MCM_VOICE_CALL_GO_PRIVATE, //!<Private call.
+    E_QL_MCM_VOICE_CALL_END_ALL     //!<End all calls.
+} ql_mcm_voice_call_operation_t;       //!< Voice call operation type.
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_END_REASON_NONE                     = 0,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_OFFLINE                   = 1,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CDMA_LOCK                 = 2,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_SRV                    = 3,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_FADE                      = 4,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INTERCEPT                 = 5,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REORDER                   = 6,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REL_NORMAL                = 7,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REL_SO_REJ                = 8,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INCOM_CALL                = 9,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ALERT_STOP                = 10,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CLIENT_END                = 11,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACTIVATION                = 12,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MC_ABORT                  = 13,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MAX_ACCESS_PROBE          = 14,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PSIST_N                   = 15,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UIM_NOT_PRESENT           = 16,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACC_IN_PROG               = 17,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACC_FAIL                  = 18,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RETRY_ORDER               = 19,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CCS_NOT_SUPPORTED_BY_BS   = 20,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_RESPONSE_FROM_BS       = 21,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REJECTED_BY_BS            = 22,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INCOMPATIBLE              = 23,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_BLOCK              = 24,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ALREADY_IN_TC             = 25,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EMERGENCY_FLASHED         = 26,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USER_CALL_ORIG_DURING_GPS = 27,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USER_CALL_ORIG_DURING_SMS = 28,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USER_CALL_ORIG_DURING_DATA= 29,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REDIR_OR_HANDOFF          = 30,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_BLOCK_ALL          = 31,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_OTASP_SPC_ERR             = 32,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_IS707B_MAX_ACC            = 33,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACC_FAIL_REJ_ORD          = 34,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACC_FAIL_RETRY_ORD        = 35,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TIMEOUT_T42               = 36,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TIMEOUT_T40               = 37,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SRV_INIT_FAIL             = 38,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_T50_EXP                   = 39,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_T51_EXP                   = 40,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RL_ACK_TIMEOUT            = 41,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BAD_FL                    = 42,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TRM_REQ_FAIL              = 43,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TIMEOUT_T41               = 44,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INCOM_REJ                 = 45,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SETUP_REJ                 = 46,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NETWORK_END               = 47,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_FUNDS                  = 48,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_GW_SRV                 = 49,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_CDMA_SRV               = 50,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_FULL_SRV               = 51,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MAX_PS_CALLS              = 52,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNKNOWN_SUBSCRIBER        = 53,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ILLEGAL_SUBSCRIBER        = 54,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BEARER_SERVICE_NOT_PROVISIONED= 55,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TELE_SERVICE_NOT_PROVISIONED  = 56,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ILLEGAL_EQUIPMENT         = 57,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_BARRED               = 58,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ILLEGAL_SS_OPERATION      = 59,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SS_ERROR_STATUS           = 60,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SS_NOT_AVAILABLE          = 61,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SS_SUBSCRIPTION_VIOLATION = 62,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SS_INCOMPATIBILITY        = 63,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_FACILITY_NOT_SUPPORTED    = 64,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ABSENT_SUBSCRIBER         = 65,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SHORT_TERM_DENIAL         = 66,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_LONG_TERM_DENIAL          = 67,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SYSTEM_FAILURE            = 68,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DATA_MISSING              = 69,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNEXPECTED_DATA_VALUE     = 70,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PWD_REGISTRATION_FAILURE  = 71,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NEGATIVE_PWD_CHECK        = 72,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NUM_OF_PWD_ATTEMPTS_VIOLATION     = 73,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_POSITION_METHOD_FAILURE   = 74,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNKNOWN_ALPHABET          = 75,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USSD_BUSY                 = 76,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REJECTED_BY_USER          = 77,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REJECTED_BY_NETWORK       = 78,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DEFLECTION_TO_SERVED_SUBSCRIBER   = 79,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SPECIAL_SERVICE_CODE      = 80,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_DEFLECTED_TO_NUMBER       = 81,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MPTY_PARTICIPANTS_EXCEEDED= 82,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RESOURCES_NOT_AVAILABLE   = 83,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNASSIGNED_NUMBER         = 84,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_ROUTE_TO_DESTINATION   = 85,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CHANNEL_UNACCEPTABLE      = 86,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_OPERATOR_DETERMINED_BARRING       = 87,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NORMAL_CALL_CLEARING      = 88,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USER_BUSY                 = 89,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_USER_RESPONDING        = 90,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USER_ALERTING_NO_ANSWER   = 91,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_REJECTED             = 92,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NUMBER_CHANGED            = 93,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PREEMPTION                = 94,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DESTINATION_OUT_OF_ORDER  = 95,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_NUMBER_FORMAT     = 96,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_FACILITY_REJECTED         = 97,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RESP_TO_STATUS_ENQUIRY    = 98,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NORMAL_UNSPECIFIED        = 99,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_CIRCUIT_OR_CHANNEL_AVAILABLE   = 100,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NETWORK_OUT_OF_ORDER      = 101,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TEMPORARY_FAILURE         = 102,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SWITCHING_EQUIPMENT_CONGESTION    = 103,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_INFORMATION_DISCARDED      = 104,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 105,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 106,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_QOS_UNAVAILABLE                   = 107,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUESTED_FACILITY_NOT_SUBSCRIBED = 108,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INCOMING_CALLS_BARRED_WITHIN_CUG  = 109,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BEARER_CAPABILITY_NOT_AUTH        = 110,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BEARER_CAPABILITY_UNAVAILABLE     = 111,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVICE_OPTION_NOT_AVAILABLE      = 112,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACM_LIMIT_EXCEEDED                = 113,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BEARER_SERVICE_NOT_IMPLEMENTED    = 114,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUESTED_FACILITY_NOT_IMPLEMENTED= 115,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 116,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 117,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_TRANSACTION_IDENTIFIER    = 118,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USER_NOT_MEMBER_OF_CUG            = 119,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INCOMPATIBLE_DESTINATION          = 120,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_TRANSIT_NW_SELECTION      = 121,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE    = 122,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_MANDATORY_INFORMATION     = 123,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MESSAGE_TYPE_NON_IMPLEMENTED      = 124,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 125,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT  = 126,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CONDITONAL_IE_ERROR               = 127,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 128,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RECOVERY_ON_TIMER_EXPIRED         = 129,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PROTOCOL_ERROR_UNSPECIFIED        = 130,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INTERWORKING_UNSPECIFIED          = 131,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_OUTGOING_CALLS_BARRED_WITHIN_CUG  = 132,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_CUG_SELECTION                  = 133,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNKNOWN_CUG_INDEX                 = 134,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CUG_INDEX_INCOMPATIBLE            = 135,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CUG_CALL_FAILURE_UNSPECIFIED      = 136,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CLIR_NOT_SUBSCRIBED               = 137,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CCBS_POSSIBLE                     = 138,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CCBS_NOT_POSSIBLE                 = 139,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_IMSI_UNKNOWN_IN_HLR               = 140,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ILLEGAL_MS                        = 141,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_IMSI_UNKNOWN_IN_VLR               = 142,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_IMEI_NOT_ACCEPTED                 = 143,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ILLEGAL_ME                        = 144,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PLMN_NOT_ALLOWED                  = 145,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_LOCATION_AREA_NOT_ALLOWED         = 146,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ROAMING_NOT_ALLOWED_IN_THIS_LOCATION_AREA = 147,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_SUITABLE_CELLS_IN_LOCATION_AREA= 148,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NETWORK_FAILURE                   = 149,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MAC_FAILURE                       = 150,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SYNCH_FAILURE                     = 151,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NETWORK_CONGESTION                = 152,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_GSM_AUTHENTICATION_UNACCEPTABLE   = 153,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVICE_NOT_SUBSCRIBED            = 154,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVICE_TEMPORARILY_OUT_OF_ORDER  = 155,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_CANNOT_BE_IDENTIFIED         = 156,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INCORRECT_SEMANTICS_IN_MESSAGE    = 157,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MANDATORY_INFORMATION_INVALID     = 158,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_FAILURE            = 159,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_SIM                       = 160,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_WRONG_STATE                       = 161,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_CLASS_BLOCKED              = 162,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_RESOURCES                      = 163,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_USER_DATA                 = 164,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TIMER_T3230_EXPIRED               = 165,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_CELL_AVAILABLE                 = 166,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ABORT_MSG_RECEIVED                = 167,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RADIO_LINK_LOST                   = 168,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TIMER_T303_EXPIRED                = 169,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CNM_MM_REL_PENDING                = 170,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_RR_REL_IND     = 171,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_RR_RANDOM_ACCESS_FAILURE   = 172,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_RRC_REL_IND                = 173,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_RRC_CLOSE_SESSION_IND      = 174,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_RRC_OPEN_SESSION_FAILURE   = 175,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_LOW_LEVEL_FAIL             = 176,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_LOW_LEVEL_FAIL_REDIAL_NOT_ALLOWED = 177,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_LOW_LEVEL_IMMED_RETRY      = 178,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ACCESS_STRATUM_REJ_ABORT_RADIO_UNAVAILABLE    = 179,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVICE_OPTION_NOT_SUPPORTED                  = 180,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_UL_DATA_CNF_FAILURE_TXN           = 181,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_UL_DATA_CNF_FAILURE_HO            = 182,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_UL_DATA_CNF_FAILURE_CONN_REL      = 183,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_UL_DATA_CNF_FAILURE_RLF           = 184,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_UL_DATA_CNF_FAILURE_CTRL_NOT_CONN = 185,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_SUCCESS                  = 186,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE                  = 187,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_ABORTED          = 188,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_ACCESS_BARRED    = 189,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_CELL_RESEL       = 190,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_CONFIG_FAILURE   = 191,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_TIMER_EXPIRED    = 192,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_LINK_FAILURE     = 193,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_NOT_CAMPED       = 194,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_SI_FAILURE       = 195,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_EST_FAILURE_CONN_REJECT      = 196,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_NORMAL                   = 197,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_RLF                      = 198,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_CRE_FAILURE              = 199,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_OOS_DURING_CRE           = 200,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_ABORTED                  = 201,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_SIB_READ_ERROR           = 202,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_CONN_REL_ABORTED_IRAT_SUCCESS     = 203,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_LRRC_RADIO_LINK_FAILURE                = 204,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_DETACH_WITH_REATTACH_LTE_NW_DETACH     = 205,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AS_REJ_DETACH_WITH_OUT_REATTACH_LTE_NW_DETACH = 206,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BAD_REQ_WAIT_INVITE           = 207,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BAD_REQ_WAIT_REINVITE         = 208,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INVALID_REMOTE_URI            = 209,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REMOTE_UNSUPP_MEDIA_TYPE      = 210,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PEER_NOT_REACHABLE            = 211,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NETWORK_NO_RESP_TIME_OUT      = 212,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NETWORK_NO_RESP_HOLD_FAIL     = 213,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DATA_CONNECTION_LOST          = 214,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UPGRADE_DOWNGRADE_REJ         = 215,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SIP_403_FORBIDDEN             = 216,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NO_NETWORK_RESP               = 217,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UPGRADE_DOWNGRADE_FAILED      = 218,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UPGRADE_DOWNGRADE_CANCELLED   = 219,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SSAC_REJECT                   = 220,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_THERMAL_EMERGENCY             = 221,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_SOFT_FAILURE           = 222,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_HARD_FAILURE           = 223,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CONNECTION_EST_FAILURE        = 224,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CONNECTION_FAILURE            = 225,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RRC_CONN_REL_NO_MT_SETUP      = 226,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ESR_FAILURE                   = 227,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MT_CSFB_NO_RESPONSE_FROM_NW   = 228,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BUSY_EVERYWHERE               = 229,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ANSWERED_ELSEWHERE            = 230,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RLF_DURING_CC_DISCONNECT      = 231,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TEMP_REDIAL_ALLOWED           = 232,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PERM_REDIAL_NOT_NEEDED        = 233,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MERGED_TO_CONFERENCE          = 234,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_LOW_BATTERY                   = 235,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_DEFLECTED                = 236,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RTP_RTCP_TIMEOUT              = 237,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RINGING_RINGBACK_TIMEOUT      = 238,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REG_RESTORATION               = 239,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CODEC_ERROR                   = 240,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNSUPPORTED_SDP               = 241,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_RTP_FAILURE                   = 242,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_QoS_FAILURE                   = 243,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MULTIPLE_CHOICES              = 244,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MOVED_PERMANENTLY             = 245,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MOVED_TEMPORARILY             = 246,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_USE_PROXY                     = 247,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ALTERNATE_SERVICE             = 248,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ALTERNATE_EMERGENCY_CALL      = 249,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNAUTHORIZED                  = 250,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PAYMENT_REQUIRED              = 251,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_METHOD_NOT_ALLOWED            = 252,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NOT_ACCEPTABLE                = 253,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PROXY_AUTHENTICATION_REQUIRED = 254,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_GONE                          = 255,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUEST_ENTITY_TOO_LARGE      = 256,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUEST_URI_TOO_LARGE         = 257,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNSUPPORTED_URI_SCHEME        = 258,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BAD_EXTENSION                 = 259,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EXTENSION_REQUIRED            = 260,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INTERVAL_TOO_BRIEF            = 261,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_OR_TRANS_DOES_NOT_EXIST  = 262,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_LOOP_DETECTED                 = 263,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_TOO_MANY_HOPS                 = 264,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_ADDRESS_INCOMPLETE            = 265,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_AMBIGUOUS                     = 266,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUEST_TERMINATED            = 267,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NOT_ACCEPTABLE_HERE           = 268,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REQUEST_PENDING               = 269,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_UNDECIPHERABLE                = 270,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVER_INTERNAL_ERROR         = 271,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_NOT_IMPLEMENTED               = 272,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_BAD_GATEWAY                   = 273,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVER_TIME_OUT               = 274,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_VERSION_NOT_SUPPORTED         = 275,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_MESSAGE_TOO_LARGE             = 276,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DOES_NOT_EXIST_ANYWHERE       = 277,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SESS_DESCR_NOT_ACCEPTABLE     = 278,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SRVCC_END_CALL                = 279,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_INTERNAL_ERROR                = 280,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_SERVER_UNAVAILABLE            = 281,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PRECONDITION_FAILURE          = 282,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DRVCC_IN_PROG                 = 283,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DRVCC_END_CALL                = 284,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CS_HARD_FAILURE               = 285,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CS_ACQ_FAILURE                = 286,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_FALLBACK_TO_CS                = 287,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_DEAD_BATTERY                  = 288,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_HO_NOT_FEASIBLE               = 289,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_PDN_DISCONNECTED              = 290,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REJECTED_ELSEWHERE            = 291,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_PULLED                   = 292,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_CALL_PULL_OUT_OF_SYNC         = 293,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_HOLD_RESUME_FAILED            = 294,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_HOLD_RESUME_CANCELED          = 295,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_REINVITE_COLLISION            = 296,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_MSG_INVAILD            = 297,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_MSG_IGNORE             = 298,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_ACQ_FAIL          = 299,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_CALL_REL_REL_ORDER= 300,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_CALL_REL_REORDER  = 301,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_CALL_REL_INTERCEPT_ORDER      = 302,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_CALL_REL_NORMAL   = 303,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_CALL_REL_SO_REJ   = 304,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAIL_CALL_REL_OTASP_SPC_ERR        = 305,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAILURE_SRCH_TT_FAIL   = 306,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAILURE_TCH_INIT_FAIL  = 307,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAILURE_FAILURE_USER_CALL_END      = 308,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAILURE_FAILURE_RETRY_EXHAUST      = 309,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAILURE_FAILURE_CALL_REL_REG_REJ   = 310,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_FAILURE_FAILURE_CALL_REL_NW_REL_ODR= 311,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_1XCSFB_HO_FAILURE                         = 312,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EMM_REJ_TIMER_T3417_EXT_EXP               = 313,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EMM_REJ_TIMER_T3417_EXP                   = 314,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EMM_REJ_SERVICE_REQ_FAILURE_LTE_NW_REJECT = 315,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EMM_REJ_SERVICE_REQ_FAILURE_CS_DOMAIN_NOT_AVAILABLE = 316,
+    E_QL_MCM_VOICE_CALL_END_CAUSE_EMM_REJ                                   = 317,
+} ql_mcm_voice_call_end_reason_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_UUS_TYPE1_IMPLICIT,          //!< Type 1 implicit.
+    E_QL_MCM_VOICE_UUS_TYPE1_REQUIRED,          //!< Type 1 required.
+    E_QL_MCM_VOICE_UUS_TYPE1_NOT_REQUIRED,      //!< Type 1 not required.
+    E_QL_MCM_VOICE_UUS_TYPE2_REQUIRED,          //!< Type 2 required.
+    E_QL_MCM_VOICE_UUS_TYPE2_NOT_REQUIRED,      //!< Type 2 not required.
+    E_QL_MCM_VOICE_UUS_TYPE3_REQUIRED,          //!< Type 3 required.
+    E_QL_MCM_VOICE_UUS_TYPE3_NOT_REQUIRED,      //!< Type 3 not required.
+    E_QL_MCM_VOICE_UUS_TYPE_DATA                //!< Data.
+} ql_mcm_voice_uus_type_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_UUS_DCS_IA5,                 //!< IA5.
+    E_QL_MCM_VOICE_UUS_DCS_OHLP,                //!< OHLP.
+    E_QL_MCM_VOICE_UUS_DCS_USP,                 //!< USP.
+    E_QL_MCM_VOICE_UUS_DCS_X244                 //!< x244.
+} ql_mcm_voice_uus_dcs_type_t;                  //!< UUS data coding scheme.
+
+
+typedef struct
+{
+    ql_mcm_voice_uus_type_t     type;           /**< UUS type; range -- 0 to 6.*/
+    ql_mcm_voice_uus_dcs_type_t dcs;            /**< UUS data coding scheme; range -- 0 to 4.*/
+    uint32_t                    uus_data_len;   /**< Must be set to the number of elements in uus_data. */
+    uint8_t                     uus_data[QL_MCM_MAX_UUS_DATA];/**< Voice call UUS data.*/
+} ql_mcm_voice_uusdata_t;
+
+typedef struct
+{
+    uint32_t                                      call_id;                                /**<   Call ID associated with this call.*/
+    ql_mcm_voice_call_state_t                     state;                                  /**<   Current call state (mcm_voice_call_state).*/
+    ql_mcm_voice_tech_t                           tech;                                   /**<   Technology (mcm_tech).*/
+    char                                          number[QL_MCM_MAX_PHONE_NUMBER + 1];    /**<   Phone number.*/
+    ql_mcm_voice_call_number_presentation_type_t  number_presentation;                    /**<   Number presentation.*/
+    ql_mcm_voice_call_direction_type_t            direction;                              /**<   Voice call direction.*/
+    uint8_t                                       uusdata_valid;                          /**<   Indicates whether UUS data is valid.*/
+    ql_mcm_voice_uusdata_t                        uusdata;                                /**<   User-to-user signaling data.*/
+    uint8_t                                       call_end_reason_valid;                  /**<   Indicates whether call_end_reason is valid.*/
+    ql_mcm_voice_call_end_reason_t                call_end_reason;
+} ql_mcm_voice_call_record_t;
+
+typedef struct
+{
+    uint32_t                      calls_len;  /**< Must be set to # of elements in calls */
+    ql_mcm_voice_call_record_t    calls[QL_MCM_MAX_VOICE_CALLS]; /**<   Calls.*/
+} ql_mcm_voice_calls_state_t;
+
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_FORWARDING_DISABLED         = 0, /**<  Disabled. */
+    E_QL_MCM_VOICE_CALL_FORWARDING_ENABLED          = 1, /**<  Enabled. */
+} QL_MCM_VOICE_CALL_FORWARDING_STATUS_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_FORWARDING_TYPE_VOICE       = 0, /**<  Voice. */
+    E_QL_MCM_VOICE_CALL_FORWARDING_TYPE_DATA        = 1, /**<  Data. */
+    E_QL_MCM_VOICE_CALL_FORWARDING_TYPE_VOICE_DATA  = 2, /**<  Voice and data. */
+} QL_MCM_VOICE_CALL_FORWARDING_TYPE_T;
+
+typedef struct
+{
+    QL_MCM_VOICE_CALL_FORWARDING_TYPE_T     type;       /**<   Call forwarding type.*/
+    char number[QL_MCM_MAX_PHONE_NUMBER + 1];           /**<   Call forwarding number.*/
+} QL_MCM_VOICE_CALL_FORWARDING_INFO_T; /* Type */
+
+typedef struct
+{
+    QL_MCM_VOICE_CALL_FORWARDING_STATUS_T     status;     /**<   Call forwarding status.*/
+    uint32_t                                  info_len;   /**< Must be set to # of elements in info */
+    QL_MCM_VOICE_CALL_FORWARDING_INFO_T       info[QL_MCM_MAX_CALL_FORWARDING_INFO];/**<   Call forwarding information.*/
+} ql_mcm_voice_call_forwarding_status_list_t; /* Message */
+
+typedef enum
+{
+    E_QL_MCM_VOICE_SERVICE_UNKOWN       =   0,
+    E_QL_MCM_VOICE_SERVICE_REGISTER     =   1,  /**<  Register. */
+    E_QL_MCM_VOICE_SERVICE_ERASE        =   2,  /**<  Erase. */
+} E_QL_MCM_VOICE_CALL_SERVICE_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_FORWARD_UNCONDITIONALLY     = 0, /**<  Unconditional call forwarding. */
+    E_QL_MCM_VOICE_CALL_FORWARD_MOBILEBUSY          = 1, /**<  Forward when the mobile device is busy. */
+    E_QL_MCM_VOICE_CALL_FORWARD_NOREPLY             = 2, /**<  Forward when there is no reply. */
+    E_QL_MCM_VOICE_CALL_FORWARD_UNREACHABLE         = 3, /**<  Forward when the call is unreachable. */
+    E_QL_MCM_VOICE_CALL_FORWARD_ALLFORWARDING       = 4, /**<  All forwarding(0-3). */
+    E_QL_MCM_VOICE_CALL_FORWARD_ALLCONDITIONAL      = 5, /**<  All conditional forwarding(1-3). */
+} E_QL_MCM_VOICE_CALL_FORWARDING_REASON_T;
+
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CALL_WAITING_VOICE_ENABLED       = 0, /**<  Voice call waiting enabled. */
+    E_QL_MCM_VOICE_CALL_WAITING_DISABLED            = 1, /**<  Voice call waiting disabled. */
+} E_QL_MCM_VOICE_CALL_WAITING_SERVICE_T;
+
+typedef struct
+{
+    E_QL_MCM_VOICE_CALL_WAITING_SERVICE_T   waiting_service;
+} ql_mcm_voice_call_waiting_service_t;
+
+
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CLIR_INVOCATION                  = 0, /**<  Invocation. */
+    E_QL_MCM_VOICE_CLIR_SUPPRESSION                 = 1, /**<  Suppression. */
+} ql_mcm_voice_clir_action_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_CLIR_NOT_PROVISIONED             = 0, /**<  Not provisioned. */
+    E_QL_MCM_VOICE_CLIR_PROVISIONED_PERMANENT_MODE  = 1, /**<  Permanently provisioned. */
+    E_QL_MCM_VOICE_CLIR_PRESENTATION_RESTRICTED     = 2, /**<  Restricted presentation. */
+    E_QL_MCM_VOICE_CLIR_PRESENTATION_ALLOWED        = 3, /**<  Allowed presentation. */
+} ql_mcm_voice_clir_presentation_t;
+
+typedef struct
+{
+    ql_mcm_voice_clir_action_t          action;
+    ql_mcm_voice_clir_presentation_t    presentation;  /**<   CLIR presentation.*/
+} ql_mcm_voice_clir_info_t;
+
+
+
+typedef enum
+{
+    E_QL_MCM_VOICE_USSD_MSG_TYPE_NEW_MESSAGE        = 0, /**<  Initiate a new USSD sesion with network. */
+    E_QL_MCM_VOICE_USSD_MSG_TYPE_REPLY_TO_IND       = 1, /**<  Reply to a USSD indication from the network. */
+} ql_mcm_voice_ussd_msg_type_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_USSD_ENCODING_ASCII              = 0, /**<  ASCII coding scheme. */
+    E_QL_MCM_VOICE_USSD_ENCODING_8BIT               = 1, /**<  8-bit coding scheme. */
+    E_QL_MCM_VOICE_USSD_ENCODING_UCS2               = 2, /**<  UCS2. */
+} ql_mcm_voice_ussd_encoding_type_t;
+
+typedef struct
+{
+    ql_mcm_voice_ussd_msg_type_t      type;           /**<   Whether sending a new request or a reply to indication*/
+    ql_mcm_voice_ussd_encoding_type_t encoding;       /**<   USSD encoding.*/
+    char ussd_string[QL_MCM_MAX_USSD_LENGTH + 1];    /**<   USSD string.*/
+} ql_mcm_voice_ussd_info_t; /* Message */
+
+
+typedef enum
+{
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_ALLOUTGOING           = 0, /**<  All outgoing. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_OUTGOINGINT           = 1, /**<  Outgoing internal. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_OUTGOINGINTEXTOHOME   = 2, /**<  Outgoing external to home. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_ALLINCOMING           = 3, /**<  All incoming. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_INCOMINGROAMING       = 4, /**<  Roaming incoming. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_ALLBARRING            = 5, /**<  All calls are barred. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_ALLOUTGOINGBARRING    = 6, /**<  All outgoing calls are barred. */
+    E_QL_MCM_SIMRIL_CHANGE_CALL_BARRING_PWD_REASON_ALLINCOMINGBARRING    = 7, /**<  All incoming calls are barred. */
+} ql_mcm_change_call_barring_pwd_reason_t;
+
+typedef struct
+{
+    ql_mcm_change_call_barring_pwd_reason_t     reason;  /**<  Reason for the password change. Refer to 3GPP TS 27.007 @xhyperref{S8,[S8]}, Section 7.4.*/
+    char                                        old_pwd[QL_MCM_MAX_PASSWORD_LENGTH + 1];
+    char                                        new_pwd[QL_MCM_MAX_PASSWORD_LENGTH + 1];
+} ql_mcm_change_call_barring_pwd_info_t; /* Message */
+
+
+typedef enum
+{
+    E_QL_MCM_SIMRIL_E911_UNKNOWN   = -1,   /**<  E911 unknown. */
+    E_QL_MCM_SIMRIL_E911_INACTIVE  = 0,    /**<  E911 INACTIVE. */
+    E_QL_MCM_SIMRIL_E911_ACTIVE    = 1,    /**<  E911 ACTIVE. */
+} ql_mcm_simril_e911_state_t;
+
+typedef ql_mcm_voice_call_state_t E_QL_VOICE_CALL_STATE_T;
+
+typedef enum
+{
+    E_QL_MCM_ECALL_TEST             = 0x01,
+    E_QL_MCM_ECALL_EMERGENCY        = 0x02,
+    E_QL_MCM_ECALL_RECONFIG         = 0x03,
+} E_QL_MCM_ECALL_VARIANT_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_AUTO_ANSWER_ENABLE       = 0,    /**<  Enable auto-answer. */
+    E_QL_MCM_VOICE_AUTO_ANSWER_DISABLE      = 1,    /**<  Disable auto-answer. */
+} E_QL_MCM_VOICE_AUTO_ANSWER_T;
+
+
+//Laurence.yin-2018/04/03-QCM9XOL00004C011-P02, <[MCM-ECALL] : add ecall status ind info.>
+typedef enum
+{
+    E_QL_MCM_VOICE_UNKOWN_IND               = 0,
+    E_QL_MCM_VOICE_CALL_IND,
+    E_QL_MCM_VOICE_ECALL_STATUE_IND,
+    E_QL_MCM_VOICE_ECALL_URC_IND,
+    E_QL_MCM_VOICE_ECALL_EVENT_IND,
+
+} E_QL_MCM_VOICE_IND_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_MSD_TRANSMISSION_STATUS_SUCCESS        = 0x00, /**<   Success \n       */
+    E_QL_MCM_VOICE_ECALL_MSD_TRANSMISSION_STATUS_FAILURE        = 0x01, /**<   Generic failure  */
+} E_QL_MCM_EALL_MSD_TRANSMISSION_STATUS_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_INACTIVE               = 0,
+    E_QL_MCM_VOICE_ECALL_ORIGINATING_CALL       = 1,
+    E_QL_MCM_VOICE_ECALL_IN_CALL_TRANSMITTING   = 2, /**<  ECALL APP TRANSMITTING */
+    E_QL_MCM_VOICE_ECALL_WATING_FOR_AL_ACK      = 3,
+    E_QL_MCM_VOICE_ECALL_IN_CALL                = 4,
+    E_QL_MCM_VOICE_ECALL_IDLE_ALLOW_MT_ECALL    = 5,
+} E_QL_MCM_ECALL_STATE_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_MODE_NOMAL   = 0,
+    E_QL_MCM_VOICE_ECALL_MODE_ONLY    = 1,
+    E_QL_MCM_VOICE_ECALL_MODE_DEFAULT = 2
+} E_QL_MCM_ECALL_MODE_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_CONFIG_ENABLE            = 0,
+    E_QL_MCM_VOICE_ECALL_CONFIG_VIOCECONF,
+    E_QL_MCM_VOICE_ECALL_CONFIG_MODE,
+    E_QL_MCM_VOICE_ECALL_CONFIG_PROCESSINFO,
+    E_QL_MCM_VOICE_ECALL_CONFIG_START_TIMER,
+    E_QL_MCM_VOICE_ECALL_CONFIG_HACK_TIMER,
+    E_QL_MCM_VOICE_ECALL_CONFIG_MSD_TRANSMISSION,
+    E_QL_MCM_VOICE_ECALL_CONFIG_MO_FAILR_REDIAL,
+    E_QL_MCM_VOICE_ECALL_CONFIG_DROP_REDIAL
+} E_QL_MCM_ECALL_CONFIG_T;
+
+typedef struct
+{
+    char                        ecall_msd[QL_MCM_MAX_ECALL_MSD];  //max msd length 140
+    uint32_t                    msd_len;
+    int                         manual;
+    E_QL_MCM_ECALL_VARIANT_T    eCallModeType;
+} ql_mcm_ecall_info;
+
+typedef struct
+{
+    uint8_t enable;           /*  Enable or disable ecall ;0 -- Disable; 1 -- Enable */
+    uint8_t voiceconfig;      /*  Enable or disable to mute IVS speaker in MSD
+                            0 -- Disable to mute IVS speaker automatical in MSD transmission
+                            1 -- Enable to mute IVS speaker automatical in MSD transmission */
+    E_QL_MCM_ECALL_MODE_T ecallmode;  /*  The Ecall mode. */
+    uint8_t processinfo;      /*  Enable or disable to report ecall event info.   0 -- Disable; 1 -- Enable */
+    uint8_t T5;               /*  The timer of IVS waiting for "START". */
+    uint8_t T6;               /*  The timer of IVS waiting for "HACK". */
+    uint8_t T7;               /*  The timer of MSD transmission. */
+    uint8_t mofailredial;     /*  The dial fail times. */
+    uint8_t dropredial;
+} ql_mcm_ecall_config_info;
+
+
+typedef struct
+{
+    uint8_t call_id;                                                    /**<  call_id.*/
+    uint8_t ecall_msd_tx_status_valid;
+    E_QL_MCM_EALL_MSD_TRANSMISSION_STATUS_T ecall_msd_tx_status;
+} ql_mcm_voice_ecall_status_t; /* Message */
+
+typedef struct
+{
+    uint8_t call_id;                /**<  call_id.*/
+    uint32_t ecall_urc_event_len;   /**< Must be set to # of elements in ecall_urc_event */
+    char ecall_urc_event[QL_MCM_MAX_ECALL_URC_EVENT_LENGTH];
+} ql_mcm_voice_ecall_urc_t;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_EVENT_FAIL_START_TIMEOUT             = 1, /**<  Wait for START timeout. */
+    E_QL_MCM_VOICE_ECALL_EVENT_FAIL_HACK_TIMEOUT              = 2, /**<  Wait for HACK timeout.    */
+    E_QL_MCM_VOICE_ECALL_EVENT_FAIL_MSD_TRANSMISSION_TIMEOUT  = 3, /**<  MSD transmission timeout.     */
+    E_QL_MCM_VOICE_ECALL_EVENT_FAIL_IVS_RESET_TIMEOUT         = 4  /**<  IVS reset. */
+} E_QL_MCM_VOICE_ECALL_EVENT_FAIL_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_IVS_START_RECEIVED_MSD = 1, /**<  IVS Link Layer receives START message and starts to send MSD */
+    E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_IVS_NACK_RECEIVED      = 2, /**<  IVS Link Layer receives NACK message. */
+    E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_IVS_ACK_RECEIVED       = 3, /**<  IVS Link Layer receives the first LACK message. */
+    E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_IVS_TX_COMPLETED       = 4, /**<  IVS MSD transmission is complete. */
+    E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_IVS_HLACK_RECEIVED     = 5  /**<  IVS Link Layer receives first HACK message. */
+} E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_EVENT_MSDUPDATE_IVS_UPDATING_MSD         = 0, /**<  Indicates MSD has been updated. */
+    E_QL_MCM_VOICE_ECALL_EVENT_MSDUPDATE_PSAP_REQURE_UPDATE_MSD   = 1, /**<  Indicate timeout of updating MSD and module starts to transfer the old MSD. */
+    E_QL_MCM_VOICE_ECALL_EVENT_MSDUPDATE_IVS_UPDATE_MSD_TIMEOUT   = 2  /**<  Indicate to update MSD in 5 seconds. */
+} E_QL_MCM_VOICE_ECALL_EVENT_MSDUPDATE_T;
+
+typedef enum
+{
+    E_QL_MCM_VOICE_ECALL_EVENT_ECALL_ESTABLISHNG_SUCCESS  = 0, /**<  Establish eCall successfully. */
+    E_QL_MCM_VOICE_ECALL_EVENT_ECALL_ESTABLISHNG_FAIL     = 1  /**<  Establish eCall fails. */
+} E_QL_MCM_VOICE_ECALL_EVENT_ESTABLISH_T;
+
+typedef struct
+{
+    uint16_t hack_code;  /**<   psap hack code.*/
+} ql_mcm_voice_ecall_event_hackcode_t; /* Type */
+
+typedef struct
+{
+    uint8_t ori_remainder_times;  /**<   originate fail remainder times*/
+    uint16_t time;                /**<   the minimum time duration between the previous call attempt*/
+} ql_mcm_voice_ecall_event_originate_fail_and_redial_t; /* Type */
+
+typedef struct
+{
+    uint8_t drop_remainder_times;  /**<   dorp remainder times*/
+    uint16_t time;                 /**<   the minimum time duration between the previous call attempt*/
+} ql_mcm_voice_ecall_event_drop_and_redial_t; /* Type */
+
+
+typedef struct
+{
+    uint8_t                                               ecall_event_fails_valid;
+    E_QL_MCM_VOICE_ECALL_EVENT_FAIL_T                     ecall_event_fails;          /**<   event of eCall Failed.*/
+    uint8_t                                               ecall_event_process_valid;
+    E_QL_MCM_VOICE_ECALL_EVENT_PROCESS_T                  ecall_event_process;        /**<   event of eCall process.*/
+    uint8_t                                               ecall_event_msdupdate_valid;
+    E_QL_MCM_VOICE_ECALL_EVENT_MSDUPDATE_T                ecall_event_msdupdate;      /**<   event of ecall msd update.*/
+    uint8_t                                               ecall_event_establish_valid;
+    E_QL_MCM_VOICE_ECALL_EVENT_ESTABLISH_T                ecall_event_establish;      /**<   event of eCall establish.*/
+    uint8_t                                               ecall_event_hackcode_valid;
+    ql_mcm_voice_ecall_event_hackcode_t                   ecall_event_hackcode;       /**<   event of eCall hack code.*/
+    uint8_t                                               ecall_event_ori_redial_valid;
+    ql_mcm_voice_ecall_event_originate_fail_and_redial_t  ecall_event_ori_redial;     /**<   event of originate fail and redial.*/
+    uint8_t                                               ecall_event_drop_redial_valid;
+    ql_mcm_voice_ecall_event_drop_and_redial_t            ecall_event_drop_redial;    /**<   event of drop and redial.*/
+} ql_mcm_voice_ecall_event_t; /* Message */
+
+
+typedef ql_mcm_voice_calls_state_t ql_mcm_voice_call_ind;
+typedef ql_mcm_voice_ecall_status_t ql_mcm_voice_ecall_status_ind;
+typedef ql_mcm_voice_ecall_urc_t ql_mcm_voice_ecall_urc_ind;
+typedef ql_mcm_voice_ecall_event_t ql_mcm_voice_ecall_event_ind;
+
+
+
+
+/* Callback function registered via QL_Voice_Call_AddStateHandler;
+   This will be called if any stated changed of call_id
+*/
+typedef void (*QL_VoiceCall_CommonStateHandlerFunc_t)
+(
+    unsigned long message_id,
+    void *ind_data,
+    uint32_t ind_data_len
+);
+
+
+typedef uint32 voice_client_handle_type;
+
+/* Callback function registered via QL_Voice_Call_AddStateHandler;
+   This will be called if any stated changed of call_id
+*/
+typedef void (*QL_VoiceCall_StateHandlerFunc_t)
+(
+    int                     call_id,
+    char*                   phone_num,
+    E_QL_VOICE_CALL_STATE_T state,
+    void                    *contextPtr
+);
+
+/* 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);
+
+/* DeInit voice module and release resources, this should be called at last */
+int QL_Voice_Call_Client_Deinit(voice_client_handle_type h_voice);
+
+/* 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);
+
+/* Remove callback function, won't receive any notify anymore */
+int QL_Voice_Call_RemoveStateHandler(voice_client_handle_type h_voice);
+
+//Laurence.yin-2018/04/03-QCM9XOL00004C011-P02, <[MCM-ECALL] : add ecall status ind info.>
+/* 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);
+
+/* Remove callback function, won't receive any notify anymore */
+int QL_Voice_Call_RemoveCommonStateHandler(voice_client_handle_type          h_voice);
+
+
+/* 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
+
+/* 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
+
+/* 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 );
+
+int QL_Voice_Call_Hold( voice_client_handle_type    h_voice);
+
+int QL_Voice_Call_UnHold( voice_client_handle_type    h_voice);
+
+int QL_Voice_Call_Conference( voice_client_handle_type   h_voice);
+
+int QL_Voice_Call_EndConference( voice_client_handle_type   h_voice);
+
+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);
+
+
+int QL_Voice_Call_SetAutoAnswer(voice_client_handle_type                h_voice,
+                                E_QL_MCM_VOICE_AUTO_ANSWER_T    eAnswerType,
+                                uint32_t                        uAnswerTime);
+
+int QL_Voice_Call_Ecall_HangUp(voice_client_handle_type h_voice);
+
+int QL_Voice_Call_Ecall_UpdateMsd(voice_client_handle_type    h_voice,const char *msd,uint32_t   msd_len);
+
+//Ecall Push caommand
+int QL_Voice_Call_Ecall_MsdPush(voice_client_handle_type h_voice,
+                                E_QL_MCM_ECALL_STATE_T *ecall_state);
+
+//Get Ecall config info
+int QL_Voice_Call_Ecall_GetConfigInfo(voice_client_handle_type h_voice,
+                                      ql_mcm_ecall_config_info *ecall_config);
+
+int QL_Voice_Call_Ecall_SetConfigInfo(voice_client_handle_type h_voice,
+                                      E_QL_MCM_ECALL_CONFIG_T ecall_config_type,
+                                      uint8_t value);
+
+
+
+//Cancel dial
+int QL_Voice_Call_CancelDial( voice_client_handle_type   h_voice);
+
+//VTS API
+int QL_Voice_Call_Dtmf( voice_client_handle_type h_voice,uint8_t digit,int call_id);
+
+
+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
+);
+
+//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
+);
+
+//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
+);
+
+//Set voice call waiting
+int QL_Voice_Call_SetWaiting
+(
+    int                                 h_voice,
+    ql_mcm_voice_call_waiting_service_t e_service
+);
+
+//Get voice call waiting status
+int QL_Voice_Call_GetWaitingStatus
+(
+    int                                 h_voice,
+    ql_mcm_voice_call_waiting_service_t *pe_service
+);
+
+
+/*
+Usage 1 (register callback and wait for new call in, then answer):
+1, QL_Voice_Call_Client_Init
+2, QL_Voice_Call_AddStateHandler(pf_cb)
+3, wait for new call arrive, pf_cb will pass the call_id to app.
+4, QL_Voice_Call_Answer(call_id)
+5, QL_Voice_Call_End
+6, QL_Voice_Call_Client_Deinit
+
+
+Usage 2 (call out):
+1, QL_Voice_Call_Client_Init
+2, QL_Voice_Call_AddStateHandler(pf_cb)
+3, QL_Voice_Call_Start
+4, QL_Voice_Call_End
+5, QL_Voice_Call_Client_Deinit
+
+
+*/
+
+
+#endif // __QL_MCM_VOICE_H__
diff --git a/mbtk/include/ql/ql_mcm_gnss.h b/mbtk/include/ql/ql_mcm_gnss.h
new file mode 100755
index 0000000..b2ee20a
--- /dev/null
+++ b/mbtk/include/ql/ql_mcm_gnss.h
@@ -0,0 +1,414 @@
+#ifndef __QL_MCM_GPS_H__
+#define __QL_MCM_GPS_H__
+#include "mbtk_type.h"
+
+
+#define     LOC_IND_LOCATION_INFO_ON            (1 << 0)
+#define     LOC_IND_STATUS_INFO_ON              (1 << 1)
+#define     LOC_IND_SV_INFO_ON                  (1 << 2)
+#define     LOC_IND_NMEA_INFO_ON                (1 << 3)
+#define     LOC_IND_CAP_INFO_ON                 (1 << 4)
+#define     LOC_IND_UTC_TIME_REQ_ON             (1 << 5)
+#define     LOC_IND_XTRA_DATA_REQ_ON            (1 << 6)
+#define     LOC_IND_AGPS_DATA_CONN_CMD_REQ_ON   (1 << 7)
+#define     LOC_IND_NI_NFY_USER_RESP_REQ_ON     (1 << 8)
+
+typedef uint32 loc_client_handle_type;
+
+typedef enum
+{
+    E_QL_LOC_POS_MODE_STANDALONE        = 0, /**<  Mode for running GPS standalone (no assistance).  */
+    E_QL_LOC_POS_MODE_MS_BASED          = 1, /**<  AGPS MS-Based mode.  */
+    E_QL_LOC_POS_MODE_MS_ASSISTED       = 2, /**<  AGPS MS-Assisted mode.  */
+}E_QL_LOC_POS_MODE_T;
+
+typedef enum
+{
+    E_QL_LOC_POS_RECURRENCE_PERIODIC    = 0, /**<  Receive GPS fixes on a recurring basis at a specified period.  */
+    E_QL_LOC_POS_RECURRENCE_SINGLE      = 1, /**<  Request a single-shot GPS fix.  */
+}E_QL_LOC_POS_RECURRENCE_T;
+
+typedef struct
+{
+  E_QL_LOC_POS_MODE_T       mode;               /*  Position mode.      */
+  E_QL_LOC_POS_RECURRENCE_T recurrence;         /*  Recurrence          */
+  uint32_t                  min_interval;       /*  Minimum Interval, NMEA report frequency, 1000 means 1Hz, 100 means 10Hz    */
+  uint32_t                  preferred_accuracy; /*  Preferred Accuracy , 30m or more, the less it takes longer timer. */
+  uint32_t                  preferred_time;     /*  Preferred Time, first cold-boot may take 100s or more, hot boot may take 2s      */
+}QL_LOC_POS_MODE_INFO_T;
+
+typedef enum
+{
+    E_QL_LOC_LOCATION_LAT_LONG_VALID   = 0x0001, /**<  GPS location has valid latitude and longitude.  */
+    E_QL_LOC_LOCATION_ALTITUDE_VALID   = 0x0002, /**<  GPS location has a valid altitude.  */
+    E_QL_LOC_LOCATION_SPEED_VALID      = 0x0004, /**<  GPS location has a valid speed.  */
+    E_QL_LOC_LOCATION_BEARING_VALID    = 0x0008, /**<  GPS location has a valid bearing.  */
+    E_QL_LOC_LOCATION_ACCURACY_VALID   = 0x0010, /**<  GPS location has valid accuracy.  */
+    E_QL_LOC_LOCATION_SOURCE_INFO_VALID= 0x0020, /**<  GPS location has valid source information.  */
+    E_QL_LOC_LOCATION_IS_INDOOR_VALID  = 0x0040, /**<  GPS location has a valid "is indoor?" flag.  */
+    E_QL_LOC_LOCATION_FLOOR_NUMBE_VALID= 0x0080, /**<  GPS location has a valid floor number.  */
+    E_QL_LOC_LOCATION_MAP_URL_VALID    = 0x0100, /**<  GPS location has a valid map URL.  */
+    E_QL_LOC_LOCATION_MAP_INDEX_VALID  = 0x0200, /**<  GPS location has a valid map index.  */
+}E_QL_LOC_LOCATION_VALID_FLAG;
+
+typedef enum
+{
+    E_QL_LOC_ULP_LOCATION_SOURCE_HYBRID= 0x0001, /**<  Position source is ULP.  */
+    E_QL_LOC_ULP_LOCATION_SOURCE_GNSS  = 0x0002, /**<  Position source is GNSS only.  */
+}E_QL_LOC_ULP_LOCATION_SOURCE;
+
+#define QL_LOC_GPS_RAW_DATA_LEN_MAX         256 /**  Raw data maximum size. */
+#define QL_LOC_GPS_LOCATION_MAP_URL_SIZE    399 /**  Location map URL maximum size (used for indoor positioning). */
+#define QL_LOC_GPS_LOCATION_MAP_IDX_SIZE    16  /**  Location map index maximum size (used for indoor positioning). */
+typedef struct
+{
+    uint32_t    size;                   /**<   Set to the size of mcm_gps_location_t. */
+    E_QL_LOC_LOCATION_VALID_FLAG flags; /**<   Contains GPS location flags bits. */
+    E_QL_LOC_ULP_LOCATION_SOURCE position_source;  /**<   Provider indicator for HYBRID or GPS. */
+    double      latitude;               /**<   Latitude in degrees. */
+    double      longitude;              /**<   Longitude in degrees. */
+    double      altitude;               /**<   Altitude in meters above the WGS 84 reference ellipsoid. */
+    float       speed;                  /**<   Speed in meters per second. */
+    float       bearing;                /**<   Heading in degrees. */
+    float       accuracy;               /**<   Expected accuracy in meters. */
+    int64_t     timestamp;              /**<   Timestamp for the location fix in UTC million-second base.  */
+    int32_t     is_indoor;              /**<   Location is indoors. */
+    float       floor_number;           /**<   Indicates the floor number. */
+    uint32_t    raw_data_len;           /**<   Must be set to # of elements in raw_data */
+    uint8_t     raw_data[QL_LOC_GPS_RAW_DATA_LEN_MAX];          /**<   Allows the HAL to pass additional information related to the location. */
+    char        map_url[QL_LOC_GPS_LOCATION_MAP_URL_SIZE + 1];  /**<   Map URL. */
+    uint8_t     map_index[QL_LOC_GPS_LOCATION_MAP_IDX_SIZE];    /**<   Map index. */
+}QL_LOC_LOCATION_INFO_T;  /* Type */
+
+typedef enum
+{
+    E_QL_LOC_STATUS_NONE            = 0, /**<  GPS status unknown.  */
+    E_QL_LOC_STATUS_SESSION_BEGIN   = 1, /**<  GPS has begun navigating.  */
+    E_QL_LOC_STATUS_SESSION_END     = 2, /**<  GPS has stopped navigating.  */
+    E_QL_LOC_STATUS_ENGINE_ON       = 3, /**<  GPS has powered on but is not navigating.  */
+    E_QL_LOC_STATUS_ENGINE_OFF      = 4, /**<  GPS is powered off.  */
+}E_QL_LOC_STATUS_VALUE_T;
+
+typedef struct
+{
+    uint32_t    size;                   /**<   Set to the size of mcm_gps_sv_info_t. */
+    int         prn;                    /**<   Pseudo-random number for the SV. */
+    float       snr;                    /**<   Signal-to-noise ratio. */
+    float       elevation;              /**<   Elevation of the SV in degrees. */
+    float       azimuth;                /**<   Azimuth of the SV in degrees. */
+}QL_LOC_SV_INFO_T;                      /* Type */
+
+#define     QL_LOC_GPS_SUPPORT_SVS_MAX   32  /**  Maximum number of satellites in view. */
+typedef struct
+{
+    uint32_t            size;                                   /**<   Set to the size of mcm_gps_sv_status_t. */
+    int                 num_svs;                                /**<   Number of SVs currently visible. */
+    QL_LOC_SV_INFO_T    sv_list[QL_LOC_GPS_SUPPORT_SVS_MAX];    /**<   Contains an array of SV information. */
+    uint32_t            ephemeris_mask;                         /**<   Bitmask indicating which SVs have ephemeris data.  */
+    uint32_t            almanac_mask;                           /**<   Bitmask indicating which SVs have almanac data.   */
+    uint32_t            used_in_fix_mask;                       /**<   Bitmask indicating which SVs were used for computing the most recent position fix. */
+}QL_LOC_SV_STATUS_T;  /* Type */
+
+
+#define QL_LOC_NMEA_MAX_LENGTH  255                 /**  NMEA string maximum length. */
+typedef struct
+{
+    int64_t     timestamp;                          /**<   System Timestamp, marked for when got the nmea data */
+    int         length;                             /**<   NMEA string length. */
+    char        nmea[QL_LOC_NMEA_MAX_LENGTH + 1];   /**<   NMEA string.*/
+}QL_LOC_NMEA_INFO_T;  /* Message */
+
+typedef enum
+{
+    E_QL_LOC_CAPABILITY_SCHEDULING      = 0x01, /**<  GPS HAL schedules fixes for GPS_POSITION_RECURRENCE_PERIODIC mode.
+                                                         If this is not set, the framework uses \n 1000 ms for min_interval
+                                                         and will call start() and stop() to schedule the GPS. */
+    E_QL_LOC_CAPABILITY_MSB             = 0x02, /**<  GPS supports MS-Based AGPS mode.  */
+    E_QL_LOC_CAPABILITY_MSA             = 0x04, /**<  GPS supports MS-Assisted AGPS mode.  */
+    E_QL_LOC_CAPABILITY_SINGLE_SHOT     = 0x08, /**<  GPS supports single-shot fixes.  */
+    E_QL_LOC_CAPABILITY_ON_DEMAND_TIME  = 0x10, /**<  GPS supports on-demand time injection.  */
+}E_QL_LOC_CAPABILITIES_T;
+
+
+#define QL_LOC_GPS_SSID_BUF_SIZE    32          /**  Maximum SSID (Service Set Identifier) buffer size. */
+#define QL_LOC_IPV6_ADDR_LEN        16          /**  IPv6 address length. */
+typedef enum
+{
+    E_QL_LOC_AGPS_TYPE_INVALID          = -1,   /**<  Invalid.  */
+    E_QL_LOC_AGPS_TYPE_ANY              = 0,    /**<  Any.  */
+    E_QL_LOC_AGPS_TYPE_SUPL             = 1,    /**<  SUPL.  */
+    E_QL_LOC_AGPS_TYPE_C2K              = 2,    /**<  C2K.  */
+    E_QL_LOC_AGPS_TYPE_WWAN_ANY         = 3,    /**<  WWAN any.  */
+    E_QL_LOC_AGPS_TYPE_WIFI             = 4,    /**<  Wi-Fi.  */
+    E_QL_LOC_AGPS_TYPE_SUPL_ES          = 5,    /**<  SUPL_ES.  */
+}E_QL_LOC_AGPS_TYPE_T;
+
+typedef enum
+{
+    E_QL_LOC_REQUEST_AGPS_DATA_CONN     = 1,    /**<  GPS requests a data connection for AGPS.  */
+    E_QL_LOC_RELEASE_AGPS_DATA_CONN     = 2,    /**<  GPS releases the AGPS data connection.  */
+    E_QL_LOC_AGPS_DATA_CONNECTED        = 3,    /**<  AGPS data connection is initiated  */
+    E_QL_LOC_AGPS_DATA_CONN_DONE        = 4,    /**<  AGPS data connection is completed.  */
+    E_QL_LOC_AGPS_DATA_CONN_FAILED      = 5,    /**<  AGPS data connection failed.  */
+}E_QL_LOC_AGPS_STATUS_VALUE_T;
+
+typedef struct
+{
+    uint32_t                        size;       /**<   Set to the size of mcm_agps_status_t. */
+    E_QL_LOC_AGPS_TYPE_T            type;       /**<   Type. */
+    E_QL_LOC_AGPS_STATUS_VALUE_T    status;     /**<   Status. */
+    int                             ipv4_addr;  /**<   IPv4 address. */
+    char                            ipv6_addr[QL_LOC_IPV6_ADDR_LEN + 1];        /**<   IPv6 address. */
+    char                            ssid[QL_LOC_GPS_SSID_BUF_SIZE + 1];         /**<   SSID. */
+    char                            password[QL_LOC_GPS_SSID_BUF_SIZE + 1];     /**<   Password. */
+}QL_LOC_AGPS_STATUS_T;
+
+
+#define QL_LOC_NI_SHORT_STRING_MAXLEN   255     /**  NI short string maximum length. */
+#define QL_LOC_NI_LONG_STRING_MAXLEN    2047    /**  NI long string maximum length. */
+typedef enum
+{
+    E_QL_LOC_NI_TYPE_VOICE          = 1,        /**<  Voice.  */
+    E_QL_LOC_NI_TYPE_UMTS_SUPL      = 2,        /**<  UMTS SUPL.  */
+    E_QL_LOC_NI_TYPE_UMTS_CTRL_PLANE= 3,        /**<  UMTS control plane.  */
+}E_QL_LOC_NI_TYPE_T;
+
+typedef enum
+{
+    E_QL_LOC_NI_NEED_NOTIFY         = 0x0001,   /**<  NI requires notification.  */
+    E_QL_LOC_NI_NEED_VERIFY         = 0x0002,   /**<  NI requires verification.  */
+    E_QL_LOC_NI_PRIVACY_OVERRIDE    = 0x0004,   /**<  NI requires privacy override; no notification/minimal trace.  */
+}E_QL_LOC_NI_NOTIFY_FLAGS_T;
+
+typedef enum
+{
+    E_QL_LOC_NI_RESPONSE_ACCEPT     = 1,        /**<  Accept.  */
+    E_QL_LOC_NI_RESPONSE_DENY       = 2,        /**<  Deny.  */
+    E_QL_LOC_NI_RESPONSE_NORESP     = 3,        /**<  No response.  */
+}E_QL_LOC_NI_USER_RESPONSE_TYPE_T;
+
+typedef enum
+{
+    E_QL_LOC_NI_ENC_NONE            = 0,        /**<  None.  */
+    E_QL_LOC_NI_ENC_SUPL_GSM_DEFAULT= 1,        /**<  SUPL GSM default.  */
+    E_QL_LOC_NI_ENC_SUPL_UTF8       = 2,        /**<  SUPL UTF8.  */
+    E_QL_LOC_NI_ENC_SUPL_UCS2       = 3,        /**<  SUPL UCS2.  */
+    E_QL_LOC_NI_ENC_UNKNOWN         = -1,       /**<  Unknown.  */
+}E_QL_LOC_NI_ENC_TYPE_T;
+
+typedef struct
+{
+    uint32_t                            size;               /**<   Set to the size of mcm_gps_ni_notification_t. */
+    int                                 notification_id;    /**<   An ID generated by the HAL to associate NI notifications and UI responses.  */
+    E_QL_LOC_NI_TYPE_T                  ni_type;            /**<   An NI type used to distinguish different categories of NI events, such as GPS_NI_TYPE_VOICE, GPS_NI_TYPE_UMTS_SUPL, etc.  */
+    E_QL_LOC_NI_NOTIFY_FLAGS_T          notify_flags;       /**<   Notification/verification options; combinations of GpsNiNotifyFlags constants.  */
+    int                                 timeout;            /**<   Timeout period to wait for a user response. Set to 0 for no timeout limit.  */
+    E_QL_LOC_NI_USER_RESPONSE_TYPE_T    default_response;   /**<   Default response when the response times out.  */
+    char                                requestor_id[QL_LOC_NI_SHORT_STRING_MAXLEN + 1];    /**<   Requestor ID.  */
+    char                                text[QL_LOC_NI_LONG_STRING_MAXLEN + 1];             /**<   Notification message. It can also be used to store the client ID in some cases.  */
+    E_QL_LOC_NI_ENC_TYPE_T              requestor_id_encoding;                              /**<   Client ID encoding scheme.  */
+    E_QL_LOC_NI_ENC_TYPE_T              text_encoding;                                      /**<   Client name encoding scheme.  */
+    char                                extras[QL_LOC_NI_LONG_STRING_MAXLEN + 1];           /**<   Pointer to extra data. Format:\n- key_1 = value_1, - key_2 = value_2 @tablebulletend */
+}QL_LOC_NI_NOTIFICATION_INTO_T;
+
+#define     QL_LOC_MAX_SEVER_ADDR_LENGTH    255 /**  Maximum generic server address length for the host name. */
+typedef struct
+{/** Indication Message; Indication with the reported XTRA server URLs. */
+    char server1[QL_LOC_MAX_SEVER_ADDR_LENGTH + 1];  /**<   server1.*/
+    char server2[QL_LOC_MAX_SEVER_ADDR_LENGTH + 1];  /**<   server2.*/
+    char server3[QL_LOC_MAX_SEVER_ADDR_LENGTH + 1];  /**<   server3.*/
+}QL_LOC_XTRA_REPORT_SERVER_INTO_T;
+
+typedef enum
+{
+    E_QL_LOC_NFY_MSG_ID_STATUS_INFO = 0,        /**<  pv_data = &E_QL_LOC_STATUS_VALUE_T  */
+    E_QL_LOC_NFY_MSG_ID_LOCATION_INFO,          /**<  pv_data = &QL_LOC_LOCATION_INFO_T  */
+    E_QL_LOC_NFY_MSG_ID_SV_INFO,                /**<  pv_data = &QL_LOC_SV_STATUS_T  */
+    E_QL_LOC_NFY_MSG_ID_NMEA_INFO,              /**<  pv_data = &QL_LOC_NMEA_INFO_T  */
+    E_QL_LOC_NFY_MSG_ID_CAPABILITIES_INFO,      /**<  pv_data = &E_QL_LOC_CAPABILITIES_T  */
+    E_QL_LOC_NFY_MSG_ID_AGPS_STATUS,            /**<  pv_data = &QL_LOC_AGPS_STATUS_T  */
+    E_QL_LOC_NFY_MSG_ID_NI_NOTIFICATION,        /**<  pv_data = &QL_LOC_NI_NOTIFICATION_INTO_T  */
+    E_QL_LOC_NFY_MSG_ID_XTRA_REPORT_SERVER,     /**<  pv_data = &QL_LOC_XTRA_REPORT_SERVER_INTO_T  */
+}E_QL_LOC_NFY_MSG_ID_T;
+
+/* callback function register to QL_LOC_AddRxIndMsgHandler
+   e_msg_id: which kind of msg can be received depend on the bit_mask set in QL_LOC_Set_Indications;
+   pv_data: depend on the e_msg_id type.
+*/
+typedef void (*QL_LOC_RxIndMsgHandlerFunc_t)
+(
+    loc_client_handle_type  h_loc,
+    E_QL_LOC_NFY_MSG_ID_T   e_msg_id,
+    void                    *pv_data,
+    void                    *contextPtr
+);
+
+typedef enum
+{
+    E_QL_LOC_DELETE_EPHEMERIS       = (1 <<  0),    /**<  Delete ephemeris data.  */
+    E_QL_LOC_DELETE_ALMANAC         = (1 <<  1),    /**<  Delete almanac data.  */
+    E_QL_LOC_DELETE_POSITION        = (1 <<  2),    /**<  Delete position data.  */
+    E_QL_LOC_DELETE_TIME            = (1 <<  3),    /**<  Delete time data.  */
+    E_QL_LOC_DELETE_IONO            = (1 <<  4),    /**<  Delete IONO data.  */
+    E_QL_LOC_DELETE_UTC             = (1 <<  5),    /**<  Delete UTC data.  */
+    E_QL_LOC_DELETE_HEALTH          = (1 <<  6),    /**<  Delete health data.  */
+    E_QL_LOC_DELETE_SVDIR           = (1 <<  7),    /**<  Delete SVDIR data.  */
+    E_QL_LOC_DELETE_SVSTEER         = (1 <<  8),    /**<  Delete SVSTEER data.  */
+    E_QL_LOC_DELETE_SADATA          = (1 <<  9),    /**<  Delete SA data.  */
+    E_QL_LOC_DELETE_RTI             = (1 << 10),    /**<  Delete RTI data.  */
+    E_QL_LOC_DELETE_CELLDB_INFO     = (1 << 11),    /**<  Delete cell DB information.  */
+    E_QL_LOC_DELETE_ALMANAC_CORR    = (1 << 12),    /**<  Delete almanac correction data.  */
+    E_QL_LOC_DELETE_FREQ_BIAS_EST   = (1 << 13),    /**<  Delete frequency bias estimate.  */
+    E_QL_LOC_DELETE_EPHEMERIS_GLO   = (1 << 14),    /**<  Delete ephemeris GLO data.  */
+    E_QL_LOC_DELETE_ALMANAC_GLO     = (1 << 15),    /**<  Delete almanac GLO data.  */
+    E_QL_LOC_DELETE_SVDIR_GLO       = (1 << 16),    /**<  Delete SVDIR GLO data.  */
+    E_QL_LOC_DELETE_SVSTEER_GLO     = (1 << 17),    /**<  Delete SVSTEER GLO data.  */
+    E_QL_LOC_DELETE_ALMANAC_CORR_GLO= (1 << 18),    /**<  Delete almanac correction GLO data.  */
+    E_QL_LOC_DELETE_TIME_GPS        = (1 << 19),    /**<  Delete time GPS data.  */
+    E_QL_LOC_DELETE_TIME_GLO        = (1 << 20),    /**<  Delete time GLO data.  */
+    E_QL_LOC_DELETE_ALL             = 0xFFFFFFFF,   /**<  Delete all location data.  */
+}E_QL_LOC_DELETE_AIDING_DATA_TYPE_T;
+
+typedef struct
+{
+    int64_t time;               /**<   Inject time.*/
+    int64_t time_reference;     /**<   Time reference.*/
+    int32_t uncertainty;        /**<   Uncertainty.*/
+}QL_LOC_INJECT_TIME_INTO_T;  /* Message */
+
+typedef struct
+{
+    double  latitude;   /**<   Latitude.*/
+    double  longitude;  /**<   Longitude.*/
+    float   accuracy;   /**<   Accuracy.*/
+}QL_LOC_INJECT_LOCATION_INTO_T;
+
+typedef enum
+{
+    E_QL_LOC_AGPS_APN_BEARER_INVALID= -1,   /**<  Invalid.  */
+    E_QL_LOC_AGPS_APN_BEARER_IPV4   = 0,    /**<  IPv4.  */
+    E_QL_LOC_AGPS_APN_BEARER_IPV6   = 1,    /**<  IPv6.  */
+    E_QL_LOC_AGPS_APN_BEARER_IPV4V6 = 2,    /**<  IPv4/v6.  */
+}E_QL_LOC_AGPS_APN_BEARER_TYPE_T;
+
+#define QL_LOC_APN_NAME_LENGTH_MAX 100
+typedef struct
+{
+    E_QL_LOC_AGPS_TYPE_T                e_agps_type;                        /**<   AGPS type.*/
+    char                                apn[QL_LOC_APN_NAME_LENGTH_MAX + 1];/**<   APN.*/
+    E_QL_LOC_AGPS_APN_BEARER_TYPE_T     e_bearer_type;                      /**<   Bearer type.*/
+}QL_LOC_AGPS_DATA_CONN_OPEN_INTO_T;
+
+#define QL_LOC_SEVER_ADDR_LENGTH_MAX    255
+typedef struct
+{
+    E_QL_LOC_AGPS_TYPE_T    e_agps_type;                                /**<   AGPS type.*/
+    char                    host_name[QL_LOC_SEVER_ADDR_LENGTH_MAX + 1];/**<   Host name.*/
+    uint32_t                port;                                       /**<   Port.*/
+}QL_LOC_AGPS_SERVER_INTO_T;
+
+typedef struct
+{
+    int32_t                             notify_id;  /**<   Notification ID.*/
+    E_QL_LOC_NI_USER_RESPONSE_TYPE_T    user_resp;  /**<   User response.*/
+}QL_LOC_NI_RESPONSE_INTO_T;
+
+
+
+/* Add callback function if anything changed specified by the mask in QL_LOC_Set_Indications*/
+int QL_LOC_AddRxIndMsgHandler(QL_LOC_RxIndMsgHandlerFunc_t handlerPtr, void* contextPtr);
+
+/* Set what we want callbacks for, for the detail mean of bit_mask, please refer to the macro of LOC_IND_xxxxx_INFO_ON */
+int QL_LOC_Set_Indications(loc_client_handle_type h_loc, int bit_mask);
+
+/* Set GPS position mode, detail info please refer to QL_LOC_POS_MODE_INFO_T */
+int QL_LOC_Set_Position_Mode(loc_client_handle_type h_loc, QL_LOC_POS_MODE_INFO_T *pt_mode);
+
+/* Start navigation, same as AT+QGPS=1, NMEA port start outputing nmea data */
+int QL_LOC_Start_Navigation(loc_client_handle_type h_loc);
+
+/* Stop navigation, same as AT+QGPSEND,  NMEA port stop outputing nmea data */
+int QL_LOC_Stop_Navigation(loc_client_handle_type h_loc);
+
+/* Set up GPS connection and start getting coordinates , this api will call QL_LOC_Start_Navigation inside first,
+   then wait for LOC_IND_LOCATION_INFO_ON event happen, if timeout, it will use last time stored loc_info.
+   If got this event, location infor will save to pt_loc_info and call QL_LOC_Stop_Navigation stop and exit. */
+int QL_LOC_Get_Current_Location(loc_client_handle_type h_loc, QL_LOC_LOCATION_INFO_T *pt_loc_info, int timeout_sec);
+
+/* Init LOC module and return the h_loc, this should be called before any other QL_LOC_xxx api. */
+int QL_LOC_Client_Init(loc_client_handle_type  *ph_loc);
+
+/* DeInit LOC module and release resource, this should be called at last. */
+int QL_LOC_Client_Deinit(loc_client_handle_type h_loc);
+
+/* Deletes location-aiding data. */
+int QL_LOC_Delete_Aiding_Data(  loc_client_handle_type              h_loc,
+                                E_QL_LOC_DELETE_AIDING_DATA_TYPE_T  flags);
+
+/* Injects time. */
+int QL_LOC_InjectTime(  loc_client_handle_type      h_loc,
+                        QL_LOC_INJECT_TIME_INTO_T   *pt_info);
+
+/* Injects Location. */
+int QL_LOC_InjectLocation( loc_client_handle_type           h_loc,
+                           QL_LOC_INJECT_LOCATION_INTO_T    *pt_info);
+
+/** Injects XTRA data.
+    Since the IPC mechanism puts a limit on the size of the data transferable in one message at 64 KB,
+    the application using this command must break the data down into chunks of a smaller size and repeatedly
+    call this API until all the data has been injected. */
+int QL_LOC_Xtra_InjectData(loc_client_handle_type h_loc,
+                            char                   *data,
+                            int                    length); // QL_LOC_XTRA_FILE_DATA_SIZE_MAX
+
+#define QL_LOC_XTRA_FILE_DATA_SIZE_MAX     0xFC00
+/* Injects xtra data via file name. */
+int QL_LOC_Xtra_InjectFile( loc_client_handle_type  h_loc,
+                            char                    *filename);
+
+/** Indicates that the AGPS data connection is open. */
+int QL_LOC_Agps_DataConnOpen( loc_client_handle_type            h_loc,
+                              QL_LOC_AGPS_DATA_CONN_OPEN_INTO_T *pt_info);
+
+/** Indicates that the AGPS data connection is closed. */
+int QL_LOC_Agps_DataConnClose(loc_client_handle_type    h_loc,
+                              E_QL_LOC_AGPS_TYPE_T      atype);
+
+/** Indicates that the AGPS data connection failed to start. */
+int QL_LOC_Agps_NfyDataConnFailed(loc_client_handle_type   h_loc,
+                                  E_QL_LOC_AGPS_TYPE_T     atype);
+
+/** Set AGPS server infor. */
+int QL_LOC_Agps_SetServer(loc_client_handle_type        h_loc,
+                          QL_LOC_AGPS_SERVER_INTO_T     *pt_info);
+
+/** Sends a user response for NI. */
+int QL_LOC_NI_SetResponse(loc_client_handle_type        h_loc,
+                          QL_LOC_NI_RESPONSE_INTO_T     *pt_info);
+
+/** Updates the network availability status. */
+int QL_LOC_Agps_UpdateNWAvailability(loc_client_handle_type  h_loc,
+                                     int                     available,
+                                     const char             *apn);
+
+/*
+Usage 1 (Normally use):
+1, QL_LOC_Client_Init
+2, QL_LOC_AddRxIndMsgHandler(pf_cb)
+3, QL_LOC_Set_Indications
+4, QL_LOC_Start_Navigation
+5, handle the events in pf_cb
+6, QL_LOC_Stop_Navigation
+7, QL_LOC_Client_Deinit
+
+
+Usage 2 (Just get position once):
+1, QL_LOC_Client_Init
+2, QL_LOC_AddRxIndMsgHandler(pf_cb) ---- This can be omitted!
+3, QL_LOC_Set_Indications, set bit_mask=LOC_IND_LOCATION_INFO_ON
+4, QL_LOC_Get_Current_Location, if not timeout, it will return current position infor or use last stored one.
+7, QL_LOC_Client_Deinit
+*/
+
+#endif // __QL_MCM_GPS_H__
+
diff --git a/mbtk/include/ql/ql_mcm_nw.h b/mbtk/include/ql/ql_mcm_nw.h
new file mode 100755
index 0000000..3ec6d62
--- /dev/null
+++ b/mbtk/include/ql/ql_mcm_nw.h
@@ -0,0 +1,467 @@
+/**
+ *@file     ql_mcm_nw.h
+ *@date     2018-02-22
+ *@author
+ *@brief
+ */
+#ifndef __QL_MCM_NW_H__
+#define __QL_MCM_NW_H__
+#include "ql_mcm.h"
+#include "mbtk_type.h"
+
+typedef uint32 nw_client_handle_type;
+
+
+#define QL_MCM_NW_MODE_NONE     0x00    /**<  No network. */
+#define QL_MCM_NW_MODE_GSM      0x01    /**<  Include GSM networks. */
+#define QL_MCM_NW_MODE_WCDMA    0x02    /**<  Include WCDMA networks. */
+#define QL_MCM_NW_MODE_CDMA     0x04    /**<  Include CDMA networks. */
+#define QL_MCM_NW_MODE_EVDO     0x08    /**<  Include EVDO networks. */
+#define QL_MCM_NW_MODE_LTE      0x10    /**<  Include LTE networks. */
+#define QL_MCM_NW_MODE_TDSCDMA  0x20    /**<  Include TDSCDMA networks. */
+#define QL_MCM_NW_MODE_PRL      0x10000 /**<  Give preference according to the preferred roaming list. */
+
+typedef enum
+{
+    E_QL_MCM_NW_ROAM_STATE_OFF  = 0,    /**<  None, or roaming indicator off. */
+    E_QL_MCM_NW_ROAM_STATE_ON   = 1     /**<  Roaming indicator on. */
+}E_QL_MCM_NW_ROAM_STATE_TYPE_T;
+
+/** Configures the settings that define the MCM network interface. */
+typedef struct
+{
+    /*  Configuration parameters for MCM network registration Network registration details Technology dependent network registration details */
+    uint64_t                        preferred_nw_mode;  /**<   Preferred network mode for connections; a bitmask of QL_MCM_NW_MODE_xxxx.*/
+    E_QL_MCM_NW_ROAM_STATE_TYPE_T   roaming_pref;       /**<   Roaming preference.*/
+}QL_MCM_NW_CONFIG_INFO_T;
+
+#define QL_MCM_NW_NITZ_BUF_LEN 30
+/** Get NITZ Time information. */
+typedef struct
+{
+    //i.e.:  nitz_time="18/09/19,07:40:18+32,00"    format: YY/MM/DD,HH:MM:SS'+/-'TZ,daylight, Here TZ multiplied by 4.
+    char        nitz_time[QL_MCM_NW_NITZ_BUF_LEN + 1];
+    uint64_t    abs_time;   // 0 means invalid
+    int8_t      leap_sec;   // 0 means invalid
+}QL_MCM_NW_NITZ_TIME_INFO_T;
+
+
+//defined for QL_MCM_NW_EventRegister
+#define     NW_IND_VOICE_REG_EVENT_IND_FLAG               (1 << 0)    /**< msg format : QL_MCM_NW_VOICE_REG_EVENT_IND_T */
+#define     NW_IND_DATA_REG_EVENT_IND_FLAG                (1 << 1)    /**< msg format : QL_MCM_NW_DATA_REG_EVENT_IND_T */
+#define     NW_IND_SIGNAL_STRENGTH_EVENT_IND_FLAG         (1 << 2)    /**< msg format : QL_MCM_NW_SINGNAL_EVENT_IND_T */
+#define     NW_IND_CELL_ACCESS_STATE_CHG_EVENT_IND_FLAG   (1 << 3)    /**< msg format : QL_MCM_NW_CELL_ACCESS_STATE_EVENT_IND_T */
+#define     NW_IND_NITZ_TIME_UPDATE_EVENT_IND_FLAG        (1 << 4)    /**< msg format : QL_MCM_NW_NITZ_TIME_EVENT_IND_T */
+
+
+
+typedef struct
+{
+    char long_eons[512 + 1];    /**<   Long EONS.*/
+    char short_eons[512 + 1];   /**<   Short EONS.*/
+    char mcc[3 + 1];            /**<   Mobile country code.*/
+    char mnc[3 + 1];            /**<   Mobile network code.*/
+}QL_MCM_NW_OPERATOR_NAME_INFO_T;
+
+typedef enum
+{
+    E_QL_MCM_NW_NETWORK_STATUS_NONE             = 0,    /**<  Network status not available. */
+    E_QL_MCM_NW_NETWORK_STATUS_CURRENT_SERVING  = 1,    /**<  Current serving network. */
+    E_QL_MCM_NW_NETWORK_STATUS_PREFERRED        = 2,    /**<  Preferred network. */
+    E_QL_MCM_NW_NETWORK_STATUS_NOT_PREFERRED    = 3,    /**<  Not the preferred network. */
+    E_QL_MCM_NW_NETWORK_STATUS_AVAILABLE        = 4,    /**<  Service available. */
+    E_QL_MCM_NW_NETWORK_STATUS_FORBIDDEN        = 5     /**<  Forbidden service. */
+}E_QL_MCM_NW_NETWORK_STATUS_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_NW_RADIO_TECH_TD_SCDMA = 1,
+    E_QL_MCM_NW_RADIO_TECH_GSM      = 2,    /**<  GSM; only supports voice. */
+    E_QL_MCM_NW_RADIO_TECH_HSPAP    = 3,    /**<  HSPA+. */
+    E_QL_MCM_NW_RADIO_TECH_LTE      = 4,    /**<  LTE. */
+    E_QL_MCM_NW_RADIO_TECH_EHRPD    = 5,    /**<  EHRPD. */
+    E_QL_MCM_NW_RADIO_TECH_EVDO_B   = 6,    /**<  EVDO B. */
+    E_QL_MCM_NW_RADIO_TECH_HSPA     = 7,    /**<  HSPA. */
+    E_QL_MCM_NW_RADIO_TECH_HSUPA    = 8,    /**<  HSUPA. */
+    E_QL_MCM_NW_RADIO_TECH_HSDPA    = 9,    /**<  HSDPA. */
+    E_QL_MCM_NW_RADIO_TECH_EVDO_A   = 10,   /**<  EVDO A. */
+    E_QL_MCM_NW_RADIO_TECH_EVDO_0   = 11,   /**<  EVDO 0. */
+    E_QL_MCM_NW_RADIO_TECH_1xRTT    = 12,   /**<  1xRTT. */
+    E_QL_MCM_NW_RADIO_TECH_IS95B    = 13,   /**<  IS95B. */
+    E_QL_MCM_NW_RADIO_TECH_IS95A    = 14,   /**<  IS95A. */
+    E_QL_MCM_NW_RADIO_TECH_UMTS     = 15,   /**<  UMTS. */
+    E_QL_MCM_NW_RADIO_TECH_EDGE     = 16,   /**<  EDGE. */
+    E_QL_MCM_NW_RADIO_TECH_GPRS     = 17,   /**<  GPRS. */
+    E_QL_MCM_NW_RADIO_TECH_NONE     = 18    /**<  No technology selected. */
+}E_QL_MCM_NW_RADIO_TECH_TYPE_T;
+
+typedef struct
+{
+    QL_MCM_NW_OPERATOR_NAME_INFO_T      operator_name;    /**<   Operator name.*/
+    E_QL_MCM_NW_NETWORK_STATUS_TYPE_T   network_status;    /**<   Network status.*/
+    E_QL_MCM_NW_RADIO_TECH_TYPE_T       rat;    /**<   Radio technology.*/
+}QL_MCM_NW_SCAN_ENTRY_INFO_T;  /* Type */
+
+#define QL_MCM_NW_SCAN_LIST_MAX 40
+/** Gets the status associated with the connection of \<id\>. */
+typedef struct
+{
+    uint32_t                    entry_len;  /**< Must be set to the number of elements in entry. */
+    QL_MCM_NW_SCAN_ENTRY_INFO_T entry[QL_MCM_NW_SCAN_LIST_MAX];    /**<   Scan entry.*/
+}QL_MCM_NW_SCAN_RESULT_LIST_INFO_T;  /* Message */
+
+
+typedef enum
+{
+    E_QL_MCM_NW_TECH_DOMAIN_NONE    = 0,    /**<  None. */
+    E_QL_MCM_NW_TECH_DOMAIN_3GPP    = 1,    /**<  3GPP. */
+    E_QL_MCM_NW_TECH_DOMAIN_3GPP2   = 2,    /**<  3GPP2. */
+}E_QL_MCM_NW_TECH_DOMAIN_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_NW_IMSI_UNKNOWN_HLR_DENY_REASON                    = 1, /**<  IMSI unknown in HLR. */
+    E_QL_MCM_NW_ILLEGAL_MS_DENY_REASON                          = 2, /**<  Illegal MS. */
+    E_QL_MCM_NW_IMSI_UNKNOWN_VLR_DENY_REASON                    = 3, /**<  IMSI unknown in VLR. */
+    E_QL_MCM_NW_IMEI_NOT_ACCEPTED_DENY_REASON                   = 4, /**<  IMEI not accepted. */
+    E_QL_MCM_NW_ILLEGAL_ME_DENY_REASON                          = 5, /**<  Illegal ME. */
+    E_QL_MCM_NW_PLMN_NOT_ALLOWED_DENY_REASON                    = 6, /**<  PLMN not allowed. */
+    E_QL_MCM_NW_LA_NOT_ALLOWED_DENY_REASON                      = 7, /**<  Location area not allowed. */
+    E_QL_MCM_NW_ROAMING_NOT_ALLOWED_LA_DENY_REASON              = 8, /**<  Roaming not allowed in this location area. */
+    E_QL_MCM_NW_NO_SUITABLE_CELLS_LA_DENY_REASON                = 9, /**<  No suitable cells in location area. */
+    E_QL_MCM_NW_NETWORK_FAILURE_DENY_REASON                     = 10, /**<  Network failure. */
+    E_QL_MCM_NW_MAC_FAILURE_DENY_REASON                         = 11, /**<  MAC failure. */
+    E_QL_MCM_NW_SYNCH_FAILURE_DENY_REASON                       = 12, /**<  Sync failure. */
+    E_QL_MCM_NW_CONGESTION_DENY_REASON                          = 13, /**<  Congestion. */
+    E_QL_MCM_NW_GSM_AUTHENTICATION_UNACCEPTABLE_DENY_REASON     = 14, /**<  GSM authentication unacceptable. */
+    E_QL_MCM_NW_NOT_AUTHORIZED_CSG_DENY_REASON                  = 15, /**<  Not authorized in this CSG. */
+    E_QL_MCM_NW_SERVICE_OPTION_NOT_SUPPORTED_DENY_REASON        = 16, /**<  Service option not supported. */
+    E_QL_MCM_NW_REQ_SERVICE_OPTION_NOT_SUBSCRIBED_DENY_REASON   = 17, /**<  Requested service option not subscribed. */
+    E_QL_MCM_NW_CALL_CANNOT_BE_IDENTIFIED_DENY_REASON           = 18, /**<  Call cannot be identified. */
+    E_QL_MCM_NW_SEMANTICALLY_INCORRECT_MSG_DENY_REASON          = 19, /**<  Semantically incorrect message. */
+    E_QL_MCM_NW_INVALID_MANDATORY_INFO_DENY_REASON              = 20, /**<  Invalid mandatory information. */
+    E_QL_MCM_NW_MSG_TYPE_NON_EXISTENT_DENY_REASON               = 21, /**<  Message type non-existent or not implemented. */
+    E_QL_MCM_NW_INFO_ELEMENT_NON_EXISTENT_DENY_REASON           = 22, /**<  Message type not compatible with the protocol state. */
+    E_QL_MCM_NW_CONDITIONAL_IE_ERR_DENY_REASON                  = 23, /**<  Conditional IE error. */
+    E_QL_MCM_NW_MSG_INCOMPATIBLE_PROTOCOL_STATE_DENY_REASON     = 24, /**<  Message not compatible with the protocol state. */
+    E_QL_MCM_NW_PROTOCOL_ERROR_DENY_REASON                      = 25, /**<  Unspecified protocol error. */
+}E_QL_MCM_NW_DENY_REASON_TYPE_T;
+
+
+typedef enum
+{
+    E_QL_MCM_NW_SERVICE_NONE     = 0x0000,  /**<  Not registered or no data. */
+    E_QL_MCM_NW_SERVICE_LIMITED  = 0x0001,  /**<  Registered; emergency service only. */
+    E_QL_MCM_NW_SERVICE_FULL     = 0x0002,  /**<  Registered, full service. */
+}E_QL_MCM_NW_SERVICE_TYPE_T;
+
+typedef struct
+{
+    E_QL_MCM_NW_TECH_DOMAIN_TYPE_T  tech_domain;        /**<   Technology, used to determine the structure type  mcm_tech: 0 -- None, 1 -- 3GPP, 2 -- 3GPP2.*/
+    E_QL_MCM_NW_RADIO_TECH_TYPE_T   radio_tech;         /**<   Radio technology; see #mcm_nw_radio_tech_t_v01.*/
+    E_QL_MCM_NW_ROAM_STATE_TYPE_T   roaming;            /**<   0 -- Off, 1 -- Roaming (3GPP2 has extended values).*/
+    E_QL_MCM_NW_DENY_REASON_TYPE_T  deny_reason;        /**<   Set when registration state is #mcm_nw_deny_reason_t_v01.*/
+    E_QL_MCM_NW_SERVICE_TYPE_T      registration_state; /**<   Registration state.*/
+}QL_MCM_NW_COMMON_REG_INFO_T;
+
+
+typedef struct
+{
+    E_QL_MCM_NW_TECH_DOMAIN_TYPE_T  tech_domain;        /**<   Technology, used to determine the structure type  mcm_tech: 0 -- None, 1 -- 3GPP, 2 -- 3GPP2.*/
+    E_QL_MCM_NW_RADIO_TECH_TYPE_T   radio_tech;         /**<   Radio technology; see #mcm_nw_radio_tech_t_v01.*/
+    char                            mcc[3+1];           /**<   Mobile country code.*/
+    char                            mnc[3+1];           /**<   Mobile network code.*/
+    E_QL_MCM_NW_ROAM_STATE_TYPE_T   roaming;            /**<   0 -- Off, 1 -- Roaming (3GPP2 has extended values).*/
+    uint8_t                         forbidden;          /**<   Forbidden: 0 -- No, 1 -- Yes.*/
+    uint32_t                        cid;                /**<   Cell ID for the registered 3GPP system.*/
+    uint16_t                        lac;                /**<   Locatin area code for the registered 3GPP system.*/
+    uint16_t                        psc;                /**<   Primary scrambling code (WCDMA only); 0 -- None.*/
+    uint16_t                        tac;                /**<   Tracking area code information for LTE.*/
+}QL_MCM_NW_3GPP_REG_INFO_T;
+
+
+typedef struct
+{
+    E_QL_MCM_NW_TECH_DOMAIN_TYPE_T  tech_domain;        /**<   Technology, used to determine structure type  mcm_tech: 0 -- None, 1 -- 3GPP, 2 -- 3GPP2.*/
+    E_QL_MCM_NW_RADIO_TECH_TYPE_T   radio_tech;         /**<   Radio technology; see #mcm_nw_radio_tech_t_v01.*/
+    char                            mcc[3+1];           /**<   Mobile country code.*/
+    char                            mnc[3+1];           /**<   Mobile network code.*/
+    E_QL_MCM_NW_ROAM_STATE_TYPE_T   roaming;            /**<   Roaming status; see #mcm_nw_roam_state_t_v01.*/
+    uint8_t                         forbidden;          /**<   Forbidden: 0 -- No, 1 -- Yes.*/
+    uint8_t                         inPRL;              /**<   0 -- Not in PRL, 1 -- In PRL.*/
+    uint8_t                         css;                /**<   Concurrent services supported: 0 -- No, 1 -- Yes.*/
+    uint16_t                        sid;                /**<   CDMA system ID.*/
+    uint16_t                        nid;                /**<   CDMA network ID.*/
+    uint16_t                        bsid;               /**<   Base station ID. @newpagetable */
+}QL_MCM_NW_3GPP2_REG_INFO_T;
+
+/** Gets the status associated with the connection of \<id\>. */
+typedef struct
+{
+    uint8_t                         voice_registration_valid;               /**< Must be set to TRUE if voice_registration is being passed. */
+    QL_MCM_NW_COMMON_REG_INFO_T     voice_registration;                     /**<   Voice registration. */
+
+    uint8_t                         data_registration_valid;                /**< Must be set to TRUE if data_registration is being passed. */
+    QL_MCM_NW_COMMON_REG_INFO_T     data_registration;                      /**<   Data registration. */
+
+    uint8_t                         voice_registration_details_3gpp_valid;  /**< Must be set to TRUE if voice_registration_details_3gpp is being passed. */
+    QL_MCM_NW_3GPP_REG_INFO_T       voice_registration_details_3gpp;        /**<   Voice registration details for 3GPP. */
+
+    uint8_t                         data_registration_details_3gpp_valid;   /**< Must be set to TRUE if data_registration_details_3gpp is being passed. */
+    QL_MCM_NW_3GPP_REG_INFO_T       data_registration_details_3gpp;         /**<   Data registration details for 3GPP. */
+
+    uint8_t                         voice_registration_details_3gpp2_valid; /**< Must be set to TRUE if voice_registration_details_3gpp2 is being passed. */
+    QL_MCM_NW_3GPP2_REG_INFO_T      voice_registration_details_3gpp2;       /**<   Voice registration details for 3GPP2. */
+
+    uint8_t                         data_registration_details_3gpp2_valid;  /**< Must be set to TRUE if data_registration_details_3gpp2 is being passed. */
+    QL_MCM_NW_3GPP2_REG_INFO_T      data_registration_details_3gpp2;        /**<   Data registration details for 3GPP2. */
+}QL_MCM_NW_REG_STATUS_INFO_T;
+
+
+typedef enum
+{
+    E_QL_MCM_NW_SELECTION_AUTOMATIC  = 0,                                   /**<  Automatic network selection. */
+    E_QL_MCM_NW_SELECTION_MANUAL     = 1,                                   /**<  Manual network selection. */
+}E_QL_MCM_NW_SELECTION_TYPE_T;
+
+typedef struct
+{
+    E_QL_MCM_NW_SELECTION_TYPE_T    nw_selection_type;                      /**< Network selection type. */
+    char                            mcc[3 + 1];                             /**<   Mobile country code for a manual network selection.*/
+    char                            mnc[3 + 1];                             /**<   Mobile network code for a manual network selection.*/
+    E_QL_MCM_NW_RADIO_TECH_TYPE_T   rat;                                    /**<   Radio technology.*/
+}QL_MCM_NW_SELECTION_INFO_T;
+
+
+typedef struct
+{
+    int8_t      rssi;       /**<   RSSI in dBm. Indicates received signal strength. A signed value; -125 or lower indicates no signal.*/
+}QL_MCM_NW_GSM_SIGNAL_INFO_T;
+
+
+typedef struct
+{
+    int8_t      rssi;       /**<   RSSI in dBm. Indicates forward link pilot Ec. A signed value; -125 or lower indicates no signal.*/
+    int16_t     ecio;       /**<   Ec/Io value representing negative 0.5 dB increments, e.g., 2 equals -1 dbm.*/
+}QL_MCM_NW_WCDMA_SIGNAL_INFO_T;
+
+typedef struct
+{
+    int8_t      rssi;       /**<   RSSI in dBm. Indicates forward link pilot Ec.    a signed value; -125 or lower indicates no signal.*/
+    int8_t      rscp;       /**<   RSCP in dBm.*/
+    int16_t     ecio;       /**<   Ec/Io value representing negative 0.5 dB increments, e.g., 2 equals -1 dbm.*/
+    int8_t      sinr;       /**<   Measured SINR in dB. @newpagetable */
+}QL_MCM_NW_TDSCDMA_SIGNAL_INFO_T;
+
+typedef struct
+{
+    int8_t      rssi;       /**<   RSSI in dBm. Indicates forward link pilot Ec. A signed value; -125 or lower indicates no signal.*/
+    int8_t      rsrq;       /**<   RSRQ value in dB (signed integer value), as measured by L1. Range: -3 to -20 (-3 equals -3 dB, -20 equals -20 dB).*/
+    int16_t      rsrp;       /**<   Current RSRP in dBm, as measured by L1. Range: -44 to -140 (-44 equals -44 dBm, -140 equals -140 dBm).*/
+    int16_t      snr;        /**<   SNR level as a scaled integer in units of 0.1 dB; e.g., -16 dB has a value of -160 and 24.6 dB has a value of 246.*/
+}QL_MCM_NW_LTE_SIGNAL_INFO_T;
+
+
+typedef struct
+{
+    int8_t      rssi;       /**<   RSSI in dBm. Indicates forward link pilot Power (AGC) + Ec/Io. A signed value; -125 or lower indicates no signal.*/
+    int16_t     ecio;       /**<   Ec/Io value representing negative 0.5 dB increments, e.g., 2 equals -1 dbm.*/
+}QL_MCM_NW_CDMA_SIGNAL_INFO_T;
+
+typedef struct
+{
+    int8_t      rssi;       /**<   RSSI in dBm. Indicates forward link pilot Power (AGC) + Ec/Io. A signed value; -125 or lower indicates no signal.*/
+    int16_t     ecio;       /**<   Ec/Io value representing negative 0.5 dB increments, e.g., 2 equals -1 dbm.*/
+    int8_t      sinr;       /**<   SINR level.*/
+    int32_t     io;         /**<   Received IO in dBm. */
+}QL_MCM_NW_HDR_SIGNAL_INFO_T;
+
+/** Gets signal strength information. */
+typedef struct
+{
+    uint8_t                         gsm_sig_info_valid;         /**< Must be set to TRUE if gsm_sig_info is being passed. */
+    QL_MCM_NW_GSM_SIGNAL_INFO_T     gsm_sig_info;               /**<   GSM signal information. */
+    uint8_t                         wcdma_sig_info_valid;       /**< Must be set to TRUE if wcdma_sig_info is being passed. */
+    QL_MCM_NW_WCDMA_SIGNAL_INFO_T   wcdma_sig_info;             /**<   WCDMA signal information. */
+    uint8_t                         tdscdma_sig_info_valid;     /**< Must be set to TRUE if tdscdma_sig_info is being passed. */
+    QL_MCM_NW_TDSCDMA_SIGNAL_INFO_T tdscdma_sig_info;           /**<   TDSCDMA signal information. */
+    uint8_t                         lte_sig_info_valid;         /**< Must be set to TRUE if lte_sig_info is being passed. */
+    QL_MCM_NW_LTE_SIGNAL_INFO_T     lte_sig_info;               /**<   LTE signal information. */
+    uint8_t                         cdma_sig_info_valid;        /**< Must be set to TRUE if cdma_sig_info is being passed. */
+    QL_MCM_NW_CDMA_SIGNAL_INFO_T    cdma_sig_info;              /**<   CDMA signal information. */
+    uint8_t                         hdr_sig_info_valid;         /**< Must be set to TRUE if hdr_sig_info is being passed. */
+    QL_MCM_NW_HDR_SIGNAL_INFO_T     hdr_sig_info;               /**<   HDR signal information. */
+}QL_MCM_NW_SIGNAL_STRENGTH_INFO_T;
+
+
+
+typedef enum
+{
+    E_QL_MCM_NW_CELL_ACCESS_NONE            = 0x00,             /**<  Unknown cell access state. */
+    E_QL_MCM_NW_CELL_ACCESS_NORMAL_ONLY     = 0x01,             /**<  Cell access is allowed for normal calls only. */
+    E_QL_MCM_NW_CELL_ACCESS_EMERGENCY_ONLY  = 0x02,             /**<  Cell access is allowed for emergency calls only. */
+    E_QL_MCM_NW_CELL_ACCESS_NO_CALLS        = 0x03,             /**<  Cell access is not allowed for any call type. */
+    E_QL_MCM_NW_CELL_ACCESS_ALL_CALLS       = 0x04,             /**<  Cell access is allowed for all call types. */
+}E_QL_MCM_NW_CELL_ACCESS_STATE_TYPE_T;
+
+
+/* @bridef Callback function registered to QL_MCM_NW_AddRxMsgHandler
+ * map of ind_flag and ind_msg_buf as bellow :
+ *  NW_IND_VOICE_REG_EVENT_IND_FLAG : QL_MCM_NW_VOICE_REG_EVENT_IND_T
+ *  NW_IND_DATA_REG_EVENT_IND_FLAG : QL_MCM_NW_DATA_REG_EVENT_IND_T
+ *  NW_IND_SIGNAL_STRENGTH_EVENT_IND_FLAG : QL_MCM_NW_SINGNAL_EVENT_IND_T
+ *  NW_IND_CELL_ACCESS_STATE_CHG_EVENT_IND_FLAG : QL_MCM_NW_CELL_ACCESS_STATE_EVENT_IND_T
+ *  NW_IND_NITZ_TIME_UPDATE_EVENT_IND_FLAG : QL_MCM_NW_NITZ_TIME_EVENT_IND_T
+ * */
+typedef void (*QL_MCM_NW_RxMsgHandlerFunc_t)(
+    nw_client_handle_type h_nw,
+    uint32_t ind_flag,
+    void                  *ind_msg_buf,
+    uint32_t              ind_msg_len,
+    void                  *contextPtr
+);
+
+
+/** Indication message; Indication for the corresponding registered event flag NW_IND_VOICE_REG_EVENT_IND_FLAG */
+typedef struct {
+
+  uint8_t                         registration_valid;               /**< Must be set to TRUE if voice_registration is being passed. */
+  QL_MCM_NW_COMMON_REG_INFO_T     registration;                     /**< Voice registration. */
+
+  uint8_t                         registration_details_3gpp_valid;  /**< Must be set to TRUE if voice_registration_details_3gpp is being passed. */
+  QL_MCM_NW_3GPP_REG_INFO_T       registration_details_3gpp;        /**< Voice registration details for 3GPP. */
+
+  uint8_t                         registration_details_3gpp2_valid; /**< Must be set to TRUE if voice_registration_details_3gpp2 is being passed. */
+  QL_MCM_NW_3GPP2_REG_INFO_T      registration_details_3gpp2;       /**< Voice registration details for 3GPP2. */
+}QL_MCM_NW_VOICE_REG_EVENT_IND_T;
+
+/** Indication message; Indication for the corresponding registered event flag NW_IND_DATA_REG_EVENT_IND_FLAG */
+typedef struct {
+
+  uint8_t                         registration_valid;               /**< Must be set to TRUE if data_registration is being passed. */
+  QL_MCM_NW_COMMON_REG_INFO_T     registration;                     /**< Data registration. */
+
+  uint8_t                         registration_details_3gpp_valid;  /**< Must be set to TRUE if data_registration_details_3gpp is being passed. */
+  QL_MCM_NW_3GPP_REG_INFO_T       registration_details_3gpp;        /**< Data registration details for 3GPP. */
+
+  uint8_t                         registration_details_3gpp2_valid; /**< Must be set to TRUE if data_registration_details_3gpp2 is being passed. */
+  QL_MCM_NW_3GPP2_REG_INFO_T      registration_details_3gpp2;       /**< Data registration details for 3GPP2. */
+}QL_MCM_NW_DATA_REG_EVENT_IND_T;
+
+
+/** Indication message; Indication for the corresponding registered event flag NW_IND_SIGNAL_STRENGTH_EVENT_IND_FLAG */
+typedef struct {
+    uint8_t gsm_sig_info_valid;                       /**< Must be set to TRUE if gsm_sig_info is being passed. */
+    QL_MCM_NW_GSM_SIGNAL_INFO_T       gsm_sig_info;   /**< GSM singal information. */
+
+    uint8_t wcdma_sig_info_valid;                     /**< Must be set to TRUE if wcdma_sig_info is being passed. */
+    QL_MCM_NW_WCDMA_SIGNAL_INFO_T wcdma_sig_info;     /**< WCDMA singal information. */
+
+    uint8_t tdscdma_sig_info_valid;                   /**< Must be set to TRUE if tdscdma_sig_info is being passed. */
+    QL_MCM_NW_TDSCDMA_SIGNAL_INFO_T tdscdma_sig_info; /**< TDSCDMA singal information. */
+
+    uint8_t lte_sig_info_valid;                       /**< Must be set to TRUE if lte_sig_info is being passed. */
+    QL_MCM_NW_LTE_SIGNAL_INFO_T lte_sig_info;         /**< LTE singal information. */
+
+    uint8_t cdma_sig_info_valid;                      /**< Must be set to TRUE if cdma_sig_info is being passed. */
+    QL_MCM_NW_CDMA_SIGNAL_INFO_T cdma_sig_info;       /**< CDMA singal information. */
+
+    uint8_t hdr_sig_info_valid;                       /**< Must be set to TRUE if hdr_sig_info is being passed. */
+    QL_MCM_NW_HDR_SIGNAL_INFO_T hdr_sig_info;         /**< HDR singal information. */
+}QL_MCM_NW_SINGNAL_EVENT_IND_T;
+
+
+/** Indication message; Indication for a change in the cell access state, e.g., emergency only, CS call only.
+ * Indication for the corresponding registered event flag NW_IND_CELL_ACCESS_STATE_CHG_EVENT_IND_FLAG */
+typedef struct {
+    E_QL_MCM_NW_CELL_ACCESS_STATE_TYPE_T state; /**< Network cell access state. */
+}QL_MCM_NW_CELL_ACCESS_STATE_EVENT_IND_T;
+
+/** Indication Message; Indication to update NITZ time.
+ * Indication for the corresponding registered event flag NW_IND_NITZ_TIME_UPDATE_EVENT_IND_FLAG */
+typedef struct {
+    QL_MCM_NW_NITZ_TIME_INFO_T info;
+}QL_MCM_NW_NITZ_TIME_EVENT_IND_T;
+
+
+
+
+E_QL_ERROR_CODE_T QL_MCM_NW_Client_Init(nw_client_handle_type  *ph_nw);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_Client_Deinit(nw_client_handle_type  h_nw);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_SetConfig
+(
+    nw_client_handle_type       h_nw,
+    QL_MCM_NW_CONFIG_INFO_T     *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_GetConfig
+(
+    nw_client_handle_type       h_nw,
+    QL_MCM_NW_CONFIG_INFO_T     *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_GetNitzTimeInfo
+(
+    nw_client_handle_type       h_nw,
+    QL_MCM_NW_NITZ_TIME_INFO_T *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_EventRegister
+(
+    nw_client_handle_type       h_nw,
+    uint32_t                    bitmask // bit OR of NW_IND_xxxx_EVENT_ON
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_GetOperatorName
+(
+    nw_client_handle_type           h_nw,
+    QL_MCM_NW_OPERATOR_NAME_INFO_T  *pt_info //You should malloc this or may cause stack overflow
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_PerformScan
+(
+    nw_client_handle_type               h_nw,
+    QL_MCM_NW_SCAN_RESULT_LIST_INFO_T   *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_GetRegStatus
+(
+    nw_client_handle_type               h_nw,
+    QL_MCM_NW_REG_STATUS_INFO_T         *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_SetLowPowerMode
+(
+    nw_client_handle_type       h_nw,
+    uint32_t                    low_power_mode_on // 0: off, other: on
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_SetSelection
+(
+    nw_client_handle_type       h_nw,
+    QL_MCM_NW_SELECTION_INFO_T  *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_GetSignalStrength
+(
+    nw_client_handle_type               h_nw,
+    QL_MCM_NW_SIGNAL_STRENGTH_INFO_T    *pt_info
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_GetCellAccessState
+(
+    nw_client_handle_type                   h_nw,
+    E_QL_MCM_NW_CELL_ACCESS_STATE_TYPE_T    *pe_state
+);
+
+E_QL_ERROR_CODE_T QL_MCM_NW_AddRxMsgHandler
+(
+    nw_client_handle_type        h_nw,
+    QL_MCM_NW_RxMsgHandlerFunc_t handlerPtr,
+    void* contextPtr
+);
+
+
+#endif//__QL_MCM_NW_H__
diff --git a/mbtk/include/ql/ql_mcm_sim.h b/mbtk/include/ql/ql_mcm_sim.h
new file mode 100755
index 0000000..4fc7b1c
--- /dev/null
+++ b/mbtk/include/ql/ql_mcm_sim.h
@@ -0,0 +1,713 @@
+/**
+ *@file     ql_mcm_sim.h
+ *@date     2017-05-02
+ *@author
+ *@brief
+ */
+#ifndef __QL_MCM_SIM_H__
+#define __QL_MCM_SIM_H__
+#include "mbtk_type.h"
+
+#include "ql_mcm.h"
+
+#define QL_SIM_IMSI_LEN_MAX     16  /**  Maximum length of IMSI data. */
+#define QL_SIM_ICCID_LEN_MAX    20  /**  Maximum length of ICCID data. */
+
+typedef uint32 sim_client_handle_type;
+
+typedef enum
+{
+    E_QL_MCM_SIM_SLOT_ID_1          = 0xB01,    /**< Identify card in slot 1.  */
+    E_QL_MCM_SIM_SLOT_ID_2          = 0xB02,    /**< Identify card in slot 2.  */
+}E_QL_MCM_SIM_SLOT_ID_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_APP_TYPE_UNKNOWN   = 0xB00,    /**<  Unknown application type  */
+    E_QL_MCM_SIM_APP_TYPE_3GPP      = 0xB01,    /**< Identify the SIM/USIM application on the card.  */
+    E_QL_MCM_SIM_APP_TYPE_3GPP2     = 0xB02,    /**< Identify the RUIM/CSIM application on the card.  */
+    E_QL_MCM_SIM_APP_TYPE_ISIM      = 0xB03,    /**< Identify the ISIM application on the card.  */
+}E_QL_MCM_SIM_APP_TYPE_T;
+
+typedef struct
+{
+    E_QL_MCM_SIM_SLOT_ID_TYPE_T     e_slot_id;  /**< Indicates the slot to be used. */
+    E_QL_MCM_SIM_APP_TYPE_T         e_app;      /**< Indicates the type of the application. */
+}QL_SIM_APP_ID_INFO_T;  /* Type */
+
+
+#define QL_SIM_MCC_LEN      3   /**  Length of the MCC. */
+#define QL_SIM_MNC_MAX      3   /**  Maximum length of the MNC. */
+#define QL_SIM_PLMN_NUM_MAX 24  /**  Maximum number of PLMN data sets. */
+typedef struct
+{
+    char mcc[QL_SIM_MCC_LEN];  /**< MCC value in ASCII characters.*/
+    uint32_t mnc_len;               /**< Must be set to the number of elements in the MNC. */
+    char mnc[QL_SIM_MNC_MAX];  /**< MNC value in ASCII characters.*/
+}QL_SIM_PLMN_INFO_T;
+
+typedef struct
+{
+    uint32_t            preferred_operator_list_len;                    /**< Must be set to the number of elements in preferred_operator_list. */
+    QL_SIM_PLMN_INFO_T  preferred_operator_list[QL_SIM_PLMN_NUM_MAX];   /**< Preferred operator list. */
+}QL_SIM_PREFERRED_OPERATOR_LIST_T;  /* Message */
+
+
+#define QL_MCM_SIM_PIN_LEN_MAX  8   /**  Maximum length of PIN data. */
+typedef enum
+{
+    E_QL_MCM_SIM_PIN_ID_1 = 0xB01,  /**< Level 1 user verification.  */
+    E_QL_MCM_SIM_PIN_ID_2 = 0xB02,  /**< Level 2 user verification.  */
+}E_QL_MCM_SIM_PIN_ID_TYPE_T;
+
+typedef struct
+{
+    QL_SIM_APP_ID_INFO_T        app_info;                           /**< Application identification information. */
+    E_QL_MCM_SIM_PIN_ID_TYPE_T  pin_id;                             /**< PIN ID. */
+    uint32_t                    pin_value_len;                      /**< Must be set to the number of elements in pin_value. */
+    char                        pin_value[QL_MCM_SIM_PIN_LEN_MAX];  /*  Value of the PIN */
+}QL_SIM_VERIFY_PIN_INFO_T;
+
+/** Changes the PIN value of an application. The application must pass both the
+    new and the old values of the PIN to complete the operation.
+    The same PIN can be used by multiple sessions (i.e., the PIN is shared
+    between GSM and RUIM in an ICC card). The PIN is automatically verified
+    for all the sessions when the command is executed. */
+typedef struct
+{
+    QL_SIM_APP_ID_INFO_T        app_info;                               /**< Application identification information. */
+    E_QL_MCM_SIM_PIN_ID_TYPE_T  pin_id;                                 /**< PIN ID. */
+    uint32_t                    old_pin_value_len;                      /**< Must be set to the number of elements in old_pin_value. */
+    char                        old_pin_value[QL_MCM_SIM_PIN_LEN_MAX];  /**< Value of the old PIN as a sequence of ASCII characters. */
+    uint32_t                    new_pin_value_len;                      /**< Must be set to the number of elements in new_pin_value. */
+    char                        new_pin_value[QL_MCM_SIM_PIN_LEN_MAX];  /**< Value of the new PIN as a sequence of ASCII characters. */
+}QL_SIM_CHANGE_PIN_INFO_T;
+
+/** Unblocks a blocked PIN using the PUK code. The client must pass PUK1 to unblock PIN1 or PUK2 to unblock PIN2.
+    The same PIN can be used by multiple sessions (i.e., the PIN is shared between GSM and RUIM in an ICC card).
+    The PIN is automatically verified for all the sessions when the command is executed. */
+typedef struct
+{
+    QL_SIM_APP_ID_INFO_T        app_info;                               /**< Application identification information. */
+    E_QL_MCM_SIM_PIN_ID_TYPE_T  pin_id;                                 /**< PIN ID. */
+    uint32_t                    puk_value_len;                          /**< Must be set to the number of elements in puk_value. */
+    char                        puk_value[QL_MCM_SIM_PIN_LEN_MAX];      /**< Value of the PUK as a sequence of ASCII characters. */
+    uint32_t                    new_pin_value_len;                      /**< Must be set to the number of elements in new_pin_value. */
+    char                        new_pin_value[QL_MCM_SIM_PIN_LEN_MAX];  /**< Value of the new PIN as a sequence of ASCII characters. */
+}QL_SIM_UNBLOCK_PIN_INFO_T;
+
+/** Enables the PIN on an application. */
+typedef  QL_SIM_VERIFY_PIN_INFO_T QL_SIM_ENABLE_PIN_INFO_T; //Same
+
+/** Disables the PIN of an application, */
+typedef  QL_SIM_VERIFY_PIN_INFO_T QL_SIM_DISABLE_PIN_INFO_T; //Same
+
+
+typedef enum
+{
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_UNKNOWN                 = 0xB00, /**<  Unknown personalization feature.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP_NETWORK            = 0xB01, /**<  Featurization based on 3GPP MCC and MNC.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP_NETWORK_SUBSET     = 0xB02, /**<  Featurization based on 3GPP MCC, MNC, and IMSI digits 6 and 7.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP_SERVICE_PROVIDER   = 0xB03, /**<  Featurization based on 3GPP MCC, MNC, and GID1.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP_CORPORATE          = 0xB04, /**<  Featurization based on 3GPP MCC, MNC, GID1, and GID2.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP_SIM                = 0xB05, /**<  Featurization based on the 3GPP IMSI.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP2_NETWORK_TYPE_1    = 0xB06, /**<  Featurization based on 3GPP2 MCC and MNC.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP2_NETWORK_TYPE_2    = 0xB07, /**<  Featurization based on 3GPP2 IRM code.  */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_3GPP2_RUIM              = 0xB08, /**<  Featurization based on 3GPP2 IMSI_M.  */
+}E_QL_MCM_SIM_PERSO_FEATURE_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_PERSO_OPERATION_DEACTIVATE                 = 0xB00, /**<  Disable an active personalization feature.  */
+    E_QL_MCM_SIM_PERSO_OPERATION_UNBLOCK                    = 0xB01, /**<  Unblock a personalization feature that has been blocked.  */
+}E_QL_MCM_SIM_PERSO_OPERATION_TYPE_T;
+
+
+#define QL_MCM_SIM_CONTROL_KEY_LEN_MAX 16   /**  Maximum length of personalization control key data */
+/** Deactivates or unblocks the personalization on the phone.
+    Each feature can be deactivated/unblocked independently of the other features. */
+typedef struct
+{
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_T       e_feature_type;                /**< Indicates the personalization feature to deactivate or unblock. */
+    E_QL_MCM_SIM_PERSO_OPERATION_TYPE_T     e_operation;              /**< Indicates the operation to perform. */
+    uint32_t                                ctrl_key_value_len;     /**< Must be set to the number of elements in ck_value. */
+    char                                    ctrl_key_value[QL_MCM_SIM_CONTROL_KEY_LEN_MAX];/**< Control key value. This value is a sequence of ASCII characters.*/
+}QL_MCM_SIM_DEPERSONALIZE_INFO_T;  /* Type */
+
+
+typedef struct
+{
+    char        mcc[5];       /**< MCC value in ASCII characters.*/
+    uint32_t    mnc_len;                        /**< Must be set to the number of elements in the MNC. */
+    char        mnc[5];       /**< MNC value in ASCII characters.*/
+}QL_MCM_SIM_NW_PERSONAL_INFO_T;
+
+typedef struct
+{
+    QL_MCM_SIM_NW_PERSONAL_INFO_T   network;    /**< MCC and MNC network information.*/
+    char                            digit6;     /**< Digit 6 of the IMSI in ASCII character.*/
+    char                            digit7;     /**< Digit 7 of the IMSI in ASCII character.*/
+}QL_MCM_SIM_NW_SUBSET_PERSONAL_INFO_T;
+
+typedef struct
+{
+    QL_MCM_SIM_NW_PERSONAL_INFO_T   network;    /**< MCC and MNC network information.*/
+    uint8_t                         gid1;       /**< Service provider code found in GID1.*/
+}QL_MCM_SIM_NW_SP_PERSONAL_INFO_T;
+
+typedef struct
+{
+    QL_MCM_SIM_NW_PERSONAL_INFO_T   network;    /**< MCC and MNC network information.*/
+    uint8_t                         gid1;       /**< Service provider code found in GID1.*/
+    uint8_t                         gid2;       /**< Corporate customer code found in GID2. @newpagetable */
+}QL_MCM_SIM_GW_CORPORATE_PERSONAL_INFO_T;
+
+#define QL_MCM_SIM_MSIN_LEN_MAX     10          /**  Maximum length of the MSIN. */
+typedef struct
+{
+    QL_MCM_SIM_NW_PERSONAL_INFO_T   network;    /**< MCC and MNC network information.*/
+    uint32_t                        msin_len;   /**< Must be set to the number of elements in MSIN. */
+    char                            msin[QL_MCM_SIM_MSIN_LEN_MAX];/**< MSIN value stored on the card in ASCII characters.*/
+}QL_MCM_SIM_SIM_PERSONAL_INFO_T;  /* Type */
+
+typedef struct
+{
+    char                            irm_code[4];/**< First 4 digits of the IRM-based MIN of IMSI_M in ASCII characters.*/
+}QL_MCM_SIM_1X_NW_TYPE2_PERSONAL_INFO_T;
+
+
+#define QL_MCM_SIM_PERSO_NUM_NW_MAX     85  /**  Maximum number of network personalization data sets. */
+#define QL_MCM_SIM_PERSO_NUM_NS_MAX     64  /**  Maximum number of network subset personalization data sets. */
+#define QL_MCM_SIM_PERSO_NUM_GW_SP_MAX  64  /**  Maximum number of service provider personalization data sets. */
+#define QL_MCM_SIM_PERSO_NUM_GW_CP_MAX  51  /**  Maximum number of corporate personalization data sets. */
+#define QL_MCM_SIM_PERSO_NUM_SIM_MAX    32  /**  Maximum number of SIM personalization data sets. */
+#define QL_MCM_SIM_PERSO_NUM_1X_NW2_MAX 128 /**  Maximum number of network type 2 personalization data sets. */
+
+typedef union
+{
+    QL_MCM_SIM_NW_PERSONAL_INFO_T               feature_gw_network_perso[QL_MCM_SIM_PERSO_NUM_NW_MAX];          /**< GW network personalization. */
+    QL_MCM_SIM_NW_SUBSET_PERSONAL_INFO_T        feature_gw_network_subset_perso[QL_MCM_SIM_PERSO_NUM_NS_MAX];   /**< GW network subset personalization. */
+    QL_MCM_SIM_NW_SP_PERSONAL_INFO_T            feature_gw_sp_perso[QL_MCM_SIM_PERSO_NUM_GW_SP_MAX];            /**< GW service provider personalization. */
+    QL_MCM_SIM_GW_CORPORATE_PERSONAL_INFO_T     feature_gw_corporate_perso[QL_MCM_SIM_PERSO_NUM_GW_CP_MAX];     /**< GW corporate personalization. */
+    QL_MCM_SIM_SIM_PERSONAL_INFO_T              feature_gw_sim_perso[QL_MCM_SIM_PERSO_NUM_SIM_MAX];             /**< GW SIM personalization. */
+    QL_MCM_SIM_NW_PERSONAL_INFO_T               feature_1x_network1_perso[QL_MCM_SIM_PERSO_NUM_NW_MAX];         /**< 1X network type 1 personalization. */
+    QL_MCM_SIM_1X_NW_TYPE2_PERSONAL_INFO_T      feature_1x_network2_perso[QL_MCM_SIM_PERSO_NUM_1X_NW2_MAX];     /**< 1X network type 3 personalization. */
+    QL_MCM_SIM_SIM_PERSONAL_INFO_T              feature_1x_ruim_perso[QL_MCM_SIM_PERSO_NUM_SIM_MAX];            /*  1x RUIM Personalization */
+}QL_MCM_SIM_PERSONAL_FEATURE_INFO_DATA_T;
+
+/** Request message; Activates and sets the personalization data on the phone. Each feature can be activated
+    independently of one another; however, network data configurations must be consistent across activated personalization
+    modes in order to prevent contradicting featurization, and only one feature can be activated per message.
+    If personalization is already activated, it must first be deactivated before being reactivated with new data. */
+typedef struct
+{
+    uint32_t                                    ctrl_key_value_len;                 /**< Must be set to the number of elements in ctrl_key_value. */
+    char                                        ctrl_key_value[60]; /**< Control key value. This value is a sequence of ASCII characters.*/
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_T           e_feature_type;
+    uint32_t                                    feature_data_len; //Valid array count of t_feature_data
+    QL_MCM_SIM_PERSONAL_FEATURE_INFO_DATA_T     t_feature_data;
+}QL_MCM_SIM_PERSONALIZE_FEATURE_INFO_T;
+
+
+typedef enum
+{
+    E_QL_MCM_SIM_CARD_STATE_UNKNOWN                     = 0xB01,    /**< Card state unknown. */
+    E_QL_MCM_SIM_CARD_STATE_ABSENT                      = 0xB02,    /**< Card is absent. */
+    E_QL_MCM_SIM_CARD_STATE_PRESENT                     = 0xB03,    /**< Card is present. */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_UNKNOWN               = 0xB04,    /**< Unknown error state. */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_POWER_DOWN            = 0xB05,    /**< Power down. */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_POLL_ERROR            = 0xB06,    /**< Poll error. */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_NO_ATR_RECEIVED       = 0xB07,    /**<  Failed to receive an answer to reset.  */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_VOLT_MISMATCH         = 0xB08,    /**< Voltage mismatch. */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_PARITY_ERROR          = 0xB09,    /**< Parity error. */
+    E_QL_MCM_SIM_CARD_STATE_ERROR_SIM_TECHNICAL_PROBLEMS= 0xB0A,    /**< Card returned technical problems. */
+}E_QL_MCM_SIM_CARD_STATE_TYPE_T;  /**< Card state. */
+
+typedef enum
+{
+    E_QL_MCM_SIM_CARD_TYPE_UNKNOWN  = 0xB00,    /**<  Unidentified card type.  */
+    E_QL_MCM_SIM_CARD_TYPE_ICC      = 0xB01,    /**<  Card of SIM or RUIM type.  */
+    E_QL_MCM_SIM_CARD_TYPE_UICC     = 0xB02,    /**<  Card of USIM or CSIM type.  */
+}E_QL_MCM_SIM_CARD_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_PROV_STATE_NONE    = 0xB00,    /**<  Nonprovisioning.  */
+    E_QL_MCM_SIM_PROV_STATE_PRI     = 0xB01,    /**<  Primary provisioning subscription.  */
+    E_QL_MCM_SIM_PROV_STATE_SEC     = 0xB02,    /**<  Secondary provisioning subscription.  */
+}QL_MCM_SIM_SUBSCRIPTION_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_APP_STATE_UNKNOWN                  = 0xB00,    /**< Application state unknown. */
+    E_QL_MCM_SIM_APP_STATE_DETECTED                 = 0xB01,    /**<  Detected state.  */
+    E_QL_MCM_SIM_APP_STATE_PIN1_REQ                 = 0xB02,    /**<  PIN1 required.  */
+    E_QL_MCM_SIM_APP_STATE_PUK1_REQ                 = 0xB03,    /**<  PUK1 required.  */
+    E_QL_MCM_SIM_APP_STATE_INITALIZATING            = 0xB04,    /**<  Initializing.  */
+    E_QL_MCM_SIM_APP_STATE_PERSO_CK_REQ             = 0xB05,    /**<  Personalization control key required.  */
+    E_QL_MCM_SIM_APP_STATE_PERSO_PUK_REQ            = 0xB06,    /**<  Personalization unblock key required.  */
+    E_QL_MCM_SIM_APP_STATE_PERSO_PERMANENTLY_BLOCKED= 0xB07,    /**<  Personalization is permanently blocked.  */
+    E_QL_MCM_SIM_APP_STATE_PIN1_PERM_BLOCKED        = 0xB08,    /**<  PIN1 is permanently blocked.  */
+    E_QL_MCM_SIM_APP_STATE_ILLEGAL                  = 0xB09,    /**<  Illegal application state.  */
+    E_QL_MCM_SIM_APP_STATE_READY                    = 0xB0A,    /**<  Application ready state.  @newpage */
+}QL_MCM_SIM_APP_STATE_TYPE_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_PIN_STATE_UNKNOWN                  = 0xB01,    /**< Unknown PIN state. */
+    E_QL_MCM_SIM_PIN_STATE_ENABLED_NOT_VERIFIED     = 0xB02,    /**<  PIN required, but has not been verified.  */
+    E_QL_MCM_SIM_PIN_STATE_ENABLED_VERIFIED         = 0xB03,    /**<  PIN required and has been verified.  */
+    E_QL_MCM_SIM_PIN_STATE_DISABLED                 = 0xB04,    /**<  PIN not required.  */
+    E_QL_MCM_SIM_PIN_STATE_BLOCKED                  = 0xB05,    /**<  PIN verification has failed too many times and is blocked. Recoverable through PUK verification.  */
+    E_QL_MCM_SIM_PIN_STATE_PERMANENTLY_BLOCKED      = 0xB06,    /**<  PUK verification has failed too many times and is not recoverable.  */
+}QL_MCM_SIM_PIN_STATE_TYPE_T;
+
+typedef struct
+{
+    QL_MCM_SIM_SUBSCRIPTION_TYPE_T      subscription;           /**<   Type of subscription (i.e., primary, secondary, etc.). */
+    QL_MCM_SIM_APP_STATE_TYPE_T         app_state;              /**<   Current state of the application. */
+    E_QL_MCM_SIM_PERSO_FEATURE_TYPE_T   perso_feature;          /**<   Current personalization state and feature enabled. */
+    uint8_t                             perso_retries;          /**<   Number of personalization retries. */
+    uint8_t                             perso_unblock_retries;  /**<   Number of personalization unblock retries. */
+    QL_MCM_SIM_PIN_STATE_TYPE_T         pin1_state;             /**<   Current PIN 1 state. */
+    uint8_t                             pin1_num_retries;       /**<   Number of PIN 1 retries. */
+    uint8_t                             puk1_num_retries;       /**<   Number of PUK 1 retries. */
+    QL_MCM_SIM_PIN_STATE_TYPE_T         pin2_state;             /**<   Current PIN 2 state. */
+    uint8_t                             pin2_num_retries;       /**<   Number of PIN 2 retries. */
+    uint8_t                             puk2_num_retries;       /**<   Number of PUK 2 retries. */
+}QL_MCM_SIM_CARD_APP_INFO_T;
+
+typedef struct
+{
+    QL_MCM_SIM_CARD_APP_INFO_T          app_3gpp;               /**<   Stores 3GPP application information. */
+    QL_MCM_SIM_CARD_APP_INFO_T          app_3gpp2;              /**<   Stores 3GPP2 application information. */
+    QL_MCM_SIM_CARD_APP_INFO_T          app_isim;               /**<   Stores ISIM application information. */
+}QL_MCM_SIM_CARD_ALL_APP_INFO_T;
+
+typedef struct
+{
+    E_QL_MCM_SIM_CARD_STATE_TYPE_T      e_card_state;/**<   Current card and card error state. */
+    E_QL_MCM_SIM_CARD_TYPE_T            e_card_type; /**<   Card type. */
+    QL_MCM_SIM_CARD_ALL_APP_INFO_T      card_app_info; /**<   Stores all relevant application information. */
+}QL_MCM_SIM_CARD_STATUS_INFO_T;
+
+#define QL_MCM_SIM_PATH_LEN_MAX     20  /**  Maximum length of a full file path in ASCII format. */
+typedef struct
+{
+    uint16_t    offset;                         /**< Offset is only required for write file access where data length is indicated.*/
+    uint8_t     record_num;                     /**< Number of records involved in file access. A record number of 0 indicates transparent file access.*/
+    uint32_t    path_len;                       /**< Must be set to the number of elements in the path. */
+    char        path[QL_MCM_SIM_PATH_LEN_MAX];  /**< File path in ASCII characters. @newpagetable */
+}QL_MCM_SIM_CARD_FILE_ACCESS_INFO_T;
+
+#define QL_MCM_SIM_DATA_LEN_MAX     4096        /**  Maximum size of data to be read/written. */
+typedef struct
+{
+    QL_SIM_APP_ID_INFO_T                app_info;                       /**< Application identification information. */
+    QL_MCM_SIM_CARD_FILE_ACCESS_INFO_T  file_access;                    /**< File access information. */
+    uint32_t                            data_len;                       /**< Must be set to the number of elements in data. */
+    uint8_t                             data[QL_MCM_SIM_DATA_LEN_MAX];  /**< Data to be updated on the card. */
+}QL_MCM_SIM_CARD_WRITE_FILE_INFO_T;
+
+
+/** Request message; Reads data to a specific file on a specified application on the card. The type of file is determined
+    by the record number field, which indicates a transparent file when zero and a record-based file otherwise.*/
+typedef struct
+{
+    QL_SIM_APP_ID_INFO_T                app_info;                       /**< Application identification information. */
+    QL_MCM_SIM_CARD_FILE_ACCESS_INFO_T  file_access;                    /**< File access information. */
+}QL_MCM_SIM_CARD_FILE_INFO_TO_READ_T;
+
+typedef struct
+{
+    uint32_t    data_len;                                               /**< Must be set to the number of elements in data. */
+    uint8_t     data[QL_MCM_SIM_DATA_LEN_MAX];                          /**< Data retrieved from the card. */
+}QL_MCM_SIM_CARD_FILE_DATA_T;
+
+/** Retrieves the size of a specific file on a specified application on the card. */
+typedef struct
+{
+    QL_SIM_APP_ID_INFO_T    app_info;                       /**< Application identification information. */
+    uint32_t                path_len;                       /**< Must be set to the number of elements in path. */
+    char                    path[QL_MCM_SIM_PATH_LEN_MAX];  /**< File path in ASCII characters.*/
+}QL_MCM_SIM_CARD_GET_FILE_SIZE_INPUT_INFO_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_FILE_TYPE_UNKNOWN      = 0xB00,/**<  Unknown file type  */
+    E_QL_MCM_SIM_FILE_TYPE_TRANSPARENT  = 0xB01,/**< File structure consisting of a sequence of bytes.  */
+    E_QL_MCM_SIM_FILE_TYPE_CYCLIC       = 0xB02,/**< File structure consisting of a sequence of records, each containing the same fixed size in
+                                                     chronological order. Once all the records have been used, the oldest data is overwritten.  */
+    MCM_SIM_FILE_TYPE_LINEAR_FIXED  = 0xB03,    /**< File structure consisting of a sequence of records, each containing the same fixed size.  */
+}E_QL_MCM_SIM_FILE_TYPE_T;
+
+typedef struct
+{
+    E_QL_MCM_SIM_FILE_TYPE_T    e_file_type;    /**<   File type: */
+    uint16_t                    file_size;      /**<   Size of transparent files.*/
+    uint16_t                    record_size;    /**<   Size of each cyclic or linear fixed file record.*/
+    uint16_t                    record_count;   /**<   Number of cyclic or linear fixed file records.*/
+}QL_MCM_SIM_FILE_SIZE_INFO_T;
+
+typedef enum
+{
+    E_QL_MCM_SIM_REFRESH_EVENT              = 0xB00,    /**< Card refresh event  */
+    E_QL_MCM_SIM_CARD_STATUS_UPDATE_EVENT   = 0xB01,    /**< Card status update event.  */
+}E_QL_SIM_NFY_MSG_ID_T;
+
+
+typedef void (*QL_SIM_CardStatusIndMsgHandlerFunc_t)
+(
+    sim_client_handle_type  h_sim,
+    E_QL_SIM_NFY_MSG_ID_T   e_msg_id,
+    void                    *pv_data,
+    void                    *contextPtr
+);
+
+
+int QL_MCM_SIM_Client_Init(sim_client_handle_type  *ph_sim);
+
+int QL_MCM_SIM_Client_Deinit(sim_client_handle_type h_sim);
+
+/* Add callback function if anything changed specified by the mask in QL_LOC_Set_Indications*/
+int QL_MCM_SIM_AddRxIndMsgHandler(QL_SIM_CardStatusIndMsgHandlerFunc_t handlerPtr, void* contextPtr);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_GetIMSI
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the IMSI (for 3GPP)
+    or IMSI_M (for 3GPP2) from the SIM in ASCII form
+
+    @return
+    void
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetIMSI
+(
+    sim_client_handle_type          h_sim,
+    QL_SIM_APP_ID_INFO_T            *pt_info,   ///< [IN] The SIM identifier info.
+    char                            *imsi,      ///< [OUT] IMSI buffer
+    size_t                          imsiLen     ///< [IN] IMSI buffer length
+);
+
+
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetIMEI
+(
+    sim_client_handle_type          h_sim,
+    char                            *imei,      ///< [OUT] IMSI buffer
+    size_t                          imeiLen     ///< [IN] IMSI buffer length
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_GetICCID
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the ICCID from
+    SIM in ASCII form
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetICCID
+(
+    sim_client_handle_type          h_sim,
+    E_QL_MCM_SIM_SLOT_ID_TYPE_T     simId,     ///< [IN] The SIM identifier.
+    char                            *iccid,    ///< [OUT] ICCID
+    size_t                          iccidLen   ///< [IN] ICCID buffer length
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_GetPhoneNumber
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the device phone
+    number from MSISDN (for 3GPP) or MDN (for 3GPP2) from the SIM in
+    ASCII form
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetPhoneNumber
+(
+    sim_client_handle_type          h_sim,
+    QL_SIM_APP_ID_INFO_T            *pt_info,   ///< [IN] The SIM identifier.
+    char                            *phone_num, ///< [OUT] phone number
+    size_t                          phoneLen    ///< [IN] phone number buffer length
+);
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_GetOperatorPlmnList
+
+===========================================================================*/
+/*
+    @brief
+    Function sends multiple record based read commands to the modem
+    to retrieve a list of operator preffered PLMN.
+
+    @note
+    Function should only be called for SIM/USIM
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetOperatorPlmnList
+(
+    sim_client_handle_type              h_sim,
+    E_QL_MCM_SIM_SLOT_ID_TYPE_T         simId,      ///< [IN] The SIM identifier.
+    QL_SIM_PREFERRED_OPERATOR_LIST_T    *pt_info    ///< [OUT] Preferred operator list
+);
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_VerifyPIN
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to verify either PIN1 or PIN2
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_VerifyPIN
+(
+    sim_client_handle_type      h_sim,
+    QL_SIM_VERIFY_PIN_INFO_T    *pt_info   ///< [IN] Verify PIN infor
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_ChangePin
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to change the value of
+    either PIN1 or PIN2
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_ChangePin
+(
+    sim_client_handle_type      h_sim,
+    QL_SIM_CHANGE_PIN_INFO_T    *pt_info   ///< [IN] Change PIN infor
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_UnblockPIN
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to unblock a PIN1 or PIN2 that
+    has been blocked
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_UnblockPIN
+(
+    sim_client_handle_type      h_sim,
+    QL_SIM_UNBLOCK_PIN_INFO_T   *pt_info   ///< [IN] Unblock PIN infor
+);
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_EnablePIN
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to enable PIN1 or PIN2
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_EnablePIN
+(
+    sim_client_handle_type      h_sim,
+    QL_SIM_ENABLE_PIN_INFO_T    *pt_info   ///< [IN] Enable PIN infor
+);
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_DisablePIN
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to disable PIN1 or PIN2
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_DisablePIN
+(
+    sim_client_handle_type      h_sim,
+    QL_SIM_DISABLE_PIN_INFO_T   *pt_info   ///< [IN] Disable PIN infor
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_GetCardStatus
+
+===========================================================================*/
+/*
+    @brief
+    Function retrieves the server cached card status informations and
+    sends the information to the client
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetCardStatus
+(
+    sim_client_handle_type          h_sim,
+    E_QL_MCM_SIM_SLOT_ID_TYPE_T     simId,     ///< [IN] The SIM identifier.
+    QL_MCM_SIM_CARD_STATUS_INFO_T   *pt_info   ///< [OUT] Cart status infor output
+);
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_Depersonalization
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to disable or unblock SIM Lock
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_Depersonalization
+(
+    sim_client_handle_type              h_sim,
+    QL_MCM_SIM_DEPERSONALIZE_INFO_T     *pt_info   ///< [OUT] Depersonalize information
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_Personalization
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to set the SIM Lock data
+    and concurrently enable SIM Lock.
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_Personalization
+(
+    sim_client_handle_type                  h_sim,
+    QL_MCM_SIM_PERSONALIZE_FEATURE_INFO_T   *pt_info   ///< [OUT] Unblock PIN infor
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_WriteFile
+
+===========================================================================*/
+/*
+    @brief
+    Function will determine whether the request is for transparent or
+    record based write command based on the record number and calls the
+    corresponding function to send the message to the card.
+
+    record number = 0  -  transparent
+    record number > 0  -  record based
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_WriteFile
+(
+    sim_client_handle_type              h_sim,
+    QL_MCM_SIM_CARD_WRITE_FILE_INFO_T   *pt_info   ///< [OUT] Verify PIN infor
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_ReadFile
+
+===========================================================================*/
+/*
+    @brief
+    Function will determine whether the request is for transparent or
+    record based read command based on the record number and calls the
+    corresponding function to send the message to the card.
+
+    record number = 0  -  transparent
+    record number > 0  -  record based
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_ReadFile
+(
+    sim_client_handle_type                  h_sim,
+    QL_MCM_SIM_CARD_FILE_INFO_TO_READ_T     *pt_info,   ///< [IN] input file info which to be read
+    QL_MCM_SIM_CARD_FILE_DATA_T             *pt_out     ///< [OUT] File data of the specified one by pt_info
+);
+
+/*===========================================================================
+
+  FUNCTION:  QL_MCM_SIM_GetFileSize
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the file type, file
+    size(transparent files) or record size and record count (record based files)
+
+    @return
+    E_QL_ERROR_CODE_T
+*/
+/*=========================================================================*/
+E_QL_ERROR_CODE_T QL_MCM_SIM_GetFileSize
+(
+    sim_client_handle_type                          h_sim,
+    QL_MCM_SIM_CARD_GET_FILE_SIZE_INPUT_INFO_T      *pt_info,   ///< [IN] input file info which to be read
+    QL_MCM_SIM_FILE_SIZE_INFO_T                     *pt_out     ///< [OUT] output file size info
+);
+
+
+
+#endif // __QL_MCM_SIM_H__
+
diff --git a/mbtk/include/ql/ql_mcm_sms.h b/mbtk/include/ql/ql_mcm_sms.h
new file mode 100755
index 0000000..1055325
--- /dev/null
+++ b/mbtk/include/ql/ql_mcm_sms.h
@@ -0,0 +1,282 @@
+/**
+ *@file     ql_sms.h
+ *@date     2017-05-02
+ *@author   
+ *@brief    
+ */
+
+#ifndef __QL_SMS_H__
+#define __QL_SMS_H__
+
+#include "mbtk_type.h"
+
+typedef uint32 sms_client_handle_type;
+
+/**  Maximum length of an SMS. */
+#define QL_SMS_MAX_MT_MSG_LENGTH    1440
+
+/**  Maximum string length. */
+#define QL_SMS_MAX_ADDR_LENGTH      252
+
+/**  Maximum string length. */
+#define QL_SMS_MAX_SCA_TYPE_LENGTH 3
+
+
+typedef enum   
+{    
+    E_QL_SMS_FORMAT_GSM_7BIT        = 0,
+    E_QL_SMS_FORMAT_BINARY_DATA     = 1,
+    E_QL_SMS_FORMAT_UCS2            = 2,
+    //<2017/12/28-QCM9XOL00004C001-P01-Vicent.Gao, <[SMS] Segment 1==> CharSet to Alpha implementation.>
+    E_QL_SMS_FORMAT_IRA             = 3,
+    //>2017/12/28-QCM9XOL00004C001-P01-Vicent.Gao
+
+}E_QL_SMS_FORMAT_T;   
+
+typedef enum   
+{    
+    E_QL_SMS_TYPE_RX                = 0,    ///< SMS mobile terminated message.  
+    E_QL_SMS_TYPE_TX                = 1,    ///< SMS mobile originated message. 
+    E_QL_SMS_TYPE_BROADCAST_RX      = 2     ///< SMS Cell Broadcast message.   
+}E_QL_SMS_TYPE_T; 
+
+typedef enum 
+{
+    E_QL_SMS_STORAGE_TYPE_NONE      = -1,   /**<  Message no need to store. */
+    E_QL_SMS_STORAGE_TYPE_UIM       = 0,    /**<  Message store to UIM. */
+    E_QL_SMS_STORAGE_TYPE_NV        = 1,    /**<  Message store to NV. */
+}E_QL_SMS_STORAGE_TYPE_T;
+
+typedef enum 
+{
+    E_QL_SMS_MESSAGE_MODE_UNKNOWN   = -1,   /**<  Message type CDMA */
+    E_QL_SMS_MESSAGE_MODE_CDMA      = 0,    /**<  Message type CDMA */
+    E_QL_SMS_MESSAGE_MODE_GW        = 1,    /**<  Message type GW. */
+}E_QL_SMS_MODE_TYPE_T;
+
+typedef struct 
+ {
+    uint8_t total_segments;     /**<     The number of long  short message*/
+    uint8_t seg_number;         /**<     Current number.*/
+	uint8_t reference_number;   /**< reference_number.*/
+}ql_sms_user_data_head_t; 
+
+typedef struct
+{
+    /* If sms is stored, it won't parse, you need read it by yourself */
+    E_QL_SMS_STORAGE_TYPE_T e_storage;                          ///specify where stored this msg
+    
+    E_QL_SMS_FORMAT_T       format;
+    E_QL_SMS_TYPE_T         type;
+    char                    sms_number_addr[QL_SMS_MAX_ADDR_LENGTH]; ///Telephone number string
+    char                    sca_number_addr[QL_SMS_MAX_ADDR_LENGTH]; //.SMS Center Number  
+    int                     sms_data_len;
+    char                    sms_data[QL_SMS_MAX_MT_MSG_LENGTH];   ///SMS content, data format depends on format
+    char                    timestamp[21];                      ///Message time stamp (in text mode). string format: "yy/MM/dd,hh:mm:ss+/-TimeZone" 
+    uint8_t                 user_data_head_valid;               //indicate whether long sms. TRUE-long sms; FALSE-short message;
+    ql_sms_user_data_head_t  user_data_head;                    //long sms user data head info.
+    E_QL_SMS_MODE_TYPE_T    e_mode;                             ///specify where stored this msg cdma or gw area
+    uint32_t                storage_index;                      ///storage index, -1 means not store
+} ql_sms_info_t;
+     
+
+typedef struct
+{
+    E_QL_SMS_STORAGE_TYPE_T e_storage;
+    E_QL_SMS_MODE_TYPE_T    e_mode;
+    uint32_t                storage_idx;
+} ql_sms_storage_info_t;
+
+/*      0 = "REC UNREAD"    */
+/*      1 = "REC READ"      */
+/*      2 = "STO UNSENT"    */
+/*      3 = "STO SENT"      */
+typedef enum _ql_SMS_SIM_STATUS
+{
+    REC_UNREAD   = 0,
+    REC_READ     = 1,
+    STO_UNSENT   = 2,
+    STO_SENT     = 3
+}ql_SMS_SIM_STATUS;
+
+typedef enum 
+{
+    E_QL_SMS_MESSAGE_CLASS_0    = 0x00, //display only
+    E_QL_SMS_MESSAGE_CLASS_1    = 0x01, //store in ME
+    E_QL_SMS_MESSAGE_CLASS_2    = 0x02, //store in SIM
+    E_QL_SMS_MESSAGE_CLASS_3    = 0x03, //
+    E_QL_SMS_MESSAGE_CLASS_NONE = 0x04, 
+    E_QL_SMS_MESSAGE_CLASS_CDMA = 0x05, 
+    E_QL_SMS_MESSAGE_CLASS_MAX  = 0x06, 
+}E_QL_SMS_MESSAGE_CLASS_TYPE_T;
+
+typedef enum 
+{
+    E_QL_SMS_UNKNOWN            = -1, 
+    E_QL_SMS_DISCARD            = 0x00, /*  Incoming messages for this route are discarded by the WMS service without 
+                                            notifying QMI_WMS clients */
+    E_QL_SMS_STORE_AND_NOTIFY   = 0x01, /*  Incoming messages for this route are stored to the specified device 
+                                            memory, and new message notifications */
+    E_QL_SMS_TRANSFER_ONLY      = 0x02, /*  Incoming messages for this route are transferred to the client, and the
+                                            client is expected to send ACK to the network */
+    E_QL_SMS_TRANSFER_AND_ACK   = 0x03, /*  Incoming messages for this route are transferred to the client, and ACK is
+                                            sent to the network */
+}E_QL_SMS_RECEPTION_ACTION_TYPE_T;
+
+typedef struct 
+{
+  E_QL_SMS_MESSAGE_CLASS_TYPE_T     message_class;
+  E_QL_SMS_STORAGE_TYPE_T           route_storage;
+  E_QL_SMS_RECEPTION_ACTION_TYPE_T  receipt_action;
+}ql_sms_route_info_t;  /* Type */
+
+typedef struct 
+{
+    ql_sms_route_info_t     route_list[E_QL_SMS_MESSAGE_CLASS_MAX];
+}ql_sms_route_info_list_t;  /* Message */
+
+#define QL_WMS_MESSAGE_LENGTH_MAX 255
+
+typedef enum 
+ {
+    E_QL_WMS_MESSAGE_FORMAT_CDMA            = 0x00,     //- 0x00 -- MESSAGE_FORMAT_CDMA -- CDMA \n 
+    E_QL_WMS_MESSAGE_FORMAT_GW_PP           = 0x06,     //- 0x06 -- MESSAGE_FORMAT_GW_PP -- GW_PP
+}E_QL_WMS_MESSAGE_FORMAT_TYPE;
+
+
+typedef struct
+ {
+  E_QL_WMS_MESSAGE_FORMAT_TYPE format;
+  uint32_t raw_message_len;                             /**< Must be set to # of elements in raw_message */
+  uint8_t raw_message[QL_WMS_MESSAGE_LENGTH_MAX];       /**< Raw message data*/
+}ql_wms_send_raw_message_data_t; 
+
+
+typedef enum
+{
+  E_QL_WMS_TL_CAUSE_CODE_ADDR_VACANT                        = 0x00, 
+  E_QL_WMS_TL_CAUSE_CODE_ADDR_TRANSLATION_FAILURE           = 0x01, 
+  E_QL_WMS_TL_CAUSE_CODE_NETWORK_RESOURCE_SHORTAGE          = 0x02, 
+  E_QL_WMS_TL_CAUSE_CODE_NETWORK_FAILURE                    = 0x03, 
+  E_QL_WMS_TL_CAUSE_CODE_INVALID_TELESERVICE_ID             = 0x04, 
+  E_QL_WMS_TL_CAUSE_CODE_NETWORK_OTHER                      = 0x05, 
+  E_QL_WMS_TL_CAUSE_CODE_NO_PAGE_RESPONSE                   = 0x20, 
+  E_QL_WMS_TL_CAUSE_CODE_DEST_BUSY                          = 0x21, 
+  E_QL_WMS_TL_CAUSE_CODE_NO_ACK                             = 0x22, 
+  E_QL_WMS_TL_CAUSE_CODE_DEST_RESOURCE_SHORTAGE             = 0x23, 
+  E_QL_WMS_TL_CAUSE_CODE_SMS_DELIVERY_POSTPONED             = 0x24, 
+  E_QL_WMS_TL_CAUSE_CODE_DEST_OUT_OF_SERV                   = 0x25, 
+  E_QL_WMS_TL_CAUSE_CODE_DEST_NOT_AT_ADDR                   = 0x26, 
+  E_QL_WMS_TL_CAUSE_CODE_DEST_OTHER                         = 0x27, 
+  E_QL_WMS_TL_CAUSE_CODE_RADIO_IF_RESOURCE_SHORTAGE         = 0x40, 
+  E_QL_WMS_TL_CAUSE_CODE_RADIO_IF_INCOMPATABILITY           = 0x41, 
+  E_QL_WMS_TL_CAUSE_CODE_RADIO_IF_OTHER                     = 0x42, 
+  E_QL_WMS_TL_CAUSE_CODE_ENCODING                           = 0x60, 
+  E_QL_WMS_TL_CAUSE_CODE_SMS_ORIG_DENIED                    = 0x61, 
+  E_QL_WMS_TL_CAUSE_CODE_SMS_TERM_DENIED                    = 0x62, 
+  E_QL_WMS_TL_CAUSE_CODE_SUPP_SERV_NOT_SUPP                 = 0x63, 
+  E_QL_WMS_TL_CAUSE_CODE_SMS_NOT_SUPP                       = 0x64, 
+  E_QL_WMS_TL_CAUSE_CODE_MISSING_EXPECTED_PARAM             = 0x65, 
+  E_QL_WMS_TL_CAUSE_CODE_MISSING_MAND_PARAM                 = 0x66, 
+  E_QL_WMS_TL_CAUSE_CODE_UNRECOGNIZED_PARAM_VAL             = 0x67, 
+  E_QL_WMS_TL_CAUSE_CODE_UNEXPECTED_PARAM_VAL               = 0x68, 
+  E_QL_WMS_TL_CAUSE_CODE_USER_DATA_SIZE_ERR                 = 0x69, 
+  E_QL_WMS_TL_CAUSE_CODE_GENERAL_OTHER                      = 0x6A, 
+}E_QL_WMS_TL_CAUSE_CODE_TYPE;
+
+typedef struct
+ {
+  uint16_t                              message_id;            /*  Message ID */
+  uint8_t                               cause_code_valid;      /**< Must be set to true if cause_code is being passed */
+  E_QL_WMS_TL_CAUSE_CODE_TYPE           cause_code;  
+}ql_wms_raw_send_resp_t;
+
+typedef struct 
+ {
+  char service_center_addr[QL_SMS_MAX_ADDR_LENGTH + 1];         /**<   Address of the service center.*/
+  uint8_t service_center_addr_type_valid;
+  char service_center_addr_type[QL_SMS_MAX_SCA_TYPE_LENGTH + 1];    /**<   129 if the SMSC address does not start with a "+" characte;
+                                                                           145 if the SMSC address starts with a "+" character*/
+}ql_sms_service_center_cfg_t;
+
+typedef ql_sms_info_t       QL_SMS_Msg_t; 
+typedef ql_sms_info_t*      QL_SMS_MsgRef; 
+
+/* Callback function registered to QL_SMS_AddRxMsgHandler, msgRef contains the detail msg infor */
+typedef void (*QL_SMS_RxMsgHandlerFunc_t)   
+(    
+    QL_SMS_MsgRef       msgRef,  
+    void*               contextPtr    
+);
+
+/* Init SMS module and return h_sms, this should be called before any othe ones */
+int QL_SMS_Client_Init(sms_client_handle_type  *ph_sms);
+
+/* Add callback function, if any new msg arrived, it will notify app */
+int QL_SMS_AddRxMsgHandler(QL_SMS_RxMsgHandlerFunc_t handlerPtr, void* contextPtr);
+
+/* Send sms, you just need to fill format/src_addr/sms_data_len/sms_data,
+   if format is UCS2, the data should be Unicode-BE format.
+*/
+int QL_SMS_Send_Sms(sms_client_handle_type h_sms, ql_sms_info_t *pt_sms_info);
+
+/* DeInit SMS module and release resource, this should be called in the last one. */
+int QL_SMS_Client_Deinit(sms_client_handle_type h_sms);
+     
+/* Delete the SMS specified in the  pt_sms_storage */
+int QL_SMS_DeleteFromStorage(sms_client_handle_type  h_sms, ql_sms_storage_info_t  *pt_sms_storage);
+
+/* Set route list, normally, sms won't be stored, the route set to transfer_and_ack by default.
+   If you want to save to storage, you can specify it with this api.
+*/
+int QL_SMS_SetRouteList(sms_client_handle_type  h_sms,  ql_sms_route_info_list_t *pt_route_list);
+
+/* Send sms PDU.
+*/
+int QL_SMS_Send_SmsPdu( sms_client_handle_type     h_sms,
+                         ql_wms_send_raw_message_data_t *raw_message_data,
+                         ql_wms_raw_send_resp_t *rawresp);
+
+int QL_SMS_Get_By_id(ql_sms_storage_info_t  *pt_sms_storage);
+
+/* Get sms center address.
+*/
+int QL_SMS_GetSmsCenterAddress( sms_client_handle_type     h_sms,
+                       ql_sms_service_center_cfg_t *set_sca_cfg);
+
+/* Set sms center address.
+*/
+int QL_SMS_SetSmsCenterAddress( sms_client_handle_type     h_sms,
+                       ql_sms_service_center_cfg_t *get_sca_cfg);
+
+int QL_SMS_Get_Storage(sms_client_handle_type  *ph_sms);
+
+int QL_SMS_Save_Sms(sms_client_handle_type h_sms, ql_sms_info_t *pt_sms_info);
+
+int QL_SMS_Delete_Sms(sms_client_handle_type h_sms, ql_sms_info_t *pt_sms_info);
+/*
+Usage 1 (register callback and wait for new sms arrive): 
+1, QL_SMS_Client_Init
+2, QL_SMS_AddRxMsgHandler(pf_cb)
+3, wait for sms arrive, pf_cb will pass the detail sms info to app.
+4, QL_SMS_Client_Deinit
+
+
+Usage 2 (Send sms): 
+1, QL_SMS_Client_Init
+2, QL_SMS_AddRxMsgHandler(pf_cb)
+3, QL_SMS_Send_Sms
+4, QL_SMS_Client_Deinit
+
+
+Usage 3 (store sms): 
+1, QL_SMS_Client_Init
+2, QL_SMS_AddRxMsgHandler(pf_cb)
+3, QL_SMS_SetRouteList (Notice: class-0 not allowed to store, class-2 must be stored to UIM)
+4, pf_cb will be called when new sms arrived, and tell you where the sms stored
+5, you can call QL_SMS_DeleteFromStorage to delete specified sms, the location can be got from pf_cb.
+6, QL_SMS_Client_Deinit
+*/
+
+#endif // __QL_SMS_H__      
+     
diff --git a/mbtk/include/ql/ql_network.h b/mbtk/include/ql/ql_network.h
new file mode 100755
index 0000000..241c718
--- /dev/null
+++ b/mbtk/include/ql/ql_network.h
@@ -0,0 +1,51 @@
+/**
+ * @file ql_network.h
+ * @brief Quectel Openlinux network public function declarations.
+ *
+ * @note
+ *
+ * @copyright Copyright (c) 2009-2017 @ Quectel Wireless Solutions Co., Ltd.
+ */
+
+#ifndef __QL_NETWORK_H__
+#define __QL_NETWORK_H__
+#include "mbtk_type.h"
+#include "mbtk_info_api.h"
+
+
+ typedef struct {
+ 	char gw_ip[20];				/* Gateway Address*/
+	char netmask[20];			         /* netmask */
+	unsigned char enable_dhcp;            /* Whether to enable DHCP; boolean value. */
+  	char dhcp_start_ip[20]; 		         /*DHCP start IP address.*/
+   	char dhcp_end_ip[20];		         /*DHCP end IP address. */
+   	unsigned int lease_time; 	         /*DHCP lease time, in seconds.*/
+ }ql_lan_dhcp_config_s;
+
+
+
+/**
+* Set the network configuration: dhcp configuration.
+*s
+* @param [in]  lan_dhcp_config
+*
+* @return
+*	On success, 0 is returned.	On error, -1 is returned.
+*
+*/
+extern int QL_LAN_DHCP_Config_Set(ql_lan_dhcp_config_s lan_dhcp_config);
+
+/**
+* Get the network configuration: dhcp configuration.
+*
+* @param [out]	 lan_dhcp_config
+*
+* @return
+*	On success, 0 is returned.	On error, -1 is returned.
+*
+*/
+extern int QL_LAN_DHCP_Config_Get(ql_lan_dhcp_config_s *lan_dhcp_config);
+
+#endif
+
+
diff --git a/mbtk/include/ql/ql_nw.h b/mbtk/include/ql/ql_nw.h
new file mode 100755
index 0000000..8e1d237
--- /dev/null
+++ b/mbtk/include/ql/ql_nw.h
@@ -0,0 +1,292 @@
+/**
+  @file
+  ql_nw.h
+
+  @brief
+  This file provides the definitions for nw, and declares the
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+14/08/2019  Nebula.li      create
+=============================================================================*/
+
+#ifndef __QL_NW_H__
+#define __QL_NW_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define  QL_NW_IND_VOICE_REG_EVENT_FLAG  (1 << 0)  //VOICE注册事件
+#define  QL_NW_IND_DATA_REG_EVENT_FLAG  (1 << 1)   //DATA注册事件
+#define  QL_NW_IND_SIGNAL_STRENGTH_EVENT_FLAG  (1 << 2)  //信号强度事件
+#define  QL_NW_IND_NITZ_TIME_UPDATE_EVENT_FLAG  (1 << 3)  //时间跟新事件
+//START baron-2020.02.29: add for ims register state indication
+#define  QL_NW_IND_IMS_NETWORK_STATE_CHANGED_FLAG    (1 << 4) //ims register state change
+//END
+#define CELL_MAX_NUM 20
+
+typedef enum
+{
+	QL_NW_SUCCESS,
+	QL_NW_GENERIC_FAILURE,
+ 	QL_NW_RADIO_NOT_AVAILABLE,
+}QL_NW_ERROR_CODE;
+
+typedef enum {
+  QL_NW_PREF_NET_TYPE_GSM_WCDMA  = 0,
+  QL_NW_PREF_NET_TYPE_GSM_ONLY  = 1,
+  QL_NW_PREF_NET_TYPE_WCDMA  = 2,
+  QL_NW_PREF_NET_TYPE_GSM_WCDMA_AUTO  = 3, //根据 PRL自动选择GSM、WCDMA
+  QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA  = 9, //自动选择LTE、GSM、WCDMA
+  QL_NW_PREF_NET_TYPE_LTE_ONLY  = 11,
+  QL_NW_PREF_NET_TYPE_LTE_WCDMA  = 12,
+  QL_NW_PREF_NET_TYPE_LTE_GSM_GSM_PREF = 13, //优先GSM
+  QL_NW_PREF_NET_TYPE_LTE_GSM_LTE_PREF = 14, //优先LTE
+  QL_NW_PREF_NET_TYPE_LTE_GSM = 15,
+  QL_NW_PREF_NET_TYPE_LTE_WCDMA_WCDMA_PREF = 16,
+  QL_NW_PREF_NET_TYPE_LTE_WCDMA_LTE_PREF = 17,
+  QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_GSM_PREF   = 19,
+  QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_WCDMA_PREF = 20,
+  QL_NW_PREF_NET_TYPE_LTE_GSM_WCDMA_LTE_PREF   = 21,
+} QL_NW_PREFERRED_NETWORK_TYPE;
+
+typedef struct
+{
+  QL_NW_PREFERRED_NETWORK_TYPE  preferred_nw_mode;  //首选的网络制式,见QL_NW_PREFERRED_NETWORK_TYPE
+  int  roaming_pref;      //漫游开关。 0 关; 1 开
+}QL_NW_CONFIG_INFO_T;
+
+typedef struct
+{
+  char        nitz_time[32];  //格式:format: YY/MM/DD HH:MM:SS '+/-'TZ daylight,   18/09/19 07:40:18 +32 00.
+  unsigned long  abs_time;   //0表示不可用
+  unsigned char      leap_sec;   //0表示不可用
+}QL_NW_NITZ_TIME_INFO_T;
+
+typedef struct
+{
+  char long_eons[128];
+  char short_eons[128];
+  char mcc[4];
+  char mnc[4];
+}QL_NW_OPERATOR_INFO_T;
+
+//START baron-2020.02.29: add for ims register state
+typedef struct __volte_state
+{
+    int reg_state;    /*0: not registered, 1: registered*/
+}VOLTE_STATE;
+//END
+
+typedef enum
+{
+  QL_NW_ACCESS_TECH_GSM   = 0,
+  QL_NW_ACCESS_TECH_GSM_COMPACT    = 1,
+  QL_NW_ACCESS_TECH_UTRAN      = 2,
+  QL_NW_ACCESS_TECH_GSM_wEGPRS    = 3,
+  QL_NW_ACCESS_TECH_UTRAN_wHSDPA   = 4,
+  QL_NW_ACCESS_TECH_UTRAN_wHSUPA     = 5,
+  QL_NW_ACCESS_TECH_UTRAN_wHSDPA_HSUPA    = 6,
+  QL_NW_ACCESS_TECH_E_UTRAN    = 7,
+  QL_NW_ACCESS_TECH_UTRAN_HSPAP   = 8,
+  QL_NW_ACCESS_TECH_E_UTRAN_CA   = 9,
+  QL_NW_ACCESS_TECH_NONE = 10,
+}QL_NW_ACCESS_TECHNOLOGY;
+
+typedef struct
+{
+  int status; //0:未知的网络;1:可用的网络;2:当前的网络;3:禁止使用的网络
+  QL_NW_OPERATOR_INFO_T operator_name; //运营商信息,见QL_NW_OPERATOR_INFO_T。
+  QL_NW_ACCESS_TECHNOLOGY  act;  //注网制式,见QL_NW_RADIO_TECH_TYPE_T。
+}QL_NW_SCAN_ENTRY_INFO_T;
+
+typedef struct
+{
+  int  entry_len; //可用网络的个数
+  QL_NW_SCAN_ENTRY_INFO_T entry[40]; //可用网络的列表,见QL_NW_SCAN_ENTRY_INFO_T。
+}QL_NW_SCAN_RESULT_LIST_INFO_T;
+
+
+typedef enum {
+    QL_NW_RADIO_TECH_UNKNOWN = 0,
+    QL_NW_RADIO_TECH_GPRS = 1,
+    QL_NW_RADIO_TECH_EDGE = 2,
+    QL_NW_RADIO_TECH_UMTS = 3,
+    QL_NW_RADIO_TECH_IS95A = 4,
+    QL_NW_RADIO_TECH_IS95B = 5,
+    QL_NW_RADIO_TECH_1xRTT =  6,
+    QL_NW_RADIO_TECH_HSDPA = 9,
+    QL_NW_RADIO_TECH_HSUPA = 10,
+    QL_NW_RADIO_TECH_HSPA = 11,
+    QL_NW_RADIO_TECH_EHRPD = 13,
+    QL_NW_RADIO_TECH_LTE = 14,
+    QL_NW_RADIO_TECH_HSPAP = 15, // HSPA+
+    QL_NW_RADIO_TECH_GSM = 16,
+    QL_NW_RADIO_TECH_TD_SCDMA = 17,
+    QL_NW_RADIO_TECH_IWLAN = 18,
+    QL_NW_RADIO_TECH_LTEP = 19,
+    QL_NW_RADIO_TECH_DC_HSPA = 20
+} QL_NW_RADIO_TECHNOLOGY;
+
+typedef enum {
+  QL_NW_REG_STATE_NOT_REGISTERED=0,  //not registered, MT is not currently searching an operator to register to
+  QL_NW_REG_STATE_HOME_NETWORK=1,  //registered, home network
+  QL_NW_REG_STATE_TRYING_ATTACH_OR_SEARCHING=2, //not registered, but MT is currently trying to attach or searching an operator to register to
+  QL_NW_REG_STATE_DENIED=3, //registration denied
+  QL_NW_REG_STATE_UNKNOWN=4, //unknown
+  QL_NW_REG_STATE_ROAMING=5, //registered, roaming
+  QL_NW_REG_STATE_HOME_NETWORK_SMS_ONLY=6, //registered for “SMS only”, home network (not applicable)
+  QL_NW_REG_STATE_ROAMING_SMS_ONLY=7,// registered for “SMS only”, roaming (not applicable)
+  QL_NW_REG_STATE_ATTACHED_EMERGENCY_ONLY=8, //attached for emergency bearer services only
+  QL_NW_REG_STATE_HOME_NETWORK_CSFB_NOT_PREFERRED=9, //registered for “CSFB not preferred”, home network (not applicable)
+  QL_NW_REG_STATE_ROAMING_CSFB_NOT_PREFERRED=10,//registered for “CSFB not preferred”, roaming (not applicable)
+  QL_NW_REG_STATE_EMERGENCY_ONLY=11,//emergency bearer services only
+}QL_NW_REG_STATE;
+
+typedef struct
+{
+	QL_NW_REG_STATE state; //注册状态
+	int lac;
+	int cid;
+	QL_NW_RADIO_TECHNOLOGY  rat;
+	int rejectCause;  //注册被拒绝的原因
+	int psc; //Primary Scrambling Code
+} QL_NW_COMMON_REG_STATUS_INFO_T;
+
+typedef struct
+{
+	QL_NW_COMMON_REG_STATUS_INFO_T voice_reg;  //VOICE注册信息,见QL_NW_COMMON_REG_STATUS_INFO_T
+	QL_NW_COMMON_REG_STATUS_INFO_T data_reg;   //DATA注册信息。
+}QL_NW_REG_STATUS_INFO_T;
+
+typedef struct
+{
+  int   nw_selection_mode; //0 自动;1手动
+  char  mcc[4];
+  char  mnc[4];
+  QL_NW_ACCESS_TECHNOLOGY  act;  //selection 制式,见QL_NW_ACCESS_TECHNOLOGY。
+}QL_NW_SELECTION_INFO_T;
+
+typedef struct {
+  int rssi;
+  int bitErrorRate;
+  int rscp;
+	int ecio;
+} QL_NW_GW_SIGNAL_STRENGTH_INFO_T;
+
+typedef struct {
+  int rssi;
+  int rsrp;
+  int rsrq;
+	int rssnr;
+	int cqi;
+} QL_NW_LTE_SIGNAL_STRENGTH_INFO_T;
+
+typedef struct {
+    QL_NW_GW_SIGNAL_STRENGTH_INFO_T   GW_SignalStrength;
+    QL_NW_LTE_SIGNAL_STRENGTH_INFO_T  LTE_SignalStrength;
+}QL_NW_SIGNAL_STRENGTH_INFO_T;
+
+/* CSQ: just get rssi and ber */
+typedef struct {
+  int rssi;
+  int bitErrorRate;
+} QL_NW_CSQ_SIGNAL_STRENGTH_INFO_T;
+
+typedef struct
+{
+    int flag;       /**Cell type, 0:present,1:neighbor.*/
+    int cid;        /**Cell ID, (0 indicates information is not represent).*/
+    int mcc;        /**This field should be ignored when cid is not present*/
+    int mnc;        /**This field should be ignored when cid is not present*/
+    int lac;        /**Location area code.(This field should be ignord when cid is not present). */
+    int arfcn;      /**Absolute RF channel number. */
+    char bsic;       /**Base station identity code. (0 indicates information is not present). */
+    int lenOfMnc;      /**Length of MNC, value range (2,3) */
+}QL_MCM_NW_GSM_CELL_INFO_T;
+
+typedef struct
+{
+    int flag;          /**Cell type, 0:present,1:inter,2:intra.*/
+    int cid;           /**Cell ID, (0 indicates information is not represent).*/
+    int lcid;          /**UTRAN Cell ID (0 indicates information is not present). */
+    int mcc;           /**This field should be ignored when cid is not present*/
+    int mnc;           /**This field should be ignored when cid is not present*/
+    int lac;           /**Location area code. (This field should be ignored when cid is not present). */
+    int uarfcn;        /**UTRA absolute RF channel number. */
+    int psc;           /**Primary scrambling code. */
+    int lenOfMnc;      /**Length of MNC, value range (2,3) */
+}QL_MCM_NW_UMTS_CELL_INFO_T;
+
+typedef struct
+{
+    int flag;          /**Cell type, 0:present,1:inter,2:intra.*/
+    int cid;           /**<Cell ID, (0 indicates information is not represent).*/
+    int mcc;           /**This field should be ignored when cid is not present*/
+    int mnc;           /**This field should be ignored when cid is not present*/
+    int tac;           /**Tracing area code (This field should be ignored when cid is not present). */
+    int pci;           /**Physical cell ID. Range: 0 to 503. */
+    int earfcn;        /**E-UTRA absolute radio frequency channel number of the cell. RANGE: 0 TO 65535. */
+    int lenOfMnc;      /**Length of MNC, value range (2,3) */
+    int rsrp;
+    int rsrq;
+}QL_MCM_NW_LTE_CELL_INFO_T;
+
+/** Gets cell information. */
+typedef struct
+{
+    int                 gsm_info_valid;                         /**< Must be set to TRUE if gsm_info is being passed. */
+    int                 gsm_info_num;                           /**< Must be set to the number of elements in entry*/
+    QL_MCM_NW_GSM_CELL_INFO_T    gsm_info[CELL_MAX_NUM];  /**<   GSM cell information (Serving and neighbor. */
+    int                 umts_info_valid;                        /**< Must be set to TRUE if umts_info is being passed. */
+    int                 umts_info_num;                          /**< Must be set to the number of elements in entry*/
+    QL_MCM_NW_UMTS_CELL_INFO_T   umts_info[CELL_MAX_NUM];/**<   UMTS cell information (Serving and neighbor). */
+    int                 lte_info_valid;                         /**< Must be set to TRUE if lte_info is being passed. */
+    int                 lte_info_num;                           /**< Must be set to the number of elements in entry*/
+    QL_MCM_NW_LTE_CELL_INFO_T    lte_info[CELL_MAX_NUM];  /**<   LTE cell information (Serving and neighbor). */
+}QL_NW_CELL_INFO_T;
+
+
+typedef void (*QL_NW_EventHandlerFunc_t)(unsigned int ind_flag, void *ind_msg_buf, unsigned int ind_msg_len, void *contextPtr);
+
+QL_NW_ERROR_CODE ql_nw_init ();
+QL_NW_ERROR_CODE ql_nw_release();
+QL_NW_ERROR_CODE ql_nw_set_config(QL_NW_CONFIG_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_get_config(QL_NW_CONFIG_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_get_nitz_time_info(QL_NW_NITZ_TIME_INFO_T *pt_info);
+QL_NW_ERROR_CODE ql_nw_event_register(unsigned int  bitmask);
+QL_NW_ERROR_CODE ql_nw_get_operator_name(QL_NW_OPERATOR_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_perform_scan(QL_NW_SCAN_RESULT_LIST_INFO_T   *pt_info);
+QL_NW_ERROR_CODE ql_nw_get_reg_status(QL_NW_REG_STATUS_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_set_selection(QL_NW_SELECTION_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_get_selection(QL_NW_SELECTION_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_get_signal_strength(QL_NW_SIGNAL_STRENGTH_INFO_T    *pt_info);
+QL_NW_ERROR_CODE ql_nw_get_cell_info(QL_NW_CELL_INFO_T  *pt_info);
+QL_NW_ERROR_CODE ql_nw_add_event_handler(QL_NW_EventHandlerFunc_t handlerPtr, void* contextPtr);
+QL_NW_ERROR_CODE ql_nw_get_volte_state(VOLTE_STATE *state);
+/* CSQ: just get rssi and ber */
+QL_NW_ERROR_CODE ql_nw_csq_get_signal_strength(QL_NW_CSQ_SIGNAL_STRENGTH_INFO_T    *pt_info);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mbtk/include/ql/ql_oe.h b/mbtk/include/ql/ql_oe.h
new file mode 100755
index 0000000..ad4f7db
--- /dev/null
+++ b/mbtk/include/ql/ql_oe.h
@@ -0,0 +1,41 @@
+/**  
+  @file
+  ql_oe.h
+
+  @brief
+  Include related header file for quectel common api.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+24/07/2019  Nebula.li      create
+03/08/2019  Juson.zhang    add spi and uart head file
+03/08/2019  Carola.zhang   add i2c and gpio head file
+=============================================================================*/
+
+#ifndef _QL_OE_H_
+#define _QL_OE_H_
+
+#include "DSI_ConnectManager.h"
+#include "ql_log.h"
+
+//-------------------------peripheral head file-------------------//
+#include "ql_uart.h"
+#include "ql_spi.h"
+#include "ql_gpio.h"
+#include "ql_i2c.h"
+#include "ql_sms.h"
+
+#endif
diff --git a/mbtk/include/ql/ql_sgmii.h b/mbtk/include/ql/ql_sgmii.h
new file mode 100755
index 0000000..292ab8c
--- /dev/null
+++ b/mbtk/include/ql/ql_sgmii.h
@@ -0,0 +1,162 @@
+/**
+ * @file ql_sgmii.h
+ * @brief Quectel Openlinux SGMII public function declarations.
+ *
+ * @note
+ *
+ * @copyright Copyright (c) 2009-2017 @ Quectel Wireless Solutions Co., Ltd.
+ */
+
+#ifndef __QL_SGMII_H__
+#define __QL_SGMII_H__
+#include "mbtk_type.h"
+
+
+typedef enum {
+	QL_SGMII_AUTONEG_OFF = 0,
+	QL_SGMII_AUTONEG_ON
+} ql_sgmii_autoneg_e;
+
+typedef enum {
+	QL_SGMII_SPEED_10MHZ = 0,
+	QL_SGMII_SPEED_100MHZ,
+	QL_SGMII_SPEED_1000MHZ /* this speed can not support */
+} ql_sgmii_speed_e;
+
+typedef enum {
+	QL_SGMII_DUPLEX_FULL = 0,
+	QL_SGMII_DUPLEX_HALF
+} ql_sgmii_duplex_e;
+
+struct ql_sgmii_info {
+	ql_sgmii_autoneg_e autoneg;
+	ql_sgmii_speed_e speed;
+	ql_sgmii_duplex_e duplex;
+	unsigned long tx_bytes;
+	unsigned long rx_bytes;
+	unsigned long tx_pkts;
+	unsigned long rx_pkts;
+};
+
+/**
+ * Enables the SGMII ethernet module.
+ *
+ * @param None
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ */
+extern int ql_sgmii_enable(void);
+
+/**
+ * Disable the SGMII ethernet module.
+ *
+ * @param None
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ */
+extern int ql_sgmii_disable(void);
+
+/**
+ * Set the SGMII ethernet configuration: the ethernet auto negotiation configuration.
+ *
+ * @param [in]         auto negotiation
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_sgmii_autoneg_set(ql_sgmii_autoneg_e autoneg);
+
+/**
+ * Get the SGMII ethernet configuration: the ethernet auto negotiation configuration.
+ *
+ * @param [out]         auto negotiation
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_sgmii_autoneg_get(ql_sgmii_autoneg_e *autoneg);
+
+/**
+ * Set the SGMII ethernet configuration: the ethernet speed configuration.
+ *
+ * @param [in]         ethernet speed
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_sgmii_speed_set(ql_sgmii_speed_e speed);
+
+/**
+ * Get the SGMII ethernet configuration: the ethernet speed configuration.
+ *
+ * @param [out]         the ethernet current speed
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_sgmii_speed_get(ql_sgmii_speed_e *speed);
+
+/**
+ * Set the SGMII ethernet configuration: the ethernet duplex configuration.
+ *
+ * @param [in]         ethernet duplex
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_sgmii_duplex_set(ql_sgmii_duplex_e duplex);
+
+/**
+ * Get the SGMII ethernet configuration: the ethernet duplex configuration.
+ *
+ * @param [out]         the ethernet current duplex
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_sgmii_duplex_get(ql_sgmii_duplex_e *duplex);
+
+/**
+ * Get the sgmii ethernet information: transmit and receive bytes, transmit and receive packets, speed, duplex.
+ *
+ * @param [out]         the ethernet information
+ *
+ * @return
+ *   On success, 0 is returned.  On error, -1 is returned.
+ *
+ * @dependencies
+ *   the ql_sgmii_enable must be set enable
+ *
+ */
+extern int ql_smgii_info_get(struct ql_sgmii_info *info);
+
+
+#endif /* end of __QL_SGMII_H__ */
diff --git a/mbtk/include/ql/ql_sim.h b/mbtk/include/ql/ql_sim.h
new file mode 100755
index 0000000..38ad65c
--- /dev/null
+++ b/mbtk/include/ql/ql_sim.h
@@ -0,0 +1,840 @@
+/**  
+  @file
+  ql_sim.h
+
+  @brief
+  This file provides the definitions for sim, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+21/08/2019  Nebula.li      create
+=============================================================================*/
+
+#ifndef __QL_SIM_H__
+#define __QL_SIM_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned long UINT32;
+typedef unsigned int UINT;
+
+typedef enum 
+{
+	QL_SIM_SUCCESS,
+	QL_SIM_GENERIC_FAILURE,
+ 	QL_SIM_RADIO_NOT_AVAILABLE,
+    QL_SIM_INCORRECT_PASSWORD,
+    QL_SIM_CARD_NO_INSERTED,
+    QL_SIM_CARD_BUSY,
+    QL_SIM_CARD_BLOCKED,
+}QL_SIM_ERROR_CODE;
+
+
+#define QL_SIM_MCC_LEN      4   /**  Length of the MCC. */
+#define QL_SIM_MNC_MAX      4   /**  Maximum length of the MNC. */
+#define QL_SIM_PLMN_NUM_MAX 24  /**  Maximum number of PLMN data sets. */
+typedef struct 
+{
+    uint8_t mcc[QL_SIM_MCC_LEN];  /**< MCC value in ASCII characters.*/
+    uint8_t mnc[QL_SIM_MNC_MAX];  /**< MNC value in ASCII characters.*/
+}QL_SIM_PLMN_INFO;  
+typedef struct 
+{
+    uint32_t            preferred_operator_list_num;                    /**< Must be set to the number of elements in preferred_operator_list. */
+    QL_SIM_PLMN_INFO    preferred_operator_list[QL_SIM_PLMN_NUM_MAX];   /**< Preferred operator list. */
+}QL_SIM_PREFERRED_OPERATOR_LIST;    /* Message */
+
+#define QL_SIM_PIN_LEN_MAX  16   /**  Maximum length of PIN data. */ 
+#define QUEC_CI_SIM_MAX_CMD_DATA_SIZE  261
+
+typedef struct 
+{
+    uint8_t                     pin_value[QL_SIM_PIN_LEN_MAX];  /*  Value of the PIN */
+}QL_SIM_VERIFY_PIN_INFO;  
+
+typedef struct 
+{
+    uint8_t                     old_pin_value[QL_SIM_PIN_LEN_MAX];  /**< Value of the old PIN as a sequence of ASCII characters. */
+    uint8_t                     new_pin_value[QL_SIM_PIN_LEN_MAX];  /**< Value of the new PIN as a sequence of ASCII characters. */
+}QL_SIM_CHANGE_PIN_INFO;  
+
+typedef struct 
+{
+    uint8_t                     puk_value[QL_SIM_PIN_LEN_MAX];      /**< Value of the PUK as a sequence of ASCII characters. */
+    uint8_t                     new_pin_value[QL_SIM_PIN_LEN_MAX];  /**< Value of the new PIN as a sequence of ASCII characters. */
+}QL_SIM_UNBLOCK_PIN_INFO;  
+
+typedef enum 
+{
+    QL_SIM_STAT_NOT_INSERTED,
+    QL_SIM_STAT_READY,
+    QL_SIM_STAT_SIM_PIN,
+    QL_SIM_STAT_SIM_PUK,
+    QL_SIM_STAT_PH_SIM_LOCK_PIN,
+    QL_SIM_STAT_PH_SIM_LOCK_PUK,
+    QL_SIM_STAT_PH_FSIM_PIN,
+    QL_SIM_STAT_PH_FSIM_PUK,
+    QL_SIM_STAT_SIM_PIN2,
+    QL_SIM_STAT_SIM_PUK2,
+    QL_SIM_STAT_PH_NET_PIN,
+    QL_SIM_STAT_PH_NET_PUK,
+    QL_SIM_STAT_PH_NET_SUB_PIN,
+    QL_SIM_STAT_PH_NET_SUB_PUK,
+    QL_SIM_STAT_PH_SP_PIN,
+    QL_SIM_STAT_PH_SP_PUK,
+    QL_SIM_STAT_PH_CORP_PIN,
+    QL_SIM_STAT_PH_CORP_PUK,
+    QL_SIM_STAT_BUSY,
+    QL_SIM_STAT_BLOCKED,
+    QL_SIM_STAT_UNKNOWN
+}QL_SIM_CARD_STATE;    /**< Card state. */
+typedef enum 
+{
+    QL_SIM_CARD_TYPE_UNKNOWN  = 0,    /**<  Unidentified card type.  */
+    QL_SIM_CARD_TYPE_ICC      = 1,    /**<  Card of SIM or RUIM type.  */
+    QL_SIM_CARD_TYPE_UICC     = 2,    /**<  Card of USIM or CSIM type.  */
+}QL_SIM_CARD_TYPE;  
+
+typedef enum CI_SIM_PRIM
+{
+  CI_SIM_PRIM_EXECCMD_REQ = 1,						/**< \brief Requests to execute a SIM command \details   */
+  CI_SIM_PRIM_EXECCMD_CNF,							/**< \brief Confirms the request to execute a SIM command \details   */
+  CI_SIM_PRIM_DEVICE_IND,								/**< \brief Indicates that the current SIM status changed \details   */
+  CI_SIM_PRIM_PERSONALIZEME_REQ,						/**< \brief Requests that ME personalization be activated, deactivated, disabled, or queried \details   */
+  CI_SIM_PRIM_PERSONALIZEME_CNF,						/**< \brief Confirms the request to activate, deactivate, disable, or query ME personalization \details   */
+  CI_SIM_PRIM_OPERCHV_REQ,							/**< \brief Requests that CHVs be verified, enabled, disabled, changed, unblocked, or queried \details   */
+  CI_SIM_PRIM_OPERCHV_CNF,							/**< \brief Confirms the request to verify, enable, disable, change, unblock, or query CHVs \details   */
+  CI_SIM_PRIM_DOWNLOADPROFILE_REQ,					/**< \brief Requests a download of the profile that shows ME capabilities relevant to SIM Application Toolkit functionality \details The functionality of this primitive is equivalent to using the SIM command TERMINAL PROFILE in the CI_SIM_PRIM_EXECCMD_REQ primitive.
+  *  This primitive saves upper layer effort to build a header for the Terminal Profile SIM command.
+  *  If the pProfile pointer is NULL for this request, the communications interface assumes that the application layer does not support
+  *  SIM Application Toolkit operations.  */
+  CI_SIM_PRIM_DOWNLOADPROFILE_CNF,					/**< \brief Confirms the request to download the profile that shows ME capabilities relevant to SIM Application Toolkit functionality  \details   */
+  CI_SIM_PRIM_ENDATSESSION_IND,						/**< \brief  \details NOT SUPPORTED REMOVE FROM API  */
+  CI_SIM_PRIM_PROACTIVE_CMD_IND,						/**< \brief Indicates a SIMAT proactive command  \details This primitive forwards the SIMAT proactive command with its original syntax. The primitive CI_SIM_PRIM_ENABLE_SIMAT_INDS_REQ enables and disables proactive command indication.  */
+  CI_SIM_PRIM_PROACTIVE_CMD_RSP,						/**< \brief Responds to the SIMAT proactive command  \details The primitive forwards a SIMAT proactive command response from the entity, such as DISPLAY or TERMINAL, that received the proactive command.  */
+  CI_SIM_PRIM_ENVELOPE_CMD_REQ,						/**< \brief Requests that an ENVELOPE command be executed \details   */
+  CI_SIM_PRIM_ENVELOPE_CMD_CNF,						/**< \brief Confirms the request to execute an ENVELOPE command  \details   */
+  CI_SIM_PRIM_GET_SUBSCRIBER_ID_REQ,					/**< \brief Requests the subscriber ID \details   */
+  CI_SIM_PRIM_GET_SUBSCRIBER_ID_CNF,					/**< \brief Confirms the request for the subscriber ID  \details   */
+  CI_SIM_PRIM_GET_PIN_STATE_REQ,						/**< \brief Requests the current PIN state \details   */
+  CI_SIM_PRIM_GET_PIN_STATE_CNF,						/**< \brief Confirms the request for the current PIN state \details   */
+  CI_SIM_PRIM_GET_TERMINALPROFILE_REQ,				/**< \brief Requests the SIMAT terminal profile  \details   */
+  CI_SIM_PRIM_GET_TERMINALPROFILE_CNF,				/**< \brief Confirms the request and returns the SIMAT terminal profile \details   */
+  CI_SIM_PRIM_ENABLE_SIMAT_INDS_REQ,					/**< \brief Requests that SIMAT related indications, such as the proactive SIM command indication and the SIMAT session ended indication, be enabled or disabled  \details   */
+  CI_SIM_PRIM_ENABLE_SIMAT_INDS_CNF,					/**< \brief Confirms the request to enable or disable SIMAT related indications  \details   */
+  CI_SIM_PRIM_LOCK_FACILITY_REQ,						/**< \brief Requests to lock, unlock, or query SIM-related ME  \details   */
+  CI_SIM_PRIM_LOCK_FACILITY_CNF,						/**< \brief Confirms a request to lock, unlock, or query SIM-related ME  \details   */
+  CI_SIM_PRIM_GET_FACILITY_CAP_REQ,					/**< \brief Requests the bitmask of supported SIM-related facility codes \details   */
+  CI_SIM_PRIM_GET_FACILITY_CAP_CNF,					/**< \brief Confirms the request for the bitmask of supported SIM-related facility codes \details   */
+  CI_SIM_PRIM_GET_SIMAT_NOTIFY_CAP_REQ,				/**< \brief Requests SIM Application Toolkit (SIMAT) notification capability information. \details   */
+  CI_SIM_PRIM_GET_SIMAT_NOTIFY_CAP_CNF,				/**< \brief Confirms the request for SIM Application Toolkit (SIMAT) notification capability information \details   */
+  CI_SIM_PRIM_GET_CALL_SETUP_ACK_IND,				/**< \brief Indicates that the SIM Application Toolkit (SIMAT) has initiated an outgoing CALL SETUP operation, and requests confirmation/acknowledgment from the mobile user \details The application returns the required acknowledgment in a CI_SIM_PRIM_GET_CALL_SETUP_ACK_RSP response.  */
+  CI_SIM_PRIM_GET_CALL_SETUP_ACK_RSP,				/**< \brief Responds with an acknowledgment from the mobile user for an outgoing CALL SETUP indication  \details The mobile user may accept (allow) or reject (disallow) the SIMAT initiated CALL SETUP operation.
+*     If the user allows the CALL SETUP, it proceeds. If the user disallows the CALL SETUP, it is aborted.
+*     If the CALL SETUP is allowed to proceed, the MO call progression is managed by the normal call control procedures. See the
+*     CI CC Service Group API definition for more information.  */
+
+  /* service provider name */
+  CI_SIM_PRIM_GET_SERVICE_PROVIDER_NAME_REQ,		/**< \brief Requests the service provider name, as stored on SIM or USIM \details The PIN status is not required to read this information.  */
+  CI_SIM_PRIM_GET_SERVICE_PROVIDER_NAME_CNF,		/**< \brief Confirms the request to get the service provider name, as stored on SIM or USIM \details The service provider name is coded as 7-bit GSM characters, with the most-significant bit of each character set to zero.
+  *  The service provider name pointer is NULL if the result code indicates an error.  */
+
+  /* Message Waiting Information */
+  CI_SIM_PRIM_GET_MESSAGE_WAITING_INFO_REQ,		/**< \brief Requests to get message waiting information stored on SIM or USIM \details The PIN status is required to read this information.  */
+  CI_SIM_PRIM_GET_MESSAGE_WAITING_INFO_CNF,			/**< \brief Confirms the request to get message waiting information stored on SIM or USIM \details If the result code indicates an error, the message waiting status information is not useful.
+  *  There is a difference between the message categories defined for 2G and 3G SIM storage. This is rationalized by the CCI implementation.  */
+  CI_SIM_PRIM_SET_MESSAGE_WAITING_INFO_REQ,			/**< \brief Requests to set message waiting information on SIM or USIM  \details Requires PIN status to write this information. There is a difference between the message categories defined for 2G and 3G SIM storage. This is rationalized by the CCI implementation.  */
+  CI_SIM_PRIM_SET_MESSAGE_WAITING_INFO_CNF,			/**< \brief Confirms a request to set the message waiting information on SIM or USIM \details   */
+
+  /* SIM Service Table */
+  CI_SIM_PRIM_GET_SIM_SERVICE_TABLE_REQ,				/**< \brief Requests to get the SIM Service Table from SIM or USIM  \details The PIN status is required to read this information. If CPHS features are not supported by the handset, this information is unavailable.  */
+  CI_SIM_PRIM_GET_SIM_SERVICE_TABLE_CNF,				/**< \brief Confirms the request to get the SIM Service Table from SIM or USIM \details If CPHS features are not supported by the handset, this information is unavailable.  */
+
+  /* CPHS Customer Service Profile */
+  CI_SIM_PRIM_GET_CUSTOMER_SERVICE_PROFILE_REQ,	/**< \brief Requests to get the CPHS customer service profile from SIM or USIM \details The PIN status is required to read this information. If CPHS features are not supported by the handset, this information is unavailable. */
+  CI_SIM_PRIM_GET_CUSTOMER_SERVICE_PROFILE_CNF,	/**< \brief Confirms the request and returns the CPHS customer service profile from SIM or USIM. \details If CPHS features are not supported by the handset, this information is unavailable.  */
+
+  /* Display Alpha and Icon Identifiers */
+  CI_SIM_PRIM_SIMAT_DISPLAY_INFO_IND,					/**< \brief Indicates to the application that text and optionally an icon should be displayed.
+														 *  The text to be displayed results from a SAT transaction such as SS, SMS, USSD, SS, or send DTMF. \details   */
+
+  /* Default Language */
+  CI_SIM_PRIM_GET_DEFAULT_LANGUAGE_REQ,			/**< \brief Requests the default language stored on the SIM/USIM card \details   */
+  CI_SIM_PRIM_GET_DEFAULT_LANGUAGE_CNF,				/**< \brief Confirms the request to get the default language stored on the SIM/USIM card and returns the first entry in the EF_LP file \details Extract from ETSI TS 102.221: "the language code is a pair of alphanumeric characters, as defined in ISO 639 [30].
+  *  Each alphanumeric character shall be coded on one byte using the SMS default 7-bit coded alphabet as defined in TS 23.038
+  *  ("Man-machine Interface (MMI) of the User Equipment", revision 3.4.0, Doc Number 3GPP TS 22.030)
+  *  with bit 8 set to 0.". 'FF FF' means undefined default language.  */
+
+  /* Generic SIM commands */
+  CI_SIM_PRIM_GENERIC_CMD_REQ,						/**< \brief Requests to send a generic command to the SIM/USIM card
+													 * \details The request reflects the structure of a SIM application protocol data unit (APDU),
+													 * as defined in ETSI 102.221. The 'class of instruction' element is not controlled by the user, comm. use class 0x0 or 0xa depending on the command.
+													 * Note that updating a file using this command only updates the file on the SIM; it does not trigger a REFRESH of the ME memory. */
+  CI_SIM_PRIM_GENERIC_CMD_CNF,						/**< \brief Confirms a request to send a generic command to the SIM or USIM  \details  */
+
+  /* Indication of card type, status and PIN state */
+  CI_SIM_PRIM_CARD_IND,								/**< \brief Indicates that the current SIM/USIM status changed \details This indication is sent each time CI_SIM_PRIM_DEVICE_IND is sent.  */
+
+  CI_SIM_PRIM_IS_EMERGENCY_NUMBER_REQ,				/**< \brief Requests to determine if the specified dial number is an emergency call code \details   */
+  CI_SIM_PRIM_IS_EMERGENCY_NUMBER_CNF,				/**< \brief Confirms the request to determine if the specified number is an emergency call code \details If a SIM card is present, the EF_ECC SIM card file is searched for the specified number. If a SIM card is not present, a default table of possible emergency call codes is searched for the specified number, as per TS 22.101. */
+
+  CI_SIM_PRIM_SIM_OWNED_IND,							/**< \brief Indicates whether the SIM is owned
+														 * \details This indication is sent each time a SIM-OK notification is received
+ * from the protocol stack and indicates that the SIM card can be accessed. SIM owned is TRUE if the IMSI did not change
+ * since the last SIM-OK notification.  */
+  CI_SIM_PRIM_SIM_CHANGED_IND,						/**< \brief Indicates whether the IMSI on the current SIM has changed
+													 * \details  This indication is sent each time a SIM-OK notification is received
+ * from the protocol stack. */
+  CI_SIM_PRIM_DEVICE_STATUS_REQ,						/**< \brief Requests SIM status \details   */
+  CI_SIM_PRIM_DEVICE_STATUS_CNF,						/**< \brief Confirms the request for the current SIM status \details   */
+  CI_SIM_PRIM_READ_MEP_CODES_REQ,			/**< \brief   Requests the MEP codes for a specified category  \details This operation does not require a password.*/
+  CI_SIM_PRIM_READ_MEP_CODES_CNF,			/**< \brief   Confirms the request and returns the MEP codes for the specified category \details */
+  CI_SIM_PRIM_UDP_LOCK_REQ, 					/**< \brief   Requests an activate, deactivate, or query UDP lock  \details  An operation can be done on only one category at a time. A password is required for an unlock operation. */
+  CI_SIM_PRIM_UDP_LOCK_CNF, 					/**< \brief   Confirms the UDP lock request \details */
+  CI_SIM_PRIM_UDP_CHANGE_PASSWORD_REQ,  	/**< \brief   Requests to set a new password for a UDP lock \details */
+  CI_SIM_PRIM_UDP_CHANGE_PASSWORD_CNF, 	/**< \brief   Confirms the request to set a new password for a UDP lock \details */
+  CI_SIM_PRIM_UDP_ASL_REQ,					/**< \brief  Requests to manipulate the UDP authorized SIM list \details */
+  CI_SIM_PRIM_UDP_ASL_CNF,					/**< \brief  Confirms the request to manipulate the UDP authorized SIM list  \details */
+/* Michal Bukai - Virtual SIM support - START */
+   CI_SIM_PRIM_SET_VSIM_REQ,                /**< \brief  Requests to enable virtual SIM
+											 * \details Virtual SIM can be enabled if no SIM is inserted.
+											 * An error is sent if the user tried to enable virtual SIM while a SIM is inserted.
+											 * The application needs to reset the communication subsystem after receiving a confirmation. */
+   CI_SIM_PRIM_SET_VSIM_CNF,                 /**< \brief Confirms setting virtual SIM
+											  * \details Virtual SIM can be enabled if no SIM is inserted.
+											 * An error is sent if the user tried to enable virtual SIM while a SIM is inserted.
+											 * The application needs to reset the communication subsystem after receiving a confirmation. */
+   CI_SIM_PRIM_GET_VSIM_REQ,                 /**< \brief Requests the current setting of the virtual SIM (enabled / disabled) \details*/
+   CI_SIM_PRIM_GET_VSIM_CNF,                 /**< \brief Confirms the request and returns the current setting of the virtual SIM (enabled / disabled) \details*/
+/* Michal Bukai - Virtual SIM support - END */
+/*Michal Bukai - OTA support for AT&T - START*/
+  CI_SIM_PRIM_CHECK_MMI_STATE_IND,	/**< \brief  \details NOT SUPPORTED REMOVE FROM API  */
+  CI_SIM_PRIM_CHECK_MMI_STATE_RSP,	/**< \brief  \details NOT SUPPORTED REMOVE FROM API  */
+/*Michal Bukai - OTA support for AT&T - END*/
+/*Michal Bukai - BT SAP support - START*/
+  CI_SIM_PRIM_BTSAP_CONNECT_REQ,					/**< \brief Requests to start a BT SAP session \details */
+  CI_SIM_PRIM_BTSAP_CONNECT_CNF,					/**< \brief Confirms the request to start a BT SAP session \details */
+  CI_SIM_PRIM_BTSAP_DISCONNECT_REQ, 				/**< \brief Requests to disconnect from a BT SAP session \details */
+  CI_SIM_PRIM_BTSAP_DISCONNECT_CNF, 				/**< \brief Confirms the request to disconnect from a BT SAP session \details */
+  CI_SIM_PRIM_BTSAP_TRANSFER_APDU_REQ,				/**< \brief Requests to transfer APDU to the SIM/USIM \details */
+  CI_SIM_PRIM_BTSAP_TRANSFER_APDU_CNF,				/**< \brief Confirms the request to transfer APDU to the SIM/USIM and may return a response APDU from the SIM/USIM \details */
+  CI_SIM_PRIM_BTSAP_TRANSFER_ATR_REQ,				/**< \brief Requests to get Answer To Reset data from SIM/USIM \details */
+  CI_SIM_PRIM_BTSAP_TRANSFER_ATR_CNF,				/**< \brief Confirms the request to get Answer To Reset data from SIM/USIM \details */
+  CI_SIM_PRIM_BTSAP_SIM_CONTROL_REQ,				/**< \brief Requests to control SIM/USIM status, this command can be used to power off, power on or reset the SIM/USIM \details */
+  CI_SIM_PRIM_BTSAP_SIM_CONTROL_CNF,				/**< \brief Confirms the SIM control request \details */
+  CI_SIM_PRIM_BTSAP_STATUS_IND,						/**< \brief indicates a change in the availably of the subscription module during BT SAP connection \details */
+  CI_SIM_PRIM_BTSAP_STATUS_REQ,						/**< \brief Requests the subscription module availability status during BT SAP connection \details */
+  CI_SIM_PRIM_BTSAP_STATUS_CNF,						/**< \brief Confirms the request and returns the status of the subscription module during BT SAP connection \details */
+  CI_SIM_PRIM_BTSAP_SET_TRANSPORT_PROTOCOL_REQ,		/**< \brief Requests to set transport protocol \details */
+  CI_SIM_PRIM_BTSAP_SET_TRANSPORT_PROTOCOL_CNF,		/**< \brief Confirms the request to set transport protocol \details */
+/*Michal Bukai - BT SAP support - END*/
+/*Michal Bukai - Add IMSI to MEP code group - START*/
+  CI_SIM_PRIM_MEP_ADD_IMSI_REQ,	/**< \brief  Requests to add the current IMSI to MEP SIM /USIM code group
+								* \details This operation requires a password.
+								* This operation requires that SIM/USIM personalization is deactivated.*/
+  CI_SIM_PRIM_MEP_ADD_IMSI_CNF,	/**< \brief Confirms the request to add the current IMSI to MEP SIM /USIM code group. \details   */
+/*Michal Bukai - Add IMSI to MEP code group - END*/
+/*Michal Bukai - SIM Logic CH - NFC\ISIM support - START*/
+  CI_SIM_PRIM_OPEN_LOGICAL_CHANNEL_REQ,		/**< \brief  Requests to open a logical channel that will be used to access the UICC application identified by DFname.  \details The UICC will open a new logical channel; select the application identified by the DFname, and return a session ID that will be used to identify the new channel.*/
+  CI_SIM_PRIM_OPEN_LOGICAL_CHANNEL_CNF,		/**< \brief  Confirms the request to open a logical channel and returns the session ID.  \details */
+  CI_SIM_PRIM_CLOSE_LOGICAL_CHANNEL_REQ,	/**< \brief  Requests to close a logical channel.  \details */
+  CI_SIM_PRIM_CLOSE_LOGICAL_CHANNEL_CNF,	/**< \brief  Confirms the request to close a logical channel.  \details */
+/*Michal Bukai - SIM Logic CH - NFC\ISIM support support - END*/
+/*Michal Bukai - additional SIMAT primitives - START*/
+  CI_SIM_PRIM_SIMAT_CC_STATUS_IND,					/**< \brief Indicates the SIM Application Toolkit (SIMAT) call control status response 
+													* \details If call control service in SIMAT is activated, all dialled digit strings, supplementary service control strings and USSD strings are passed to the UICC before the call setup request, 
+													* the supplementary service operation or the USSD operation is sent to the network.
+													* The SIMAT has the ability to allow, bar or modify the request. 
+													* In addition SIMAT has the ability to replace the request by another operation, for instance call request may be replaced by SS or USSD operation.
+													*/
+  CI_SIM_PRIM_SIMAT_SEND_CALL_SETUP_RSP_IND,		/**< \brief Indicates the response sent to SIM Application Toolkit (SIMAT) after call setup. \details */
+  CI_SIM_PRIM_SIMAT_SEND_SS_USSD_RSP_IND, 			/**< \brief Indicates the response sent to SIM Application Toolkit (SIMAT) after SS or USSD operation. \details */
+  CI_SIM_PRIM_SIMAT_SM_CONTROL_STATUS_IND, 			/**< \brief Indicates the SIM Application Toolkit (SIMAT) short message control status response. 
+													\details If SM control service in SIMAT is activated, all MO short messages are passed to the UICC before the short message is sent to the network.
+													* The SIMAT has the ability to allow, bar or modify the destination address.
+													*/
+  CI_SIM_PRIM_SIMAT_SEND_SM_RSP_IND,				/**< \brief Indicates the response sent to SIM Application Toolkit (SIMAT) after SM operation. \details */
+/*Michal Bukai - additional SIMAT primitives - END*/
+
+/*Michal Bukai - RSAP support - START*/
+  CI_SIM_PRIM_RSAP_CONN_REQ_IND,		/**< \brief  Request to connect to a remote SIM received from the protocol stack \details */
+  CI_SIM_PRIM_RSAP_CONN_REQ_RSP,		/**< \Response to protocol stack request to connect to a remote SIM \details */
+  CI_SIM_PRIM_RSAP_STAT_REQ,			/**< \brief  Request received from a SAP conversion module to update the RSAP card status. 
+										* \details This request is actually an indication from a remote SAP conversion module indicating a status change in the remote connection or card status */
+  CI_SIM_PRIM_RSAP_STAT_CNF,			/**< \brief  Confirms that the update of the remote card status was received by the protocol stack \details */
+  CI_SIM_PRIM_RSAP_DISCONN_REQ_IND,		/**< \brief  Request to disconnect from a remote SIM received from the protocol stack \details */
+  CI_SIM_PRIM_RSAP_DISCONN_REQ_RSP,		/**< \Response to protocol stack request to disconnect from a remote SIM \details */
+  CI_SIM_PRIM_RSAP_GET_ATR_IND,			/**< \brief Request to get ATR from a remote SIM received from the protocol stack \details */
+  CI_SIM_PRIM_RSAP_GET_ATR_RSP,			/**< \brief Response from a remote SIM with the ATR APDU \details */
+  CI_SIM_PRIM_RSAP_GET_STATUS_REQ_IND,	/**< \brief  Request from the protocol stack to get the RSAP connection status. 
+										* \details The request is answered by CI_SIM_PRIM_RSAP_CONN_STAT_REQ */
+
+  CI_SIM_PRIM_RSAP_SET_TRAN_P_REQ_IND,	/**< \brief Request from the protocol stack to change the transport protocol of the remote SIM \details */
+  CI_SIM_PRIM_RSAP_SET_TRAN_P_REQ_RSP,	/**< \brief Response to a protocol stack request to change the transport protocol of the remote SIM.
+										* \details If the requested transport protocol is supported by the remote SIM and by the SAP conversion module, 
+										* the requested transport protocol is selected and the remote SIM is reset.	If the requested transport protocol is not supported, 
+										* SIM status is changed to CARD_NOT_ACC. The request is followed by CI_SIM_PRIM_RSAP_CONN_STAT_REQ, which indicates the new remote SIM status.*/
+  CI_SIM_PRIM_RSAP_SIM_CONTROL_REQ_IND,	/**< \brief  Request from the protocol stack to control the remote SIM status. 
+										* \details This command can be used to power off, power on, or reset the remote SIM */
+  CI_SIM_PRIM_RSAP_SIM_CONTROL_REQ_RSP,	/**< \brief  Response to a protocol stack request to control the remote SIM status. 
+										* \details The response is followed by CI_SIM_PRIM_RSAP_CONN_STAT_REQ, which indicates the new status of the remote SIM.*/
+  CI_SIM_PRIM_RSAP_SIM_SELECT_REQ,		/**< \brief Request to select the local or remote SIM \details */
+  CI_SIM_PRIM_RSAP_SIM_SELECT_CNF,		/**< \brief Confirms the request to select the local or remote SIM \details */
+  CI_SIM_PRIM_RSAP_STATUS_IND,			/**< \brief Indicates that the current SIM/USIM status changed during RSAP connection \details */
+  CI_SIM_PRIM_RSAP_TRANSFER_APDU_IND,	/**< \brief Request from the protocol stack to transfer APDU to the remote SIM \details */
+  CI_SIM_PRIM_RSAP_TRANSFER_APDU_RSP,	/**< \brief Request from the protocol stack to transfer APDU to the remote SIM. 
+										* \details A response APDU is returned if the transfer of APDU is successful.*/
+  /*Michal Bukai - RSAP support - END*/
+
+  CI_SIM_PRIM_DEVICE_RSP, 				/**< \brief Response to CI_SIM_PRIM_DEVICE_RSP.
+										* \details This response is confirms that the CI_SIM_PRIM_DEVICE_RSP has been received and handled. Specially the SIM clock stop level. This indicates the Comm that D2 can be enabled on SIM driver level.*/
+//ICC ID feature
+  CI_SIM_PRIM_ICCID_IND, 				/**< \brief Indicates the content of the EF-ICCID file. This indication is sent at init. The EF-ICCID can be accessed even if PIN is required.*/
+  CI_SIM_PRIM_GET_ICCID_REQ, 			/**< \brief Request to get the content of the EF-ICCID file. Can be sent if ICC is ready.
+										* \details Can be sent when the SIM state is CI_SIM_ST_READY or CI_SIM_ST_INSERTED.	Otherwise the request will fail.*/
+
+  CI_SIM_PRIM_GET_ICCID_CNF,			/**< \brief Confirmation with the ICC id to the request to get the ICC Id.*/
+//ICC ID feature
+  CI_SIM_PRIM_EAP_AUTHENTICATION_REQ,	/**< \brief Requests to exchange EAP packets with the UICC. */
+  CI_SIM_PRIM_EAP_AUTHENTICATION_CNF,	/**< \brief Confirms the EAP authentication request and returns the authentication response */
+
+  CI_SIM_EAP_RETRIEVE_PARAMETERS_REQ, /**< \brief Requests to retrieve EAP parameters from the UICC. */
+  CI_SIM_EAP_RETRIEVE_PARAMETERS_CNF, /**< \brief Confirms the request to retrieve EAP parameters and returns the contents of the
+										* \elementary file corresponding to requested parameter.*/
+
+  CI_SIM_PRIM_GET_NUM_UICC_APPLICATIONS_REQ,/**< \brief Requests to get number of applications available on the UICC. */
+  CI_SIM_PRIM_GET_NUM_UICC_APPLICATIONS_CNF,/**< \brief Confirms the request to get number of applications available on the UICC. */
+
+  CI_SIM_PRIM_GET_UICC_APPLICATIONS_INFO_REQ, /**< \brief Requests to get list of applications available on the UICC. */
+  CI_SIM_PRIM_GET_UICC_APPLICATIONS_INFO_CNF, /**< \brief Confirms the request to get list of applications available on the UICC. */
+  /* ADD NEW COMMON PRIMITIVES HERE, BEFORE 'CI_SIM_PRIM_LAST_COMMON_PRIM' */
+  /*2013.12.11, added by Xili for CQ00051618, begin*/
+  CI_SIM_PRIM_ISIM_AID_IND,                         /**< \brief Indicates the content of the ISIM Aid. This indication is sent at init if it had one. */
+  /*2013.12.11, added by Xili for CQ00051618, end*/
+
+  /* Add by jungle for CQ00057999 on 2014-04-02 Begin */
+  CI_SIM_PRIM_APP_PIN_REQ,
+  CI_SIM_PRIM_APP_PIN_CNF,
+  /* Add by jungle for CQ00057999 on 2014-04-02 End*/
+
+  /*2014.05.08, added by Xili for CQ00060947, begin*/
+  CI_SIM_PRIM_ADMIN_DATA_IND,  
+  /*2014.05.08, added by Xili for CQ00060947, end*/
+
+  /*2015.03.19, mod by Xili for adding ECC list indication, CQ00088196 begin*/
+  CI_SIM_PRIM_ECC_LIST_IND,  
+  /*2015.03.19, mod by Xili for adding ECC list indication, CQ00088196 end*/
+
+  /* Mod by jungle for CQ00089692 on 2015-04-08 Begin */
+  CI_SIM_PRIM_EXEC_LARGE_CMD_CNF,
+  CI_SIM_PRIM_GENERIC_LARGE_CMD_CNF,
+  /* Mod by jungle for CQ00089692 on 2015-04-08 End */
+
+  CI_SIM_PRIM_UPDATE_COUNT_REQ,
+  CI_SIM_PRIM_UPDATE_COUNT_CNF,
+  
+  /* END OF COMMON PRIMITIVES LIST */
+  CI_SIM_PRIM_LAST_COMMON_PRIM
+
+  /* The customer specific extension primitives are added starting from
+  * CI_SIM_PRIM_firstCustPrim = CI_SIM_PRIM_LAST_COMMON_PRIM as the first identifier.
+  * The actual primitive names and IDs are defined in the associated
+  * 'ci_sim_cust_xxx.h' file.
+  */
+
+  /* DO NOT ADD ANY MORE PRIMITIVES HERE */
+
+} _QuecCiSimPrim;
+
+typedef struct 
+{
+    uint8_t                         pin1_num_retries;       /**<   Number of PIN 1 retries. */
+    uint8_t                         puk1_num_retries;       /**<   Number of PUK 1 retries. */
+    uint8_t                         pin2_num_retries;       /**<   Number of PIN 2 retries. */
+    uint8_t                         puk2_num_retries;       /**<   Number of PUK 2 retries. */
+}QL_SIM_CARD_PIN_INFO;  
+ 
+typedef struct 
+{
+    QL_SIM_CARD_TYPE      card_type; // SIM card type
+    QL_SIM_CARD_STATE     card_state;  //SIM card state
+    QL_SIM_CARD_PIN_INFO  card_pin_info; // PIN info
+}QL_SIM_CARD_STATUS_INFO;  
+
+
+#define QL_SIM_DATA_LEN_MAX     255
+typedef struct 
+{
+    uint32_t    data_len;                        /**< Must be set to the number of elements in data. */
+    uint8_t     data[QL_SIM_DATA_LEN_MAX];       /**< Data retrieved from the card. */
+}QL_SIM_CARD_FILE_DATA;  
+ 
+typedef enum 
+{
+    QL_SIM_FILE_TYPE_UNKNOWN      = 0,/**<  Unknown file type  */
+    QL_SIM_FILE_TYPE_TRANSPARENT  = 1,/**< File structure consisting of a sequence of bytes.  */
+    QL_SIM_FILE_TYPE_CYCLIC       = 2,/**< File structure consisting of a sequence of records, each containing the same fixed size in 
+                                                     chronological order. Once all the records have been used, the oldest data is overwritten.  */
+    QL_SIM_FILE_TYPE_LINEAR_FIXED  = 3,    /**< File structure consisting of a sequence of records, each containing the same fixed size.  */
+}QL_SIM_FILE_TYPE;
+
+typedef enum 
+{
+    QL_SIM_FILE_ACCESS_TYPE_ALWAYS      =0,
+    QL_SIM_FILE_ACCESS_TYPE_CHV1        =1,
+    QL_SIM_FILE_ACCESS_TYPE_CHV2        =2,
+    QL_SIM_FILE_ACCESS_TYPE_ADM         =3,
+}QL_SIM_FILE_ACCESS_TYPE;
+
+typedef enum 
+{
+    QL_SIM_FILE_STATUS_INVALID      =0,
+    QL_SIM_FILE_STATUS_EFFECTIVE    =1,
+}QL_SIM_FILE_STATUS;
+
+typedef struct 
+{
+    QL_SIM_FILE_ACCESS_TYPE read_access;
+    QL_SIM_FILE_ACCESS_TYPE update_access;
+}QL_SIM_FILE_ACCESS_INFO;
+
+typedef struct 
+{
+    unsigned int                id;
+    QL_SIM_FILE_TYPE            type;    /**<   File type: */
+    QL_SIM_FILE_ACCESS_INFO     access;    /**<   File access conditions: */
+    QL_SIM_FILE_STATUS          status;    /**<   File status: */
+    unsigned int                size;      /**<   Size of transparent files.*/
+    unsigned int                record_len;    /**<   Size of each cyclic or linear fixed file record.*/
+    unsigned int                record_count;   /**<   Number of cyclic or linear fixed file records.*/
+}QL_SIM_FILE_INFO;  
+
+typedef struct 
+{
+    int sw1;
+    int sw2;
+}QL_SIM_FILE_OPERATION_RET;
+
+typedef struct 
+{ // when write, if phonenum is empty, it means to delete this item specified by index  
+    int          index;  // the record index in phone book
+    uint8_t      username[32];   //  username
+    uint8_t      phonenum[24];   //  Phone number, it can include '+'*/
+}QL_SIM_PHONE_BOOK_RECORD_INFO;
+
+typedef struct
+{
+    int total;      //total number of locations
+    int used;       //used number of locations
+}QL_SIM_PHONEBOOK_STATE;
+
+#define QL_SIM_PHONE_BOOK_RECORDS_MAX_COUNT 20
+typedef struct 
+{
+    int record_count;  //the count of record
+    QL_SIM_PHONE_BOOK_RECORD_INFO record[QL_SIM_PHONE_BOOK_RECORDS_MAX_COUNT]; // the list of record
+}QL_SIM_PHONE_BOOK_RECORDS_INFO;
+
+typedef enum
+{
+    QL_SIM_PHONE_BOOK_STORAGE_DC,
+    QL_SIM_PHONE_BOOK_STORAGE_EN,
+    QL_SIM_PHONE_BOOK_STORAGE_FD,
+    QL_SIM_PHONE_BOOK_STORAGE_LD,
+    QL_SIM_PHONE_BOOK_STORAGE_MC,
+    QL_SIM_PHONE_BOOK_STORAGE_ME,
+    QL_SIM_PHONE_BOOK_STORAGE_MT,
+    QL_SIM_PHONE_BOOK_STORAGE_ON,
+    QL_SIM_PHONE_BOOK_STORAGE_RC,
+    QL_SIM_PHONE_BOOK_STORAGE_SM,
+    QL_SIM_PHONE_BOOK_STORAGE_AP,
+    QL_SIM_PHONE_BOOK_STORAGE_MBDN,
+    QL_SIM_PHONE_BOOK_STORAGE_MN,
+    QL_SIM_PHONE_BOOK_STORAGE_SDN,
+    QL_SIM_PHONE_BOOK_STORAGE_ICI,
+    QL_SIM_PHONE_BOOK_STORAGE_OCI,
+}QL_SIM_PHONE_BOOK_STORAGE;
+
+
+
+typedef enum 
+{
+    QL_SIM_CARD_STATUS_UPDATE_EVENT   = 0,    /**< Card status update event.  */
+    
+}QL_SIM_NFY_MSG_ID;  
+
+typedef void (*QL_SIM_CardStatusIndMsgHandlerFunc_t)   
+(    
+    QL_SIM_NFY_MSG_ID     msg_id,
+    void                  *pv_data,
+    int                   pv_data_len,
+    void                  *contextPtr    
+);
+
+
+QL_SIM_ERROR_CODE ql_sim_init();
+
+QL_SIM_ERROR_CODE ql_sim_release();
+
+/* Add callback function if anything changed specified by the mask in QL_LOC_Set_Indications*/
+QL_SIM_ERROR_CODE ql_sim_add_event_handler(QL_SIM_CardStatusIndMsgHandlerFunc_t handlerPtr, void* contextPtr);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_get_imsi
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the IMSI (for 3GPP)
+    or IMSI_M (for 3GPP2) from the SIM in ASCII form
+
+    @return
+    void
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_imsi
+(
+    uint8_t   *imsi,      ///< [OUT] IMSI buffer
+    size_t    imsiLen     ///< [IN] IMSI buffer length
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_get_iccid
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the ICCID from
+    SIM in ASCII form
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_iccid
+(
+    uint8_t    *iccid,    ///< [OUT] ICCID
+    size_t     iccidLen   ///< [IN] ICCID buffer length
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  QL_SIM_GetPhoql_sim_get_phonenumberneNumber
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the device phone
+    number from MSISDN (for 3GPP) or MDN (for 3GPP2) from the SIM in
+    ASCII form
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_phonenumber
+(
+    uint8_t   *phone_num, ///< [OUT] phone number
+    size_t    phoneLen    ///< [IN] phone number buffer length
+);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_get_operator_plmn_list
+
+===========================================================================*/
+/*
+    @brief
+    Function sends multiple record based read commands to the modem
+    to retrieve a list of operator preffered PLMN.
+
+    @note
+    Function should only be called for SIM/USIM
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_operator_plmn_list
+(
+    QL_SIM_PREFERRED_OPERATOR_LIST      *pt_info    ///< [OUT] Preferred operator list
+);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_verify_pin
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to verify either PIN1 or PIN2
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_verify_pin
+(
+    QL_SIM_VERIFY_PIN_INFO      *pt_info   // [IN] PIN/PIN2
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_change_pin
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to change the value of
+    either PIN
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_change_pin
+(
+    QL_SIM_CHANGE_PIN_INFO      *pt_info   // [IN] PIN 
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_unblock_pin
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to unblock a PIN1 or PIN2 that
+    has been blocked
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_unblock_pin
+(
+    QL_SIM_UNBLOCK_PIN_INFO     *pt_info   // [IN] input PUK/PUK2 and new PIN/PIN2
+);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_enable_pin
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to enable PIN
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_enable_pin
+(
+    QL_SIM_VERIFY_PIN_INFO      *pt_info   // [IN] PIN
+);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_disable_pin
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to disable PIN
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_disable_pin
+(
+    QL_SIM_VERIFY_PIN_INFO     *pt_info   // [IN] PIN 
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_get_card_status
+
+===========================================================================*/
+/*
+    @brief
+    Function get sim card status informations
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_card_status
+(
+    QL_SIM_CARD_STATUS_INFO     *pt_info   ///< [OUT] sim card status info output
+);
+
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_get_file_info
+
+===========================================================================*/
+/*
+    @brief
+    Function sends a command to the modem to retrieve the file info
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_file_info
+(
+    unsigned int fileid,
+    QL_SIM_FILE_INFO  *file_info,     // [OUT] output file info
+    QL_SIM_FILE_OPERATION_RET *operation_ret // [OUT] return the operation status code 
+);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_read_file
+
+===========================================================================*/
+/*
+    @brief
+    Function get the data of a EF file.
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_read_file
+(
+    unsigned int fileid,  // EF file id
+    unsigned int index,   // the index of record for a record EF file, the offest of date for a transparent EF file.
+    unsigned int data_max_len, // the max length of output data.
+    QL_SIM_CARD_FILE_DATA  *file_data,     // [OUT] File data
+    QL_SIM_FILE_OPERATION_RET *operation_ret // [OUT] return the operation status code 
+);
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_write_file
+
+===========================================================================*/
+/*
+    @brief
+    Function write data to a EF file.
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_write_file
+(
+    unsigned int fileid, // EF file id
+    int index, // the index of record for a record EF file, the offest of date for a transparent EF file.
+    QL_SIM_CARD_FILE_DATA  *file_data,     ///< [IN] File data of the specified one by pt_info
+    QL_SIM_FILE_OPERATION_RET *operation_ret // [OUT] return the operation status code
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_read_phonebook_record
+
+===========================================================================*/
+/*
+    @brief
+    Function will get the phone book record.
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_read_phonebook_record
+(
+    QL_SIM_PHONE_BOOK_STORAGE storage, //IN the storage position of the phone book
+    int start_index, // the start index of records, 0: read record by username.
+    int end_index, // the end index of records
+    uint8_t *username, // the username in a record, it is valid when start_index is 0
+    QL_SIM_PHONE_BOOK_RECORDS_INFO   *records  // the list of records 
+);
+
+
+/*===========================================================================
+
+  FUNCTION:  ql_sim_write_phonebook_record
+
+===========================================================================*/
+/*
+    @brief
+    Function will write  a record to a phone book.
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_write_phonebook_record
+(
+    QL_SIM_PHONE_BOOK_STORAGE storage, //IN the storage position of the phone book
+    QL_SIM_PHONE_BOOK_RECORD_INFO   *record //IN  a record
+);
+
+
+/*===========================================================================*/
+/*
+    @brief
+    Function will return the state of currently selected phonebook
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_get_phonebook_state(QL_SIM_PHONEBOOK_STATE *state);
+
+
+/*===========================================================================*/
+/*
+    @brief
+    Function will request to select the local or remote SIM
+
+    @return
+    QL_SIM_ERROR_CODE
+*/
+/*=========================================================================*/
+QL_SIM_ERROR_CODE ql_sim_select(UINT service, UINT is_remote);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
diff --git a/mbtk/include/ql/ql_sleep_wakelock.h b/mbtk/include/ql/ql_sleep_wakelock.h
new file mode 100755
index 0000000..e3266d1
--- /dev/null
+++ b/mbtk/include/ql/ql_sleep_wakelock.h
@@ -0,0 +1,31 @@
+#ifndef __QL_SLEEP_WAKELOCK_H__
+#define __QL_SLEEP_WAKELOCK_H__
+#include <stddef.h>
+
+/*
+ * create wakelock, return the file description of the wakelock
+ */
+extern int Ql_SLP_WakeLock_Create(const char *name, size_t len);
+
+/*
+ * lock the wakelock by the file description of the wakelock
+ */
+extern int Ql_SLP_WakeLock_Lock(int fd);
+
+
+/*
+ * unlock the wakelock by the file description of the wakelock
+ */
+extern int Ql_SLP_WakeLock_Unlock(int fd);
+
+/*
+ * destroy the wakelock by the file description of the wakelock
+ */
+extern int Ql_SLP_WakeLock_Destroy(int fd);
+
+/*
+ * Enable/Disable autosleep function
+ */
+extern int Ql_Autosleep_Enable(char enable);
+
+#endif  //__QL_SLEEP_WAKELOCK_H__
diff --git a/mbtk/include/ql/ql_sms.h b/mbtk/include/ql/ql_sms.h
new file mode 100755
index 0000000..cf5c872
--- /dev/null
+++ b/mbtk/include/ql/ql_sms.h
@@ -0,0 +1,196 @@
+/*****************************************************************************
+ *  Copyright Statement:
+ *  --------------------
+ *  This software is protected by Copyright and the information contained
+ *  herein is confidential. The software may not be copied and the information
+ *  contained herein may not be used or disclosed except with the written
+ *  permission of Quectel Co., Ltd. 2016
+ *
+ *****************************************************************************/
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *   ql_sms.h
+ *
+ * Project:
+ * --------
+ *   OpenLinux
+ *
+ * Description:
+ * ------------
+ *   API definition for SMS.
+ *
+ *============================================================================
+ *             HISTORY
+ *----------------------------------------------------------------------------
+ * WHO            WHEN                WHAT
+ *----------------------------------------------------------------------------
+ * Pony.ma       19/09/2019           Create
+ ****************************************************************************/
+
+#ifndef __QL_SMS_H__
+#define __QL_SMS_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define MAX_ADDR_LEN            24
+#define FALSE                   0
+#define TRUE                    1
+
+#define QL_SMS_MIN_LEN          1       
+#define MAX_LONGSMS_SEGMENT     8
+#define MAX_SMS_LENGTH          (160*4)
+#define SMS_BUF_LEN             (MAX_SMS_LENGTH + 32)
+#define MAX_LONGSMS_LENGTH      (160*4*MAX_LONGSMS_SEGMENT)
+#define CI_MAX_COUNT_SMS_OF_SIM 50
+
+
+typedef unsigned char           UINT8;
+typedef unsigned short          UINT16;
+typedef unsigned int            UINT32;
+
+typedef enum{
+	QL_SMS_SUCCESS,
+	QL_SMS_GENERIC_FAILURE,
+	QL_SMS_PRAR_ERROR,
+	QL_GET_RESPONSE_ERROR,
+}QL_SMS_ERROR_CODE;
+
+typedef enum 
+{
+	QL_SMS_RECV_EVENT   = 0,    /**< SMS come event.  */
+	QL_SMS_RECV_INDEX_EVENT,    /**< SMS come event for index.  */
+}QL_SMS_NFY_MSG_ID; 
+
+typedef enum 
+{
+	QL_SMS_MODE_GSM = 0,    //GSM
+    QL_SMS_MODE_UCS2        //UCS2
+}QL_SMS_CODE_MODE;
+
+typedef struct
+{
+	char number[32];
+	char body[280]; // 姣忔潯鏀跺埌鐨勭煭淇¢暱搴︽渶澶т负280
+	char time[32];
+	int  body_len;
+    QL_SMS_CODE_MODE  code_mode;
+	char *pdu_str;
+}QL_SMS_STATUS_INFO;
+
+typedef struct
+{
+	int  item;
+	char *name;
+}ql_sms_item;
+
+typedef void (*QL_SMS_StatusIndMsgHandlerFunc_t)   
+	(    
+	 QL_SMS_NFY_MSG_ID     msg_id,
+	 void                  *pv_data,
+	 int                   pv_data_len,
+	 void                  *contextPtr    
+	);
+
+typedef enum{
+	QL_SMS_ClientInit = 0,
+	QL_SMS_ClientRelease,
+	//QL_SMS_SendSMS,
+	QL_SMS_DeleteSMS,	
+	QL_SMS_SearchSMSTextMessage,
+	QL_SMS_SearchSMSPduMessage,
+	QL_SMS_AddSMSEventHandler,
+	QL_SMS_GetSMSCenterAddress,
+	QL_SMS_SetSMSCenterAddress,
+	QL_SMS_SetSaveLocation,
+	QL_SMS_GetSaveLocation,
+	QL_SMS_SetSMSNotSave,
+	QL_SMS_SetSMSMsgMode,
+	QL_SMS_GetSMSMsgMode,
+	QL_SMS_SetSMSCodeMode,
+	QL_SMS_GetSMSCodeMode,
+	QL_SMS_SetSMSReceiveDealmode,
+	QL_SMS_SendTextSMS,
+	QL_SMS_SendPduSMS,
+	QL_SMS_GetSimNum,
+	QL_SMS_GetIndex,
+	QL_SMS_OptionMax,
+}QL_SMS_OPTION;
+
+typedef struct
+{
+	char mem[5];
+	int  cur_num;  //current sms numbers
+	int  max_nums; //Maximum number of messages that can be stored
+}sms_mem_t;
+
+typedef struct
+{
+	sms_mem_t mem1; //messages to be read and deleted from this memory storage.
+	sms_mem_t mem2; //messages will be written and sent to this memory storage.
+	sms_mem_t mem3; //received messages will be placed in this memory storage if routing to PC is not set.
+}ql_sms_mem_info_t;
+
+typedef struct recvmessage_struct{
+	char num[32];
+	char buf[400];
+	int buflen;	
+}recvmessage;
+typedef struct{
+	int storage_index;					  // 存贮索引
+} ql_sms_recv_index_event_t;
+
+
+typedef struct{
+	int sms_index[CI_MAX_COUNT_SMS_OF_SIM];
+	int count;
+} ql_auto_sms_index;
+
+
+
+
+/* init sms client */
+QL_SMS_ERROR_CODE ql_sms_init();
+/* deinit sms clint */
+QL_SMS_ERROR_CODE ql_sms_release();
+/* send message api */
+//QL_SMS_ERROR_CODE ql_sms_send_msg(uint8_t *destNum,uint8_t *data,size_t dataLen,int sms_type);
+/* get smsc api */
+QL_SMS_ERROR_CODE ql_sms_get_sms_center_address(uint8_t *sms_center_addree);
+/* register sms event header api*/
+QL_SMS_ERROR_CODE ql_sms_add_event_handler(QL_SMS_StatusIndMsgHandlerFunc_t handlerPtr, void* contextPtr);
+/* set smsc api */
+QL_SMS_ERROR_CODE ql_sms_set_sms_center_address(unsigned char *destNum);
+/* delete message api */
+QL_SMS_ERROR_CODE ql_sms_delete_msg(size_t index); 
+/* set sms storage api */
+QL_SMS_ERROR_CODE ql_sms_set_sms_pref_storage(size_t location);
+/* set sms not storage api */
+QL_SMS_ERROR_CODE ql_sms_set_sms_desave();
+QL_SMS_ERROR_CODE ql_set_sms_msg_mode(int messagemode);
+QL_SMS_ERROR_CODE ql_get_sms_msg_mode(int *messagemode);
+QL_SMS_ERROR_CODE ql_set_sms_code_mode(char* codemode);
+QL_SMS_ERROR_CODE ql_get_sms_code_mode(char *codemode);
+QL_SMS_ERROR_CODE ql_sms_get_sms_pref_storage(ql_sms_mem_info_t *mem_info);
+//QL_SMS_ERROR_CODE ql_search_sms_message(int index, recvmessage* payload);
+QL_SMS_ERROR_CODE ql_search_sms_text_message(int index, recvmessage* payload);
+QL_SMS_ERROR_CODE ql_search_sms_pdu_message(int index, recvmessage* payload);
+QL_SMS_ERROR_CODE ql_set_sms_recive_dealmode(int dealmode);
+QL_SMS_ERROR_CODE ql_sms_send_pdu_msg(uint8_t *phone_num,uint8_t *data,int sms_type);
+QL_SMS_ERROR_CODE ql_sms_send_text_msg(uint8_t *phone_num,uint8_t *data,int sms_type);
+QL_SMS_ERROR_CODE ql_sms_get_sim_num(uint8_t *sim_num);
+QL_SMS_ERROR_CODE ql_get_sms_index( int *sms_msg_info_ptr,int *smsnum);
+QL_SMS_ERROR_CODE ql_sms_list_sms(int stat, int index, char *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/mbtk/include/ql/ql_spi.h b/mbtk/include/ql/ql_spi.h
new file mode 100755
index 0000000..d33660b
--- /dev/null
+++ b/mbtk/include/ql/ql_spi.h
@@ -0,0 +1,79 @@
+/**  
+  @file
+  ql_spi.h
+
+  @brief
+  This file provides the definitions for spi driver, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+2019/08/20  Juson          create
+=============================================================================*/
+#ifndef __QL_SPI_H__
+#define __QL_SPI_H__
+
+#define SPI_CPHA		0x01
+#define SPI_CPOL		0x02
+
+typedef enum
+{
+	SPIMODE0  =   (0|0),
+	SPIMODE1  =   (0|SPI_CPHA),
+	SPIMODE2  =   (SPI_CPOL|0),
+	SPIMODE3  =   (SPI_CPOL|SPI_CPHA),
+}SPI_MODE;
+
+typedef enum
+{
+	S_6_5M  =   6500000,
+	S_13M 	=   13000000,
+	S_26M  	=   26000000,
+	S_52M  	=   50000000,
+}SPI_SPEED;
+
+/**
+ * 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);
+
+/**
+ * Function: Ql_SPI_DeInit
+ * Description: spi deinit
+ * Parameters: fd---spi fd
+ * Return:
+ */ 
+int Ql_SPI_DeInit(int fd);
+
+/**
+ * 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);
+
+#endif/* __QL_SPI_H__ */
\ No newline at end of file
diff --git a/mbtk/include/ql/ql_tlv_user.h b/mbtk/include/ql/ql_tlv_user.h
new file mode 100755
index 0000000..a4e710a
--- /dev/null
+++ b/mbtk/include/ql/ql_tlv_user.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ *
+ *  Filename: ql_tlv_user.h
+ *
+ *  Description: flash tlv format param config header file.
+ *
+ *  When        Who         Why
+ *  2019/09/28  juson       Creation of file
+ *
+ *  Notes:
+ *
+ ******************************************************************************/
+#ifndef __QL_TLV_USER_H__
+#define __QL_TLV_USER_H__
+
+typedef enum {
+    SYS_CONFIG_START = 0,
+    SYS_CONFIG_AP_RSTLEVEL_ID,
+    SYS_CONFIG_MODEM_RSTLEVEL_ID,
+    SYS_CONFIG_RECOVERY_ID,
+    SYS_CONFIG_CONSOLE_LOG_ID,
+    SYS_CONFIG_END,
+}SYS_CFG_ID_E;
+
+/* 128bytes */
+typedef struct ql_tlv_struct {
+    SYS_CFG_ID_E type;
+    unsigned int len;
+    char value[120];
+}ql_tlv_t;
+
+int quectel_tlv_write(SYS_CFG_ID_E param_id, ql_tlv_t tlv_data);
+int quectel_tlv_read(SYS_CFG_ID_E param_id, ql_tlv_t *tlv_data);
+int ql_onoff_console_log(unsigned char onoff_flag);
+
+#endif /* __QL_TLV_USER_H__ */
+
+
diff --git a/mbtk/include/ql/ql_uart.h b/mbtk/include/ql/ql_uart.h
new file mode 100755
index 0000000..3808419
--- /dev/null
+++ b/mbtk/include/ql/ql_uart.h
@@ -0,0 +1,89 @@
+/**  
+  @file
+  ql_uart.h
+
+  @brief
+  This file provides the definitions for uart, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+2019/08/20  Juson          create
+=============================================================================*/
+
+#ifndef __QL_UART_H__
+#define __QL_UART_H__
+
+typedef enum {
+    FC_NONE = 0,  // None Flow Control
+    FC_RTSCTS,    // Hardware Flow Control (rtscts)
+    FC_XONXOFF    // Software Flow Control (xon/xoff)
+}Enum_FlowCtrl;
+
+typedef enum {
+    PB_NONE = 0,  //none parity check
+    PB_ODD,       //odd parity check
+    PB_EVEN       //even parity check
+}Enum_ParityBit;
+
+typedef enum {
+    DB_CS5 = 5,
+    DB_CS6 = 6,
+    DB_CS7 = 7,
+    DB_CS8 = 8
+}Enum_DataBit;
+
+typedef enum {
+    SB_1 = 1,
+    SB_2 = 2
+}Enum_StopBit;
+
+typedef enum {
+	B_300 		= 300,
+	B_600 		= 600,
+	B_1200 		= 1200,
+	B_2400 		= 2400,
+	B_4800 		= 4800,
+	B_9600 		= 9600,
+	B_19200 	= 19200,
+	B_38400 	= 38400,
+	B_57600 	= 57600,
+	B_115200 	= 115200,
+	B_230400 	= 230400,
+	B_460800 	= 460800,
+	B_921600	= 921600,
+	B_3000000	= 3000000,
+	B_4000000	= 4000000,
+}Enum_BaudRate;
+
+typedef struct {
+    Enum_BaudRate       baudrate; 
+    Enum_DataBit       	databit;
+    Enum_StopBit       	stopbit;
+    Enum_ParityBit      parity;
+    Enum_FlowCtrl       flowctrl;
+}ST_UARTDCB;
+
+int Ql_UART_Open(const char* port, Enum_BaudRate baudrate, Enum_FlowCtrl flowctrl);
+int Ql_UART_Read(int fd, char* buf, unsigned int buf_len);
+int Ql_UART_Write(int fd, const char* buf, unsigned int buf_len);
+int Ql_UART_SetDCB(int fd, ST_UARTDCB *dcb);
+int Ql_UART_GetDCB(int fd, ST_UARTDCB *dcb);
+int Ql_UART_IoCtl(int fd, unsigned int cmd, void* pValue);
+int Ql_UART_Close(int fd);
+
+#endif /* __QL_UART_H__ */
+
diff --git a/mbtk/include/ql/ql_vcall.h b/mbtk/include/ql/ql_vcall.h
new file mode 100755
index 0000000..c1b0545
--- /dev/null
+++ b/mbtk/include/ql/ql_vcall.h
@@ -0,0 +1,296 @@
+/**
+ *@file     ql_voicecall.h
+ *@date     2017-05-02
+ *@author   
+ *@brief    
+ */
+
+#ifndef __QL_VCALL_H__
+#define __QL_VCALL_H__
+
+#define QL_QMI_VCALL_ECALL_MSD_MAX_LEN 140
+
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Reference returned by Start function and used by End function
+ */
+//--------------------------------------------------------------------------------------------------
+//typedef struct QL_VCALL_Call* ST_VCALL_CallRef;
+typedef int ST_VCALL_CallRef;
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * SIM identifiers.
+ *
+ */
+//--------------------------------------------------------------------------------------------------
+typedef enum
+{
+    E_QL_VCALL_EXTERNAL_SLOT_1,
+    E_QL_VCALL_EXTERNAL_SLOT_2,
+    E_QL_VCALL_EMBEDDED,
+    E_QL_VCALL_REMOTE,
+    E_QL_VCALL_ID_MAX
+}E_QL_VCALL_ID_T;
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Voice call establishment states.
+ */
+//--------------------------------------------------------------------------------------------------
+typedef enum
+{
+    E_QL_VCALL_EVENT_ALERTING = 0,
+   ///< Voice call establishment in progress.
+   ///< Far end is now alerting its user (outgoing call).
+
+    E_QL_VCALL_EVENT_CONNECTED = 1,
+   ///< Call has been established, and is media is active.
+
+    E_QL_VCALL_EVENT_TERMINATED = 2,
+   ///< Call has terminated.
+
+    E_QL_VCALL_EVENT_OFFLINE = 3,
+   ///< NO Service available to try establish a voice call.
+
+    E_QL_VCALL_EVENT_BUSY = 4,
+   ///< Remote party (callee) is busy.
+
+    E_QL_VCALL_EVENT_RESOURCE_BUSY = 5,
+   ///< All local connection resources (lines/channels) are in use.
+
+    E_QL_VCALL_EVENT_CALL_END_FAILED = 6,
+   ///< Call ending failed.
+
+    E_QL_VCALL_EVENT_CALL_ANSWER_FAILED = 7,
+   ///< Call answering failed.
+
+    E_QL_VCALL_EVENT_INCOMING = 8
+   ///< Incoming voice call in progress.
+}E_QL_VCALL_EVENT_T;
+
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Voice call termination reason.
+ */
+//--------------------------------------------------------------------------------------------------
+typedef enum
+{
+    E_QL_VCALL_TERM_NETWORK_FAIL = 0,
+   ///< Network could not complete the call.
+
+    E_QL_VCALL_TERM_BAD_ADDRESS = 1,
+   ///< Remote address could not be resolved.
+
+    E_QL_VCALL_TERM_BUSY = 2,
+   ///< Caller is currently busy and cannot take the call.
+
+    E_QL_VCALL_TERM_LOCAL_ENDED = 3,
+   ///< Local party ended the call.
+
+    E_QL_VCALL_TERM_REMOTE_ENDED = 4,
+   ///< Remote party ended the call.
+
+    E_QL_VCALL_TERM_UNDEFINED = 5
+   ///< Undefined reason.
+}E_QL_VCALL_TerminationReason_t;
+
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Reference type used by Add/Remove functions for EVENT 'QL_VCALL_State'
+ */
+//--------------------------------------------------------------------------------------------------
+//typedef struct QL_VCALL_StateHandler* QL_VCALL_StateHandlerRef_t;
+typedef int QL_VCALL_StateHandlerRef_t;
+
+
+typedef enum
+{
+    E_QL_VCALL_DIRECTION_MO = 1,
+    E_QL_VCALL_DIRECTION_MT = 2
+}E_QL_VCALL_DIRECTION_T;
+
+typedef enum
+{
+    E_QL_VCALL_STATE_ORIGINATING = 1,   //Origination
+    E_QL_VCALL_STATE_INCOMING,          //Incoming
+    E_QL_VCALL_STATE_CONVESATION,       //Conversation
+    E_QL_VCALL_STATE_CC_IN_PROGRESS,    //Call is originating but waiting for call control to complete
+    E_QL_VCALL_STATE_ALERTING,          //Alerting
+    E_QL_VCALL_STATE_HOLD,              //Hold
+    E_QL_VCALL_STATE_WAITING,           //Waiting
+    E_QL_VCALL_STATE_DISCONNECTING,     //Disconnecting
+    E_QL_VCALL_STATE_END,               //End
+    E_QL_VCALL_STATE_SETUP,             //MT call is in setup state in 3GPP
+}E_QL_VCALL_STATE_T;
+
+typedef enum
+{
+    E_QL_VCALL_TYPE_VOICE = 0,      //Voice
+    E_QL_VCALL_TYPE_VOICE_FORCED,   //Avoid modem call classification
+    E_QL_VCALL_TYPE_VOICE_IP,       //Voice over IP
+    E_QL_VCALL_TYPE_VT,             //VideoTelephony call over IP
+    E_QL_VCALL_TYPE_VIDEOSHARE ,    //Videoshare
+    E_QL_VCALL_TYPE_TEST,           //Test call
+    E_QL_VCALL_TYPE_OTAPA,          //OTAPA
+    E_QL_VCALL_TYPE_STD_OTASP,      //Standard OTASP
+    E_QL_VCALL_TYPE_NON_STD_OTASP,  //Nonstandard OTASP
+    E_QL_VCALL_TYPE_EMERGENCY,      //Emergency
+    E_QL_VCALL_TYPE_SUPS,           //Supplementary Service
+    E_QL_VCALL_TYPE_EMERGENCY_IP,   //Emergency VoIP
+    E_QL_VCALL_TYPE_ECALL           //eCall
+}E_QL_VCALL_TYPE_T;
+
+typedef struct
+{
+    uint8_t                 call_id;
+    char                    PhoneNum[20];      ///Telephone number string.  
+    E_QL_VCALL_DIRECTION_T  e_direct;
+    E_QL_VCALL_STATE_T      e_state;
+    E_QL_VCALL_TYPE_T       e_type;
+} vcall_info_t;
+
+typedef enum
+{
+    E_QL_VCALL_ECALL_MANUAL = 5,
+    E_QL_VCALL_ECALL_AUTO = 6
+}E_QL_VCALL_ECALL_CAT_T;
+
+typedef enum 
+{
+    E_QL_VCALL_ECALL_TEST		   	= 0x01, 
+    E_QL_VCALL_ECALL_EMERGENCY     	= 0x02, 
+    E_QL_VCALL_ECALL_RECONFIG		= 0x03, 
+}E_QL_VCALL_ECALL_VARIANT_T;
+
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Handler for voice call state changes.
+ *
+ * @param reference
+ *   Event voice call object reference.
+ * @param identifier
+ *   Identifier of the remote party
+ * @param event
+ *   Voice call event.
+ * @param contextPtr
+ */
+//--------------------------------------------------------------------------------------------------
+typedef void (*QL_VCALL_StateHandlerFunc_t)
+(
+    ST_VCALL_CallRef reference,
+    const char* 	identifier,
+    E_QL_VCALL_STATE_T  event,
+    void* contextPtr
+);
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Add handler function for EVENT 'QL_VCALL_State'
+ *
+ * This event provides information on voice call state changes
+ */
+//--------------------------------------------------------------------------------------------------
+QL_VCALL_StateHandlerRef_t QL_VCALL_AddStateHandler
+(
+    QL_VCALL_StateHandlerFunc_t handlerPtr,
+   ///< [IN]
+
+    void* contextPtr
+   ///< [IN]
+);
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Remove handler function for EVENT 'QL_VCALL_State'
+ */
+//--------------------------------------------------------------------------------------------------
+void QL_VCALL_RemoveStateHandler
+(
+    QL_VCALL_StateHandlerRef_t addHandlerRef
+   ///< [IN]
+);
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Start a voice call.
+ *
+ * @return
+ * - Reference to the voice call (to be used later for releasing the voice call)
+ * - NULL if the voice call could not be processed
+ */
+//--------------------------------------------------------------------------------------------------
+ST_VCALL_CallRef QL_VCALL_Start
+(
+    E_QL_VCALL_ID_T simId,
+    const char* DestinationID
+   ///< [IN] Destination identifier for the voice
+);
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Release a voice call.
+ *
+ * @return
+ * - E_QL_OK if the end of voice call can be processed.
+ * - E_QL_NOT_FOUND if the voice call object reference is not found.
+ */
+//--------------------------------------------------------------------------------------------------
+int QL_VCALL_End
+(
+    ST_VCALL_CallRef reference
+   ///< [IN] Voice call object reference to hang-up.
+);
+
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Answer to incoming voice call.
+ *
+ * @return
+ * - E_QL_OK if the incoming voice call can be answered
+ * - E_QL_NOT_FOUND if the incoming voice call object reference is not found.
+ */
+//--------------------------------------------------------------------------------------------------
+int QL_VCALL_Answer
+(
+    ST_VCALL_CallRef reference
+   ///< [IN] Incoming voice call object reference to answer.
+);
+
+//--------------------------------------------------------------------------------------------------
+/**
+ * Get the termination reason of a voice call reference.
+ *
+ * @return
+ * - E_QL_OK if the termination reason is got
+ * - E_QL_NOT_FOUND if the incoming voice call object reference is not found.
+ * - E_QL_FAULT if the voice call is not terminated.
+ */
+//--------------------------------------------------------------------------------------------------
+int QL_VCALL_GetTerminationReason
+(
+    ST_VCALL_CallRef reference,
+   ///< [IN] Voice call object reference to read from.
+
+    E_QL_VCALL_TerminationReason_t* reasonPtr
+   ///< [OUT] Termination reason of the voice call.
+);
+
+
+int QL_VCALL_Ecall(E_QL_VCALL_ID_T 				simId,
+					char*           			phone_number, 
+                    char* 						ecall_msd,
+                    E_QL_VCALL_ECALL_CAT_T  	emer_cat,
+                    E_QL_VCALL_ECALL_VARIANT_T	eCallModeType, 
+                    ST_VCALL_CallRef   			*reference);	//call id
+
+int QL_VCALL_UpdateMsd(	const char *msd);
+
+
+#endif // __QL_VCALL_H__
+
diff --git a/mbtk/include/ql/ql_voice.h b/mbtk/include/ql/ql_voice.h
new file mode 100755
index 0000000..7d4e038
--- /dev/null
+++ b/mbtk/include/ql/ql_voice.h
@@ -0,0 +1,201 @@
+/**  
+  @file
+  ql_voice.h
+
+  @brief
+  This file provides the definitions for voice, and declares the 
+  API functions.
+
+*/
+/*============================================================================
+  Copyright (c) 2017 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+ =============================================================================*/
+/*===========================================================================
+
+                        EDIT HISTORY FOR MODULE
+
+This section contains comments describing changes made to the module.
+Notice that changes are listed in reverse chronological order.
+
+
+WHEN        WHO            WHAT, WHERE, WHY
+----------  ------------   ----------------------------------------------------
+14/11/2019  gunner.yang      create
+06/01/2020  pony.made        add net_state
+18/02/2020  gale.gao       Add API: imsd get, wait status get, voice unhold;
+=============================================================================*/
+
+#ifndef __QL_VOICE_H__
+#define __QL_VOICE_H__
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum 
+{
+	QL_VOICE_SUCCESS,
+	QL_VOICE_GENERIC_FAILURE,
+ 	QL_VOICE_RADIO_NOT_AVAILABLE,
+}QL_VOICE_ERROR_CODE;
+
+typedef enum{
+    GSM = 0,
+    GSM_COMPACT,
+    GSM_wEGPRS,
+    UTRAN,
+    UTRAN_wHSDPA,
+    UTRAN_wHSUPA,
+    UTRAN_wHSDPA_HSUPA,
+    E_UTRAN,
+    UTRAN_HSPA_PLUS,
+}QL_REG_STATE;
+
+typedef enum{
+    REASON_INVALID=-1,
+    REASON_UNCONDITIONAL =0,
+    REASON_DEVICE_BUSY =1,
+    REASON_DEVICE_NO_REPLY =2,
+    REASON_DEVICE_UNREACHABLE =3,
+    REASON_DEVICE_ALL_FORWARDING =4,
+    REASON_DEVICE_ALL_CONDITIONAL =5,
+}QL_VOICE_CALL_FW_REASON;
+
+typedef enum{
+    MODE_DISABLE=0,
+    MODE_ENABLE,
+    MODE_QUERY_STATUS,
+    MODE_REGISTRATION,
+    MODE_ERASURE,
+}QL_VOICE_CALL_FW_MODE;
+
+typedef struct
+{
+    int     status;
+    int     fw_class;
+    char    num[20];
+    int     type;
+    char    subaddr[20];
+    int     satype;
+    int     time;
+} ql_voice_call_fw_list_t;
+
+typedef enum {
+    QL_CALL_ACTIVE = 0,
+    QL_CALL_HOLDING = 1,
+    QL_CALL_DIALING = 2,    /* MO call only */
+    QL_CALL_ALERTING = 3,   /* MO call only */
+    QL_CALL_INCOMING = 4,   /* MT call only */
+    QL_CALL_WAITING = 5,     /* MT call only */
+    QL_CALL_OFFERING = 6,	  /*MT call offering (call setup)*/
+    QL_CALL_DISCONNECTING = 7, /*call in disconnect procedure*/
+    QL_CALL_DISCONNECTED = 8, /*call is disconnected*/
+} QL_CallState;
+
+typedef struct
+{
+    int idx;            /*call index, identification number*/
+    int dir;            /*0: mobile originated(MO) call, 1: mobile terminated(MT) call*/
+    int state;          /*define in QL_CallState*/
+    char number[20];    /*string type phone number in format specified by <type>*/
+    int type;           /*type of address octet in interger format(refer TS24.008 subclause 10.5.4.7)*/
+}ql_voice_call_item;
+
+typedef struct
+{
+    int count;
+    ql_voice_call_item items[16];
+}ql_voice_call_list_t;
+/*
+    callbackfunction prototype
+*/
+typedef void (*QL_VOICE_EventHandlerFunc_t)(QL_CallState voice_flag, char *number,void *contextPtr);
+
+QL_VOICE_ERROR_CODE ql_voice_call_init ();
+QL_VOICE_ERROR_CODE ql_voice_call_release();
+
+/*
+    Register voice call event.
+     -handlerPtr    : user_cb
+     -contextPtr    : user_cb_data
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_event_register(QL_VOICE_EventHandlerFunc_t handlerPtr, void* contextPtr);
+
+
+/*
+    Phone call.
+     -call_num   : dst phone number
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_start(char* call_num);
+
+
+/*
+    Put through.
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_answer();
+QL_VOICE_ERROR_CODE ql_voice_auto_answer(int seconds);
+
+
+/*
+    Hang up.
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_end();
+
+
+/* dfmf call */
+QL_VOICE_ERROR_CODE ql_voice_call_dtmf(char *dtmf,int duration);
+
+/* get voice net state
+ * Just use in call to judge Volte or CS-vioce 
+ * regstate: 
+ * 		7	-> Volte call
+ * 		else	-> CS call
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_get_regstate(int* regstate);
+
+/* set imsd value
+    1: open votle
+    0: close votle
+ */
+QL_VOICE_ERROR_CODE ql_voice_call_set_imsd(int imsd);
+
+/* get imsd value 
+   1: open volte
+   0: close volte
+ */
+QL_VOICE_ERROR_CODE ql_voice_call_get_imsd(int *imsd);
+
+/* set call wait
+    0: close
+    1: open  */
+QL_VOICE_ERROR_CODE ql_voice_call_set_wait(int wait);
+
+/* get call wait status
+    0: close
+    1: open  */
+QL_VOICE_ERROR_CODE ql_voice_call_get_wait(int *wait);
+
+/* hold the voice */
+QL_VOICE_ERROR_CODE ql_voice_call_hold();
+
+/* unhold the voice */
+QL_VOICE_ERROR_CODE ql_voice_call_unhold();
+
+QL_VOICE_ERROR_CODE ql_voice_call_fw_set(QL_VOICE_CALL_FW_REASON reason, QL_VOICE_CALL_FW_MODE mode, char *num);
+
+QL_VOICE_ERROR_CODE ql_voice_call_fw_query(QL_VOICE_CALL_FW_REASON reason, ql_voice_call_fw_list_t *resp_data);
+
+/**
+ * get the current call list, same as AT+CLCC
+*/
+QL_VOICE_ERROR_CODE ql_voice_call_get_current_list(ql_voice_call_list_t *resp_data);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mbtk/include/ql/ql_wifi.h b/mbtk/include/ql/ql_wifi.h
new file mode 100755
index 0000000..a5f97d7
--- /dev/null
+++ b/mbtk/include/ql/ql_wifi.h
@@ -0,0 +1,652 @@
+/**
+ * @file ql_wifi.h
+ * @brief Quectel Openlinux WiFi public function declarations.
+ * 
+ * @note 
+ *
+ * @copyright Copyright (c) 2009-2017 @ Quectel Wireless Solutions Co., Ltd.
+ */
+/*================================================================
+  Copyright (c) 2018 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
+  Quectel Wireless Solution Proprietary and Confidential.
+=================================================================*/
+
+/*=====================================================================
+  
+                         EDIT HISTORY FOR MODULE
+
+  This section contains comments describing changes made to the module.
+  Notice that changes are listed in reverse chronological order.
+
+  WHEN             WHO         WHAT, WHERE, WHY
+  ------------     -------     ----------------------------------------
+  11/20/2011       Paddy        Initial creation.
+
+=======================================================================*/
+
+#ifndef __QL_WIFI_H__
+#define __QL_WIFI_H__
+
+#include <stdbool.h>
+#include <netinet/in.h>
+
+#define QL_WIFI_AP_AUTH_OPEN                  "none"
+#define QL_WIFI_AP_AUTH_WPA_PSK               "psk"
+#define QL_WIFI_AP_AUTH_WPA2_PSK              "psk2"
+#define QL_WIFI_AP_AUTH_WPA_WPA2_PSK          "psk-mixed"
+
+#define QL_WIFI_AP_AUTH_WPA_PAIRWISE_TKIP     "tkip"
+#define QL_WIFI_AP_AUTH_WPA_PAIRWISE_AES      "aes"
+#define QL_WIFI_AP_AUTH_WPA_PAIRWISE_BOTH     "tkip+aes"
+
+#define QL_WIFI_AP_BANDWIDTH_20MHZ             "HT20"
+#define QL_WIFI_AP_BANDWIDTH_40MHZ             "HT40-"
+#define QL_WIFI_AP_BANDWIDTH_80MHZ             "HT40+"
+
+#define QL_WIFI_AP_MODE_80211B                "11b"
+#define QL_WIFI_AP_MODE_80211BG               "11bg"
+#define QL_WIFI_AP_MODE_80211BGN              "11bgn"
+
+
+typedef enum {
+	WIFI_WORK_MODE_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.	Do not change or use*/
+	WIFI_WORK_MODE_AP_V01 = 0, 
+	WIFI_WORK_MODE_STA_V01 = 1, 
+	WIFI_WORK_MODE_AP_STA_V01 = 2, 
+	WIFI_WORK_MODE_AP_AP_V01 = 3, 
+	WIFI_WORK_MODE_MAX_V01 = 4, 
+	WIFI_WORK_MODE_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}wifi_work_mode_e_v01;
+	
+typedef enum {
+	WIFI_IEEE80211_MODE_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.  Do not change or use*/
+	WIFI_MODE_11A_V01 = 0, 
+	WIFI_MODE_11AN_V01 = 1, 
+	WIFI_MODE_11B_V01 = 2, 
+	WIFI_MODE_11BG_V01 = 3, 
+	WIFI_MODE_11BGN_V01 = 4, 
+	WIFI_MODE_11AC_V01 = 5, 
+	WIFI_IEEE80211_MODE_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}wifi_ieee80211_mode_e_v01;;
+
+
+	
+typedef enum {
+	WIFI_BANDWIDTH_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.  Do not change or use*/
+	WIFI_BANDWIDTH_20MHZ_V01 = 0, 
+	WIFI_BANDWIDTH_40MHZ_V01 = 1, 
+	WIFI_BANDWIDTH_80MHZ_V01 = 2, 
+	WIFI_BANDWIDTH_160MHZ_V01 = 3, 
+	WIFI_BANDWIDTH_MAX_V01 = 4, 
+	WIFI_BANDWIDTH_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}wifi_bandwidth_e_v01;
+
+typedef enum {
+	WIFI_AUTH_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.  Do not change or use*/
+	WIFI_AUTH_OPEN_V01 = 0, 
+	WIFI_AUTH_WEP_V01 = 1, 
+	WIFI_AUTH_WPA_PSK_V01 = 2, 
+	WIFI_AUTH_WPA2_PSK_V01 = 3, 
+	WIFI_AUTH_WPA_WPA2_PSK_BOTH_V01 = 4, 
+	WIFI_AUTH_WPA_V01 = 5, 
+	WIFI_AUTH_WPA2_V01 = 6, 
+	WIFI_AUTH_WPA_WPA2_BOTH_V01 = 7, 
+	WIFI_AUTH_WPS_V01 = 8, 
+	WIFI_AUTH_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}wifi_auth_e_v01;
+/**
+    @}
+  */
+
+/** @addtogroup ql_manager_access_msgr_wifi_qmi_enums
+    @{
+  */
+typedef enum {
+	WIFI_WPA_PAIRWISE_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.  Do not change or use*/
+	WIFI_AUTH_WPA_PAIRWISE_TKIP_V01 = 0, 
+	WIFI_AUTH_WPA_PAIRWISE_AES_V01 = 1, 
+	WIFI_AUTH_WPA_PAIRWISE_BOTH_V01 = 2, 
+	WIFI_WPA_PAIRWISE_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}wifi_wpa_pairwise_e_v01;
+
+typedef enum {
+    QL_WIFI_EVENT_ENABLE_STATUS = 0,
+    QL_WIFI_EVENT_DISABLE_STATUS,
+    QL_WIFI_EVENT_AP_STATION,
+    QL_WIFI_EVENT_STA_STATUS,
+    QL_WIFI_EVENT_STA_SCAN_DONE,
+} ql_wifi_event_type_e;
+
+typedef enum {
+    QL_WIFI_STATUS_ENABLE = 0,
+    QL_WIFI_STATUS_DISABLE,
+    QL_WIFI_STATUS_ERR_DRIVER,
+    QL_WIFI_STATUS_ERR_SOFTWARE,
+} ql_wifi_status_e;
+
+typedef enum {
+    QL_WIFI_STATION_DISABLE = 0,    /* WiFi station is not enable */
+    QL_WIFI_STATION_CONNECTED,      /* WiFi station is connected hotspot */
+    QL_WIFI_STATION_DISCONNECTED    /* WiFi station is disconnect hotspot */
+} ql_wifi_station_status_e;
+
+typedef struct {
+    ql_wifi_event_type_e id;
+    union {
+        /* the QL_WIFI_ENABLE_STATUS or QL_WIFI_DISABLE_STATUS event */
+        ql_wifi_status_e status;
+        struct {
+            /* 
+             * If connected is true, the station is connected wifi hotspot.
+             * If connected is false, the station is disconnected wifi hotspot.
+             */
+            bool connected;
+            unsigned char mac[6];
+        } ap_sta_info;
+        ql_wifi_station_status_e sta_status;
+    };
+} ql_wifi_event_s;
+
+typedef void (*wifi_event_handle)(ql_wifi_event_s *event, void *arg);
+
+typedef enum {
+    QL_WIFI_WORK_MODE_STA = 0,      /* WiFi is in STA Mode */
+    QL_WIFI_WORK_MODE_AP0,          /* WiFi is in AP Mode */
+    QL_WIFI_WORK_MODE_AP0_STA,      /* WiFi is in AP/STA Mode */
+    QL_WIFI_WORK_MODE_AP0_AP1       /* WiFi is in AP/AP Mode */
+} ql_wifi_work_mode_e;
+
+typedef enum {
+    QL_WIFI_AP_INDEX_AP0 = 0,       /* Index 0 of AP/AP-STA/AP-AP Mode */
+    QL_WIFI_AP_INDEX_AP1            /* Index 1 of AP/AP-STA/AP-AP Mode */
+} ql_wifi_ap_index_e;
+
+typedef enum {
+    QL_WIFI_MODE_80211B = 0,        /* IEEE 802.11b (2.4 GHz) */
+    QL_WIFI_MODE_80211BG,           /* IEEE 802.11bg (2.4 GHz) */
+    QL_WIFI_MODE_80211BGN,          /* IEEE 802.11bgn (2.4 GHz) */
+    QL_WIFI_MODE_80211A,            /* IEEE 802.11a (5 GHz) */
+    QL_WIFI_MODE_80211AN,           /* IEEE 802.11an (5 GHz) */
+    QL_WIFI_MODE_80211AC            /* IEEE 802.11ac (5 GHz) */
+} ql_wifi_mode_type_e;
+
+typedef enum {
+    QL_WIFI_BANDWIDTH_HT20 = 0,    
+    QL_WIFI_BANDWIDTH_HT40,
+    QL_WIFI_BANDWIDTH_HT80
+} ql_wifi_bandwidth_type_e;
+
+typedef enum {
+    QL_WIFI_SSID_HIDE_DISABLE = 0,    
+    QL_WIFI_SSID_HIDE_ENABLE,
+} ql_wifi_ssidhide_type_e;
+
+typedef enum {
+    QL_WIFI_AUTH_OPEN = 0,             /* Open */
+    QL_WIFI_AUTH_WPA_PSK,              /* WPA Personal */
+    QL_WIFI_AUTH_WPA2_PSK,             /* WPA2 Personal */
+    QL_WIFI_AUTH_WPA_WPA2_PSK_BOTH,    /* WPA&WPA2 Personal */
+} ql_wifi_auth_e;
+
+typedef enum {
+    QL_WIFI_AUTH_WPA_PAIRWISE_AUTO = 0,    /* contain TKIP and AES */
+    QL_WIFI_AUTH_WPA_PAIRWISE_TKIP,
+    QL_WIFI_AUTH_WPA_PAIRWISE_AES
+} ql_wifi_auth_wpa_psk_e;
+
+typedef struct {
+    int auth;
+    union {
+        struct {
+            int default_index;
+            char passwd[4][64];
+        } wep;
+
+        struct {
+            short pairwise;
+            char passwd[64];
+            int group_rekey;
+        } wpa_psk;
+    };
+} ql_wifi_ap_auth_s;
+
+
+typedef enum {
+	WIFI_IDX_AP_0 = 1,
+	WIFI_IDX_AP_1,
+	WIFI_IDX_STA_0
+} wifi_index_e;
+
+typedef enum {
+	WIFI_WORK_MODE_AP = 0,
+	WIFI_WORK_MODE_STA,
+	WIFI_WORK_MODE_AP_STA,
+	WIFI_WORK_MODE_AP_AP,
+	WIFI_WORK_MODE_MAX
+} wifi_work_mode_e;
+
+typedef enum {
+	WIFI_START = 0,
+	WIFI_STOP,
+	WIFI_RESTART,
+} wifi_active_e;
+
+typedef enum {
+	WIFI_MODE_11A = 0,
+	WIFI_MODE_11AN,
+	WIFI_MODE_11B,
+	WIFI_MODE_11BG,
+	WIFI_MODE_11BGN,
+	WIFI_MODE_11AC
+} wifi_ieee80211_mode_e;
+
+typedef enum {
+	WIFI_BANDWIDTH_20MHZ = 0,
+	WIFI_BANDWIDTH_40MHZ,
+	WIFI_BANDWIDTH_80MHZ,
+	WIFI_BANDWIDTH_160MHZ,
+	WIFI_BANDWIDTH_MAX,
+} wifi_bandwidth_e;
+
+typedef enum {
+	WIFI_AUTH_OPEN = 0,
+	WIFI_AUTH_WEP,
+	WIFI_AUTH_WPA_PSK,
+	WIFI_AUTH_WPA2_PSK,
+	WIFI_AUTH_WPA_WPA2_PSK_BOTH,
+	WIFI_AUTH_WPA,
+	WIFI_AUTH_WPA2,
+	WIFI_AUTH_WPA_WPA2_BOTH,
+	WIFI_AUTH_WPS
+} wifi_auth_e;
+
+typedef enum {
+	WIFI_AUTH_WPA_PAIRWISE_TKIP = 0,
+	WIFI_AUTH_WPA_PAIRWISE_AES,
+	WIFI_AUTH_WPA_PAIRWISE_BOTH
+} wifi_wpa_pairwise_e;
+
+typedef enum {
+	WIFI_SSID_HIDE_DISABLE = 0,
+	WIFI_SSID_HIDE_ENABLE
+} wifi_ssid_hide_state_e;
+
+
+struct _auth {
+	unsigned char auth;
+	struct {
+		unsigned char pairwise;
+		unsigned char group_rekey;
+		unsigned char passwd[64];
+	} wpa_psk;
+	
+};
+
+
+typedef enum {
+	WIFI_INDEX_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.  Do not change or use*/
+	WIFI_IDX_AP_0_V01 = 1, 
+	WIFI_IDX_AP_1_V01 = 2, 
+	WIFI_IDX_STA_0_V01 = 3, 
+	WIFI_INDEX_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}wifi_index_e_v01;
+
+typedef enum {
+	RTK_WIFI_IEEE80211_MODE_E_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum.  Do not change or use*/
+	RTK_WIFI_WORKMODE_11B_V01 = 1, 
+	RTK_WIFI_WORKMODE_11BG_V01 = 3, 
+	RTK_WIFI_WORKMODE_11BGN_V01 = 11, 
+	RTK_WIFI_IEEE80211_MODE_E_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum.  Do not change or use*/
+}rtk_wifi_ieee80211_mode_e_v01;
+
+typedef enum {
+    QL_WIFI_AUTH_OPEN_V01 = 0,             /* Open */
+    QL_WIFI_SHARED_KEY,              /* Shared key */
+    QL_WIFI_AUTO                   /* Auto */
+} ql_wifi_auth_type_e;
+
+typedef enum {
+    QL_WIFI_ENCRYPT_TKIP = 2,           /* TKIP */
+    QL_WIFI_ENCRYPT_AES = 8,        /* AES */
+    QL_WIFI_ENCRYPT_TKIP_AES_MIXED = 10     /* TKIP & AES MIXED */
+} ql_wifi_encrypt_mode_e;
+
+typedef enum {
+    QL_WIFI_PSK_DISABLE = 0,    /* Encrypt disable */
+    QL_WIFI_PSK_WPA,            /* WPA */
+    QL_WIFI_PSK_WPA2,           /* WPA2 */
+    QL_WIFI_PSK_WPA_WPA2,       /* WPA-WPA2 */
+} ql_wifi_psk_enable_e;
+
+
+
+#define QL_WIFI_MAX_STA_NUM 16
+	
+	struct ql_mgmt_client_wifi_work_mode {
+		/*
+		 * WiFi work mode support AP, STA, AP+STA, AP-AP
+		 */
+		wifi_work_mode_e work_mode;
+	};
+	
+	struct ql_mgmt_client_wifi_enable {
+		bool state;
+	};
+	
+	struct ql_mgmt_client_wifi_country_code {
+		char country_code[2];
+	};
+	
+	struct ql_mgmt_client_wifi_mode {
+		wifi_index_e id;
+		wifi_ieee80211_mode_e mode;
+	};
+	
+	struct ql_mgmt_client_wifi_channel {
+		wifi_index_e id;
+		int channel;
+	};
+	
+	struct ql_mgmt_client_wifi_essid {
+		wifi_index_e id;
+		char ssid[32];
+	};
+	
+	struct ql_mgmt_client_wifi_ssid_hide {
+		wifi_index_e id;
+		wifi_ssid_hide_state_e state;
+	};
+	
+	struct ql_mgmt_client_wifi_bandwidth {
+		wifi_index_e id;
+		wifi_bandwidth_e bandwidth;
+	};
+	
+	struct ql_mgmt_client_wifi_max_sta {
+		wifi_index_e id;
+		int num;
+	};
+
+	
+	struct ql_mgmt_client_wifi_active {
+		wifi_index_e_v01 id;
+		unsigned char action_type;
+	};
+	
+	struct ql_mgmt_client_wifi_auth {
+		wifi_index_e id;
+		wifi_auth_e auth;
+		union {
+			struct {
+				int default_index;
+				char password[4][64];
+			} wep;
+			struct {
+				wifi_wpa_pairwise_e pairwise;
+				char password[64];
+				int group_rekey;
+			} wpa_psk;
+		};
+	};
+	
+	struct ql_mgmt_client_wifi_rssi {
+		wifi_index_e id;
+		int rssi;
+	};
+	
+	struct ql_mgmt_client_wifi_sta_info {
+		int count;
+		struct {
+			int ip;
+			char mac[6];
+			char hostname[32];
+			char ssid[32];
+			int uptime;
+			long long tx_bytes;
+			long long rx_bytes;
+		} sta[QL_WIFI_MAX_STA_NUM];
+	};
+	typedef struct{
+		struct ql_mgmt_client_wifi_enable enable;
+	
+	
+	}ql_mgmt_client_wifi_s_test;
+	
+	typedef struct {
+		union {
+			struct ql_mgmt_client_wifi_work_mode work_mode;
+			struct ql_mgmt_client_wifi_enable enable;
+			struct ql_mgmt_client_wifi_country_code country_code;
+			struct ql_mgmt_client_wifi_mode mode;
+			struct ql_mgmt_client_wifi_channel channel;
+			struct ql_mgmt_client_wifi_essid ssid;
+			struct ql_mgmt_client_wifi_ssid_hide ssid_hide;
+			struct ql_mgmt_client_wifi_bandwidth bandwidth;
+			struct ql_mgmt_client_wifi_max_sta max_sta;
+			struct ql_mgmt_client_wifi_active active;
+			struct ql_mgmt_client_wifi_auth auth;
+			struct ql_mgmt_client_wifi_rssi rssi;
+			struct ql_mgmt_client_wifi_sta_info sta_info;
+		};
+	} ql_mgmt_client_wifi_s;
+
+
+extern int ql_wifi_enable(void);
+
+/**
+ * Disables the WLAN. This function removes the kernel module for the Wi-Fi driver.
+ *
+ * @param None
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_disable(void);
+
+/**
+ * Create thread to enables the WLAN. This function enables the WLAN based on the hostpad or wpa_supplicant 
+ * configuration provided. This function inserts the WLAN kernel module and advertises the SSID.
+ * 
+ * @param None
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+
+
+extern int ql_wifi_status_get(ql_wifi_status_e *status);
+
+/**
+ * Set the WiFi configuration: WiFi work mode configuration.
+ *
+ * @param [in]   WiFi work mode
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ * @dependencies
+ *   ql_wifi_disable is must be disable
+ *
+ */
+
+extern int ql_wifi_ap_ssid_set(ql_wifi_ap_index_e idx, char *ssid);
+
+/**
+ * Get the WiFi configuration: the hotspot ssid mode configuration.
+ *
+ * @param [in]    Index of AP mode
+ * @param [out]   the hotspot ssid name
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_ssid_get(ql_wifi_ap_index_e idx, char *ssid);
+
+/**
+ * Set the WiFi configuration: hidden hotspot configuration.
+ *
+ * @param [in]    Index of AP mode
+ * @param [in]    If set true, hidden hotspot
+ *                If set false, open hotspot
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_ssid_hide_set(ql_wifi_ap_index_e idx, bool hide);
+
+/**
+ * Get the WiFi configuration: hidden hotspot configuration.
+ *
+ * @param [in]    Index of AP mode
+ * @param [in]    Get the hotspot hidden status
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_ssid_hide_get(ql_wifi_ap_index_e idx, bool *hide);
+
+/**
+ * Set the WiFi configuration: Operation mode configuration, such as 802.11a/b/n/ac.
+ *
+ * @param [in]   Index of AP mode
+ * @param [in]   Operation mode
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_mode_set(ql_wifi_ap_index_e idx, ql_wifi_mode_type_e mode);
+
+/**
+ * Get the WiFi configuration: Operation mode configuration, such as 802.11a/b/n/ac.
+ *
+ * @param [in]    Index of AP mode
+ * @param [out]   Operation mode
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_mode_get(ql_wifi_ap_index_e idx, ql_wifi_mode_type_e *mode);
+
+/**
+ * Set the WiFi configuration: HT or VHT capabilities (20MHz, 40MHz, 80MHz).
+ *
+ * @param [in]   Index of AP mode
+ * @param [in]   Bandwidth
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ * @dependencies
+ *   The WiFi Operation mode must be set 802.11bgn/802.11an/802.11ac.
+ */
+extern int ql_wifi_ap_bandwidth_set(ql_wifi_ap_index_e idx, ql_wifi_bandwidth_type_e bandwidth);
+
+/**
+ * Get the WiFi configuration: HT or VHT capabilities (20MHz, 40MHz, 80MHz).
+ *
+ * @param [in]    Index of AP mode
+ * @param [Out]   Bandwidth
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ * @dependencies
+ *   The WiFi Operation mode must be set 802.11bgn/802.11an/802.11ac.
+ */
+extern int ql_wifi_ap_bandwidth_get(ql_wifi_ap_index_e idx, ql_wifi_bandwidth_type_e *bandwidth);
+
+/**
+ * Set the WiFi configuration: channel number configuration.
+ *
+ * @param [in]   Index of AP mode
+ * @param [in]   Channel number
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ * @dependencies
+ *   1. if WiFi set 2.4GHz, the channel list: 
+ *   0/1/2/3/4/5/6/7/8/9/10/11/12/13/14
+ *   2. if WiFi set 5GHz, the channel list:
+ *   36/40/44/48/52/56/60/64/100/104/108/112/116/120/124/128/132/136/140/144/149/153/157/161/165/175/181 
+ */
+extern int ql_wifi_ap_channel_set(ql_wifi_ap_index_e idx, int channel);
+
+/**
+ * Get the WiFi configuration: channel number configuration.
+ *
+ * @param [in]    Index of AP mode
+ * @param [out]   Channel number
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ * @dependencies
+ *   1. if WiFi set 2.4GHz, the channel list: 
+ *   0/1/2/3/4/5/6/7/8/9/10/11/12/13/14
+ *   2. if WiFi set 5GHz, the channel list:
+ *   36/40/44/48/52/56/60/64/100/104/108/112/116/120/124/128/132/136/140/144/149/153/157/161/165/175/181 
+ */
+extern int ql_wifi_ap_channel_get(ql_wifi_ap_index_e idx, int *channel);
+
+/**
+ * Set the WiFi configuration: IEEE 802.11 specifies two authentication algorithms and WPA/IEEE 802.11i configuration.
+ *
+ * @param [in]   Index of AP mode
+ * @param [in]   authentication configuration
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_auth_set(ql_wifi_ap_index_e idx, ql_wifi_ap_auth_s *auth);
+
+/**
+ * Get the WiFi configuration: IEEE 802.11 specifies two authentication algorithms and WPA/IEEE 802.11i configuration.
+ *
+ * @param [in]   Index of AP mode
+ * @param [out]   authentication configuration
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_auth_get(ql_wifi_ap_index_e idx, ql_wifi_ap_auth_s *auth);
+
+/**
+ * Set the WiFi configuration: Maximum number of stations allowed in station table.
+ *
+ * @param [in]   Index of AP mode
+ * @param [in]   Maximum number of stations
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_max_sta_set(ql_wifi_ap_index_e idx, int max_sta_num);
+
+/**
+ * Get the WiFi configuration: Maximum number of stations allowed in station table.
+ *
+ * @param [in]    Index of AP mode
+ * @param [out]   Maximum number of stations
+ *
+ * @return 
+ *   On success, 0 is returned.  On error, -1 is returned.
+ * 
+ */
+extern int ql_wifi_ap_max_sta_get(ql_wifi_ap_index_e idx, int *max_sta_num);
+
+extern int ql_wifi_set_to_ap(ql_wifi_ap_index_e idx);
+
+extern int ql_wifi_set_to_sta(ql_wifi_ap_index_e idx);
+
+#endif /* end of __QL_WIFI_H__ */
+
diff --git a/mbtk/lynq_lib/Makefile b/mbtk/lynq_lib/Makefile
new file mode 100755
index 0000000..6e5be89
--- /dev/null
+++ b/mbtk/lynq_lib/Makefile
@@ -0,0 +1,41 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/lynq_lib
+
+INC_DIR +=
+	
+LIB_DIR +=
+
+LIBS += -llog -lmbtk_lib
+
+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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/lib/liblynq_lib.so
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
+
diff --git a/mbtk/lynq_lib/src/lynq_audio.c b/mbtk/lynq_lib/src/lynq_audio.c
new file mode 100755
index 0000000..21640ac
--- /dev/null
+++ b/mbtk/lynq_lib/src/lynq_audio.c
@@ -0,0 +1,333 @@
+/**
+ *   \file lynq_audio_api.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  luojian
+ *   \Version: 1.0.0
+ *   \Date: 2022-10-27
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_audio.h"
+
+static int rec_fd = 0;
+static int play_fd = 0;
+static mbtk_audio_handle play_hdl = NULL;
+static mbtk_audio_handle record_hdl = NULL;
+int volume_size = 0;
+pthread_t  paly_thread;
+
+
+void dtmf_cb(char dtmf)
+{
+    printf("%s:%c\n", __FUNCTION__, dtmf);
+}
+
+void audio_volume_cb(int volume)
+{
+	volume_size = volume;
+    printf("%s:%d\n", __FUNCTION__, volume);
+}
+
+int lynq_memscpy
+(
+  void        *dst,
+  int      dst_size,
+  const void  *src,
+  int      src_size
+)
+{
+  if(dst_size == 0 || src_size == 0 || dst == NULL || src == NULL)
+  {
+    return 0;
+  }
+  else
+  {
+    return memcpy( dst, src,src_size);
+  }
+} /* dsatutil_free_memory() */
+
+static int lynq_get_path_name ( const char* path_name,char* path )
+{
+    int i=0;
+    int last = -1;
+    int len = strlen ( path_name );
+    if ( len > 0 )
+    {
+        for ( i=len - 1; i >= 0; i-- )
+        {
+            if ( path_name[i] == '/' )
+            {
+                last = i;
+                break;
+            }
+        }
+        if ( i != -1 )
+        {
+            lynq_memscpy ( path, ( i + 1 ) * sizeof ( char ), path_name, ( i + 1 ) * sizeof ( char ) );
+            printf ( "mbtk_get_path %s", path );
+            return 0;
+        }
+    }
+    return -1;
+}
+
+int lynq_create_audio_dir(const char *dirname)
+{
+    DIR *p_dir;
+    int res = -1, i = 0;;
+	char str[512];
+    strncpy(str, dirname, 512);
+    int len=strlen(str);
+
+    if(NULL == (p_dir = opendir((const char *)dirname)))
+    {
+		for(i=0; i<len; i++ )
+	    {
+	        if( str[i]=='/' )
+	        {
+	            str[i] = '\0';
+	            if( access(str,0)!=0 )
+	            {
+					if(mkdir(dirname, 0777) == 0)
+					{
+					    res = 0;
+					}
+					else
+					{
+					    fprintf(stderr, "create audio dir error \n");
+					    res = -1;
+					}
+	            }
+	            str[i]='/';
+	        }
+	    }
+	    if( len>0 && access(str,0)!=0 )
+	    {
+	        if(mkdir(dirname, 0777) == 0)
+	        {
+	            res = 0;
+	        }
+	        else
+	        {
+	            fprintf(stderr, "create audio dir error \n");
+	            res = -1;
+	        }
+	    }
+    }
+    else
+    {
+        closedir(p_dir);
+        res = 0;
+    }
+    return res;
+}
+
+void lynq_record_cb_func(int cb_result, char* databuf, unsigned int len)
+{
+    int rc;
+ //   printf("lynq_record_cb_func()        len:%d, rec_fd:%d\n", len, rec_fd);
+    if(NULL == databuf)
+    {
+        printf("NULL == databuf\n");
+    }
+
+    if(NULL != databuf && len > 0 && rec_fd > 0)
+    {
+        //for debug:save into file
+        rc = write(rec_fd, databuf, len);
+        if (rc < 0) {
+            printf("%s: error writing to file!\n", __FUNCTION__);
+        } else if (rc < len) {
+            printf("%s: wrote less the buffer size!\n", __FUNCTION__);
+        }
+    }
+}
+
+int lynq_media_rec_audio(const char *path)
+{
+	int ret = 0;
+	char audio_dir[50] ={0};
+	char audio_wav[10] = {0};
+	lynq_get_path_name(path, audio_dir);
+    printf("path:%s, audio_dir:%s\n", path, audio_dir);
+
+    record_hdl = mbtk_audio_open(MBTK_AUTIO_TYPE_IN, 1, 8000, NULL);
+    if (record_hdl == 0)
+    {
+        printf("AudRecorder open error\n");
+        return -1;
+    }
+
+    lynq_create_audio_dir(audio_dir);
+    rec_fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (rec_fd <= 0)
+    {
+        printf("file open error\n");
+        goto err;
+    }
+
+    if(-1 == mbtk_audio_record(record_hdl, lynq_record_cb_func, NULL))
+    {
+        printf("file write error\n");
+        goto err;
+    }
+
+    return 0;
+//    sleep(10);
+err:
+//    Ql_AudRecorder_Close();
+	if(rec_fd > 0)
+	{
+		close(rec_fd);
+		rec_fd = 0;
+	}
+
+	return -1;
+}
+
+
+
+//停止录制音频文件
+void lynq_media_rec_stop_audio(void)
+{
+//	sleep(10);
+    mbtk_audio_close(record_hdl);
+    if(rec_fd > 0)
+    {
+        close(rec_fd);
+        rec_fd = 0;
+    }
+    return 0;
+}
+
+//播放音频文件
+int lynq_media_play_audio_thread_handle(void *argv)
+{
+    char databuf[1024];
+    int size;
+
+    char *path = (char *)argv;
+	printf("lynq_media_play_audio() start \npath:%s\n",path);
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    play_hdl = mbtk_audio_open(MBTK_AUTIO_TYPE_OUT, 1, 8000, NULL);
+    if(NULL == play_hdl)
+        printf("mbtk_audio_open fail\n");
+
+    play_fd = open(path, O_RDWR);
+    if (play_fd <= 0)
+    {
+        printf("file open error\n");
+        goto err;
+    }
+    memset(databuf, 0, sizeof(databuf));
+    while(0 < (size = read(play_fd, databuf, sizeof(databuf))))
+    {
+        if(-1 == mbtk_audio_play_stream(play_hdl, databuf, size))
+            break;
+    }
+    printf("aplay Stream end \n");
+
+err:
+	if(play_fd > 0)
+	{
+		close(play_fd);
+		play_fd = 0;
+	}
+
+	pthread_exit(&paly_thread);
+    mbtk_audio_close(play_hdl);
+	return 0;
+}
+
+//创建线程播放音频文件
+int lynq_media_play_audio(const char *path)
+{
+	int ret = pthread_create(&paly_thread, NULL, lynq_media_play_audio_thread_handle, (void *)path);
+	if (ret != 0) {
+		printf("create thread failed!\n");
+		return -1;
+	}
+
+	pthread_detach(paly_thread);
+	return 0;
+}
+
+
+//停止播放音频文件
+void lynq_media_stop_audio(void)
+{
+	printf("lynq_media_stop_audio()----\n");
+	if(play_fd > 0)
+	{
+	    int ret = pthread_cancel(paly_thread);
+	    if (ret != 0) {
+	        printf("cancle paly_thread fail\n");
+	        return ;
+	    }
+		close(play_fd);
+        play_fd = 0;
+	}
+	mbtk_audio_close(play_hdl);
+}
+
+
+int lynq_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb)
+{
+    if(rec_fd > 0 || play_fd > 0)
+	{
+		printf("rec or play need close\n");
+		return -1;
+	}
+	return mbtk_audio_ubus_client_init(ph_audio, cb);
+}
+
+int lynq_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio)
+{
+    if(rec_fd > 0 || play_fd > 0)
+	{
+		printf("rec or play need close\n");
+		return -1;
+	}
+	return mbtk_audio_ubus_client_deinit(h_audio);
+}
+
+
+int lynq_get_spk_volume(int * volume)
+{
+	mbtk_audio_ubus_volume_get(audio_volume_cb);
+	*volume = volume_size;
+	return 0;
+}
+
+
+int lynq_set_spk_volume(const int volume)
+{
+    mbtk_audio_ubus_volume_set(volume);
+    return 0;
+}
+
+
+
+
diff --git a/mbtk/lynq_lib/src/lynq_call_api.c b/mbtk/lynq_lib/src/lynq_call_api.c
new file mode 100755
index 0000000..1645803
--- /dev/null
+++ b/mbtk/lynq_lib/src/lynq_call_api.c
@@ -0,0 +1,439 @@
+#include "lynq/lynq_call_api.h"
+#include "mbtk_info_api.h"
+
+static mbtk_info_handle_t* info_handle = NULL;
+int lynq_volume_size = 0;
+mbtk_audio_client_handle_type lynq_dtmf_handle;
+mbtk_call_info_t lynq_reg[5]={0};
+int *handle_ptr=null;
+void (*incoming_call_cb_p)(int x)=NULL;
+void lynq_call_state_change_cb(const void* data, int data_len)
+{
+    mbtk_call_info_t *reg = (mbtk_call_info_t *)data;
+    switch (reg->call_wait)
+    {
+        case MBTK_CLCC:
+        {
+            lynq_reg[reg->dir1].dir1 = reg->dir1;
+            lynq_reg[reg->dir1].dir = reg->dir;
+            lynq_reg[reg->dir1].state = reg->state;
+            lynq_reg[reg->dir1].mode = reg->mode;
+            lynq_reg[reg->dir1].mpty = reg->mpty;
+            memset(lynq_reg[reg->dir1].phone_number,0,strlen(reg->phone_number));
+            memcpy(lynq_reg[reg->dir1].phone_number,reg->phone_number,strlen(reg->phone_number));
+            lynq_reg[reg->dir1].type = reg->type;
+            printf("\r\nRING : %d, %d, %d, %d, %d, %s, %d, %d\r\n", reg->dir1, reg->dir, reg->state, reg->mode, reg->mpty, reg->phone_number, reg->type,strlen(reg->phone_number));
+            if(handle_ptr != null)
+            {
+                if(*handle_ptr != reg->dir1)
+                {
+                    *handle_ptr = reg->dir1;
+                    printf("reg->dir1 : %d\r\n handle=%d\n", reg->dir1,*handle_ptr);
+                    handle_ptr = NULL;
+                }
+            }
+            if(reg->dir == 1)
+                (*incoming_call_cb_p)(reg->dir1);
+            break;
+        }
+        case MBTK_DISCONNECTED:
+            memset(&(lynq_reg[reg->disconnected_id]),0,sizeof(lynq_reg[reg->disconnected_id]));
+            printf("\r\nRING : call dis connected: %d!\r\n", reg->disconnected_id);
+            printf("phone number : %s",lynq_reg[reg->disconnected_id].phone_number);
+            lynq_set_mute_mic(0);
+            break;
+        case MBTK_CPAS:
+            printf("\r\nCALL : Call state = %d\r\n", reg->pas);
+            /*
+                MBTK_CALL_RADY,                 //MT allows commands from TA/TE
+                MBTK_CALL_UNAVAILABLE,          //MT does not allow commands from TA/TE
+                MBTK_CALL_UNKNOWN,              //MT is not guaranteed to respond to instructions
+                MBTK_CALL_RINGING,              //MT is ready for commands from TA/TE, but the ringer is active
+                MBTK_CALL_PROGRESS,             //MT is ready for commands from TA/TE, but a call is in progress
+                MBTK_CALL_ASLEEP,               //MT is unable to process commands from TA/TE because it is in a low functionality state
+                MBTK_CALL_ACTIVE,
+            */
+           switch (reg->pas)
+           {
+                case MBTK_CALL_RADY:
+                    printf("CALL: call READY\r\n");
+                    break;
+                case MBTK_CALL_UNAVAILABLE:
+                    printf("CALL: call unavaliable\r\n");
+                    break;
+                case MBTK_CALL_UNKNOWN:
+                    printf("CALL: call unknown\r\n");
+                    break;
+                case MBTK_CALL_RINGING:
+                    printf("CALL: call ringing\r\n");
+                    break;
+                case MBTK_CALL_PROGRESS:
+                    printf("CALL: call progress\r\n");
+                    break;
+                case MBTK_CALL_ASLEEP:
+                    printf("CALL: call asleep\r\n");
+                    break;
+                case MBTK_CALL_ACTIVE:
+                    printf("CALL: call active\r\n");
+                    break;
+                default:
+                    printf("\r\n");
+                    break;
+           }
+            break;
+        default:
+            printf("\r\nRING : None call_wait = %d\r\n", reg->call_wait);
+            break;
+    }
+    /*
+    if(reg->call_wait == )         //CLCC
+    {
+        printf("\r\nRING : %d, %d, %d, %d, %d, %s, %d\r\n", reg->dir1, reg->dir, reg->state, reg->mode, reg->mpty, reg->phone_number, reg->type);
+    }
+    else if(reg->call_wait == 2)    //Disconnected
+    {
+        printf("\r\nRING : call dis connected!\r\n");
+    }
+    else
+    {
+        printf("\r\nRING : None\r\n");
+    }
+    */
+}
+
+
+void lynq_dtmf_cb(char dtmf)
+{
+    printf("%s:%c\n", __FUNCTION__, dtmf);
+}
+
+int lynq_init_call(int uToken)
+{
+    UNUSED(uToken);
+    mbtk_audio_ubus_client_init(&lynq_dtmf_handle, lynq_dtmf_cb);
+    if(info_handle == NULL)
+    {
+        info_handle = mbtk_info_handle_get();
+        if(info_handle)
+        {
+            int err = mbtk_call_state_change_cb_reg(info_handle, lynq_call_state_change_cb);
+            if(err) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    return -1;
+}
+
+int lynq_deinit_call(void)
+{
+    if(info_handle)
+    {
+        return mbtk_info_handle_free(&info_handle);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int lynq_call(int *handle, char addr[])
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    if(strlen(addr)>=90)
+    {
+        printf("\ninput phone number over load!\n");
+        return -1;
+    }
+    char *buf = addr;
+    int err = mbtk_call_start(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        handle_ptr = handle;
+        return 0;
+    }
+}
+
+int lynq_call_answer()
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_call_answer(info_handle);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_call_hungup_all()
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_call_hang(info_handle);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_call_hungup(int *handle)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_a_call_hang(info_handle, *handle);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_hangup_waiting_or_background(void)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_waiting_or_background_call_hang(info_handle);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_hangup_foreground_resume_background(void)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_foreground_resume_background_call_hang(info_handle);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_switch_waiting_or_holding_and_active(void)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_call_answer(info_handle);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_wait_incoming_call(void *incoming_call_cb)
+{
+    if(incoming_call_cb == NULL)
+        return -1;
+    incoming_call_cb_p = incoming_call_cb;
+    return 0;
+}
+
+int lynq_get_mute_mic (int *status)
+{
+    if(status == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_mute_state_get(info_handle, status);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_set_mute_mic(const int enable)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_mute_state_set(info_handle, enable);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_set_DTMF(const char callnum)
+{
+    //0......9 A B C D * #
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    char callnum_default[17]="0123456789ABCD*#";
+    if((strchr(callnum_default,callnum))==NULL)
+    {
+        printf("please input 0123456789ABCD*#\n");
+        return -1;
+    }
+    mbtk_call_dtmf_info_t dtmf_character;
+    dtmf_character.character = callnum;
+    dtmf_character.duration = 500;
+    int err = mbtk_dtmf_send(info_handle, &dtmf_character);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_get_current_call_state(int *handle,int *call_state,int*toa,int *direction,char addr[])
+{
+    int flag=0;
+    int i;
+    for (i = 0; i < 5; i++)
+    {
+        if(lynq_reg[i].dir1 == *handle)
+        {
+            *direction = lynq_reg[i].dir;
+            *toa = lynq_reg[i].type;
+            memset(addr,0,sizeof(addr));
+            memcpy(addr, lynq_reg[i].phone_number, strlen(lynq_reg[i].phone_number));
+            int len = strlen(lynq_reg[i].phone_number);
+            addr[len]='\0';
+            switch (lynq_reg[i].state)
+            {
+                case MBTK_ACTIVE:
+                    *call_state = LYNQ_CALL_ACTIVE;
+                    break;
+                case MBTK_HELD:
+                    *call_state = LYNQ_CALL_HOLDING;
+                    break;
+                case MBTK_DIALING:
+                    *call_state = LYNQ_CALL_DIALING;
+                    break;
+                case MBTK_ALERTING:
+                    *call_state = LYNQ_CALL_ALERTING;
+                    break;
+                case MBTK_INCOMING:
+                    *call_state = LYNQ_CALL_INCOMING;
+                    break;
+                case MBTK_WAITING:
+                    *call_state = LYNQ_CALL_WAITING;
+                    break;
+                case MBTK_OFFERING:
+                    *call_state = LYNQ_CALL_OFFERING;
+                    break;
+                default:
+                    break;
+            }
+            flag = 1;
+            break;
+        }
+    }
+    if(flag == 0)
+    {
+        return -1;
+    }
+    return 0;
+
+    /*
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+    int err = mbtk_call_reg_get(info_handle, &reg);
+    if(err) {
+        return -1;
+    } else {
+        printf("CLCC : %d, %d, %d, %d, %d, %s, %d", reg.dir1, reg.dir, reg.state, reg.mode, reg.mpty, reg.phone_number, reg.type);
+        *direction = reg.dir;
+        *toa = reg.type;
+        memcpy(addr, reg.phone_number, strlen(reg.phone_number));
+        switch (reg.state)
+        {
+            case MBTK_ACTIVE:
+                *call_state = LYNQ_CALL_ACTIVE;
+                break;
+            case MBTK_HELD:
+                *call_state = LYNQ_CALL_HOLDING;
+                break;
+            case MBTK_DIALING:
+                *call_state = LYNQ_CALL_DIALING;
+                break;
+            case MBTK_ALERTING:
+                *call_state = LYNQ_CALL_ALERTING;
+                break;
+            case MBTK_INCOMING:
+                *call_state = LYNQ_CALL_INCOMING;
+                break;
+            case MBTK_WAITING:
+                *call_state = LYNQ_CALL_WAITING;
+                break;
+            case MBTK_OFFERING:
+                *call_state = LYNQ_CALL_OFFERING;
+                break;
+            default:
+                break;
+        }
+        return 0;
+    }
+    */
+
+}
+
+void lynq_audio_volume_cb(int volume)
+{
+	lynq_volume_size = volume;
+    if(lynq_volume_size <= 0 || lynq_volume_size > 100)
+    {
+
+    }
+    else
+    {
+        //printf("%s:%d\n", __FUNCTION__, volume);
+        printf("%s:%d\n", __FUNCTION__, lynq_volume_size);
+    }
+}
+
+int lynq_set_speech_volume(const int volume)
+{
+    if(volume <= 0 || volume >= 101)
+    {
+        printf("input error\n");
+        return -1;
+    }
+    else
+    {
+        int set_volume = 0;
+        set_volume = volume;
+        mbtk_audio_ubus_volume_set(set_volume);
+        return 0;
+    }
+}
+
+int lynq_get_speech_volume(int * volume)
+{
+	mbtk_audio_ubus_volume_get(lynq_audio_volume_cb);
+    sleep(1);
+	*volume = lynq_volume_size;
+	return 0;
+}
\ No newline at end of file
diff --git a/mbtk/lynq_lib/src/lynq_gnss.c b/mbtk/lynq_lib/src/lynq_gnss.c
new file mode 100755
index 0000000..b746c31
--- /dev/null
+++ b/mbtk/lynq_lib/src/lynq_gnss.c
@@ -0,0 +1,151 @@
+/**
+ *   \file gnss_test.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <e190@163.com>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-26
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include "mbtk_type.h"
+#include "mbtk_gnss.h"
+#include "lynq/lynq_gnss.h"
+
+static mbtk_gnss_client_handle _gnss_handle = 0;
+
+static lynq_gnss_rx_ind_msg_handler_t handler_ptr = NULL;
+
+void lynq_gnss_handler_function
+(
+    mbtk_gnss_client_handle  h_loc,
+    int   e_msg_id,
+    void                    *pv_data,
+    void                    *context_ptr
+)
+{
+    if(NULL == handler_ptr)
+        return;
+
+    if(E_LYNQ_LOC_MSG_ID_NMEA_INFO == e_msg_id) {
+        handler_ptr(h_loc, e_msg_id, pv_data, context_ptr);
+    } else {
+    }
+}
+
+//该函数用于进行GNSS初始化
+int lynq_gnss_init(void)
+{
+	int ret=0;
+
+    ret = mbtk_gnss_client_init(&_gnss_handle);
+	if(ret < 0) {
+		printf("mopen_gnss_client_init FAIL.	ret:%d\n",ret);
+		return -1;
+	}
+
+	return 0;
+}
+
+//该函数用于取消GNSS初始化
+int lynq_gnss_deinit(void)
+{
+    int ret;
+	if(0 == _gnss_handle) {
+		return -1;
+	}
+
+    ret = mbtk_gnss_client_deinit(_gnss_handle);
+	if(ret < 0) {
+		printf("mopen_gnss_client_deinit FAIL.	ret:%d\n",ret);
+		return -1;
+	}
+
+	_gnss_handle = 0;
+    return 0;
+}
+
+//该函数用于GNSS回调函数初始化
+
+int lynq_gnss_callback_reg(lynq_gnss_rx_ind_msg_handler_t handlerPtr)
+{
+    int ret;
+
+	if(0 == _gnss_handle) {
+		return -1;
+	}
+	mbtk_gnss_print_version(_gnss_handle);
+
+    ret = mbtk_gnss_add_rx_msg_handler(_gnss_handle, lynq_gnss_handler_function);
+    if(0 == ret && handlerPtr)
+        handler_ptr = handlerPtr;
+    else
+        return -1;
+	return 0;
+}
+
+//该函数用于启动GNSS。
+int lynq_gnss_start(void)
+{
+	if(0 == _gnss_handle) {
+		return -1;
+	}
+
+    mbtk_gnss_set_mode(_gnss_handle, 0);
+    return mbtk_gnss_set_mode(_gnss_handle, 3);
+}
+
+//该函数用于关闭GNSS。
+int lynq_gnss_stop(void)
+{
+	if(0 == _gnss_handle) {
+		return -1;
+	}
+
+    return mbtk_gnss_set_mode(_gnss_handle, 0);
+}
+
+
+int lynq_gnss_agps_dataconnopen(void)
+{
+    int ret;
+
+    ret = mbtk_gnss_download_tle();
+    if(ret)
+    {
+        printf("%s: download injects failed!!\n", __FUNCTION__);
+        return -1;
+    }
+    return mbtk_gnss_injects_aidpos(_gnss_handle);
+}
+
+int lynq_gnss_dev_reset(void)
+{
+	int ret = 0;
+	if(_gnss_handle < 0)
+	{
+		return -1;
+	}
+	ret = mbtk_gnss_dev_reset(_gnss_handle, 0, 0);
+	return ret;
+}
+
+int lynq_gnss_enable_glonass(void)
+{
+    mbtk_gnss_firmware_update();
+    return 0;
+}
diff --git a/mbtk/lynq_lib/src/lynq_net_api.c b/mbtk/lynq_lib/src/lynq_net_api.c
new file mode 100755
index 0000000..f2195e0
--- /dev/null
+++ b/mbtk/lynq_lib/src/lynq_net_api.c
@@ -0,0 +1,708 @@
+#include "lynq/lynq_net_api.h"
+
+static mbtk_info_handle_t* info_handle = 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}
+};
+
+int lynq_network_init(int uToken)
+{
+    UNUSED(uToken);
+    if(info_handle == NULL)
+    {
+        info_handle = mbtk_info_handle_get();
+        if(info_handle)
+        {
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+int lynq_network_deinit(void)
+{
+    if(info_handle)
+    {
+        return mbtk_info_handle_free(&info_handle);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int lynq_get_version(char buf[])
+{
+    if(info_handle == NULL || buf == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_version_get(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_get_imei(char buf[])
+{
+    if(info_handle == NULL || buf == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_imei_get(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_get_sn(char buf[])
+{
+    if(info_handle == NULL || buf == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_sn_get(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_get_zone_tmp(ZONE_NUM num, int *temp)
+{
+    if(info_handle == NULL || temp == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_temp_get(info_handle, num, temp);
+}
+
+int lynq_shutdown(char options[])
+{
+    if(options == NULL)
+    {
+        return -1;
+    }
+
+    if(!strcmp(options, "reboot")) {
+        return mbtk_system_reboot(0);
+    } else if(!strcmp(options, "poweroff")) {
+        return mbtk_system_reboot(1);
+    } else if(!strcmp(options, "halt")) {
+        return mbtk_system_reboot(2);
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+int lynq_time_set(mbtk_time_type_enum time_type, char* time_str)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_time_set(info_handle, time_type, time_str);
+}
+
+int lynq_get_sim_status(int *card_status)
+{
+    if(info_handle == NULL || card_status == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_sim_state_enum sim;
+    int err = mbtk_sim_state_get(info_handle, &sim);
+    if(err) {
+        return -1;
+    } else {
+        *card_status = sim;
+        return 0;
+    }
+}
+
+int lynq_get_imsi(char buf[])
+{
+    if(info_handle == NULL || buf == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_imsi_get(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_get_iccid(char buf[])
+{
+    if(info_handle == NULL || buf == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_iccid_get(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_query_phone_number(char buf[])
+{
+    if(info_handle == NULL || buf == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_phone_number_get(info_handle, buf);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_sim_power (int mode)
+{
+    if(mode != 0 && mode != 1)
+    {
+        return -1;
+    }
+
+    return mbtk_sim_power_set(mode);
+}
+
+int lynq_query_operater(char *OperatorFN,char *OperatorSH,char *MccMnc)
+{
+    if(info_handle == NULL || OperatorFN == NULL || OperatorSH == NULL || MccMnc == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_net_info_t net;
+    if(!mbtk_net_sel_mode_get(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);
+        }
+        return 0;
+    }
+
+    return -1;
+}
+
+int lynq_query_network_selection_mode (int *netselMode)
+{
+    if(info_handle == NULL || netselMode == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_net_info_t net;
+    if(!mbtk_net_sel_mode_get(info_handle, &net))
+    {
+        // printf("Net : %d, %d, %d\n", net.net_sel_mode, net.net_type, net.plmn);
+        *netselMode = net.net_sel_mode;
+        return 0;
+    }
+
+    return -1;
+}
+
+int lynq_set_network_selection_mode(const char *mode, const char* mccmnc)
+{
+    if(info_handle == NULL || str_empty(mode))
+    {
+        return -1;
+    }
+
+    mbtk_net_info_t net;
+    net.net_type = 0xFF;
+    if(!strcmp(mode, "Auto"))
+    {
+        net.net_sel_mode = 0;
+        net.plmn = 0;
+    }
+    else if(!strcmp(mode, "Manual") && !str_empty(mccmnc))
+    {
+        net.net_sel_mode = 1;
+        net.plmn = (uint32)atoi(mccmnc);
+    }
+    else
+    {
+        return -1;
+    }
+    if(!mbtk_net_sel_mode_set(info_handle, &net))
+    {
+        return 0;
+    }
+
+    return -1;
+}
+
+int lynq_query_available_network(list_node_t** net_list)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_available_net_get(info_handle, net_list);
+}
+
+int lynq_query_registration_state(const char *type, int* regState,int *imsRegState,char * LAC,char *CID,int *netType,int * radioTechFam,int *netRejected)
+{
+    if(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(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;
+    }
+}
+
+int lynq_query_prefferred_networktype (int *preNetType)
+{
+    if(info_handle == NULL || preNetType == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_band_info_t band;
+    int err = mbtk_current_band_get(info_handle, &band);
+    if(err) {
+        return -1;
+    } else {
+        //printf("Band : %d, %d, %d, %d, %d\n", band.net_pref, band.gsm_band, band.umts_band, band.tdlte_band, band.fddlte_band);
+        *preNetType = band.net_pref;
+        return 0;
+    }
+}
+
+int lynq_set_prefferred_networktype (const int preNetType)
+{
+
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+	if(preNetType < 0 || preNetType > 15)
+	{
+		return -2;
+	}
+    mbtk_band_info_t band;
+    memset(&band, 0, sizeof(mbtk_band_info_t));
+    band.net_pref = preNetType;
+    int err = mbtk_current_band_set(info_handle, &band);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_set_band_mode(int gsm_band, int umts_band, int tdlte_band, int fddlte_band)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_band_info_t band;
+    band.net_pref = 0xFF; // No change network pref.
+    band.gsm_band = (uint16)gsm_band;
+    band.umts_band = (uint16)umts_band;
+    band.tdlte_band = (uint32)tdlte_band;
+    band.fddlte_band = (uint32)fddlte_band;
+    int err = mbtk_current_band_set(info_handle, &band);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_query_available_bandmode (int *gsm_band, int *umts_band, int *tdlte_band, int *fddlte_band)
+{
+    if(info_handle == NULL || gsm_band == NULL || umts_band == NULL || tdlte_band == NULL || fddlte_band == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_band_info_t band;
+    int err = mbtk_support_band_get(info_handle, &band);
+    if(err) {
+        return -1;
+    } else {
+        //printf("Band : %d, %d, %d, %d, %d\n", band.net_pref, band.gsm_band, band.umts_band, band.tdlte_band, band.fddlte_band);
+        *gsm_band = band.gsm_band;
+        *umts_band = band.umts_band;
+        *tdlte_band = band.tdlte_band;
+        *fddlte_band = band.fddlte_band;
+        return 0;
+    }
+}
+
+int lynq_radio_on (const int data)
+{
+    if(info_handle == NULL || (data != 0 && data != 1))
+    {
+        return -1;
+    }
+
+    int err = mbtk_radio_state_set(info_handle, data);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_query_radio_tech (int* radioTech)
+{
+    if(info_handle == NULL || radioTech == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_radio_state_get(info_handle, radioTech);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_solicited_signal_strength (signalStrength_t *solSigStren)
+{
+    if(info_handle == NULL || solSigStren == NULL)
+    {
+        return -1;
+    }
+
+    mbtk_signal_info_t signal;
+    int err = mbtk_net_signal_get(info_handle, &signal);
+    if(err) {
+        return -1;
+    } else {
+        memset(solSigStren, 0, sizeof(signalStrength_t));
+        switch(mbtk_net_type_get(signal.type))
+        {
+            case MBTK_NET_TYPE_GSM:
+                solSigStren->gsm_sig_valid = 1;
+                break;
+            case MBTK_NET_TYPE_UMTS:
+                solSigStren->umts_sig_valid = 1;
+                break;
+            case MBTK_NET_TYPE_LTE:
+                solSigStren->lte_sig_valid = 1;
+                break;
+            default:
+                break;
+        }
+        solSigStren->rssi = signal.rssi;
+        solSigStren->ber = signal.ber;
+        solSigStren->rxlev = signal.rxlev;
+        solSigStren->rscp = signal.rscp;
+        solSigStren->ecno = signal.ecno;
+        solSigStren->rsrq = signal.rsrq;
+        solSigStren->rsrp = signal.rsrp;
+        return 0;
+    }
+}
+
+int lynq_set_ims (const int ims_mode)
+{
+    if(info_handle == NULL || (ims_mode != 0 && ims_mode != 1))
+    {
+        return -1;
+    }
+
+    int err = mbtk_volte_state_set(info_handle, ims_mode);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int lynq_init_cell(void)
+{
+    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 -1;
+		}
+    }
+
+    return 0;
+}
+
+int lynq_deinit_cell(void)
+{
+    if(info_handle)
+    {
+        return mbtk_info_handle_free(&info_handle);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+/*
+* Get current cell infomation.
+*/
+int lynq_query_cell_info(int *type, list_node_t **cell_list)
+{
+    if(info_handle == NULL || type == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_cell_get(info_handle, type, cell_list);
+}
+
+/*
+* set current cell infomation.
+*/
+void lynq_set_cell_info(char *mem)
+{
+    if(info_handle == NULL || mem == NULL)
+    {
+        return -1;
+    }
+
+	char resp[1024] = {0};
+    mbtk_cell_set(info_handle, mem, resp);
+
+	return ;
+}
+
+/*
+* Set specific APN informations.
+*
+* cid : 2-7
+*/
+int lynq_apn_set(int cid, mbtk_ip_type_enum ip_type, const void* apn_name,
+                    const void *user_name, const void *user_pass, const void *auth)
+{
+    if(info_handle == NULL || str_empty(apn_name))
+    {
+        return -1;
+    }
+
+    return mbtk_apn_set(info_handle, cid, ip_type, apn_name, user_name, user_pass, auth);
+}
+
+/*
+* Get current all APN informations.
+*/
+int lynq_apn_get(int *apn_num, mbtk_apn_info_t apns[])
+{
+    if(info_handle == NULL || apn_num == NULL || apns == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_apn_get(info_handle, apn_num, apns);
+}
+
+/*
+* Start data call.
+*/
+int lynq_data_call_start(int cid, int timeout)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_data_call_start(info_handle, cid, 0, FALSE, timeout);
+}
+
+/*
+* Stop data call.
+*/
+int lynq_data_call_stop(int cid, int timeout)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_data_call_stop(info_handle, cid, timeout);
+}
+
+/*
+* Query data call state.
+*/
+int lynq_data_call_query(int cid, mbtk_ipv4_info_t *ipv4, mbtk_ipv6_info_t *ipv6)
+{
+    if(info_handle == NULL || ipv4 == NULL || ipv6 == NULL)
+    {
+        return -1;
+    }
+
+    return mbtk_data_call_state_get(info_handle, cid, ipv4, ipv6);
+}
+
+/*
+ * Get the native ip and free port.
+ */
+int lynq_get_ip_and_port(char *ipBuf_out,int *port,int iptype)
+{
+    char psz_port_cmd[128];
+    int i=0;
+
+    *port = rand() % (60000 - 50000 + 1) + 50000;
+    sprintf(psz_port_cmd, "netstat -an | grep :%d > /dev/null", *port);
+
+        char ipBuf[32] = "";
+        FILE *fstream=NULL;
+
+        char buff[1024];
+        char iptype_str[8];
+        memset(buff,0,sizeof(buff));
+        /*eth0????eth1?docker0?em1?lo?*/
+        if(iptype == 1)
+        {
+
+            if(NULL==(fstream=popen("ifconfig ccinet0 | grep \"inet6 addr: 2\" | awk '{print $3}'","r")))
+            {
+                snprintf(ipBuf, 39, "%s","0:0:0:0:0:0:0:0");
+            }
+            if(NULL!=fgets(buff, sizeof(buff), fstream))
+            {
+                snprintf(ipBuf, 39, "%s",buff);
+            }
+            else
+            {
+                snprintf(ipBuf, 39, "%s","0:0:0:0:0:0:0:0");
+                pclose(fstream);
+            }
+        }
+        else if(iptype == 0)
+        {
+            if(NULL==(fstream=popen("ifconfig ccinet0 | grep \"inet addr:\" | awk \'{print $2}\' | cut -c 6-","r")))
+            {
+                snprintf(ipBuf, 18, "%s","0.0.0.0");
+            }
+            if(NULL!=fgets(buff, sizeof(buff), fstream))
+            {
+                snprintf(ipBuf, 18, "%s",buff);
+            }
+            else
+            {
+                snprintf(ipBuf, 18, "%s","0.0.0.0");
+                pclose(fstream);
+            }
+        }
+        else
+        {
+            return -1;
+        }
+            pclose(fstream);
+
+        printf("ip:%s\n", ipBuf);
+        memcpy(ipBuf_out, ipBuf, 32);
+        return 0;
+}
+
+int lynq_get_modem_fun(MBTK_DEV_MODEM_FUNCTION *fun)
+{
+    if(info_handle == NULL)
+    {
+        return -1;
+    }
+
+    int err = mbtk_get_modem_fun(info_handle, fun);
+    if(err) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
diff --git a/mbtk/lynq_lib/src/lynq_sms_api.c b/mbtk/lynq_lib/src/lynq_sms_api.c
new file mode 100755
index 0000000..4fa4007
--- /dev/null
+++ b/mbtk/lynq_lib/src/lynq_sms_api.c
@@ -0,0 +1,291 @@
+#include "lynq/lynq_sms_api.h"

+#include "mbtk_info_api.h"

+

+

+static mbtk_info_handle_t* info_handle = NULL;

+

+

+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));

+}

+

+

+int lynq_init_sms(int uToken)

+{

+    UNUSED(uToken);

+    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 -1;

+		}

+    }

+

+    return 0;

+}

+

+int lynq_deinit_sms(void)

+{

+    if(info_handle)

+    {

+        return mbtk_info_handle_free(&info_handle);

+    }

+    else

+    {

+        return -1;

+    }

+}

+

+

+/*

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

+> CMGS TEST

++CMGS: 17

+OK

+*/

+/*

+int charset: send sms mode

+	 0:pdu, 1:text

+

+*/

+

+int lynq_send_sms(char *telephony_num, int state, char *msg)

+{

+    if(info_handle == NULL || msg == NULL || telephony_num == NULL)

+    {

+        return -1;

+    }

+

+	char cmgs[MSM_NUMBER_MAX] = {0};

+	char resp[RES_NUM_MIN] = {0};

+	int mode = 0;

+	int err = 0;

+	if(strlen(msg) > 512 || strlen(msg) == 0 || strlen(telephony_num) == 0)

+	{

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

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

+		return -1;

+	}

+

+	if(state)	// 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");

+	}

+

+	sprintf(cmgs,"%s,%s",telephony_num, msg);

+	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;

+}

+

+int lynq_wait_receive_new_sms(int *handle)

+{

+    if(info_handle == NULL)

+    {

+        return -1;

+    }

+

+	int ret = mbtk_sms_cnmi_set(info_handle);

+	if(ret)

+	{

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

+		return -1;

+	}

+

+	mbtk_sms_state_change_cb_reg(info_handle, lynq_sms_state_change_cb);

+	return 0;

+}

+

+/*

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

+

+	Deletes message based on index

+	node:

+		index is -1, delete all message

+		delflag set 4

+*/

+int lynq_delete_sms(int 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;

+}

+

+

+/*

+function: lynq_list_sms

+stat:0:pud, 1:text

+index: 0, list index;

+	  > 0,

+

+*/

+int lynq_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 lynq_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;

+}

+

+

+int lynq_get_smsc_address(char *serviceNumber)

+{

+	char csca[128] = {0};

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

+    {

+		return -1;

+	}

+

+	int err = mbtk_sms_csca_get(info_handle, serviceNumber);

+	if(err) {

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

+		return err;

+	} else {

+		printf("lynq_get_smsc_address success\n");

+	}

+

+	return 0;

+}

+

+

+int lynq_set_smsc_address(const char* service_num)

+{

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

+	{

+		return -1;

+	}

+

+	int err = mbtk_sms_csca_set(info_handle, service_num);

+	if(err) {

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

+		return err;

+	} else {

+		printf("lynq_set_smsc_address success\n");

+	}

+	return 0;

+}

+

+

+

+

+

diff --git a/mbtk/mbtk_adbd/Makefile b/mbtk/mbtk_adbd/Makefile
new file mode 100755
index 0000000..4420021
--- /dev/null
+++ b/mbtk/mbtk_adbd/Makefile
@@ -0,0 +1,41 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_adbd
+
+INC_DIR += \
+		-I$(LOCAL_PATH)/inc
+	
+LIB_DIR +=
+
+LIBS += -lmbtk_lib -lprop2uci -lmtel -laudio-apu -lcutils -ltinyalsa -lacm
+
+CFLAGS += 
+
+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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/bin/mbtk_adbd
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
diff --git a/mbtk/mbtk_adbd/inc/mbtk_adb_info.h b/mbtk/mbtk_adbd/inc/mbtk_adb_info.h
new file mode 100755
index 0000000..0c51a8e
--- /dev/null
+++ b/mbtk/mbtk_adbd/inc/mbtk_adb_info.h
@@ -0,0 +1,55 @@
+#ifndef MBTK_ADB_INFO_H
+#define MBTK_ADB_INFO_H
+#include "mbtk_type.h"
+
+#define MBTK_ADB_PACK_FLAG 0xF6F7F8F9
+
+// flag[4] + type[1] + data_len[2] [+ data[data_len]]
+#define MBTK_ADB_PACK_HEAD_SIZE 7
+
+// Message ID.
+typedef enum
+{
+    MBTK_ADB_MSG_CONN_START = 0x01,  // cli->ser : Start handshake.
+    MBTK_ADB_MSG_CONN_SUCCESS,    // ser->cli : Connect success.
+    MBTK_ADB_MSG_PUSH,            // cli->ser : Start push data(ARG : data_len[4] path_len[2] path[path_len]).
+    MBTK_ADB_MSG_PUSH_READY,      // ser->cli : Server ready,client can send data.
+    MBTK_ADB_MSG_PUSH_COMPLETE,   // cli->ser : Push complete.
+    MBTK_ADB_MSG_PUSH_SIZE,       // ser->cli : Server recv data lenght(ARG : data_len[4]).
+    MBTK_ADB_MSG_CMD_REQ,         // cli->ser : Send shell/at command.(ARG : shell/at command).
+    MBTK_ADB_MSG_CMD_RSP,         // ser->cli : Shell/at command response.(ARG : shell/at command response).
+    MBTK_ADB_MSG_CMD_KILL,      // cli->ser : Kill shell command.
+    MBTK_ADB_MSG_CMD_RSP_COMPLETE,    // ser->cli : Shell/at command response complete.
+    MBTK_ADB_MSG_CLOSE_START,     // cli->ser : Start close connect.
+    MBTK_ADB_MSG_CLOSE_SUCCESS,   // ser->cli : Close connect success.
+
+    // ERR start
+//    MBTK_ADB_MSG_ERR_UNKNOWN = 0x80,
+
+    MBTK_ADB_MSG_DATA = 0xFF             // Data
+} mbtk_adb_msg_enum;
+
+// Message error ID.
+typedef enum
+{
+    MBTK_ADB_MSG_ERR_SUCCESS = 0x0,
+    MBTK_ADB_MSG_ERR_UNKNOWN = 0x80,
+    MBTK_ADB_MSG_ERR_PACK,  // Packet error.
+    MBTK_ADB_MSG_ERR_IO,    // Read/Write error.
+    MBTK_ADB_MSG_ERR_FILE_SIZE,    // File size error.
+    MBTK_ADB_MSG_ERR_FILE_PATH,    // File path error.
+    MBTK_ADB_MSG_ERR_TRANS_NO_START,    // Data transfer not started.
+    MBTK_ADB_MSG_ERR_UNKNOWN_MSG,  // Unknown msg.
+    MBTK_ADB_MSG_ERR_COMMAND,    // Shell or AT command error.
+
+} mbtk_adb_msg_err_enum;
+
+typedef struct
+{
+    mbtk_adb_msg_enum msg_id;
+
+    uint16 data_len;
+    uint8 *data;
+} mbtk_adb_pack_t;
+
+#endif /* MBTK_ADB_INFO_H */
diff --git a/mbtk/mbtk_adbd/src/main.c b/mbtk/mbtk_adbd/src/main.c
new file mode 100755
index 0000000..996839a
--- /dev/null
+++ b/mbtk/mbtk_adbd/src/main.c
@@ -0,0 +1,495 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <cutils/properties.h>
+#include <time.h>
+#include <sys/time.h>
+#include <termios.h>    //UART
+
+#include "mbtk_log.h"
+#include "mbtk_adb_info.h"
+#include "mbtk_file.h"
+#include "mbtk_utils.h"
+
+// 同步收发数据
+#define MBTK_ADB_MSG_SYNC 1
+#define ADB_BUFF_SIZE 2048
+
+#define DATABITS	CS8
+#define STOPBITS	0
+#define PARITYON        0
+#define PARITY          0
+
+static uint8 adb_buff[ADB_BUFF_SIZE];
+static int adb_buff_size = 0;
+static uint8 *adb_buff_ptr = NULL;
+static int file_fd = -1;
+static int adb_fd = -1;
+static char shell_cmd[ADB_BUFF_SIZE];
+
+static int adb_port_open(const char *dev, unsigned int baud)
+{
+#if 0
+    //unsigned int    baud = B921600;
+    //unsigned int    baud = B3000000;
+    struct termios  options;
+#if MBTK_ADB_MSG_SYNC
+    int fd = open(dev, O_RDWR | O_NOCTTY, 0644);
+#else
+    int fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0644);
+#endif
+    if (fd < 0)
+    {
+        LOGE("Can't open device = (%s)", dev);
+        return -1;
+    }
+
+    tcgetattr(fd, &options);
+    cfmakeraw(&options);
+    cfsetospeed(&options, baud);
+    if (tcsetattr(fd, TCSAFLUSH, &options) != 0)
+    {
+        LOGE("setting fd tc");
+        close(fd);
+        return -1;
+    }
+
+    tcflush(fd, TCIFLUSH);
+    return fd;
+#else
+
+    int fd = open(dev, O_RDWR);
+	/* set newtio */
+	struct termios newtio;
+	memset(&newtio, 0, sizeof(newtio));
+	(void)fcntl(fd, F_SETFL, 0);
+#if 1    //UART2_AT
+	/* no flow control for uart by default */
+	newtio.c_cflag = baud | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
+#else
+	newtio.c_cflag = baud | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
+#endif
+	newtio.c_iflag = IGNPAR;
+            //newtio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+	newtio.c_oflag = 0;
+	newtio.c_lflag = 0;    /* disable ECHO, ICANON, etc... */
+
+	newtio.c_cc[VERASE]   = 0x8;      /* del */
+	newtio.c_cc[VEOF]     = 4;      /* Ctrl-d */
+	newtio.c_cc[VMIN]     = 1;      /* blocking read until 1 character arrives */
+	newtio.c_cc[VEOL]     = 0xD;      /* '\0' */
+
+	tcflush(fd, TCIFLUSH);
+	tcsetattr(fd, TCSANOW, &newtio);
+
+    return fd;
+#endif
+}
+
+static int adb_msg_send(int fd, int msg, const void *data, int data_len)
+{
+    uint8 buff[ADB_BUFF_SIZE] = {0};
+    uint8 *ptr = buff;
+
+    uint32_2_byte(MBTK_ADB_PACK_FLAG, ptr, true);
+    ptr += sizeof(uint32);
+
+    *ptr = (uint8)msg;
+    ptr++;
+
+    uint16_2_byte((uint16)data_len, ptr, false);
+    ptr += sizeof(uint16);
+
+    if(data && data_len > 0) {
+        memcpy(ptr, data, data_len);
+        ptr += data_len;
+    }
+    int result = file_write(fd, buff, ptr - buff);
+
+    LOGD("SEND : %d / %d", result, ptr - buff);
+    log_hex("SEND", buff, ptr - buff);
+    return result;
+}
+
+static void shell_cmd_cb_func(char *buf,int buf_size)
+{
+    LOGD("data_len : %d", buf_size);
+    if(buf == NULL || buf_size == 0) { // shell complete
+        if(adb_msg_send(adb_fd, MBTK_ADB_MSG_CMD_RSP_COMPLETE, NULL, 0) <= 0) {
+            LOGE("Send MBTK_ADB_MSG_CMD_RSP_COMPLETE fail.");
+        }
+
+        memset(shell_cmd, 0, ADB_BUFF_SIZE);
+    } else {
+        if(adb_msg_send(adb_fd, MBTK_ADB_MSG_CMD_RSP, buf, buf_size) <= 0) {
+            LOGE("Send MBTK_ADB_MSG_CMD_RSP fail.");
+        }
+
+        usleep(10);
+    }
+}
+
+static void* shell_or_at_func(void* argv)
+{
+    UNUSED(argv);
+
+    // Process in thread.
+    LOGD("CMD : %s", shell_cmd);
+    if(!strncasecmp(shell_cmd, "at ", 3)) { // AT command.
+        LOGE("Process AT:%s", shell_cmd + 3);
+
+        // "at ati"
+        if(!mbtk_cmd_line_ex(shell_cmd, shell_cmd_cb_func)) {
+            LOGE("Shell or AT command error.");
+        }
+    } else if(!strncasecmp(shell_cmd, "shell ", 6)) { // Shell command.
+        if(!strcmp(shell_cmd + 6, "cd") || !strncmp(shell_cmd + 6, "cd ", 3)) {
+            char *cmd = NULL;
+            if(!strncmp(shell_cmd + 6, "cd ", 3)) {
+                cmd = shell_cmd + 9;
+            } else {
+                cmd = "/";
+            }
+
+            if(chdir(cmd)) {
+                char buff[ADB_BUFF_SIZE] = {0};
+                sprintf(buff, "Can't cd to %s", cmd);
+                if(adb_msg_send(adb_fd, MBTK_ADB_MSG_CMD_RSP_COMPLETE, buff, strlen(buff)) <= 0) {
+                    LOGE("Send MBTK_ADB_MSG_CMD_RSP_COMPLETE fail.");
+                }
+            } else {
+                if(adb_msg_send(adb_fd, MBTK_ADB_MSG_CMD_RSP_COMPLETE, NULL, 0) <= 0) {
+                    LOGE("Send MBTK_ADB_MSG_CMD_RSP_COMPLETE fail.");
+                }
+            }
+        } else {
+            if(!mbtk_cmd_line_ex(shell_cmd + 6, shell_cmd_cb_func)) {
+                LOGE("Shell or AT command error.");
+            }
+        }
+    } else {
+        LOGE("Command error.");
+        if(adb_msg_send(adb_fd, MBTK_ADB_MSG_ERR_COMMAND, NULL, 0) <= 0) {
+            LOGE("Send MBTK_ADB_MSG_ERR_COMMAND fail.");
+        }
+    }
+
+    return NULL;
+}
+
+static mbtk_adb_msg_err_enum adb_pack_process(int fd, mbtk_adb_pack_t *pack)
+{
+    static int data_recv_len = 0;
+    static int data_recv_count_len = 0;
+//  mbtk_adb_msg_err_enum err = MBTK_ADB_MSG_ERR_SUCCESS;
+    switch(pack->msg_id) {
+        case MBTK_ADB_MSG_CONN_START:
+        {
+            if(adb_msg_send(fd, MBTK_ADB_MSG_CONN_SUCCESS, NULL, 0) <= 0) {
+                return MBTK_ADB_MSG_ERR_IO;
+            }
+
+            LOGD("CONN_SUCCESS");
+
+            chdir("/");
+            break;
+        }
+        case MBTK_ADB_MSG_PUSH:
+        {
+            // data_len[4] path_len[2] path[path_len]
+            uint8 *ptr = pack->data;
+
+            data_recv_count_len = byte_2_uint32(ptr, false);
+            if(data_recv_count_len <= 0) {
+                LOGE("File size error:%d", data_recv_count_len);
+                return MBTK_ADB_MSG_ERR_FILE_SIZE;
+            }
+            ptr += sizeof(uint32);
+
+            char path[1024] = {0};
+            int path_len = byte_2_uint16(ptr, false);
+            if(path_len <= 0) {
+                LOGE("path length error:%d", path_len);
+                return MBTK_ADB_MSG_ERR_FILE_PATH;
+            }
+            ptr += sizeof(uint16);
+
+            memcpy(path, ptr, path_len);
+
+            file_fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0777);
+            if(file_fd < 0) {
+                LOGE("Open file(%s) error:%d", path, errno);
+                return MBTK_ADB_MSG_ERR_FILE_PATH;
+            }
+
+            data_recv_len = 0;
+            if(adb_msg_send(fd, MBTK_ADB_MSG_PUSH_READY, NULL, 0) <= 0) {
+                return MBTK_ADB_MSG_ERR_IO;
+            }
+
+            LOGD("Start recv file data.");
+            break;
+        }
+        case MBTK_ADB_MSG_PUSH_COMPLETE:
+        {
+            close(file_fd);
+            file_fd = -1;
+
+            if(adb_msg_send(fd, MBTK_ADB_MSG_PUSH_SIZE, &data_recv_len, sizeof(uint32)) <= 0) {
+                return MBTK_ADB_MSG_ERR_IO;
+            }
+
+            LOGD("PUSH_COMPLETE : %d / %d", data_recv_len, data_recv_count_len);
+            break;
+        }
+        case MBTK_ADB_MSG_CMD_REQ:
+        {
+            // Shell command or AT command.
+            memset(shell_cmd, 0, ADB_BUFF_SIZE);
+            memcpy(shell_cmd, pack->data, pack->data_len);
+
+            pthread_t pid;
+            if (pthread_create(&pid, NULL, shell_or_at_func, NULL) != 0) {
+                LOGE("Create shell/at thread fail.");
+                return MBTK_ADB_MSG_ERR_COMMAND;
+            }
+            break;
+        }
+        case MBTK_ADB_MSG_CMD_KILL:
+        {
+            if(!strncasecmp(shell_cmd, "at ", 3)) { // AT command.
+                LOGE("Kill AT:%s", shell_cmd + 3);
+
+            } else if(!strncasecmp(shell_cmd, "shell ", 6)) { // Shell command.
+                LOGD("Kill cmd:%s", shell_cmd + 6);
+                char cmd[1024] = {0};
+                snprintf(cmd,1024,"kill `pidof %s | awk '{print $1}'`", shell_cmd + 6);
+                system(cmd);
+            } else {
+                LOGE("Kill Command/AT error.");
+            }
+            break;
+        }
+        case MBTK_ADB_MSG_CLOSE_START:
+        {
+            if(adb_msg_send(fd, MBTK_ADB_MSG_CLOSE_SUCCESS, NULL, 0) <= 0) {
+                return MBTK_ADB_MSG_ERR_IO;
+            }
+            break;
+        }
+        case MBTK_ADB_MSG_DATA:
+        {
+            if(file_fd < 0) {
+                LOGE("Data transfer not started.");
+                return MBTK_ADB_MSG_ERR_TRANS_NO_START;
+            }
+
+            if(pack->data_len > 0) {
+                int size = write(file_fd, pack->data, pack->data_len);
+                if(size == pack->data_len) {
+                    data_recv_len += size;
+                } else {
+                    LOGE("Write error:%d", errno);
+                    return MBTK_ADB_MSG_ERR_IO;
+                }
+            }
+            break;
+        }
+        default:
+        {
+            LOGE("MSG id error:%d", pack->msg_id);
+            return MBTK_ADB_MSG_ERR_UNKNOWN_MSG;
+        }
+    }
+
+    return MBTK_ADB_MSG_ERR_SUCCESS;
+}
+
+/*
+*                   1        2       data_len
+*   F6 F7 F8 F9 [msg_id] [data_len] [data...]
+*/
+static mbtk_adb_msg_err_enum adb_read_a_pack(int fd, mbtk_adb_pack_t *pack)
+{
+    memset(pack, 0x0, sizeof(mbtk_adb_pack_t));
+    if(adb_buff_size < MBTK_ADB_PACK_HEAD_SIZE) {
+read_once:
+        // LOGD("Will read:adb_buff_size = %d", adb_buff_size);
+        if(adb_buff_size > 0) {
+            memmove(adb_buff, adb_buff_ptr, adb_buff_size);
+            adb_buff_ptr = adb_buff;
+        } else if(adb_buff_size == 0) {
+            adb_buff_ptr = adb_buff;
+        } else {
+            LOGE("Data error:%d", adb_buff_size);
+            goto error;
+        }
+        int size = read(fd, adb_buff_ptr + adb_buff_size, ADB_BUFF_SIZE - (adb_buff_ptr - adb_buff) - adb_buff_size);
+        if(size <= 0) {
+            LOGE("read() error:%d.", errno);
+            goto error;
+        }
+
+#if 0
+        log_hex("RECV", adb_buff_ptr + adb_buff_size, size);
+#endif
+        adb_buff_size += size;
+    }
+
+    if(adb_buff_size < MBTK_ADB_PACK_HEAD_SIZE) {
+        goto read_once;
+    }
+
+    if(MBTK_ADB_PACK_FLAG != byte_2_uint32(adb_buff_ptr, true))
+    {
+        LOGE("Packet FLAG error.");
+        goto error;
+    }
+
+    pack->msg_id = (mbtk_adb_msg_enum)*(adb_buff_ptr + sizeof(uint32));
+    pack->data_len = byte_2_uint16(adb_buff_ptr + sizeof(uint32) + sizeof(uint8), false);
+
+    if(pack->data_len > 0 && adb_buff_size < MBTK_ADB_PACK_HEAD_SIZE + pack->data_len) {
+        goto read_once;
+    }
+
+    if(pack->msg_id == MBTK_ADB_MSG_DATA)
+        LOGD("DATA : %d", pack->data_len);
+    else
+        log_hex("PACK", adb_buff_ptr, MBTK_ADB_PACK_HEAD_SIZE + pack->data_len);
+
+    // Jump 'flag'
+    adb_buff_ptr += MBTK_ADB_PACK_HEAD_SIZE;
+    adb_buff_size -= MBTK_ADB_PACK_HEAD_SIZE;
+
+    if(pack->data_len > 0) {
+        pack->data = adb_buff_ptr;
+
+        // Jump 'data'
+        adb_buff_ptr += pack->data_len;
+        adb_buff_size -= pack->data_len;
+    }
+
+    return MBTK_ADB_MSG_ERR_SUCCESS;
+error:
+    return MBTK_ADB_MSG_ERR_PACK;
+}
+
+
+int main(int argc, char *argv[])
+{
+    char port_config[32] = {0};
+    mbtk_log_init("radio", "MBTK_ADBD");
+    memset(port_config, 0, 32);
+    property_get("persist.mbtk.dev_ttyGS0", port_config, "at");
+    if(strcmp(port_config, "adb")) {
+        memset(port_config, 0, 32);
+        property_get("persist.mbtk.dev_ttymodem0", port_config, "at");
+        if(strcmp(port_config, "adb")) {
+            memset(port_config, 0, 32);
+            property_get("persist.mbtk.dev_ttyS1", port_config, "at");
+            if(strcmp(port_config, "adb")) {
+                LOGE("No config mbtk adb port.");
+                return 0;
+            } else {
+                memset(port_config, 0, 32);
+                strcpy(port_config, "/dev/ttyS1");
+            }
+        } else {
+            memset(port_config, 0, 32);
+            strcpy(port_config, "/dev/ttymodem0");
+        }
+    } else {
+        memset(port_config, 0, 32);
+        strcpy(port_config, "/dev/ttyGS0");
+    }
+
+    LOGD("Port : %s", port_config);
+
+    if(access(port_config, R_OK | W_OK)) {
+        LOGE("Dev %s error:%d", port_config, errno);
+        return 0;
+    }
+
+    if((adb_fd = adb_port_open(port_config, B921600)) < 0) {
+        LOGE("Open dev %s fail:%d", port_config, errno);
+        return 0;
+    }
+
+#if MBTK_ADB_MSG_SYNC
+
+    mbtk_adb_pack_t pack;
+    mbtk_adb_msg_err_enum err;
+    while(1) {
+        memset(adb_buff, 0x0, ADB_BUFF_SIZE);
+        memset(&pack, 0x0, sizeof(mbtk_adb_pack_t));
+        adb_buff_size = 0;
+        adb_buff_ptr = adb_buff;
+
+        LOGD("Start/Restart connectting.");
+        while(1) {
+            err = adb_read_a_pack(adb_fd, &pack);
+            if(MBTK_ADB_MSG_ERR_SUCCESS != err) {
+                adb_msg_send(adb_fd, err, NULL, 0);
+                break;
+            }
+
+            err = adb_pack_process(adb_fd, &pack);
+            if(MBTK_ADB_MSG_ERR_SUCCESS != err) {
+                adb_msg_send(adb_fd, err, NULL, 0);
+                break;
+            }
+        }
+    }
+#else
+    int select_timeout = 30;    // 30s
+    do
+    {
+        struct timeval timeval;
+        fd_set fdr, fdw;
+        int ret = 0;
+
+        FD_ZERO(&fdw);
+        FD_ZERO(&fdr);
+        FD_SET(adb_fd, &fdr);
+
+        timeval.tv_sec  = select_timeout;
+        timeval.tv_usec = 0;
+
+        ret = select(adb_fd + 1, &fdr, &fdw, 0, &timeval);
+        if (ret < 0)
+        {
+            if (errno == EINTR)
+            {
+                continue;
+            }
+            LOGE("select error, errno = %d (%s)", errno, strerror(errno));
+            break;
+        }
+        else if (ret == 0)
+        {
+            LOGE("select timeout");
+            continue;
+        }
+
+        // New AT command recv.
+        if (FD_ISSET(adb_fd, &fdr))
+        {
+
+        }
+        else
+        {
+            LOGW("Unknown select event.");
+            continue;
+        }
+    } while(1);
+#endif
+
+    LOGD("EXIT!");
+
+    return 0;
+}
+
diff --git a/mbtk/mbtk_lib/Makefile b/mbtk/mbtk_lib/Makefile
new file mode 100755
index 0000000..0e51728
--- /dev/null
+++ b/mbtk/mbtk_lib/Makefile
@@ -0,0 +1,53 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_lib
+
+INC_DIR += \
+	-I$(LOCAL_PATH)/inc
+	
+LIB_DIR +=
+
+LIBS += -llog -lubus -lubox -lprop2uci -luci -lrilutil -lpolarssl \
+	-lavcodec \
+	-lavdevice \
+	-lavfilter \
+	-lavformat \
+	-lavutil \
+	-lpostproc \
+	-lswresample \
+	-lswscale \
+	-lcutils \
+	-laudio-apu
+	
+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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/lib/libmbtk_lib.so
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+
+clean:
+	
+
diff --git a/mbtk/mbtk_lib/inc/ds_ASBuffer.h b/mbtk/mbtk_lib/inc/ds_ASBuffer.h
new file mode 100644
index 0000000..492b436
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/ds_ASBuffer.h
@@ -0,0 +1,268 @@
+/*==============================================================================

+

+                              ds_ASBuffer.h

+

+GENERAL DESCRIPTION

+  A buffer class with utility functions for parsing raw bytes.

+

+EXTERNALIZED FUNCTIONS

+

+INITIALIZATION AND SEQUENCING REQUIREMENTS

+

+  Copyright (c) 2014 by Qualcomm Technologies Incorporated. All Rights Reserved.

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

+

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

+                           EDIT HISTORY FOR MODULE

+

+This section contains comments describing changes made to the module.

+Notice that changes are listed in reverse chronological order.

+

+when        who    what, where, why

+--------    ---    ----------------------------------------------------------

+04/21/14    ml     Created file/Initial version.

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

+

+#ifndef __DS_AS_BUFFER_H__

+#define __DS_AS_BUFFER_H__

+

+//#include "comdef.h"

+#include "mbtk_type.h"

+class ASString;

+

+

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

+CLASS ASBuffer

+

+DESCRIPTION

+  A buffer class with utility functions for parsing raw bytes.

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

+class ASBuffer

+{

+public:

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

+  FUNCTION ASBuffer CONSTRUCTOR

+

+  DESCRIPTION

+    Creates a new ASBuffer.

+

+  DEPENDENCIES

+    capacity - The initial buffer capacity to set.

+

+  SIDE EFFECTS

+    None

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

+  ASBuffer();

+  ASBuffer(uint32 capacity);

+

+  ASBuffer(ASBuffer &buf);

+  ASBuffer(const ASBuffer &buf);

+  ASBuffer(const uint8* buf, uint32 capacity);

+

+  ~ASBuffer();

+

+

+  ASBuffer& operator=(const ASBuffer &rhs);

+

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

+  FUNCTION ASBuffer::content

+

+  DESCRIPTION

+    Returns a pointer to the buffer content

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  const uint8* content() const;

+

+

+

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

+  FUNCTION ASBuffer::non_const_content

+

+  DESCRIPTION

+    Returns a pointer to the buffer content. Use this function ONLY if you need

+    a non-const version and it is guaranteed that the returned pointer will

+    never be modified.

+

+    Note: Workaround function for MD5 auth-int. Otherwise shouldn't be used.

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  uint8* non_const_content();

+

+

+

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

+  FUNCTION ASBuffer::c_str

+

+  DESCRIPTION

+    Returns a pointer to the buffer content. This assumes the buffer content is

+    in c-string format

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  const char* c_str() const;

+

+

+

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

+  FUNCTION ASBuffer::size

+

+  DESCRIPTION

+    Returns the size of the buffer

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  uint32 size() const;

+

+

+

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

+  FUNCTION ASBuffer::empty

+

+  DESCRIPTION

+    Returns true if the buffer is empty

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  bool empty() const;

+

+

+

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

+  FUNCTION ASBuffer::error

+

+  DESCRIPTION

+    Returns true if the buffer is in error status due to internal memory

+    allocation failure.

+

+    This can happen when

+      - Constructor fails to allocate memory for the new buffer

+      - Append requires to resize the buffer but fails

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  bool error() const;

+

+

+

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

+  FUNCTION ASBuffer::append

+

+  DESCRIPTION

+    Appends the given data to the buffer. Returns true if append is successful,

+    false if append fails.

+

+  PARAMETERS

+    [In] append_buffer - The data to append

+    [In] size          - The number of bytes to append

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  bool append(const uint8* append_buffer, const uint32 size);

+  bool append(const char append_buffer);

+  bool append(const char* append_buffer);

+  bool append(const char* append_buffer, const uint32 size);

+  bool append(const ASBuffer& append_buffer);

+  bool append(const ASString& append_buffer); // temp

+

+

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

+  FUNCTION ASBuffer::clear

+

+  DESCRIPTION

+    Returns true if the buffer is in error status due to internal memory

+    allocation failure.

+

+    This can happen when

+      - Constructor fails to allocate memory for the new buffer

+      - Append requires to resize the buffer but fails

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  void clear();

+

+

+

+private:

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

+  FUNCTION ASBuffer::init

+

+  DESCRIPTION

+    Initialize buffer

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  void init();

+  bool increment_buffer_capacity(const uint32 req_size);

+

+

+  uint8* buffer; // Buffer object. Memory dynamically allocated as necessary

+  uint32 buffer_size;

+  uint32 buffer_capacity;

+  bool   error_status; // true if error, else false

+};

+

+

+

+#endif /* __DS_AS_BUFFER_H__ */

diff --git a/mbtk/mbtk_lib/inc/ds_ASString.h b/mbtk/mbtk_lib/inc/ds_ASString.h
new file mode 100644
index 0000000..02319ca
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/ds_ASString.h
@@ -0,0 +1,265 @@
+/*==============================================================================

+

+                              ds_ASString.h

+

+GENERAL DESCRIPTION

+  A string class with utility functions for parsing AS.

+

+EXTERNALIZED FUNCTIONS

+

+INITIALIZATION AND SEQUENCING REQUIREMENTS

+

+  Copyright (c) 2014 by Qualcomm Technologies Incorporated. All Rights Reserved.

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

+

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

+                           EDIT HISTORY FOR MODULE

+

+This section contains comments describing changes made to the module.

+Notice that changes are listed in reverse chronological order.

+

+when        who    what, where, why

+--------    ---    ----------------------------------------------------------

+04/21/14    ml     Created file/Initial version.

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

+#ifndef DS_AS_STRING_H

+#define DS_AS_STRING_H

+

+//#include "comdef.h"

+#include "mbtk_type.h"

+

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

+CLASS ASString

+

+DESCRIPTION

+  A string class with utility functions for parsing AS.

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

+class ASString

+{

+public:

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

+  FUNCTION ASString CONSTRUCTOR

+

+  DESCRIPTION

+    Creates a new ASString. Default constructor will create an empty string.

+    The other constructors will make a copy of the given string.

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  ASString();

+  ASString(const char* src);

+  ASString(const char* src, uint32 len);

+

+  // copy constructor

+  ASString(ASString& src);

+  ASString(const ASString& src);

+

+  ~ASString();

+

+

+  ASString& operator=(const ASString& rhs);

+  ASString& operator=(const char* rhs);

+  char      operator[](const int index) const;

+  char&     operator[](const int index);

+

+

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

+  FUNCTION ASString::c_str

+

+  DESCRIPTION

+    Returns the raw c-string

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  const char* c_str() const;

+

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

+  FUNCTION ASString::size

+  FUNCTION ASString::length

+

+  DESCRIPTION

+    Returns the length of the string

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  uint32 size() const;

+  uint32 length() const;

+

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

+  FUNCTION ASString::empty

+

+  DESCRIPTION

+    Returns true if the string is empty or NULL

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  bool empty() const;

+

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

+  FUNCTION ASString::remove_trailing_spaces

+

+  DESCRIPTION

+    Removes all whiltespace, including tabs and newlines, at the end of the string.

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  void remove_trailing_spaces();

+

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

+  FUNCTION ASString::resolve_xml_escapes

+

+  DESCRIPTION

+    Replaces XML escape strings with the corresponding character.

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  bool resolve_xml_escapes();

+

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

+  FUNCTION ASString::to_lower

+

+  DESCRIPTION

+    Converts all characters in the string to lower case.

+

+  PARAMETERS

+    None

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  void to_lower();

+

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

+  FUNCTION ASString::limit_cmp

+

+  DESCRIPTION

+    Partial string compare up to len. Returns true if same, else false.

+

+  PARAMETERS

+    [In] cstr - The string to compare

+    [In] len  - The number of characters to compare.

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  bool limit_cmp(const char* cstr, const uint32 len) const;

+

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

+  FUNCTION ASString::append

+

+  DESCRIPTION

+    Appends the given string to the string it holds.

+

+  PARAMETERS

+    [In] append_str - The string to append

+    [In] len        - The number of characters to append

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  void append(const char* append_str);

+  void append(const char* append_str, const uint32 len);

+  void append(const ASString& append_str);

+

+protected:

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

+  FUNCTION ASString::copy_string

+

+  DESCRIPTION

+    Partial string compare up to len. Returns true if same, else false.

+

+  PARAMETERS

+    [In] src - The string to copy

+    [In] len - The number of characters to copy

+

+  DEPENDENCIES

+    None

+

+  SIDE EFFECTS

+    None

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

+  void copy_string(const char* src, uint32 len);

+

+  char* str; // C-string object. Memory dynamically allocated as necessary

+};

+

+

+

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

+FUNCTION operator==

+FUNCTION operator!=

+FUNCTION operator<

+FUNCTION operator>

+

+DESCRIPTION

+  Compares the two strings and returns true/false based on the operator. The

+  comparison will be case insensitive.

+

+PARAMETERS

+  [In] lhs - The string to compare

+  [In] rhs - The other string to compare

+

+DEPENDENCIES

+  None

+

+SIDE EFFECTS

+  None

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

+bool operator== (const ASString& lhs, const ASString& rhs);

+bool operator!= (const ASString& lhs, const ASString& rhs);

+

+bool operator== (const ASString& lhs, const char* rhs);

+bool operator!= (const ASString& lhs, const char* rhs);

+

+bool operator< (const ASString& lhs, const ASString& rhs);

+bool operator> (const ASString& lhs, const ASString& rhs);

+

+#endif /* DS_AS_STRING_H */

diff --git a/mbtk/mbtk_lib/inc/g711_pcm_convert.h b/mbtk/mbtk_lib/inc/g711_pcm_convert.h
new file mode 100644
index 0000000..688dcb4
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/g711_pcm_convert.h
@@ -0,0 +1,46 @@
+#ifndef G711_PCM_CONVERT_H_
+#define G711_PCM_CONVERT_H_
+
+enum g711type {
+    G711ALAW,
+    G711ULAW
+};
+
+/**
+ * @brief pcm data encode to g711 data
+ * 
+ *  user should be responsible for pCodecbit memmory
+ * 
+ * @param pCodecBits store g711 encoded data 
+ * @param pBuffer pcm raw data
+ * @param BufferSize pcm data len
+ * @param type g711 data type
+ * @return int encode data length
+ */
+int G711EnCode(char* pCodecBits, char* pBuffer, int BufferSize, enum g711type type);
+
+/**
+ * @brief g711 data decode to pcm data
+ * 
+ * user should be responsible for pRawData memmory
+ * 
+ * @param pRawData store uncoded pcm data
+ * @param pBuffer g711 encoded data
+ * @param BufferSize g711 data len
+ * @param type g711 data type
+ * @return int pcm data len
+ */
+int G711Decode(char* pRawData, char* pBuffer, int BufferSize, enum g711type type);
+
+/**
+ * @brief g711 u-law data and a-law data convert
+ * 
+ * @param alawdata g711 a-law data
+ * @param ulawdata g711 u-lwa data
+ * @param datasize input data length
+ * @param type target g711 data type
+ * @return int sucess:1; failed:0
+ */
+int G711TypeChange(unsigned char* alawdata, unsigned char* ulawdata, int datasize, enum g711type type);
+
+#endif /* G711_PCM_CONVERT_H_ */
\ No newline at end of file
diff --git a/mbtk/mbtk_lib/inc/gpio-define.h b/mbtk/mbtk_lib/inc/gpio-define.h
new file mode 100644
index 0000000..36c497e
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/gpio-define.h
@@ -0,0 +1,133 @@
+/**
+ *   \file gpio-define.h
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-04-26
+ */
+
+#ifndef __GPIO_DEFINE_H__
+#define __GPIO_DEFINE_H__
+
+/*
+4组GPIO共128个GPIO,分别从GPIO_0到GPIO_127
+GPIO22位于0xd4019000这一组的BIT22
+
+GPIO0_BASE 0xD4019000
+GPIO1_BASE 0xD4019004
+GPIO2_BASE 0xD4019008
+GPIO3_BASE 0xD4019100
+ */
+/*
+MMC_CMD	    GPIO_41
+MMC_DATA0	GPIO_40
+MMC_DATA1	GPIO_39
+MMC_DATA2	GPIO_38
+MMC_DATA3	GPIO_37
+
+SD_DET	GPIO_43
+WLAN_DAT3	GPIO_48
+
+
+*/
+#define  GPIO_FUNC_MMC1_DAT3	0xD401E094
+#define  GPIO_FUNC_MMC1_DAT2	0xD401E098
+#define  GPIO_FUNC_MMC1_DAT1	0xD401E09C
+#define  GPIO_FUNC_MMC1_DAT0	0xD401E0A0
+#define  GPIO_FUNC_MMC1_CMD	0xD401E0A4
+#define  GPIO_FUNC_MMC1_CLK	0xD401E0A8
+#define  GPIO_FUNC_MMC1_CD	0xD401E0AC
+#define  GPIO_FUNC_USB_ID	    0xD401E0B0
+#define  GPIO_FUNC_PRI_TDI	0xD401E0B4
+#define  GPIO_FUNC_PRI_TMS	0xD401E0B8
+#define  GPIO_FUNC_PRI_TCK	0xD401E0BC
+#define  GPIO_FUNC_PRI_TDO	0xD401E0C0
+#define  GPIO_FUNC_QSPI_VMODE_GPIO	0xD401E0C4
+#define  GPIO_FUNC_VBUS_DRV	0xD401E0C8
+#define  GPIO_FUNC_CLK_REQ	0xD401E0CC
+#define  GPIO_FUNC_VCXO_REQ	0xD401E0D4
+#define  GPIO_FUNC_VCXO_OUT	0xD401E0D8
+#define  GPIO_FUNC_GPIO_00	0xD401E0DC
+#define  GPIO_FUNC_GPIO_01	0xD401E0E0
+#define  GPIO_FUNC_GPIO_02	0xD401E0E4
+#define  GPIO_FUNC_GPIO_03	0xD401E0E8
+#define  GPIO_FUNC_GPIO_04	0xD401E0EC
+#define  GPIO_FUNC_GPIO_05	0xD401E0F0
+#define  GPIO_FUNC_GPIO_06	0xD401E0F4
+#define  GPIO_FUNC_GPIO_07	0xD401E0F8
+#define  GPIO_FUNC_GPIO_08	0xD401E0FC
+#define  GPIO_FUNC_GPIO_09	0xD401E100
+#define  GPIO_FUNC_GPIO_10	0xD401E104
+#define  GPIO_FUNC_GPIO_11	0xD401E108
+#define  GPIO_FUNC_GPIO_12	0xD401E10C
+#define  GPIO_FUNC_GPIO_13	0xD401E110
+#define  GPIO_FUNC_GPIO_14	0xD401E114
+#define  GPIO_FUNC_GPIO_15	0xD401E118
+#define  GPIO_FUNC_GPIO_16	0xD401E11C
+#define  GPIO_FUNC_GPIO_17	0xD401E120
+#define  GPIO_FUNC_GPIO_18	0xD401E124
+#define  GPIO_FUNC_GPIO_19	0xD401E128
+#define  GPIO_FUNC_GPIO_20	0xD401E12C
+#define  GPIO_FUNC_GPIO_21	0xD401E130
+#define  GPIO_FUNC_GPIO_22	0xD401E134
+#define  GPIO_FUNC_GPIO_23	0xD401E138
+#define  GPIO_FUNC_GPIO_24	0xD401E13C
+#define  GPIO_FUNC_GPIO_25	0xD401E140
+#define  GPIO_FUNC_GPIO_26	0xD401E144
+#define  GPIO_FUNC_GPIO_27	0xD401E148
+#define  GPIO_FUNC_GPIO_28	0xD401E14C
+#define  GPIO_FUNC_GPIO_29	0xD401E150
+#define  GPIO_FUNC_GPIO_30	0xD401E154
+#define  GPIO_FUNC_GPIO_31	0xD401E158
+#define  GPIO_FUNC_GPIO_32	0xD401E15C
+#define  GPIO_FUNC_GPIO_33	0xD401E160
+#define  GPIO_FUNC_GPIO_34	0xD401E164
+#define  GPIO_FUNC_GPIO_35	0xD401E168
+#define  GPIO_FUNC_GPIO_36	0xD401E16C
+#define  GPIO_FUNC_GPIO_49	0xD401E1A0
+#define  GPIO_FUNC_GPIO_50	0xD401E1A4
+#define  GPIO_FUNC_GPIO_51	0xD401E1A8
+#define  GPIO_FUNC_GPIO_52	0xD401E1AC
+#define  GPIO_FUNC_GPIO_53	0xD401E1B0
+#define  GPIO_FUNC_GPIO_54	0xD401E1B4
+#define  GPIO_FUNC_DVL_0      0xD401E2B4
+#define  GPIO_FUNC_DVL_1      0xD401E2B8
+#define  GPIO_FUNC_GPIO_69	0xD401E2BC
+#define  GPIO_FUNC_GPIO_70	0xD401E2C0
+#define  GPIO_FUNC_QSPI_DAT3	0xD401E2C4
+#define  GPIO_FUNC_QSPI_DAT2	0xD401E2C8
+#define  GPIO_FUNC_QSPI_DAT1	0xD401E2CC
+#define  GPIO_FUNC_QSPI_DAT0	0xD401E2D0
+#define  GPIO_FUNC_QSPI_CLK	0xD401E2D4
+#define  GPIO_FUNC_QSPI_CS1	0xD401E2D8
+#define  GPIO_FUNC_GPIO_77	0xD401E2DC
+#define  GPIO_FUNC_GPIO_78	0xD401E2E0
+#define  GPIO_FUNC_GPIO_79	0xD401E2E4
+#define  GPIO_FUNC_GPIO_80	0xD401E2E8
+#define  GPIO_FUNC_SDIO_DAT3	0xD401E2EC
+#define  GPIO_FUNC_SDIO_DAT2	0xD401E2F0
+#define  GPIO_FUNC_SDIO_DAT1	0xD401E2F4
+#define  GPIO_FUNC_SDIO_DAT0	0xD401E2F8
+#define  GPIO_FUNC_SDIO_CMD	0xD401E2FC
+#define  GPIO_FUNC_SDIO_CLK	0xD401E300
+#define  GPIO_FUNC_GPIO_60	0xD401E304
+#define  GPIO_FUNC_USIM_UCLK	0xD401E320
+#define  GPIO_FUNC_USIM_UIO	0xD401E324
+#define  GPIO_FUNC_USIM_URSTn	0xD401E328
+
+
+#define  GPIO0_BASE 0xD4019000
+#define  GPIO1_BASE 0xD4019004
+#define  GPIO2_BASE 0xD4019008
+#define  GPIO3_BASE 0xD4019100
+
+struct gpio_register_function
+{
+    int  reg;
+    int  func_gpio; // 第 [func_gpio] 功能为 GPIO
+};
+
+
+#endif /*__GPIO_DEFINE_H__*/
diff --git a/mbtk/mbtk_lib/inc/mbtk_alphabet.h b/mbtk/mbtk_lib/inc/mbtk_alphabet.h
new file mode 100644
index 0000000..1ffece7
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_alphabet.h
@@ -0,0 +1,140 @@
+//
+// Created by hitmoon on 15-12-10.
+//
+
+
+struct map_node {
+    unsigned short key;
+    unsigned short value;
+};
+
+
+#define map_size(map) (sizeof(map) / sizeof(struct map_node))
+
+
+// Unicode编码到GSM编码转换
+struct map_node UCS2ToBIT7[] = {
+        {0x000C, 0x1B0A},
+        {0x0024, 0x0002},
+        {0x0040, 0x0000},
+        {0x005B, 0x1B3C},
+        {0x005C, 0x1B2F},
+        {0x005D, 0x1B3E},
+        {0x005E, 0x1B14},
+        {0x005F, 0x0011},
+        {0x007B, 0x1B28},
+        {0x007C, 0x1B40},
+        {0x007D, 0x1B29},
+        {0x007E, 0x1B3D},
+        {0x00A0, 0x001B},
+        {0x00A1, 0x0040},
+        {0x00A3, 0x0001},
+        {0x00A4, 0x0024},
+        {0x00A5, 0x0003},
+        {0x00A7, 0x005F},
+        {0x00BF, 0x0060},
+        {0x00C4, 0x005B},
+        {0x00C5, 0x000E},
+        {0x00C6, 0x001C},
+        {0x00C9, 0x001F},
+        {0x00D1, 0x005D},
+        {0x00D6, 0x005C},
+        {0x00D8, 0x000B},
+        {0x00DC, 0x005E},
+        {0x00DF, 0x001E},
+        {0x00E0, 0x007F},
+        {0x00E4, 0x007B},
+        {0x00E5, 0x000F},
+        {0x00E6, 0x001D},
+        {0x00E7, 0x0009},
+        {0x00E8, 0x0004},
+        {0x00E9, 0x0005},
+        {0x00EC, 0x0007},
+        {0x00F1, 0x007D},
+        {0x00F2, 0x0008},
+        {0x00F6, 0x007C},
+        {0x00F8, 0x000C},
+        {0x00F9, 0x0006},
+        {0x00FC, 0x007E},
+        {0x0393, 0x0013},
+        {0x0394, 0x0010},
+        {0x0398, 0x0019},
+        {0x039B, 0x0014},
+        {0x039E, 0x001A},
+        {0x03A0, 0x0016},
+        {0x03A3, 0x0018},
+        {0x03A6, 0x0012},
+        {0x03A8, 0x0017},
+        {0x03A9, 0x0015},
+        {0x20AC, 0x1B65}
+};
+
+// GSM编码到Unicode编码转换
+struct map_node BIT7ToUCS2[] = {
+        {0x0000, 0x0040},
+        {0x0001, 0x00A3},
+        {0x0002, 0x0024},
+        {0x0003, 0x00A5},
+        {0x0004, 0x00E8},
+        {0x0005, 0x00E9},
+        {0x0006, 0x00F9},
+        {0x0007, 0x00EC},
+        {0x0008, 0x00F2},
+        {0x0009, 0x00E7},
+        {0x000B, 0x00D8},
+        {0x000C, 0x00F8},
+        {0x000E, 0x00C5},
+        {0x000F, 0x00E5},
+        {0x0010, 0x0394},
+        {0x0011, 0x005F},
+        {0x0012, 0x03A6},
+        {0x0013, 0x0393},
+        {0x0014, 0x039B},
+        {0x0015, 0x03A9},
+        {0x0016, 0x03A0},
+        {0x0017, 0x03A8},
+        {0x0018, 0x03A3},
+        {0x0019, 0x0398},
+        {0x001A, 0x039E},
+        {0x001B, 0x00A0},
+        {0x001C, 0x00C6},
+        {0x001D, 0x00E6},
+        {0x001E, 0x00DF},
+        {0x001F, 0x00C9},
+        {0x0024, 0x00A4},
+        {0x0040, 0x00A1},
+        {0x005B, 0x00C4},
+        {0x005C, 0x00D6},
+        {0x005D, 0x00D1},
+        {0x005E, 0x00DC},
+        {0x005F, 0x00A7},
+        {0x0060, 0x00BF},
+        {0x007B, 0x00E4},
+        {0x007C, 0x00F6},
+        {0x007D, 0x00F1},
+        {0x007E, 0x00FC},
+        {0x007F, 0x00E0}
+};
+// GSM编码转义序列到Unicode编码转换
+struct map_node BIT7EToUCS2[] = {
+        {0x000A, 0x000C},
+        {0x0014, 0x005E},
+        {0x0028, 0x007B},
+        {0x0029, 0x007D},
+        {0x002F, 0x005C},
+        {0x003C, 0x005B},
+        {0x003D, 0x007E},
+        {0x003E, 0x005D},
+        {0x0040, 0x007C},
+        {0x0065, 0x20AC}
+};
+
+// map 中查询键值
+int32_t map_get_value(struct map_node *map, unsigned int size, unsigned short key) {
+	int i = 0;
+    for (i = 0; i < size; i++) {
+        if (map[i].key == key)
+            return map[i].value;
+    }
+    return -1;
+}
diff --git a/mbtk/mbtk_lib/inc/mbtk_coap_pdu.h b/mbtk/mbtk_lib/inc/mbtk_coap_pdu.h
new file mode 100644
index 0000000..334301a
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_coap_pdu.h
@@ -0,0 +1,288 @@
+

+#ifndef __MBTK_COAP_H__

+#define __MBTK_COAP_H__

+#include <stdint.h>

+//#include "ps_in.h"

+#include "ds_ASBuffer.h"

+#include "mbtk_type.h"

+

+#define COAP_HDR_SIZE 4

+#define COAP_OPTION_HDR_BYTE 1

+

+typedef unsigned char               uint8_t;

+typedef unsigned short              uint16_t;

+//typedef unsigned long               uint32_t;

+typedef unsigned long long          uint64_t;

+

+/*

+enum ds_appsrv_mem_e_type { APPSRV_MEM };

+

+void* operator new(unsigned int size, void* alloc, ds_appsrv_mem_e_type mem_type) throw();

+void  operator delete(void* obj, void* alloc, ds_appsrv_mem_e_type mem_type) throw();

+*/

+

+#define ps_ntohs(x)                                                      \

+          (((((uint16)(x) & 0x00FF) << 8) | (((uint16)(x) & 0xFF00) >> 8)))

+

+

+#define endian_be16(x) ps_ntohs(x)

+

+#define endian_load16(cast, from) ((cast)( \

+        (((uint16_t)((uint8_t*)(from))[0]) << 8) | \

+        (((uint16_t)((uint8_t*)(from))[1])     ) ))

+

+#define endian_load32(cast, from) ((cast)( \

+        (((uint32_t)((uint8_t*)(from))[0]) << 24) | \

+        (((uint32_t)((uint8_t*)(from))[1]) << 16) | \

+        (((uint32_t)((uint8_t*)(from))[2]) <<  8) | \

+        (((uint32_t)((uint8_t*)(from))[3])      ) ))

+

+#define endian_load64(cast, from) ((cast)( \

+        (((uint64_t)((uint8_t*)(from))[0]) << 56) | \

+        (((uint64_t)((uint8_t*)(from))[1]) << 48) | \

+        (((uint64_t)((uint8_t*)(from))[2]) << 40) | \

+        (((uint64_t)((uint8_t*)(from))[3]) << 32) | \

+        (((uint64_t)((uint8_t*)(from))[4]) << 24) | \

+        (((uint64_t)((uint8_t*)(from))[5]) << 16) | \

+        (((uint64_t)((uint8_t*)(from))[6]) << 8)  | \

+        (((uint64_t)((uint8_t*)(from))[7])     )  ))

+

+#define endian_store16(to, num) \

+    do { uint16_t val = endian_be16(num); memcpy(to, &val, 2); } while(0)

+

+// CoAP PDU format

+

+//   0                   1                   2                   3

+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+// |Ver| T |  TKL  |      Code     |          Message ID           |

+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+// |   Token (if any, TKL bytes) ...

+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+// |   Options (if any) ...

+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+// |1 1 1 1 1 1 1 1|    Payload (if any) ...

+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+

+class CoapPDU

+{

+

+

+public:

+    /// CoAP message types. Note, values only work as enum.

+    enum Type

+    {

+        COAP_CONFIRMABLE=0x00,

+        COAP_NON_CONFIRMABLE=0x10,

+        COAP_ACKNOWLEDGEMENT=0x20,

+        COAP_RESET=0x30

+    };

+

+    // CoAP response codes.

+    enum Code

+    {

+        COAP_EMPTY=0x00,

+        COAP_GET,

+        COAP_POST,

+        COAP_PUT,

+        COAP_DELETE,

+        COAP_LASTMETHOD=0x1F,

+        COAP_CREATED=0x41,

+        COAP_DELETED,

+        COAP_VALID,

+        COAP_CHANGED,

+        COAP_CONTENT,

+        COAP_CONTINUE=0x5F,

+        COAP_BAD_REQUEST=0x80,

+        COAP_UNAUTHORIZED,

+        COAP_BAD_OPTION,

+        COAP_FORBIDDEN,

+        COAP_NOT_FOUND,

+        COAP_METHOD_NOT_ALLOWED,

+        COAP_NOT_ACCEPTABLE,

+        COAP_PRECONDITION_FAILED=0x8C,

+        COAP_REQUEST_ENTITY_TOO_LARGE=0x8D,

+        COAP_UNSUPPORTED_CONTENT_FORMAT=0x8F,

+        COAP_INTERNAL_SERVER_ERROR=0xA0,

+        COAP_NOT_IMPLEMENTED,

+        COAP_BAD_GATEWAY,

+        COAP_SERVICE_UNAVAILABLE,

+        COAP_GATEWAY_TIMEOUT,

+        COAP_PROXYING_NOT_SUPPORTED,

+        COAP_UNDEFINED_CODE=0xFF

+    };

+

+    /// CoAP option numbers.

+    enum Option

+    {

+        COAP_OPTION_IF_MATCH=1,

+        COAP_OPTION_URI_HOST=3,

+        COAP_OPTION_ETAG,

+        COAP_OPTION_IF_NONE_MATCH,

+        COAP_OPTION_OBSERVE,

+        COAP_OPTION_URI_PORT,

+        COAP_OPTION_LOCATION_PATH,

+        COAP_OPTION_URI_PATH=11,

+        COAP_OPTION_CONTENT_FORMAT,

+        COAP_OPTION_MAX_AGE=14,

+        COAP_OPTION_URI_QUERY,

+        COAP_OPTION_ACCEPT=17,

+        COAP_OPTION_LOCATION_QUERY=20,

+        COAP_OPTION_BLOCK2=23,

+        COAP_OPTION_BLOCK1=27,

+        COAP_OPTION_SIZE2,

+        COAP_OPTION_PROXY_URI=35,

+        COAP_OPTION_PROXY_SCHEME=39,

+        COAP_OPTION_SIZE1=60

+    };

+

+    /// CoAP content-formats.

+    enum ContentFormat

+    {

+        COAP_CONTENT_FORMAT_TEXT_PLAIN = 0,

+        COAP_CONTENT_FORMAT_APP_LINK  = 40,

+        COAP_CONTENT_FORMAT_APP_XML,

+        COAP_CONTENT_FORMAT_APP_OCTET,

+        COAP_CONTENT_FORMAT_APP_EXI   = 47,

+        COAP_CONTENT_FORMAT_APP_JSON  = 50

+    };

+

+    /// Sequence of these is returned by CoapPDU::getOptions()

+    struct CoapOption

+    {

+        uint16_t optionDelta;

+        uint16_t optionNumber;

+        uint16_t optionValueLength;

+        int totalLength;

+        uint8_t *optionPointer;

+        uint8_t *optionValuePointer;

+    };

+

+    // construction and destruction

+    CoapPDU();

+    CoapPDU(uint8_t *buffer, int bufferLength, int pduLength);

+    ~CoapPDU();

+    int reset();

+    int validate();

+

+    // version

+    int setVersion(uint8_t version);

+    uint8_t getVersion();

+

+    // message type

+    void setType(int type);

+    int getType();

+

+    // tokens

+    int setTokenLength(uint8_t tokenLength);

+    int getTokenLength();

+    uint8_t* getTokenPointer();

+    int setToken(uint8_t *token, uint8_t tokenLength);

+

+    // message code

+    void setCode(int code);

+    int getCode();

+    int httpStatusToCode(int httpStatus);

+

+    // message ID

+    int setMessageID(uint16_t messageID);

+    uint16_t getMessageID();

+

+    // options

+    int addOption(uint16_t optionNumber, uint16_t optionLength, uint8_t *optionValue);

+    // gets a list of all options

+    CoapOption* getOptions();

+    int getNumOptions();

+    // shorthand helpers

+    int setURI(char *uri);

+    int setURI(char *uri, int urilen);

+    int getURI(char *dst, int dstlen, int *outLen);

+    int addURIQuery(char *query);

+

+    // content format helper

+    int setContentFormat(int format);

+

+    // payload

+    uint8_t* mallocPayload(int bytes);

+    int setPayload(uint8_t *value, int len);

+    uint8_t* getPayloadPointer();

+    int getPayloadLength();

+    uint8_t* getPayloadCopy();

+

+    // pdu

+    int getPDULength();

+    uint8_t* getPDUPointer();

+    void setPDULength(int len);

+    void getOptionValueById(uint16_t optionNumber, uint16_t *optionValueLength,uint8_t *optionValuePointer);

+    const char *printHuman();

+    const char * printHex();

+    int hasOption(uint16_t optionNumber);

+private:

+    // variables

+    uint8_t *_pdu;

+    int _pduLength;

+

+    int _constructedFromBuffer;

+    int _bufferLength;

+

+    uint8_t *_payloadPointer;

+    int _payloadLength;

+

+    int _numOptions;

+    uint16_t _maxAddedOptionNumber;

+    ASBuffer content;

+

+    // functions

+    void shiftPDUUp(int shiftOffset, int shiftAmount);

+    void shiftPDUDown(int startLocation, int shiftOffset, int shiftAmount);

+    uint8_t codeToValue(int c);

+

+    // option stuff

+    int findInsertionPosition(uint16_t optionNumber, uint16_t *prevOptionNumber);

+    int computeExtraBytes(uint16_t n);

+    int insertOption(int insertionPosition, uint16_t optionDelta, uint16_t optionValueLength, uint8_t *optionValue);

+    uint16_t getOptionDelta(uint8_t *option);

+    void setOptionDelta(int optionPosition, uint16_t optionDelta);

+    uint16_t getOptionValueLength(uint8_t *option);

+

+};

+

+/*

+#define COAP_CODE_EMPTY 0x00

+

+// method codes 0.01-0.31

+#define COAP_CODE_GET   0x01

+#define COAP_CODE_POST  0x02

+#define COAP_CODE_PUT   0x03

+#define COAP_CODE_DELETE 0x04

+

+// Response codes 2.00 - 5.31

+// 2.00 - 2.05

+#define COAP_CODE_CREATED 0x41

+#define COAP_CODE_DELETED 0x42

+#define COAP_CODE_VALID   0x43

+#define COAP_CODE_CHANGED 0x44

+#define COAP_CODE_CONTENT 0x45

+

+// 4.00 - 4.15

+#define COAP_CODE_BAD_REQUEST                0x80

+#define COAP_CODE_UNAUTHORIZED               0x81

+#define COAP_CODE_BAD_OPTION                 0x82

+#define COAP_CODE_FORBIDDEN                  0x83

+#define COAP_CODE_NOT_FOUND                  0x84

+#define COAP_CODE_METHOD_NOT_ALLOWED         0x85

+#define COAP_CODE_NOT_ACCEPTABLE             0x86

+#define COAP_CODE_PRECONDITION_FAILED        0x8C

+#define COAP_CODE_REQUEST_ENTITY_TOO_LARGE   0x8D

+#define COAP_CODE_UNSUPPORTED_CONTENT_FORMAT 0x8F

+

+// 5.00 - 5.05

+#define COAP_CODE_INTERNAL_SERVER_ERROR      0xA0

+#define COAP_CODE_NOT_IMPLEMENTED            0xA1

+#define COAP_CODE_BAD_GATEWAY                0xA2

+#define COAP_CODE_SERVICE_UNAVAILABLE        0xA3

+#define COAP_CODE_GATEWAY_TIMEOUT            0xA4

+#define COAP_CODE_PROXYING_NOT_SUPPORTED     0xA5

+*/

+

+#endif

diff --git a/mbtk/mbtk_lib/inc/mbtk_http_base.h b/mbtk/mbtk_lib/inc/mbtk_http_base.h
new file mode 100644
index 0000000..2490b78
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_http_base.h
@@ -0,0 +1,124 @@
+/*************************************************************
+Description:
+    HTTP platform related function implementation.
+Author:
+    LiuBin
+Date:
+    2020/4/30 14:02:58
+*************************************************************/
+#ifndef _MBTK_HTTP_BASE_H
+#define _MBTK_HTTP_BASE_H
+
+#include <stdio.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "mbtk_sock2.h"
+
+/*************************************************************
+    Public Function Declaration
+*************************************************************/
+int mbtk_http_init();
+int mbtk_http_deinit();
+int mbtk_http_open
+(
+    bool is_ssl,
+    bool ingnore_cert,
+    const void *host,
+    uint16 port
+);
+
+/*=============================================
+FUNCTION
+    mbtk_http_read
+
+DESCRIPTION
+    read content from socket.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    *buf      Store read content.
+    len       the length of Content.
+    timeout   Set timeout
+
+RETURN VALUE
+    Length of read content
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_http_read
+(
+    int sock_fd,
+    void *buf,
+    uint16 len,
+    int timeout_ms
+);
+
+#if 0
+int mbtk_http_read_line
+(
+    FILE *file,
+    void *buf,
+    uint16 len
+);
+#else
+int mbtk_http_read_line
+(
+    int sock_fd,
+    void *buf,
+    uint16 len
+);
+#endif
+
+/*=============================================
+FUNCTION
+    mbtk_http_write
+
+DESCRIPTION
+    Write content to socket.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    *buf    Content to be transferred
+    len     the length of Content.
+
+RETURN VALUE
+    Length of written content
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_http_write
+(
+    int sock_fd,
+    void *buf,
+    uint16 len
+);
+
+/*=============================================
+FUNCTION
+    mbtk_http_close
+
+DESCRIPTION
+    close HTTP service.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    *err    Error number
+
+RETURN VALUE
+    TURE or FALSE
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_http_close(int sock_fd);
+
+#endif /* _MBTK_HTTP_BASE_H */
diff --git a/mbtk/mbtk_lib/inc/mbtk_http_chunks.h b/mbtk/mbtk_lib/inc/mbtk_http_chunks.h
new file mode 100644
index 0000000..eff228c
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_http_chunks.h
@@ -0,0 +1,66 @@
+#ifndef _MBTK_HTTP_CHUNKS_H
+#define _MBTK_HTTP_CHUNKS_H
+#include "mbtk_type.h"
+
+/*
+ * The longest possible hexadecimal number we support in a chunked transfer.
+ * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
+ * to convert it, we "only" support 2^32 bytes chunk data.
+ */
+#define MAXNUM_SIZE 16
+
+typedef enum {
+  /* await and buffer all hexadecimal digits until we get one that isn't a
+     hexadecimal digit. When done, we go CHUNK_LF */
+  CHUNK_HEX,
+
+  /* wait for LF, ignore all else */
+  CHUNK_LF,
+
+  /* We eat the amount of data specified. When done, we move on to the
+     POST_CR state. */
+  CHUNK_DATA,
+
+  /* POSTLF should get a CR and then a LF and nothing else, then move back to
+     HEX as the CRLF combination marks the end of a chunk. A missing CR is no
+     big deal. */
+  CHUNK_POSTLF,
+
+  /* At this point optional trailer headers can be found, unless the next line
+     is CRLF */
+  CHUNK_TRAILER,
+
+  /* Used to mark that we're out of the game.  NOTE: that there's a 'dataleft'
+     field in the struct that will tell how many bytes that were not passed to
+     the client in the end of the last buffer! */
+  CHUNK_STOP
+} http_chunk_state;
+
+typedef enum {
+  CHUNKE_STOP = -1,
+  CHUNKE_OK = 0,
+  CHUNKE_TOO_LONG_HEX = 1,
+  CHUNKE_ILLEGAL_HEX,
+  CHUNKE_BAD_CHUNK,
+  CHUNKE_BAD_ENCODING,
+  CHUNKE_OUT_OF_MEMORY,
+  CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */
+  CHUNKE_LAST
+} http_chunk_code;
+
+typedef struct {
+  char hexbuffer[MAXNUM_SIZE + 1];
+  int hexindex;
+  http_chunk_state state;
+  int datasize;
+  int dataleft; /* untouched data amount at the end of the last buffer */
+} http_chunker_t;
+
+/* The following functions are defined in http_chunks.c */
+void http_chunk_init(http_chunker_t *chunker);
+http_chunk_code http_chunk_parse(http_chunker_t *chunker, char *src, int src_len,
+            char *dest,int *dest_len);
+
+#endif /* _MBTK_HTTP_CHUNKS_H */
+
+
diff --git a/mbtk/mbtk_lib/inc/mbtk_info.h b/mbtk/mbtk_lib/inc/mbtk_info.h
new file mode 100755
index 0000000..7277171
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_info.h
@@ -0,0 +1,496 @@
+#ifndef MBTK_INFO_INCLUDE
+#define MBTK_INFO_INCLUDE
+#include <netinet/in.h>
+
+#include "mbtk_type.h"
+#include "mbtk_list.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+#include "mbtk_info_api.h"
+
+#define MBTK_INFO_PACKET_FLAG 0x5F6F7F8F
+#define SOCK_INFO_PATH "/tmp/info_sock"
+#define SOCK_MSG_LEN_MAX 2048
+
+// Tag(4) + Packet_Length(2)
+#define SOCK_PACK_EXTRA_LEN 6
+// SOCK_PACK_EXTRA_LEN + Id(2) + Error(2) + Number(2)
+#define SOCK_PACK_LEN_MIN (SOCK_PACK_EXTRA_LEN + 6)
+
+typedef enum
+{
+    MBTK_INFO_TYPE_REQ,
+    MBTK_INFO_TYPE_RSP,
+    MBTK_INFO_TYPE_IND,
+    MBTK_INFO_TYPE_UNKNOWN
+} mbtk_info_type_enum;
+
+typedef enum
+{
+    // Device Information
+    MBTK_INFO_ID_DEV_BEGIN = 0,
+    // <string> IMEI
+    MBTK_INFO_ID_DEV_IMEI_REQ,
+    MBTK_INFO_ID_DEV_IMEI_RSP,
+    // <string> SN
+    MBTK_INFO_ID_DEV_SN_REQ,
+    MBTK_INFO_ID_DEV_SN_RSP,
+    // <string> MEID
+    MBTK_INFO_ID_DEV_MEID_REQ,
+    MBTK_INFO_ID_DEV_MEID_RSP,
+    // <string> VERSION
+    MBTK_INFO_ID_DEV_VERSION_REQ,
+    MBTK_INFO_ID_DEV_VERSION_RSP,
+    // <string> MODEL
+    MBTK_INFO_ID_DEV_MODEL_REQ,
+    MBTK_INFO_ID_DEV_MODEL_RSP,
+    // <uint8> 0:Close 1:Open
+    MBTK_INFO_ID_DEV_VOLTE_REQ,
+    MBTK_INFO_ID_DEV_VOLTE_RSP,
+    // <string> Temperature
+    MBTK_INFO_ID_DEV_TEMP_REQ,  // Temperature
+    MBTK_INFO_ID_DEV_TEMP_RSP,
+    // <uint8><string>  YYYY-MM-DD-HH:MM:SS
+    MBTK_INFO_ID_DEV_TIME_REQ,  // Time
+    MBTK_INFO_ID_DEV_TIME_RSP,
+    //<string>  "23/03/20,01:58:00+32"
+    MBTK_INFO_ID_NET_TIME_REQ,  // Time
+    MBTK_INFO_ID_NET_TIME_RSP,
+
+    MBTK_INFO_ID_DEV_MODEM_REQ,
+    MBTK_INFO_ID_DEV_MODEM_RSP,
+
+    MBTK_INFO_ID_DEV_END,
+
+    // Sim Information
+    MBTK_INFO_ID_SIM_BEGIN = 1000,
+    // <uint8> 0:NOT_EXIST 1:READY ...
+    MBTK_INFO_ID_SIM_STATE_REQ,
+    MBTK_INFO_ID_SIM_STATE_RSP,
+    // <uint8> 0: SIM 1: USIM 2: TEST SIM 3: TEST USIM 4: UNKNOWN
+    MBTK_INFO_ID_SIM_STYPE_REQ,
+    MBTK_INFO_ID_SIM_STYPE_RSP,
+    // <string> PIN
+    MBTK_INFO_ID_SIM_PIN_REQ,
+    MBTK_INFO_ID_SIM_PIN_RSP,
+    // <string> PIN
+    MBTK_INFO_ID_SIM_ENABLE_PIN_REQ,
+    MBTK_INFO_ID_SIM_ENABLE_PIN_RSP,
+    // <string> PUK
+    MBTK_INFO_ID_SIM_PUK_REQ,
+    MBTK_INFO_ID_SIM_PUK_RSP,
+    // <string> PLMN
+    MBTK_INFO_ID_SIM_PLMN_REQ,
+    MBTK_INFO_ID_SIM_PLMN_RSP,
+    // <uint8> <uint8> <uint8> <uint8> PIN PUK LAST TIMES
+    MBTK_INFO_ID_SIM_PINPUK_TIMES_REQ,
+    MBTK_INFO_ID_SIM_PINPUK_TIMES_RSP,
+    // <string> IMSI
+    MBTK_INFO_ID_SIM_IMSI_REQ,
+    MBTK_INFO_ID_SIM_IMSI_RSP,
+    // <string> ICCID
+    MBTK_INFO_ID_SIM_ICCID_REQ,
+    MBTK_INFO_ID_SIM_ICCID_RSP,
+    // <string> Phone Number
+    MBTK_INFO_ID_SIM_PN_REQ,
+    MBTK_INFO_ID_SIM_PN_RSP,
+    // <string> <string> old_PIN new_PIN
+    MBTK_INFO_ID_SIM_CHANGE_PIN_REQ,
+    MBTK_INFO_ID_SIM_CHANGE_PIN_RSP,
+
+    MBTK_INFO_ID_SIM_END,
+
+    // Network Information
+    MBTK_INFO_ID_NET_BEGIN = 2000,
+    // <uint8> 0:OFF 1:ON
+    MBTK_INFO_ID_NET_RADIO_REQ,
+    MBTK_INFO_ID_NET_RADIO_RSP,
+    // sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+    MBTK_INFO_ID_NET_AVAILABLE_REQ,
+    MBTK_INFO_ID_NET_AVAILABLE_RSP,
+    // <uint8> 0: automatic 1: manual
+    // or
+    // sel_mode(uint8)type(uint8)plmn(uint32)
+    MBTK_INFO_ID_NET_SEL_MODE_REQ,
+    MBTK_INFO_ID_NET_SEL_MODE_RSP,
+    // mbtk_band_info_t
+    MBTK_INFO_ID_NET_BAND_REQ,
+    MBTK_INFO_ID_NET_BAND_RSP,
+    // mbtk_signal_info_t
+    MBTK_INFO_ID_NET_SIGNAL_REQ,
+    MBTK_INFO_ID_NET_SIGNAL_RSP,
+    // mbtk_net_reg_info_t
+    MBTK_INFO_ID_NET_REG_REQ,
+    MBTK_INFO_ID_NET_REG_RSP,
+    // mbtk_apn_info_t
+    MBTK_INFO_ID_NET_APN_REQ,
+    MBTK_INFO_ID_NET_APN_RSP,
+    // mbtk_cell_info_t[]
+    MBTK_INFO_ID_NET_CELL_REQ,
+    MBTK_INFO_ID_NET_CELL_RSP,
+    // REQ:
+    // <call_type[1]><cid[1]><timeout[1]>
+    //  call_type : mbtk_data_call_type_enum
+    //  cid : 1 - 15
+    //  timeout : second
+    // RSP:
+    //  <type[1]><ipv4><ipv6>
+    //  type : 0-IPV4   1-IPV6  2-IPV4V6
+    //  ipv4 : mbtk_ipv4_info_t
+    //  ipv6 : mbtk_ipv6_info_t
+    MBTK_INFO_ID_NET_DATA_CALL_REQ,
+    MBTK_INFO_ID_NET_DATA_CALL_RSP,
+
+    MBTK_INFO_ID_NET_END,
+
+    // Call Information
+    MBTK_INFO_ID_CALL_BEGIN = 3000,
+    MBTK_INFO_ID_CALL_STATE_REQ,
+    MBTK_INFO_ID_CALL_STATE_RSP,
+
+    // Start call.
+    MBTK_INFO_ID_CALL_START_REQ,
+    MBTK_INFO_ID_CALL_START_RSP,
+    //answer call
+    MBTK_INFO_ID_CALL_ANSWER_REQ,
+    MBTK_INFO_ID_CALL_ANSWER_RSP,
+    //hang up all call
+    MBTK_INFO_ID_CALL_HANGUP_REQ,
+    MBTK_INFO_ID_CALL_HANGUP_RSP,
+    //hang up a call
+    MBTK_INFO_ID_CALL_HANGUP_A_REQ,
+    MBTK_INFO_ID_CALL_HANGUP_A_RSP,
+    //hang up waiting or background call
+    MBTK_INFO_ID_CALL_HANGUP_B_REQ,
+    MBTK_INFO_ID_CALL_HANGUP_B_RSP,
+    //hang up foreground resume background
+    MBTK_INFO_ID_CALL_HANGUP_C_REQ,
+    MBTK_INFO_ID_CALL_HANGUP_C_RSP,
+    //wait in call
+    MBTK_INFO_ID_CALL_WAITIN_REQ,
+    MBTK_INFO_ID_CALL_WAITIN_RSP,
+    //mute call
+    MBTK_INFO_ID_CALL_MUTE_REQ,
+    MBTK_INFO_ID_CALL_MUTE_RSP,
+    //dtmf call
+    MBTK_INFO_ID_CALL_DTMF_REQ,
+    MBTK_INFO_ID_CALL_DTMF_RSP,
+
+    MBTK_INFO_ID_CALL_END,
+
+    // SMS Information
+    MBTK_INFO_ID_SMS_BEGIN = 4000,
+    MBTK_INFO_ID_SMS_STATE_REQ,
+    MBTK_INFO_ID_SMS_STATE_RSP,
+    MBTK_INFO_ID_SMS_CMGF_REQ,
+    MBTK_INFO_ID_SMS_CMGF_RSP,
+    MBTK_INFO_ID_SMS_CPMS_REQ,
+    MBTK_INFO_ID_SMS_CPMS_RSP,
+    MBTK_INFO_ID_SMS_CMGS_REQ,
+    MBTK_INFO_ID_SMS_CMGS_RSP,
+    MBTK_INFO_ID_SMS_CMSS_REQ,
+    MBTK_INFO_ID_SMS_CMSS_RSP,
+    MBTK_INFO_ID_SMS_CMGR_REQ,
+    MBTK_INFO_ID_SMS_CMGR_RSP,
+    MBTK_INFO_ID_SMS_CMGW_REQ,
+    MBTK_INFO_ID_SMS_CMGW_RSP,
+    MBTK_INFO_ID_SMS_CMGD_REQ,
+    MBTK_INFO_ID_SMS_CMGD_RSP,
+    MBTK_INFO_ID_SMS_CMGL_REQ,
+    MBTK_INFO_ID_SMS_CMGL_RSP,
+    MBTK_INFO_ID_SMS_CSCA_REQ,
+    MBTK_INFO_ID_SMS_CSCA_RSP,
+    MBTK_INFO_ID_SMS_CSMP_REQ,
+    MBTK_INFO_ID_SMS_CSMP_RSP,
+    MBTK_INFO_ID_SMS_CSCB_REQ,
+    MBTK_INFO_ID_SMS_CSCB_RSP,
+    MBTK_INFO_ID_SMS_CNMI_REQ,
+    MBTK_INFO_ID_SMS_CNMI_RSP,
+
+    MBTK_INFO_ID_SMS_END,
+
+    // PhoneBook Information
+    MBTK_INFO_ID_PB_BEGIN = 5000,
+    MBTK_INFO_ID_PB_STATE_REQ,
+    MBTK_INFO_ID_PB_STATE_RSP,
+
+    MBTK_INFO_ID_PB_END,
+
+    // IND Information
+    MBTK_INFO_ID_IND_BEGIN = 10000,
+    // <uint8>  State
+    MBTK_INFO_ID_IND_NET_STATE_CHANGE,
+    // <uint8>  State
+    MBTK_INFO_ID_IND_CALL_STATE_CHANGE,
+    // <uint8>  State
+    MBTK_INFO_ID_IND_SMS_STATE_CHANGE,
+    // <uint8>  State
+    MBTK_INFO_ID_IND_RADIO_STATE_CHANGE,
+    // <uint8>  State
+    MBTK_INFO_ID_IND_SIM_STATE_CHANGE,
+    // <uint8>  State
+    MBTK_INFO_ID_IND_PDP_STATE_CHANGE,
+    // <uint8> State
+    MBTK_INFO_ID_IND_SERVER_STATE_CHANGE,////mbtk wyq for server_ready_status add
+
+    MBTK_INFO_ID_IND_END,
+    MBTK_INFO_ID_REQ_UNKNOWN        // Unknown information.
+} mbtk_info_id_enum;
+
+typedef enum {
+    MBTK_NET_CS_STATE = 0,
+    MBTK_NET_PS_STATE
+} mbtk_net_state_type_enum;
+
+typedef enum {
+    MBTK_INFO_ERR_SUCCESS = 300,
+    MBTK_INFO_ERR_FORMAT,       // Packet format error.
+    MBTK_INFO_ERR_REQ_UNKNOWN,  // Unknown request.
+    MBTK_INFO_ERR_REQ_PARAMETER,  // Request parameter error.
+    MBTK_INFO_ERR_UNSUPPORTED,  // Unsupported operation.
+    MBTK_INFO_ERR_MEMORY,       // Insufficient memory.
+    MBTK_INFO_ERR_IND_FULL,     // Register IND fail(FULL).
+    MBTK_INFO_ERR_IND_UNKNOWN,  // Register IND fail(Unknown IND).
+    MBTK_INFO_ERR_CID,  // CID error.
+    MBTK_INFO_ERR_TIMEOUT,  // Timeout.
+    MBTK_INFO_ERR_TIME_FORMAT,  // Time format error.
+    
+    //mbtk wyq for data_call add start
+    MBTK_INFO_ERR_CID_EXIST,
+    MBTK_INFO_ERR_CID_NO_EXIST,
+    MBTK_INFO_ERR_NET_NO_INIT,
+    //mbtk wyq for data_call add end
+
+    MBTK_INFO_ERR_UNKNOWN = 400,  // Unknown error.
+    // CME error start index.
+    MBTK_INFO_ERR_CME = 500,
+    MBTK_INFO_ERR_CME_NON = 1000
+} mbtk_info_err_enum;
+
+/*
+GSM band��
+    1 �C PGSM 900 (standard or primary)
+    2 �C DCS GSM 1800
+    4 �C PCS GSM 1900
+    8 �C EGSM 900 (extended)
+    16 �C GSM 450
+    32 �C GSM 480
+    64 �C GSM 850
+    512 - BAND_LOCK_BIT // used for GSM band setting
+*/
+typedef enum
+{
+    MBTK_GSM_BAND_PGSM_900 = 1,
+    MBTK_GSM_BAND_DCS_GSM_1800 = 2,
+    MBTK_GSM_BAND_PCS_GSM_1900 = 4,
+    MBTK_GSM_BAND_EGSM_900 = 8,
+    MBTK_GSM_BAND_GSM_450 = 16,
+    MBTK_GSM_BAND_GSM_480 = 32,
+    MBTK_GSM_BAND_GSM_850 = 64,
+    MBTK_GSM_BAND_BAND_LOCK_BIT = 512
+} mbtk_gsm_band_enum;
+
+/*
+UMTS band��
+    1 �C UMTS_BAND_1
+    2 �C UMTS_BAND_2
+    4 �C UMTS_BAND_3
+    8 �C UMTS_BAND_4
+    16 �C UMTS_BAND_5
+    32 �C UMTS_BAND_6
+    64 �C UMTS_BAND_7
+    128 �C UMTS_BAND_8
+    256 �C UMTS_BAND_9
+*/
+typedef enum
+{
+    MBTK_UMTS_BAND_1 = 1,
+    MBTK_UMTS_BAND_2 = 2,
+    MBTK_UMTS_BAND_3 = 4,
+    MBTK_UMTS_BAND_4 = 8,
+    MBTK_UMTS_BAND_5 = 16,
+    MBTK_UMTS_BAND_6 = 32,
+    MBTK_UMTS_BAND_7 = 64,
+    MBTK_UMTS_BAND_8 = 128,
+    MBTK_UMTS_BAND_9 = 256
+} mbtk_umts_band_enum;
+
+/*
+LTEbandH(TDD-LTE band)
+    32 �C TDLTE_BAND_38
+    64 �C TDLTE_BAND_39
+    128 �C TDLTE_BAND_40
+    256 �C TDLTE_BAND_41
+*/
+typedef enum
+{
+    MBTK_TDLTE_BAND_38 = 32,
+    MBTK_TDLTE_BAND_39 = 64,
+    MBTK_TDLTE_BAND_40 = 128,
+    MBTK_TDLTE_BAND_41 = 256
+} mbtk_tdlte_band_enum;
+
+/*
+LTEbandL(FDD-LTE band)
+    1 �C FDDLTE_BAND_1
+    4 �C FDDLTE _BAND_3
+    8 �C FDDLTE _BAND_4
+    64 �C FDDLTE _BAND_7
+    65536 �C FDDLTE _BAND_17
+    524288 �C FDDLTE _BAND_20
+*/
+typedef enum
+{
+    MBTK_FDDLTE_BAND_1 = 1,
+    MBTK_FDDLTE_BAND_3 = 4,
+    MBTK_FDDLTE_BAND_4 = 8,
+    MBTK_FDDLTE_BAND_7 = 64,
+    MBTK_FDDLTE_BAND_17 = 65536,
+    MBTK_FDDLTE_BAND_20 = 524288
+} mbtk_fddlte_band_enum;
+
+/*
+0: unknown
+1: available
+2: current
+3: forbidden
+*/
+typedef enum
+{
+    MBTK_NET_AVIL_STATE_UNKNOWN = 0,
+    MBTK_NET_AVIL_STATE_AVAILABLE,
+    MBTK_NET_AVIL_STATE_CURRENT,
+    MBTK_NET_AVIL_STATE_FORBIDDEN
+} mbtk_net_avil_state_enum;
+
+typedef struct
+{
+    uint16 tac;
+    uint16 earfcn;
+} mbtk_local_info_t;
+
+typedef struct
+{
+    uint16 info_id;
+    uint16 info_err;
+    const uint8 *data;
+    uint16 data_len;
+} mbtk_info_pack_t;
+
+typedef struct
+{
+    uint8 type; // 0: GSM 1: UMTS 2: LTE
+    bool running;
+
+    int cell_num;
+    mbtk_cell_info_t cell[CELL_NUM_MAX];
+} mbtK_cell_pack_info_t;
+
+typedef enum {
+    MBTK_MOBILE_ORIGINATED_CALL,
+    MBTK_TERMINATED_CALL,
+} mbtk_call_dir_enum;
+
+typedef enum {
+    MBTK_VOICE,
+    MBTK_DATA,
+    MBTK_FAX,
+    MBTK_VOICE_FOLLOWED_BY_DATA_VOICE_MODE,
+    MBTK_ALTERNATING_VOICE_VOICE_MODE,
+    MBTK_ALTERNATING_FAX_VOICE_MODE,
+    MBTK_VOICE_FOLLOWED_BY_DATA_DATA_MODE,
+    MBTK_ALTERNATING_VOICE_DATA_MODE,
+    MBTK_ALTERNATING_FAX_FAX_MODE,
+    MBTL_UNKNOW,
+} mbtk_call_mode_enum;
+
+typedef enum {
+    MBTK_NOT_MULITYPARTY_CALL,
+    MBTK_MULITYPARTY__CALL,
+} mbtk_call_mpty_enum;
+
+typedef struct
+{
+    int cid;
+    bool act;
+    bool waitting;
+} info_cgact_wait_t;
+
+typedef struct
+{
+    uint32 count;
+    list_node_t *net_list;
+} mbtk_net_array_info_t;
+
+typedef struct
+{
+    bool inited;
+    mbtk_radio_state_enum radio_state;
+    mbtk_sim_state_enum sim_state;
+    mbtk_radio_technology_enum net_type;
+    mbtk_ip_type_enum ip_type;
+    struct sockaddr_in addr4;
+    struct sockaddr_in preferred_dns4;
+    struct sockaddr_in alternate_dns4;
+
+    struct sockaddr_in6 addr6;
+    struct sockaddr_in6 preferred_dns6;
+    struct sockaddr_in6 alternate_dns6;
+} net_info_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+char* type2str(mbtk_info_type_enum type);
+
+char* apn2str(mbtk_ip_type_enum type);
+
+char* id2str(int id);
+
+char* err2str(mbtk_info_err_enum err);
+
+/*
+IPv6 : 254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239 -> uint128
+*/
+int str_2_ipv6(const void *ip_str, void *ipv6);
+
+/*
+IPv6 : uint128 -> fe80::215:1dff:fe81:484c
+*/
+int ipv6_2_str(const void *ipv6, void *ipv6_str);
+
+/*
+0   GSM
+1   GSM_COMPACT
+2   UTRAN
+3   GSM_EGPRS
+4   UTRAN_HSDPA
+5   UTRAN_HSUPA
+6   UTRAN_HSDPA_HSUPA
+7   EUTRAN
+8   ECGSM
+*/
+mbtk_net_type_enum mbtk_net_type_get(mbtk_radio_technology_enum radio_tech);
+
+mbtk_info_type_enum mbtk_info_type_get(int info_id);
+
+mbtk_info_pack_t* mbtk_info_pack_creat(int info_id);
+
+#if 0
+int mbtk_info_pack_data_set(mbtk_info_pack_t *pack, const void *data, int data_len);
+void* mbtk_info_pack_data_get(mbtk_info_pack_t *pack, int *data_len);
+#endif
+
+int mbtk_info_pack_send(int fd, mbtk_info_pack_t *pack);
+
+mbtk_info_pack_t** mbtk_info_pack_recv(int fd, bool is_server, mbtk_info_err_enum *err);
+
+int mbtk_info_pack_free(mbtk_info_pack_t **pack);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* MBTK_INFO_INCLUDE */
+
+
diff --git a/mbtk/mbtk_lib/inc/mbtk_pdu_sms.h b/mbtk/mbtk_lib/inc/mbtk_pdu_sms.h
new file mode 100755
index 0000000..c6416df
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_pdu_sms.h
@@ -0,0 +1,191 @@
+//

+// Created by hitmoon on 15-12-9.

+//

+

+#ifndef SMS_SMS_H

+#define SMS_SMS_H

+

+#include <string.h>

+#include "mbtk_utf.h"

+#include "mbtk_type.h"

+

+#define MAX_SMS_NR 32

+

+//typedef int bool;

+

+#define true 1

+#define false 0

+

+enum EnumDCS {

+    BIT7 = 0,            // GSM 字符集

+    BIT8 = 1,            // ASCII字符集

+    UCS2 = 2             // Unicode 字符集

+};

+

+enum EnumUDL {

+    BIT7UDL = 160,

+    BIT8UDL = 140,

+    UCS2UDL = 70

+};

+

+enum EnumCSMIEI {

+    BIT8MIEI = 0,

+    BIT16MIEI = 8

+};

+

+struct PDUUDH {

+    unsigned int count;    // 信息元素数据字节数

+    char IEI;           // 信息元素标识

+    char *IED;          // 信息元素数据

+};

+

+// 用户数据头

+struct UDHS {

+    int count;

+    struct PDUUDH *UDH;

+};

+

+// 用户数据数组,用于拆分短信

+struct UDS {

+    unsigned int total;

+    char **Data;

+};

+

+// 编码后短信

+struct PDUS {

+    unsigned int count;

+    char **PDU;

+};

+

+struct ByteArray {

+    char *array;

+    unsigned int len;

+};

+

+struct SMS_Struct {

+    char *SCA;         // 服务中心地址

+    char *OA;          // 发送方地址

+    char *SCTS;        // 服务中心时间戳

+    struct UDHS *UDH;     // 用户数据头

+    char *UD;          // 用户数据

+

+    bool RP;              // 应答路径

+    bool UDHI;            // 用户数据头标识

+    bool SRI;             // 状态报告指示

+    bool MMS;             // 更多信息发送

+    int MTI;              // 信息类型指示

+

+    char PID;          // PID 协议标识

+

+    enum EnumDCS DCS;      // 数据编码方案

+    bool TC;              // 文本压缩指示 0: 未压缩 1:压缩

+    int MC;               // 消息类型 -1: 无 1:移动设备特定类型 2:SIM特定类型 3:终端设备特定类型

+

+};

+

+

+// 短信解码

+struct SMS_Struct PDUDecoding(const char *data);

+

+// 短信编码, 自动确定编码方案

+struct PDUS *PDUEncoding(char *SCA, char *DA, char *UDC, struct UDHS *udhs);

+

+// 短信编码真正的工作

+/// 发送方PDU格式(SMS-SUBMIT-PDU)

+/// SCA(Service Center Adress):短信中心,长度1-12

+/// PDU-Type(Protocol Data Unit Type):协议数据单元类型,长度1

+/// MR(Message Reference):消息参考值,为0~255。长度1

+/// DA(Destination Adress):接收方SME的地址,长度2-12

+/// PID(Protocol Identifier):协议标识,长度1

+/// DCS(Data Coding Scheme):编码方案,长度1

+/// VP(Validity Period):有效期,长度为1(相对)或者7(绝对或增强)

+/// UDL(User Data Length):用户数据段长度,长度1

+/// UD(User Data):用户数据,长度0-140

+

+struct PDUS *PDUDoEncoding(char *SCA, char *DA, char *UDC, struct UDHS *udhs, enum EnumDCS DCS);

+

+

+// 服务中心地址解码

+char *SCADecoding(const char *data, int *EndIndex);

+

+// 原始地址解码

+char *OADecoding(const char *data, int index, int *EndIndex);

+

+// 服务中心时间戳解码

+char *SCTSDecoding(const char *data, int index);

+

+// BCD 解码

+int BCDDecoding(const char *data, int index, bool isMSB);

+

+// 用户数据头解码

+struct UDHS *UDHDecoding(const char *data, int index);

+

+// 用户数据解码

+char *UserDataDecoding(const char *data, int index, bool UDHI, enum EnumDCS dcs);

+

+// 7-Bit编码解压缩

+char *BIT7Unpack(const char *data, int index, int Septets, int FillBits);

+

+// 转换GSM字符编码到Unicode编码

+char *BIT7Decoding(char *BIT7Data, unsigned int size);

+

+// 7-Bit序列和Unicode编码是否相同

+int isBIT7Same(u_int16_t UCS2);

+

+// 判断是否是GSM字符串

+int isGSMString(char *Data);

+

+// 用户数据拆分

+struct UDS *UDCSplit(char *UDC, struct UDHS *uhds, enum EnumDCS DCS);

+

+// 获得用户数据头长度

+int getUDHL(struct UDHS *udhs);

+

+// 计算需要的7-Bit编码字节数

+int SeptetsLength(char *source);

+

+// 将7-Bit编码字节数换算成UCS2编码字符数

+int SeptetsToChars(char *source, int index, int septets);

+

+// 在用户数据头中增加长短信信息元素

+struct UDHS *UpdateUDH(struct UDHS *udhs, int CSMMR, int total, int index);

+

+//单条短信编码

+char *SoloPDUEncoding(char *SCA, char *DA, char *UC, struct UDHS *udhs, enum EnumDCS DCS);

+

+// SCA编码

+char *SCAEncoding(char *SCA);

+

+// PDUTYPE 编码

+char *PDUTypeEncoding(bool UDH);

+

+// MR,消息参考值

+char *MREncoding();

+

+//接收方SME地址

+char *DAEncoding(char *DA);

+

+// 协议标识

+char *PIDEncoding();

+

+// 编码方案

+char *DCSEncoding(char *UD, enum EnumDCS DCS);

+

+// 用户数据长度及内容

+char *UDEncoding(char *UD, struct UDHS *udhs, enum EnumDCS DCS);

+

+// 用户数据头编码

+char *UDHEncoding(struct UDHS *udhs, int *UDHL);

+

+// 用户数据内容编码

+char *UDCEncoding(char *UDC, int *UDCL, int UDHL, enum EnumDCS DCS);

+

+// 将UCS2编码字符串转换成7-Bit编码字节 序列

+struct ByteArray *BIT7Encoding(char *UDC, int *Septets);

+

+//  7-Bit编码压缩

+char *BIT7Pack(struct ByteArray *Bit7Array, int UDHL);

+

+void sms_init();

+

+#endif //SMS_SMS_H

diff --git a/mbtk/mbtk_lib/inc/mbtk_sock_internal.h b/mbtk/mbtk_lib/inc/mbtk_sock_internal.h
new file mode 100644
index 0000000..9e2ec2e
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_sock_internal.h
@@ -0,0 +1,58 @@
+#ifndef MBTK_SOCK_INTERNAL_INCLUDE
+#define MBTK_SOCK_INTERNAL_INCLUDE
+#include "mbtk_sock2.h"
+//#include <openssl/ssl.h>
+
+#define MBTK_HANDLE_MAX_NUM 5
+#define MBTK_SOCK_MAX_NUM 10
+
+typedef struct {
+    int fd;
+    entropy_context* entropy;
+    ctr_drbg_context* ctr_drbg;
+    ssl_context *ssl;
+    ssl_session *saved_session;
+    x509_crt *cacert;
+    x509_crt *clicert;
+    pk_context* pkey;
+} mbtk_sock_inter_info_s;
+
+typedef struct {
+    mbtk_init_info init_info;
+    int sock_num;
+    mbtk_sock_inter_info_s inter_infos[MBTK_SOCK_MAX_NUM];
+    mbtk_sock_info infos[MBTK_SOCK_MAX_NUM];
+} mbtk_sock_s;
+struct options
+{
+    const char *server_name;    /* hostname of the server (client only)     */
+    const char *server_addr;    /* address of the server (client only)      */
+    int server_port;            /* port on which the ssl service runs       */
+    int debug_level;            /* level of debugging                       */
+    int nbio;                   /* should I/O be blocking?                  */
+    const char *request_page;   /* page on server to request                */
+    int request_size;           /* pad request with header to requested size */
+    const char *ca_file;        /* the file with the CA certificate(s)      */
+    const char *ca_path;        /* the path with the CA certificate(s) reside */
+    const char *crt_file;       /* the file with the client certificate     */
+    const char *key_file;       /* the file with the client key             */
+    const char *psk;            /* the pre-shared key                       */
+    const char *psk_identity;   /* the pre-shared key identity              */
+    int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
+    int renegotiation;          /* enable / disable renegotiation           */
+    int allow_legacy;           /* allow legacy renegotiation               */
+    int renegotiate;            /* attempt renegotiation?                   */
+    int renego_delay;           /* delay before enforcing renegotiation     */
+    int exchanges;              /* number of data exchanges                 */
+    int min_version;            /* minimum protocol version accepted        */
+    int max_version;            /* maximum protocol version accepted        */
+    int auth_mode;              /* verify mode for connection               */
+    unsigned char mfl_code;     /* code for maximum fragment length         */
+    int trunc_hmac;             /* negotiate truncated hmac or not          */
+    int reconnect;              /* attempt to resume session                */
+    int reco_delay;             /* delay in seconds before resuming session */
+    int tickets;                /* enable / disable session tickets         */
+    const char *alpn_string;    /* ALPN supported protocols                 */
+} opt;
+
+#endif /* MBTK_SOCK_INTERNAL_INCLUDE */
\ No newline at end of file
diff --git a/mbtk/mbtk_lib/inc/mbtk_utf.h b/mbtk/mbtk_lib/inc/mbtk_utf.h
new file mode 100644
index 0000000..6a16ced
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/mbtk_utf.h
@@ -0,0 +1,85 @@
+//

+// Created by hitmoon on 15-12-17.

+//

+

+#ifndef SMS_UTF_H

+#define SMS_UTF_H

+

+#include <stddef.h>

+#include <sys/types.h>

+

+typedef unsigned int UTF32;

+/* at least 32 bits */

+typedef unsigned short UTF16;

+/* at least 16 bits */

+typedef unsigned char UTF8;

+/* typically 8 bits */

+typedef unsigned char Boolean; /* 0 or 1 */

+

+/* Some fundamental constants */

+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD

+#define UNI_MAX_BMP (UTF32)0x0000FFFF

+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF

+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF

+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF

+

+typedef enum {

+    conversionOK, /* conversion successful */

+            sourceExhausted, /* partial character in source, but hit end */

+            targetExhausted, /* insuff. room in target for conversion */

+            sourceIllegal        /* source sequence is illegal/malformed */

+} ConversionResult;

+

+typedef enum {

+    strictConversion = 0,

+    lenientConversion

+} ConversionFlags;

+

+/* This is for C++ and does no harm in C */

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+ConversionResult ConvertUTF8toUTF16(

+        const UTF8 **sourceStart, const UTF8 *sourceEnd,

+        UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);

+

+ConversionResult ConvertUTF16toUTF8(

+        const UTF16 **sourceStart, const UTF16 *sourceEnd,

+        UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);

+

+ConversionResult ConvertUTF8toUTF32(

+        const UTF8 **sourceStart, const UTF8 *sourceEnd,

+        UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);

+

+ConversionResult ConvertUTF32toUTF8(

+        const UTF32 **sourceStart, const UTF32 *sourceEnd,

+        UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);

+

+ConversionResult ConvertUTF16toUTF32(

+        const UTF16 **sourceStart, const UTF16 *sourceEnd,

+        UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);

+

+ConversionResult ConvertUTF32toUTF16(

+        const UTF32 **sourceStart, const UTF32 *sourceEnd,

+        UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);

+

+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);

+

+#ifdef __cplusplus

+}

+#endif

+

+// 获得下一个char的起始地址

+u_int32_t next_char(unsigned char **string);

+

+const unsigned char *utf32toutf8(wchar_t *source, unsigned char *target, size_t size,  int *len);

+

+unsigned char *utf16toutf8(unsigned short *source, unsigned char *target, size_t size,  int *len);

+unsigned short *utf8toutf16(unsigned char *source, unsigned short *target, size_t size,  int *len);

+

+int utf8len(unsigned char *string);

+int is_acsii(unsigned char *string);

+size_t utf8_get_size(unsigned char *source, size_t num);

+

+#endif //SMS_UTF_H

diff --git a/mbtk/mbtk_lib/inc/ringbuffer.h b/mbtk/mbtk_lib/inc/ringbuffer.h
new file mode 100755
index 0000000..dfe8b4c
--- /dev/null
+++ b/mbtk/mbtk_lib/inc/ringbuffer.h
@@ -0,0 +1,138 @@
+#include <inttypes.h>
+#include <stddef.h>
+#include <assert.h>
+/**
+ * @file
+ * Prototypes and structures for the ring buffer module.
+ */
+
+#ifndef RINGBUFFER_H
+#define RINGBUFFER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define RING_BUFFER_ASSERT(x) assert(x)
+
+/**
+ * Checks if the buffer_size is a power of two.
+ * Due to the design only <tt> RING_BUFFER_SIZE-1 </tt> items
+ * can be contained in the buffer.
+ * buffer_size must be a power of two.
+*/
+#define RING_BUFFER_IS_POWER_OF_TWO(buffer_size) ((buffer_size & (buffer_size - 1)) == 0)
+
+/**
+ * The type which is used to hold the size
+ * and the indicies of the buffer.
+ */
+typedef size_t ring_buffer_size_t;
+
+/**
+ * Used as a modulo operator
+ * as <tt> a % b = (a & (b − 1)) </tt>
+ * where \c a is a positive index in the buffer and
+ * \c b is the (power of two) size of the buffer.
+ */
+#define RING_BUFFER_MASK(rb) (rb->buffer_mask)
+
+/**
+ * Simplifies the use of <tt>struct ring_buffer_t</tt>.
+ */
+typedef struct ring_buffer_t ring_buffer_t;
+
+/**
+ * Structure which holds a ring buffer.
+ * The buffer contains a buffer array
+ * as well as metadata for the ring buffer.
+ */
+struct ring_buffer_t {
+  /** Buffer memory. */
+  char *buffer;
+  /** Buffer mask. */
+  ring_buffer_size_t buffer_mask;
+  /** Index of tail. */
+  ring_buffer_size_t tail_index;
+  /** Index of head. */
+  ring_buffer_size_t head_index;
+};
+
+/**
+ * Initializes the ring buffer pointed to by <em>buffer</em>.
+ * This function can also be used to empty/reset the buffer.
+ * @param buffer The ring buffer to initialize.
+ * @param buf The buffer allocated for the ringbuffer.
+ * @param buf_size The size of the allocated ringbuffer.
+ */
+void ring_buffer_init(ring_buffer_t *buffer, char *buf, size_t buf_size);
+
+/**
+ * Adds a byte to a ring buffer.
+ * @param buffer The buffer in which the data should be placed.
+ * @param data The byte to place.
+ */
+void ring_buffer_queue(ring_buffer_t *buffer, char data);
+
+/**
+ * Adds an array of bytes to a ring buffer.
+ * @param buffer The buffer in which the data should be placed.
+ * @param data A pointer to the array of bytes to place in the queue.
+ * @param size The size of the array.
+ */
+void ring_buffer_queue_arr(ring_buffer_t *buffer, const char *data, ring_buffer_size_t size);
+
+/**
+ * Returns the oldest byte in a ring buffer.
+ * @param buffer The buffer from which the data should be returned.
+ * @param data A pointer to the location at which the data should be placed.
+ * @return 1 if data was returned; 0 otherwise.
+ */
+uint8_t ring_buffer_dequeue(ring_buffer_t *buffer, char *data);
+
+/**
+ * Returns the <em>len</em> oldest bytes in a ring buffer.
+ * @param buffer The buffer from which the data should be returned.
+ * @param data A pointer to the array at which the data should be placed.
+ * @param len The maximum number of bytes to return.
+ * @return The number of bytes returned.
+ */
+ring_buffer_size_t ring_buffer_dequeue_arr(ring_buffer_t *buffer, char *data, ring_buffer_size_t len);
+/**
+ * Peeks a ring buffer, i.e. returns an element without removing it.
+ * @param buffer The buffer from which the data should be returned.
+ * @param data A pointer to the location at which the data should be placed.
+ * @param index The index to peek.
+ * @return 1 if data was returned; 0 otherwise.
+ */
+uint8_t ring_buffer_peek(ring_buffer_t *buffer, char *data, ring_buffer_size_t index);
+
+
+/**
+ * Returns whether a ring buffer is empty.
+ * @param buffer The buffer for which it should be returned whether it is empty.
+ * @return 1 if empty; 0 otherwise.
+ */
+uint8_t ring_buffer_is_empty(ring_buffer_t *buffer);
+/**
+ * Returns whether a ring buffer is full.
+ * @param buffer The buffer for which it should be returned whether it is full.
+ * @return 1 if full; 0 otherwise.
+ */
+uint8_t ring_buffer_is_full(ring_buffer_t *buffer);
+
+/**
+ * Returns the number of items in a ring buffer.
+ * @param buffer The buffer for which the number of items should be returned.
+ * @return The number of items in the ring buffer.
+ */
+ring_buffer_size_t ring_buffer_num_items(ring_buffer_t *buffer);
+
+void ring_buffer_clean(ring_buffer_t *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RINGBUFFER_H */
diff --git a/mbtk/mbtk_lib/src/ds_ASBuffer.cpp b/mbtk/mbtk_lib/src/ds_ASBuffer.cpp
new file mode 100755
index 0000000..dc06fc1
--- /dev/null
+++ b/mbtk/mbtk_lib/src/ds_ASBuffer.cpp
@@ -0,0 +1,297 @@
+/*==============================================================================

+

+                            ds_ASBuffer.cpp

+

+GENERAL DESCRIPTION

+  A buffer class with utility functions for parsing raw bytes.

+

+EXTERNALIZED FUNCTIONS

+

+INITIALIZATION AND SEQUENCING REQUIREMENTS

+  None

+

+  Copyright (c) 2014 by Qualcomm Technologies Incorporated. All Rights Reserved.

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

+

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

+                           EDIT HISTORY FOR MODULE

+

+This section contains comments describing changes made to the module.

+Notice that changes are listed in reverse chronological order.

+

+when        who    what, where, why

+--------    ---    ----------------------------------------------------------

+06/03/15    ml     Remove memory allocation on default constructor

+05/20/15    ml     Use memory from modem heap

+04/21/14    ml     Created file/Initial version.

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

+#include "ds_ASBuffer.h"

+

+//#include "ds_appsrv_mem.h"

+#include <string.h>

+#include <mbtk_type.h>

+#include <stdlib.h>

+

+#include <cctype> // isspace

+

+

+// temp

+#include "ds_ASString.h"

+

+#define DEFAULT_BUFFER_SIZE 256

+

+// static const uint8 EMPTY_STRING[] = "";

+

+void memscpy(void* dest, size_t destLen, const void* src, size_t srcLen) {

+    if (srcLen <= destLen)

+        memcpy(dest, src, srcLen);

+}

+

+

+ASBuffer::ASBuffer()

+: buffer(NULL), buffer_size(0), buffer_capacity(DEFAULT_BUFFER_SIZE), error_status(false)

+{ }

+

+

+

+ASBuffer::ASBuffer(uint32 capacity)

+: buffer(NULL), buffer_size(0), buffer_capacity(capacity), error_status(false)

+{ }

+

+

+

+ASBuffer::ASBuffer(ASBuffer &buf)

+: buffer(NULL), buffer_size(0), buffer_capacity(buf.buffer_capacity), error_status(false)

+{

+  init();

+  append(buf);

+}

+

+

+

+ASBuffer::ASBuffer(const ASBuffer &buf)

+: buffer(NULL), buffer_size(0), buffer_capacity(buf.buffer_capacity), error_status(false)

+{

+  init();

+  append(buf);

+}

+

+

+

+ASBuffer::ASBuffer(const uint8* buf, uint32 buf_size)

+: buffer(NULL), buffer_size(0), buffer_capacity(buf_size), error_status(false)

+{

+  init();

+  append(buf, buf_size);

+}

+

+

+

+ASBuffer::~ASBuffer()

+{

+  if(NULL != buffer)

+  {

+    free(buffer);

+	buffer = NULL;

+  }

+}

+

+

+

+ASBuffer& ASBuffer::operator=(const ASBuffer &rhs)

+{

+  clear();

+  append(rhs);

+  return *this;

+}

+

+

+

+

+void ASBuffer::init()

+{

+  if(0 == buffer_capacity)

+  {

+    error_status = true;

+  }

+  else if(NULL == buffer)

+  {

+    buffer = (uint8*)malloc(sizeof(uint8) * (buffer_capacity+1));

+    error_status = (NULL == buffer);

+  }

+}

+

+

+

+// temp name

+#define DO_NOT_DOUBLE_IF_LARGER 2147483647

+bool ASBuffer::increment_buffer_capacity(const uint32 req_size)

+{

+  uint32 new_capacity = buffer_capacity;

+  uint8* tmp          = NULL;

+

+  while(req_size > new_capacity)

+  {

+    // will cause overflow if doubled

+    if(DO_NOT_DOUBLE_IF_LARGER < new_capacity)

+      return false;

+

+    new_capacity *= 2;

+  }

+

+  tmp = (uint8*)malloc(sizeof(uint8) * new_capacity+1);

+  if(NULL == tmp)

+    return false;

+

+  memset(tmp, 0, new_capacity+1);

+  memscpy(tmp, new_capacity, buffer, buffer_size);

+  free(buffer);

+  buffer = NULL;

+

+  buffer          = tmp;

+  buffer_capacity = new_capacity;

+

+  return true;

+}

+

+

+

+uint8* ASBuffer::non_const_content()

+{

+  return buffer;

+}

+

+

+const uint8* ASBuffer::content() const

+{

+  return buffer;

+}

+

+

+const char* ASBuffer::c_str() const

+{

+  if(NULL == buffer)

+    return "";

+  else

+    return (const char*)buffer;

+}

+

+

+

+uint32 ASBuffer::size() const

+{

+  return buffer_size;

+}

+

+

+

+bool ASBuffer::empty() const

+{

+  return (0 == buffer_size);

+}

+

+

+

+bool ASBuffer::error() const

+{

+  return error_status;

+}

+

+

+

+void ASBuffer::clear()

+{

+  if(NULL == buffer)

+  {

+    init();

+  }

+  else

+  {

+    memset(buffer, 0, buffer_capacity+1);

+  }

+  buffer_size = 0;

+}

+

+

+

+bool ASBuffer::append(const uint8* append_buffer, const uint32 append_size)

+{

+  if(NULL == append_buffer || 0 == append_size)

+    return true;

+

+  if(NULL == buffer)

+    init();

+

+  if(error_status) // do nothing if in error state

+    return false;

+

+  uint32 new_size = buffer_size + append_size;

+  if(new_size > buffer_capacity)

+  {

+    if(!increment_buffer_capacity(new_size))

+    {

+      error_status = true;

+      return false;

+    }

+  }

+

+  memscpy(

+          buffer + buffer_size,

+          buffer_capacity - buffer_size,

+          append_buffer,

+          append_size

+          );

+  buffer_size = new_size;

+

+  return true;

+}

+

+

+

+bool ASBuffer::append(const char* append_buffer)

+{

+  if(NULL == append_buffer)

+    return false;

+  else

+    return append((uint8*)append_buffer, strlen(append_buffer));

+}

+

+

+bool ASBuffer::append(const char append_buffer)

+{

+  char buffer[1];

+  buffer[0] = append_buffer;

+

+  return append((uint8*)buffer, 1);

+}

+

+

+bool ASBuffer::append(const char* append_buffer, const uint32 size)

+{

+  if(NULL == append_buffer)

+    return false;

+  else

+    return append((uint8*)append_buffer, size);

+}

+

+

+

+bool ASBuffer::append(const ASBuffer& append_buffer)

+{

+  if(append_buffer.empty())

+    return false;

+  else

+    return append(append_buffer.content(), append_buffer.size());

+}

+

+

+

+bool ASBuffer::append(const ASString& append_buffer)

+{

+  if(append_buffer.empty())

+    return false;

+  else

+    return append((uint8*)append_buffer.c_str(), append_buffer.size());

+}

+

+

diff --git a/mbtk/mbtk_lib/src/ds_ASString.cpp b/mbtk/mbtk_lib/src/ds_ASString.cpp
new file mode 100755
index 0000000..eaa1b82
--- /dev/null
+++ b/mbtk/mbtk_lib/src/ds_ASString.cpp
@@ -0,0 +1,396 @@
+/*==============================================================================

+

+                            ds_ASString.cpp

+

+GENERAL DESCRIPTION

+  A string class with utility functions for parsing AS.

+

+EXTERNALIZED FUNCTIONS

+

+INITIALIZATION AND SEQUENCING REQUIREMENTS

+  None

+

+  Copyright (c) 2014 by Qualcomm Technologies Incorporated. All Rights Reserved.

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

+

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

+                           EDIT HISTORY FOR MODULE

+

+This section contains comments describing changes made to the module.

+Notice that changes are listed in reverse chronological order.

+

+when        who    what, where, why

+--------    ---    ----------------------------------------------------------

+05/20/15    ml     Use memory from modem heap

+04/21/14    ml     Created file/Initial version.

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

+#include "ds_ASString.h"

+

+//#include "ds_appsrv_mem.h"

+//#include "data_msg.h"

+#include "mbtk_type.h"

+#include <string.h>

+#include <stdlib.h>

+#include <cctype> // isspace, tolower

+

+// #define DS_ASSTRING_MAX_LEN 4294967295 // uint32 max

+#define DS_ASSTRING_MAX_LEN 400000

+

+static const char AS_ESCAPE_MARK = '&';

+static const char EMPTY_STRING[] = "";

+

+static const char* ESCAPE_CHARS[] = {"&lt;", "&gt;", "&amp;", "&apos;", "&quot;"};

+static const char UNESCAPE_CHARS[] = {'<', '>', '&', '\'', '"'};

+static const uint32 NUM_ESCAPE_CHARS = 5;

+

+

+static bool has_string_at_start(const char* buf, const char* cmp);

+

+static void memscpy(void* dest, size_t destLen, const void* src, size_t srcLen) {

+    if (srcLen <= destLen)

+        memcpy(dest, src, srcLen);

+}

+

+

+ASString::ASString()

+: str(NULL) { }

+

+

+ASString::ASString(const char* src)

+: str(NULL)

+{

+  if(NULL == src)

+  {

+    str = NULL;

+    return;

+  }

+  copy_string(src, strlen(src));

+}

+

+

+ASString::ASString(const char* src, uint32 len)

+: str(NULL)

+{

+  copy_string(src, len);

+}

+

+

+// copy constructor

+ASString::ASString(ASString& src)

+: str(NULL)

+{

+  copy_string(src.c_str(), src.size());

+}

+

+

+ASString::ASString(const ASString& src)

+: str(NULL)

+{

+  copy_string(src.c_str(), src.size());

+}

+

+

+ASString::~ASString()

+{

+  if(NULL != str)

+  {

+	free(str);

+  }

+}

+

+// Assumes this->str with no memory allocated

+void ASString::copy_string(const char* src, uint32 len)

+{

+  if(NULL == src || 0 == len)

+  {

+    str = NULL;

+    return;

+  }

+  if(len > DS_ASSTRING_MAX_LEN)

+    return;

+

+  str = (char*)malloc(sizeof(char) * (len + 1));

+  if(NULL != str)

+  {

+    memscpy(str, len, src, len);

+  }

+}

+

+

+ASString& ASString::operator=(const ASString& rhs)

+{

+  if(&rhs != this)

+  {

+    if(NULL != str)

+    {

+		free(str);

+		str = NULL;

+	}

+

+    if(NULL == rhs.str)

+      str = NULL;

+    else

+      copy_string(rhs.str, rhs.size());

+  }

+  return *this;

+}

+

+

+ASString& ASString::operator=(const char* rhs)

+{

+  if(NULL != str)

+  {

+	free(str);

+	str = NULL;

+  }

+

+  if(NULL == rhs)

+    str = NULL;

+  else

+    copy_string(rhs, strlen(rhs));

+

+  return *this;

+}

+

+

+

+char ASString::operator[](const int index) const

+{

+  return str[index];

+}

+

+

+char& ASString::operator[](int index)

+{

+  return str[index];

+}

+

+

+const char* ASString::c_str() const

+{

+  if(NULL == str)

+    return EMPTY_STRING;

+  return str;

+}

+

+

+uint32 ASString::size() const

+{

+  return length();

+}

+

+

+uint32 ASString::length() const

+{

+  if(NULL == str)

+    return 0;

+  return (uint32)strlen(str);

+}

+

+

+bool ASString::empty() const

+{

+  return (0 == length());

+}

+

+void ASString::remove_trailing_spaces()

+{

+  uint32 end = length();

+

+  if(0 == end)

+    return;

+

+  while(0 != end)

+  {

+    if(!isspace(str[--end]))

+    {

+      end++;

+      break;

+    }

+  }

+

+  str[end] = '\0';

+}

+

+

+

+

+bool ASString::resolve_xml_escapes()

+{

+  bool   replaced = false;

+  uint32 counter  = 0;

+  uint32 len      = length();

+  char*  buf      = str;

+  char*  new_str  = NULL;

+

+  if(0 == len)

+    return true;

+

+  new_str = (char*)malloc(sizeof(char) * (len + 1) );

+  if(NULL == new_str)

+    return true;

+

+  while('\0' != *buf && counter < len)

+  {

+    if(AS_ESCAPE_MARK == *buf)

+    {

+      replaced = false;

+      for(uint32 i=0; i<NUM_ESCAPE_CHARS; i++)

+      {

+        if(has_string_at_start(buf, ESCAPE_CHARS[i]))

+        {

+          new_str[counter++] = UNESCAPE_CHARS[i];

+          buf += strlen(ESCAPE_CHARS[i]);

+          replaced = true;

+          break;

+        }

+      }

+

+      if(!replaced)

+      {

+		free(new_str);

+        return false;

+      }

+    }

+    else

+    {

+      new_str[counter++] = *buf;

+      buf++;

+    }

+  }

+

+  free(str);

+  str = new_str;

+

+  return true;

+}

+

+

+

+void ASString::to_lower()

+{

+  uint32 len = length();

+  for(uint32 i = 0; i < len; ++i)

+  {

+    str[i] = tolower(str[i]);

+  }

+}

+

+

+

+bool ASString::limit_cmp(const char* cstr, const uint32 len) const

+{

+  return (0 == strncmp(str, cstr, len));

+}

+

+

+

+void ASString::append(const char* append_str)

+{

+  if(NULL == append_str)

+    return;

+

+  append(append_str, strlen(append_str));

+}

+

+

+

+void ASString::append(const char* append_str, const uint32 len)

+{

+  uint32 prev_size, new_size;

+

+  if(NULL == append_str)

+    return;

+

+  if(strlen(append_str) < len || 0 == len)

+    return;

+

+  prev_size = length();

+  new_size  = prev_size + len + 1;

+

+  if(new_size < prev_size || new_size < len || DS_ASSTRING_MAX_LEN < new_size) // overflow?

+  {

+    printf("append - append size too long");

+    return;

+  }

+

+  char* tmp = (char*)malloc(sizeof(char) * new_size);

+  if(NULL == tmp)

+  {

+    printf("append - Failed to allocate memory for result string");

+    return;

+  }

+

+  if(NULL != str)

+  {

+    // copy the current string to the new string.

+    memscpy(tmp, new_size, str, prev_size);

+	free(str);

+    str = NULL;

+  }

+  // add the new string

+  memscpy(tmp+prev_size, new_size - prev_size, append_str, len);

+

+  str = tmp;

+}

+

+

+void ASString::append(const ASString& append_str)

+{

+  if(append_str.empty())

+    return;

+  append(append_str.c_str(), append_str.length());

+}

+

+

+

+

+

+bool operator== (const ASString& lhs, const ASString& rhs)

+{

+  return (0 == strcasecmp(lhs.c_str(), rhs.c_str()));

+}

+

+bool operator!= (const ASString& lhs, const ASString& rhs)

+{

+  return (0 != strcasecmp(lhs.c_str(), rhs.c_str()));

+}

+

+

+bool operator== (const ASString& lhs, const char* rhs)

+{

+  return (0 == strcasecmp(lhs.c_str(), rhs));

+}

+

+bool operator!= (const ASString& lhs, const char* rhs)

+{

+  return (0 != strcasecmp(lhs.c_str(), rhs));

+}

+

+

+/*

+res <  0 if lhs <  rhs

+res == 0 if lhs == rhs

+res >  0 if lhs <  rhs

+*/

+bool operator< (const ASString& lhs, const ASString& rhs)

+{

+  return (0 > strcasecmp(lhs.c_str(), rhs.c_str()));

+}

+

+bool operator> (const ASString& lhs, const ASString& rhs)

+{

+  return (0 < strcasecmp(lhs.c_str(), rhs.c_str()));

+}

+

+

+

+

+

+

+

+static bool has_string_at_start(const char* buf, const char* cmp)

+{

+  return (0 == strncasecmp(buf, cmp, strlen(cmp)));

+}

+

diff --git a/mbtk/mbtk_lib/src/g711_pcm_convert.c b/mbtk/mbtk_lib/src/g711_pcm_convert.c
new file mode 100755
index 0000000..0927253
--- /dev/null
+++ b/mbtk/mbtk_lib/src/g711_pcm_convert.c
@@ -0,0 +1,351 @@
+#include "g711_pcm_convert.h"
+
+
+#define SIGN_BIT    (0x80)      /* Sign bit for a A-law byte. */
+#define QUANT_MASK  (0xf)       /* Quantization field mask. */
+#define NSEGS       (8)     /* Number of A-law segments. */
+#define SEG_SHIFT   (4)     /* Left shift for segment number. */
+#define SEG_MASK    (0x70)      /* Segment field mask. */
+#define BIAS        (0x84)      /* Bias for linear code. */
+
+
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+                           0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
+                          };
+
+/* copy from CCITT G.711 specifications */
+unsigned char _u2a[128] = {         /* u- to A-law conversions */
+    1,  1,  2,  2,  3,  3,  4,  4,
+    5,  5,  6,  6,  7,  7,  8,  8,
+    9,  10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24,
+    25, 27, 29, 31, 33, 34, 35, 36,
+    37, 38, 39, 40, 41, 42, 43, 44,
+    46, 48, 49, 50, 51, 52, 53, 54,
+    55, 56, 57, 58, 59, 60, 61, 62,
+    64, 65, 66, 67, 68, 69, 70, 71,
+    72, 73, 74, 75, 76, 77, 78, 79,
+    81, 82, 83, 84, 85, 86, 87, 88,
+    89, 90, 91, 92, 93, 94, 95, 96,
+    97, 98, 99, 100,    101,    102,    103,    104,
+    105,    106,    107,    108,    109,    110,    111,    112,
+    113,    114,    115,    116,    117,    118,    119,    120,
+    121,    122,    123,    124,    125,    126,    127,    128
+};
+
+unsigned char _a2u[128] = {         /* A- to u-law conversions */
+    1,  3,  5,  7,  9,  11, 13, 15,
+    16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 26, 27, 28, 29, 30, 31,
+    32, 32, 33, 33, 34, 34, 35, 35,
+    36, 37, 38, 39, 40, 41, 42, 43,
+    44, 45, 46, 47, 48, 48, 49, 49,
+    50, 51, 52, 53, 54, 55, 56, 57,
+    58, 59, 60, 61, 62, 63, 64, 64,
+    65, 66, 67, 68, 69, 70, 71, 72,
+    73, 74, 75, 76, 77, 78, 79, 79,
+    80, 81, 82, 83, 84, 85, 86, 87,
+    88, 89, 90, 91, 92, 93, 94, 95,
+    96, 97, 98, 99, 100,    101,    102,    103,
+    104,    105,    106,    107,    108,    109,    110,    111,
+    112,    113,    114,    115,    116,    117,    118,    119,
+    120,    121,    122,    123,    124,    125,    126,    127
+};
+
+
+static short search(short val, short* table, short size)
+{
+    short i;
+    for (i = 0; i < size; i++) {
+        if (val <= *table++) {
+            return (i);
+        }
+    }
+    return (size);
+}
+
+/**
+ * @brief Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ *   Linear Input Code   Compressed Code
+ *  ------------------------    ---------------
+ *  0000000wxyza            000wxyz
+ *  0000001wxyza            001wxyz
+ *  000001wxyzab            010wxyz
+ *  00001wxyzabc            011wxyz
+ *  0001wxyzabcd            100wxyz
+ *  001wxyzabcde            101wxyz
+ *  01wxyzabcdef            110wxyz
+ *  1wxyzabcdefg            111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char linear2alaw(short pcm_val)    /* 2's complement (16-bit range) */
+{
+    short     mask;
+    short     seg;
+    unsigned char   aval;
+
+    if (pcm_val >= 0) {
+        mask = 0xD5;        /* sign (7th) bit = 1 */
+    } else {
+        mask = 0x55;        /* sign bit = 0 */
+        pcm_val = -pcm_val - 8;
+    }
+
+    /* Convert the scaled magnitude to segment number. */
+    seg = search(pcm_val, seg_end, 8);
+
+    /* Combine the sign, segment, and quantization bits. */
+
+    if (seg >= 8) {      /* out of range, return maximum value. */
+        return (0x7F ^ mask);
+    } else {
+        aval = seg << SEG_SHIFT;
+        if (seg < 2) {
+            aval |= (pcm_val >> 4) & QUANT_MASK;
+        } else {
+            aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+        }
+        return (aval ^ mask);
+    }
+}
+
+/**
+ * @brief Convert an A-law value to 16-bit linear PCM
+ *
+ */
+short alaw2linear(unsigned char a_val)
+{
+    short     t;
+    short     seg;
+
+    a_val ^= 0x55;
+    t = (a_val & QUANT_MASK) << 4;
+    seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+
+    switch (seg) {
+        case 0:
+            t += 8;
+            break;
+        case 1:
+            t += 0x108;
+            break;
+        default:
+            t += 0x108;
+            t <<= seg - 1;
+    }
+
+    return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+/**
+ * @brief Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ *  Biased Linear Input Code    Compressed Code
+ *  ------------------------    ---------------
+ *  00000001wxyza           000wxyz
+ *  0000001wxyzab           001wxyz
+ *  000001wxyzabc           010wxyz
+ *  00001wxyzabcd           011wxyz
+ *  0001wxyzabcde           100wxyz
+ *  001wxyzabcdef           101wxyz
+ *  01wxyzabcdefg           110wxyz
+ *  1wxyzabcdefgh           111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz.  * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char linear2ulaw(int pcm_val)    /* 2's complement (16-bit range) */
+{
+    short     mask;
+    short     seg;
+    unsigned char   uval;
+
+    /* Get the sign and the magnitude of the value. */
+    if (pcm_val < 0) {
+        pcm_val = BIAS - pcm_val;
+        mask = 0x7F;
+    } else {
+        pcm_val += BIAS;
+        mask = 0xFF;
+    }
+
+    /* Convert the scaled magnitude to segment number. */
+    seg = search(pcm_val, seg_end, 8);
+
+    /*
+     * Combine the sign, segment, quantization bits;
+     * and complement the code word.
+     */
+    if (seg >= 8) {      /* out of range, return maximum value. */
+        return (0x7F ^ mask);
+    } else {
+        uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+        return (uval ^ mask);
+    }
+}
+
+/**
+ * @brief Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int  ulaw2linear(unsigned char u_val)
+{
+    short     t;
+
+    /* Complement to obtain normal u-law value. */
+    u_val = ~u_val;
+
+    /*
+     * Extract and bias the quantization bits. Then
+     * shift up by the segment number and subtract out the bias.
+     */
+    t = ((u_val & QUANT_MASK) << 3) + BIAS;
+    t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+    return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+/**
+ * @brief A-law to u-law conversion
+ *
+ * @param aval A-law value
+ * @return unsigned char u-law value
+ */
+unsigned char alaw2ulaw(unsigned char aval)
+{
+    aval &= 0xff;
+    return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+            (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/**
+ * @brief u-law to A-law conversion
+ *
+ * @param uval u-law value
+ * @return unsigned char A-law value
+ */
+unsigned char ulaw2alaw(unsigned char uval)
+{
+    uval &= 0xff;
+    return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+            (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
+
+/**
+ * @brief pcm data encode to g711 data
+ *
+ *  user should be responsible for pCodecbit memmory
+ *
+ * @param pCodecBits store g711 encoded data
+ * @param pBuffer pcm raw data
+ * @param BufferSize pcm data len
+ * @param type g711 data type
+ * @return int encode data length
+ */
+int G711EnCode(char* pCodecBits, char* pBuffer, int BufferSize, enum g711type type)
+{
+    int i;
+    unsigned char* codecbits = (unsigned char*)pCodecBits;
+    short* buffer = (short*)pBuffer;
+
+    if (pCodecBits == 0 || pBuffer == 0 || BufferSize <= 0) {
+        return -1;
+    }
+
+    if (type == G711ALAW) {
+        for (i = 0; i < BufferSize / 2; i++)  {
+            codecbits[i] = linear2alaw(buffer[i]);
+        }
+    } else {
+        for (i = 0; i < BufferSize / 2; i++)  {
+            codecbits[i] = linear2ulaw(buffer[i]);
+        }
+    }
+
+    return BufferSize / 2;
+}
+
+/**
+ * @brief g711 data decode to pcm data
+ *
+ * user should be responsible for pRawData memmory
+ *
+ * @param pRawData store uncoded pcm data
+ * @param pBuffer g711 encoded data
+ * @param BufferSize g711 data len
+ * @param type g711 data type
+ * @return int pcm data len
+ */
+int G711Decode(char* pRawData, char* pBuffer, int BufferSize, enum g711type type)
+{
+    int i;
+    short* out_data = (short*)pRawData;
+    unsigned char* buffer = (unsigned char*)pBuffer;
+
+    if (pRawData == 0 || pBuffer == 0 || BufferSize <= 0) {
+        return -1;
+    }
+
+    if (type == G711ALAW) {
+        for (i = 0; i < BufferSize; i++) {
+            out_data[i] = alaw2linear(buffer[i]);
+        }
+    } else {
+        for (i = 0; i < BufferSize; i++) {
+            out_data[i] = ulaw2linear(buffer[i]);
+        }
+    }
+
+    return BufferSize * 2;
+}
+
+/**
+ * @brief g711 u-law data and a-law data convert
+ *
+ * @param alawdata g711 a-law data
+ * @param ulawdata g711 u-lwa data
+ * @param datasize input data length
+ * @param type target g711 data type
+ * @return int sucess:1; failed:0
+ */
+int G711TypeChange(unsigned char* alawdata, unsigned char* ulawdata, int datasize, enum g711type type)
+{
+    int i;
+
+    if (alawdata == 0 || ulawdata == 0 || datasize <= 0) {
+        return 0;
+    }
+
+    if (type == G711ALAW) {
+        for (i = 0; i < datasize; i++) {
+            alawdata[i] = ulaw2alaw(ulawdata[i]);
+        }
+    } else {
+        for (i = 0; i < datasize; i++) {
+            ulawdata[i] = alaw2ulaw(alawdata[i]);
+        }
+    }
+    return 1;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_adc.c b/mbtk/mbtk_lib/src/mbtk_adc.c
new file mode 100755
index 0000000..222d828
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_adc.c
@@ -0,0 +1,60 @@
+/**
+ *   \file mbtk_adc.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-04-22
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_adc.h"
+
+#define ADC_DEVICE "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.2/i2c-2/2-0030/pm802-bat/adc"
+
+int mbtk_adc_get(mbtk_adc_enum channle)
+{
+    int ret = 0;
+    int fd = 0;
+    char adc_buf[24] = {0};
+    char *adc_value = NULL;
+    char adc = (channle == MBTK_ADC0 ? '0' : '1');
+
+    fd = open(ADC_DEVICE, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if(fd < 0) {
+        LOGE("[%s]  file open error\n", __FUNCTION__);
+        return -2;
+    }
+    ret = write(fd, &adc, 1);
+    if (ret < 0) {
+        LOGE("%s: error writing to file!\n", __FUNCTION__);
+        close(fd);
+        return -2;
+    }
+    ret = read(fd, adc_buf, 24);
+    if (ret < 0) {
+        LOGE("%s: error writing to file!\n", __FUNCTION__);
+        close(fd);
+        return -2;
+    }else{
+        LOGI("%s %d adc:%s\n", __FUNCTION__, __LINE__, adc_buf);
+        adc_value = strstr(adc_buf, "channel");
+    }
+    close(fd);
+    if(adc_value)
+        LOGI("%s adc: %s\n", __FUNCTION__, adc_value);
+    else
+        return -2;
+
+    return atoi(&adc_value[9]);
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_at.c b/mbtk/mbtk_lib/src/mbtk_at.c
new file mode 100755
index 0000000..8721a52
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_at.c
@@ -0,0 +1,207 @@
+#include <termios.h>
+#include <pthread.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "mbtk_log.h"
+
+#define MBTK_AT_SOCK "/tmp/atcmd_at"
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+
+static char *at_rsp_complete_tag[] = {
+        "OK",
+        "ERROR",
+        "CONNECT",
+		"+CMS ERROR:",
+		"+CME ERROR:",
+		"NO ANSWER",
+		"NO DIALTONE",
+		NULL};
+static int at_fd = -1;
+
+static int openSocket(const char* sockname)
+{
+	int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		LOGE("Error create socket: %s\n", strerror(errno));
+		return -1;
+	}
+	struct sockaddr_un addr;
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, sockname, sizeof(addr.sun_path));
+	while (TEMP_FAILURE_RETRY(connect(sock,(const struct sockaddr*)&addr, sizeof(addr))) != 0) {
+		LOGE("Error connect to socket %s: %s, try again", sockname, strerror(errno));
+		sleep(1);
+	}
+
+#if 0
+	int sk_flags = fcntl(sock, F_GETFL, 0);
+	fcntl(sock, F_SETFL, sk_flags | O_NONBLOCK);
+#endif
+
+	return sock;
+}
+
+
+static int at_complete(char *rsp)
+{
+#if 0
+    char *ptr = at_rsp_complete_tag;
+    while(ptr) {
+        LOGD("ptr = %s", ptr);
+        if(strstr(rsp, ptr)) {
+            LOGD("%s , %s", rsp, ptr);
+            return 1;
+        }
+        ptr++;
+    }
+#else
+    int i = 0;
+    while(at_rsp_complete_tag[i]) {
+        LOGD("ptr = %s", at_rsp_complete_tag[i]);
+        if(strstr(rsp, at_rsp_complete_tag[i])) {
+            LOGD("%s , %s", rsp, at_rsp_complete_tag[i]);
+            return 1;
+        }
+        i++;
+    }
+
+#endif
+    return 0;
+}
+
+static int at_rsp_read(char* rsp, int rsp_len)
+{
+    int len = 0;
+    int index = 0;
+    memset(rsp, 0x0, rsp_len);
+    while(1) {
+        if((len = read(at_fd, rsp + index, rsp_len - index)) > 0) {
+            if(at_complete(rsp)) {
+                LOGD("AT<%s", rsp);
+                return 0;
+            } else {
+                index += len;
+
+                if(index >= rsp_len) {
+                    LOGE("Buffer too small.");
+                    return -1;
+                }
+            }
+        } else {
+            printf("Read error:%d\n",errno);
+            return -1;
+        }
+    }
+}
+
+
+/*===========================================================================
+FUNCTION mbtk_at_init
+
+DESCRIPTION:
+  Initial MBTK AT.
+
+PARAMETERS:
+  None.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_at_init()
+{
+    if(at_fd > 0) {
+        LOGW("MBTK AT has inited.");
+        return 0;
+    }
+
+    at_fd = openSocket(MBTK_AT_SOCK);
+    return at_fd > 0 ? 0 : -1;
+}
+
+
+/*===========================================================================
+FUNCTION mbtk_at_deinit
+
+DESCRIPTION:
+  Deinitial MBTK AT.
+
+PARAMETERS:
+  None.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_at_deinit()
+{
+    if(at_fd < 0) {
+        LOGW("MBTK AT not inited.");
+        return 0;
+    }
+
+    close(at_fd);
+    at_fd = -1;
+    return 0;
+}
+
+/*===========================================================================
+FUNCTION mbtk_at_send
+
+DESCRIPTION:
+  Send AT command.
+
+PARAMETERS:
+  cmd [IN]: AT command.
+  rsp [OUT]: AT command response.
+  rsp_len[IN] : AT command response buffer size.
+
+RETURN VALUE:
+  int : Return 0 if success,other for failure.
+
+===========================================================================*/
+int mbtk_at_send(char* cmd, char* rsp, int rsp_len)
+{
+    if(cmd == NULL || strlen(cmd) == 0 || rsp == NULL || rsp_len <= 0) {
+        return -1;
+    }
+    char at_cmd[2048] = {0};
+    memcpy(at_cmd, cmd, strlen(cmd));
+    char *ptr = at_cmd + strlen(at_cmd) - 1;
+    while(ptr >= at_cmd && (*ptr == '\r' || *ptr == '\n'))
+    {
+        *ptr-- = '\0';
+    }
+    if(!strncasecmp(at_cmd, "at", 2))
+    {
+        LOGD("AT>%s", at_cmd);
+        *(++ptr) = '\r';
+        *(++ptr) = '\n';
+        if(write(at_fd, at_cmd, strlen(at_cmd)) != strlen(at_cmd)) {
+            LOGE("Write error:%d",errno);
+            return -1;
+        }
+
+        return at_rsp_read(rsp, rsp_len);
+    } else {
+        LOGE("AT command error:%s",at_cmd);
+        return -1;
+    }
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_audio.c b/mbtk/mbtk_lib/src/mbtk_audio.c
new file mode 100755
index 0000000..5d4af20
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_audio.c
@@ -0,0 +1,861 @@
+/**
+ *   \file mbtk_audio.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-31
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include "mbtk_audio.h"
+
+/******************************************************************************\
+ *  Macros / Defines
+\******************************************************************************/
+
+#ifndef UNUSEDPARAM
+#define UNUSEDPARAM(a)		(void)(a)
+#endif
+
+#define AUDIO_UBUS_REQUEST_NAME         "audio_if"
+#define mbtk_dtmf_UBUS_NAME	            "proslic_uBus"      //Used by wake lock
+#define DTMFCODEID                      "dtmfcode"
+#define DTMFCODE_NOTIFICATION_NAME      "audioif.dtmfcode"
+#define AUDIO_UBUS_VOLUME_SET           "volume_set"
+#define AUDIO_UBUS_VOLUME_GET           "volume_status"
+#define AUDIO_UBUS_MODE_SET             "audio_mode_set"
+#define AUDIO_UBUS_DSP_SET          	"config_dspgain"
+#define AUDIO_UBUS_LOOPBACK_EN          "loopback_enable"
+#define AUDIO_UBUS_LOOPBACK_DIS         "loopback_disable"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+	#define mbtk_audio_log(...)                    mbtk_audio_log(__VA_ARGS__)
+#else
+	#define mbtk_audio_log(...)
+#endif
+
+typedef enum {
+    PARAM_INT_POLICY_0,
+    PARAM_INT_POLICY_1,
+    PARAM_INT_POLICY_2,
+    PARAM_INT_POLICY_3,
+    PARAM_INT_POLICY_MAX,
+} PARAM_INT_POLICY;
+const struct blobmsg_policy int_policy[] ={
+	[PARAM_INT_POLICY_0] = {
+		.name = "param0",
+		.type = BLOBMSG_TYPE_INT32,
+	},
+};
+
+const struct blobmsg_policy dtmf_code_policy[] = {
+	[0] = {
+		.name = DTMFCODEID,
+		.type = BLOBMSG_TYPE_INT32,
+	},
+};
+
+static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout);
+static struct uloop_timeout mbtk_dtmf_add_subscribe_timeout_AudioIf =
+{
+    .cb = mbtk_dtmf_add_subscriber_AudioIf,
+};
+
+static struct blob_buf audio_cm_b;
+pthread_mutex_t mbtk_dtmf_mutex;
+int  mbtk_dtmf_PMConstraintWorks;
+//For UBUS listening to RILD & audio_if
+struct mbtk_audio_ubus_db_t
+{
+    pthread_t  dtmf_pthread;
+    mbtk_dtmf_cb dtmf_cb;
+    mbtk_volume_cb audio_volume_get_cb;
+    int work_state;
+    struct ubus_context     *ctx;
+
+    /* Audio_If */
+    struct ubus_subscriber 	audioif_event;
+    uint32_t	 		    audioif_subscriber_id;
+    uint32_t	 		    audioif_request_id;
+};
+
+static struct mbtk_audio_ubus_db_t  *mbtk_audio_ubus_db = NULL;
+
+
+static int record_fd = 0;
+
+#define AUDIO_FILE_DIR	"/data"
+#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
+
+int create_audio_dir(const char *dirname)
+{
+    DIR *p_dir;
+    int res = -1;
+
+    if(NULL == (p_dir = opendir((const char *)dirname)))
+    {
+        if(mkdir(dirname, 0777) == 0)
+        {
+            res = 0;
+        }
+        else
+        {
+            fprintf(stderr, "create audio dir error \n");
+            res = -1;
+        }
+    }
+    else
+    {
+        closedir(p_dir);
+        res = 0;
+    }
+    return res;
+}
+int mbtk_at_play(const char *args)
+{
+    int fd = 0;
+    int play_hdl = 0;
+    char databuf[1024];
+    int size;
+
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    // play_hdl = Ql_AudPlayer_Open(NULL, NULL);
+    play_hdl = mbtk_audio_open(0, 1, 8000, NULL);
+    if(0 == play_hdl)
+        printf("Ql_AudPlayer_Open fail\n");
+
+    fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+    if (fd <= 0)
+    {
+        printf("file open error\n");
+        goto err;
+    }
+    memset(databuf, 0, sizeof(databuf));
+    while(0 < (size = read(fd, databuf, sizeof(databuf))))
+    {
+        if(-1 == mbtk_audio_play_stream(play_hdl, databuf, size))
+            break;
+    }
+    mbtk_audio_log("aplay Stream end \n");
+
+err:
+    if(fd > 0)
+        close(fd);
+    mbtk_audio_close(play_hdl);
+
+    return 0;
+}
+
+void record_cb_func(int cb_result, char* databuf, unsigned int len)
+{
+    int rc;
+
+    if(NULL != databuf && len > 0 && record_fd > 0)
+    {
+        //for debug:save into file
+        rc = write(record_fd, databuf, len);
+        if (rc < 0) {
+            printf("%s: error writing to file!\n", __FUNCTION__);
+        } else if (rc < len) {
+            printf("%s: wrote less the buffer size!\n", __FUNCTION__);
+        }
+    }
+}
+
+int mbtk_at_rec(const char *args)
+{
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    //hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
+    void *record_hdl = mbtk_audio_open(1, 1, 8000, NULL);
+    if (record_hdl == NULL)
+    {
+        printf("AudRecorder open error\n");
+        return -1;
+    }
+
+    create_audio_dir(AUDIO_FILE_DIR);
+    record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (record_fd <= 0)
+    {
+        printf("file open error\n");
+        goto err;
+    }
+
+    if(-1 == mbtk_audio_record(record_hdl, record_cb_func, NULL))
+    {
+        printf("file write error\n");
+        close(record_fd);
+        record_fd = 0;
+    }
+    sleep(10);
+err:
+    mbtk_audio_close(record_hdl);
+    record_hdl = NULL;
+    if(record_fd > 0)
+    {
+        close(record_fd);
+        record_fd = 0;
+    }
+
+    return 0;
+}
+
+static void mbtk_ubus_complete_cb(struct ubus_request *req, int rc)
+{
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    if (req)
+    {
+        free(req);
+        req = NULL;
+    }
+    mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+    LOGI("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+    if(mbtk_audio_ubus_db->work_state)
+        mbtk_audio_ubus_db->work_state--;
+}
+/**
+ * @brief      mbtk_audio_mode_set
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *             "param0": UINT32
+ *             typedef enum {
+ *                 AUDIO_MODE_INVALID = -2,
+ *                 AUDIO_MODE_CURRENT = -1,
+ *                 AUDIO_MODE_NORMAL = 0,
+ *                 AUDIO_MODE_RINGTONE = 1,
+ *                 AUDIO_MODE_IN_CALL = 2,
+ *                 AUDIO_MODE_IN_COMMUNICATION=3,
+ *                 AUDIO_MODE_IN_VT_CALL= 4,
+ *                 AUDIO_MODE_CNT,
+ *                 AUDIO_MODE_MAX = AUDIO_MODE_CNT-1,
+ *             } audio_mode_
+ * @return     return type
+ */
+static void mbtk_audio_mode_set(int mode)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", mode);
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_MODE_SET,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_MODE_SET, ubus_strerror(rc));
+    }
+    else
+    {
+        printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+        mbtk_audio_ubus_db->work_state++;
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
+int mbtk_audio_dsp_set(int type, int gain)
+{
+    LOGE("1type:%d, gain:%d\n", type, gain);
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        LOGE("mbtk_dtmf_ubus not init!\n");
+        return -1;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        LOGE("leave %s: lack of memory\n", __FUNCTION__);
+        return -1;
+    }
+
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "type", type);
+	blobmsg_add_u32(&audio_cm_b, "gain", gain);
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_DSP_SET,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        LOGE("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_DSP_SET, ubus_strerror(rc));
+        return -1;
+    }
+    else
+    {
+        LOGE("%s: ubus_invoke_async success\n", __FUNCTION__);
+        mbtk_audio_ubus_db->work_state++;
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+    return 0;
+}
+/**
+ * @brief      mbtk_audio_loopback_start
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *             device: UINT32
+ *             0: earpiece
+ *             1: speaker
+ *             2: headset
+ * @return     return type
+ */
+static void mbtk_audio_loopback_start(int device)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        LOGI("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        LOGI("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", device);
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_LOOPBACK_EN,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        LOGI("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        LOGI("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
+
+static void mbtk_audio_loopback_stop(void)
+{
+    int rc = 0;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    blob_buf_init(&audio_cm_b, 0);
+
+    if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
+                          mbtk_audio_ubus_db->audioif_request_id,
+                          AUDIO_UBUS_LOOPBACK_DIS,
+                          audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
+    {
+        LOGI("%s, ubus_invoke volume get failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        LOGI("%s: ubus_invoke success\n", __FUNCTION__);
+    }
+}
+
+int mbtk_at_loopback(int type)
+{
+    static mbtk_audio_client_handle_type audio_handle = 0;
+    int ret = 0;
+
+    LOGI("%s %d:%d", __FUNCTION__, __LINE__, type);
+    if(0 == type) // Stop
+    {
+        mbtk_audio_loopback_stop();
+        if(audio_handle)
+        {
+            mbtk_audio_ubus_client_deinit(audio_handle);
+            audio_handle = 0;
+        }
+    }
+    else // Start
+    {
+        if(NULL == mbtk_audio_ubus_db)
+            ret = mbtk_audio_ubus_client_init(&audio_handle, NULL);
+        if(ret)
+        {
+            return -1;
+        }
+        mbtk_audio_mode_set(0);
+        mbtk_audio_loopback_start(2);
+    }
+
+    return 0;
+}
+
+/*****************************************************  \
+ *   Retry mechanism to add subscriber for Audio_if
+\*****************************************************/
+static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout)
+{
+    /* add subscriber for Audio_If */
+    if (ubus_lookup_id(mbtk_audio_ubus_db->ctx, DTMFCODE_NOTIFICATION_NAME, &mbtk_audio_ubus_db->audioif_subscriber_id))
+    {
+        printf("%s, Failed to look up %s\n", __FUNCTION__, DTMFCODE_NOTIFICATION_NAME);
+        uloop_timeout_set(timeout, 2000);
+        return;
+    }
+
+    ubus_subscribe(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event, mbtk_audio_ubus_db->audioif_subscriber_id);
+    mbtk_audio_log("Audio_If subscribe %s object ok\n", DTMFCODE_NOTIFICATION_NAME);
+    return;
+}
+/*******************************************************************************\
+*   Function:      mbtk_dtmf_uBus_pmConstraint
+*   Description:   Lock/unlock system power management.
+*                   0: unlock
+*                   1: lock
+*   Returns:
+\*******************************************************************************/
+static void mbtk_dtmf_uBus_PMConstraint(int set)
+{
+    FILE *flk;
+    if (mbtk_dtmf_PMConstraintWorks != 0)
+        return; //wake_lock unavailable or not exist. Do nothing
+
+#ifdef PROSLIC_ENABLEFREERUN
+    mbtk_audio_log("%s(%d): %s\n", __FUNCTION__, set, set ? "no sleep" : "sleep after 7s");
+#else
+    mbtk_audio_log("%s(%d): free-run is disabled, no sleep\n", __FUNCTION__, set);
+#endif
+
+    /* Do Not check fopen success. It must be ok, if failed
+    ** (for any reason) better to crash for logging and recovery
+    */
+    flk = fopen("/sys/power/wake_lock", "w");
+    if(set)
+    {
+        fprintf(flk, mbtk_dtmf_UBUS_NAME);
+    }
+    else
+    {
+#ifdef PROSLIC_ENABLEFREERUN
+        /* Clear constraint but with TimeOut enough
+        ** Stay awake for (mbtk_dtmf_DIAL_TIMER + 1) seconds, wait for ringing timer expire
+        */
+        fprintf(flk, mbtk_dtmf_UBUS_NAME " 7000000000"/*nsec*/);
+#endif
+    }
+
+    fclose(flk);
+}
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusInd_AudioIf_remove
+*   Description:    Handle upon Audio_if remove indication.
+*   Returns:
+\*******************************************************************************/
+static void mbtk_dtmf_uBusInd_AudioIf_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
+                              uint32_t id)
+{
+    UNUSEDPARAM(ctx);
+    UNUSEDPARAM(s);
+    UNUSEDPARAM(id);
+
+    mbtk_audio_log("%s\n", __FUNCTION__);
+    uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 2000);
+}
+
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusInd_AudioIf
+*   Description:    Handle upon Audio_If incoming indication.
+*   Returns:        0 on success
+\*******************************************************************************/
+static int mbtk_dtmf_uBusInd_AudioIf(struct ubus_context *ctx, struct ubus_object *obj,
+                               struct ubus_request_data *req, const char *method,
+                               struct blob_attr *msg)
+{
+    UNUSEDPARAM(ctx);
+    UNUSEDPARAM(obj);
+    UNUSEDPARAM(req);
+    UNUSEDPARAM(method);
+
+    char DTMFCode = 0;
+    struct blob_attr *tb[1];
+    int rc = 0;
+
+    //Lock from mbtk_dtmf interrupt handler (mbtk_dtmf_MainLoop)
+    pthread_mutex_lock(&mbtk_dtmf_mutex);
+    mbtk_audio_log("==================================%s : Begin==================================\n", __FUNCTION__);
+    mbtk_dtmf_uBus_PMConstraint(1);
+
+    /*parsing blob to be accessed easily with tb array - parse "1" argument*/
+    rc = blobmsg_parse(dtmf_code_policy, 1, tb, blob_data(msg), blob_len(msg));
+
+    if (rc < 0) {
+    	printf("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc);
+    }
+    else {
+        DTMFCode = (char)blobmsg_get_u32(tb[0]);
+        if(mbtk_audio_ubus_db->dtmf_cb)
+            mbtk_audio_ubus_db->dtmf_cb(DTMFCode);
+        mbtk_audio_log("%s got DTMF Code: Char[%c]=ASCII[0x%x]\n", __FUNCTION__, DTMFCode, DTMFCode);
+    }
+
+    mbtk_dtmf_uBus_PMConstraint(0);
+    mbtk_audio_log("==================================%s : End==================================", __FUNCTION__);
+    pthread_mutex_unlock(&mbtk_dtmf_mutex);
+
+    return rc;
+}
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusRegisterNotifications
+*   Description:    Register UBUS notifications of RIL and Audio_If.
+*   Returns:        0 on success
+\*******************************************************************************/
+static int mbtk_dtmf_uBusRegisterNotifications(void)
+{
+    int ret = 0;
+
+    /* register UBUS notifications of Audio_If */
+    ret = ubus_register_subscriber(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event);
+    if (ret)
+    {
+        printf("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret));
+        return -1;
+    }
+
+    /* specify callback to handle notifications */
+    mbtk_audio_ubus_db->audioif_event.remove_cb = mbtk_dtmf_uBusInd_AudioIf_remove;
+    mbtk_audio_ubus_db->audioif_event.cb = mbtk_dtmf_uBusInd_AudioIf;
+
+    /* add subscribe */
+    uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 0);
+
+    mbtk_audio_log("%s: Make use of DTMF detection in modem.\n", __FUNCTION__);
+
+    return 0;
+}
+
+void mbtk_switch_dtmf_detection_cb(struct ubus_request *req, int rc)
+{
+    if (req)
+    {
+        free(req);
+        req = NULL;
+    }
+    mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+}
+/**
+ * @brief      mbtk_switch_dtmf_detection
+ *
+ * @details    detailed description
+ *
+ * @param      param
+ *            “param0": UINT32 onoff
+ *              0: disbale Tx DTMF detection
+ *              1: enable Tx DTMF detection
+ *              2: disbale Rx DTMF detection
+ *              3: enable Rx DTMF detection
+ * @return     return type
+ */
+void mbtk_switch_dtmf_detection(unsigned short on_off, unsigned short param1,
+                                unsigned short param2, unsigned short param3)
+{
+#if PCM_CTRL_OVER_VCM
+    vcm_DTMFDetection(on_off, param1, param2, param3);
+#else
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", on_off);
+    blobmsg_add_u32(&audio_cm_b, "param1", param1);
+    blobmsg_add_u32(&audio_cm_b, "param2", param2);
+    blobmsg_add_u32(&audio_cm_b, "param3", param3);
+
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, "dtmf_detection", audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke dtmf_detection failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->complete_cb = mbtk_switch_dtmf_detection_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+#endif
+}
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusInit
+*   Description:    Init UBUS context and register UBUS notifications of RIL.
+*   Returns:        0 on success
+\*******************************************************************************/
+int mbtk_dtmf_uBusInit(void)
+{
+    int rc = 0;
+
+    uloop_init();
+
+    mbtk_audio_ubus_db->ctx = ubus_connect(NULL);
+    if (mbtk_audio_ubus_db->ctx == NULL)
+    {
+        printf(" %s Failed to connect to ubus\n", __FUNCTION__);
+        return -1;
+    }
+
+    ubus_add_uloop(mbtk_audio_ubus_db->ctx);
+
+    /* lookup fail if audio_if is not ready */
+    while(1)
+    {
+        rc = ubus_lookup_id(mbtk_audio_ubus_db->ctx, AUDIO_UBUS_REQUEST_NAME, &mbtk_audio_ubus_db->audioif_request_id);
+        if (0 != rc)
+        {
+            printf("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME, rc);
+            usleep(600000); //600ms
+        }
+        else
+            break;
+    }
+    mbtk_audio_log("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME);
+
+    /* subscribe for RIL & audio_if notifications */
+    if (mbtk_dtmf_uBusRegisterNotifications() != 0)
+        return -1;
+
+    mbtk_audio_log("%s success!\n", __FUNCTION__);
+    return 0;
+}
+
+
+/*******************************************************************************\
+*   Function:       mbtk_dtmf_uBusRun
+*   Description:    Start running of UBUS.
+*   Returns:
+\*******************************************************************************/
+static void mbtk_audio_ubus_thread(void* hdl)
+{
+    pthread_detach(pthread_self());
+    uloop_run();
+    mbtk_audio_log("%s exit!\n", __FUNCTION__);
+    pthread_exit(NULL);
+}
+
+int mbtk_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb)
+{
+    int id;
+
+    // Set call handle.
+    if(ph_audio == NULL || mbtk_audio_ubus_db != NULL)
+    {
+        printf("ARG error or has inited.");
+        return -1;
+    }
+    mbtk_audio_ubus_db = malloc(sizeof(struct mbtk_audio_ubus_db_t));
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("malloc memory error\n");
+    }
+    memset(mbtk_audio_ubus_db, 0, sizeof(struct mbtk_audio_ubus_db_t));
+
+	mbtk_dtmf_PMConstraintWorks = access("/sys/power/wake_lock", R_OK | W_OK);
+    mbtk_dtmf_uBusInit();
+    mbtk_audio_ubus_db->dtmf_cb = cb;
+
+    mbtk_switch_dtmf_detection(3, 50, 4, 3);
+    pthread_create(&mbtk_audio_ubus_db->dtmf_pthread, NULL, (void *)mbtk_audio_ubus_thread, (void *)mbtk_audio_ubus_db);
+
+    *ph_audio = mbtk_audio_ubus_db;
+    LOGI("%s %d:%x", __FUNCTION__, __LINE__, mbtk_audio_ubus_db);
+
+    return 0;
+}
+
+int mbtk_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio)
+{
+    int ret;
+    struct mbtk_audio_ubus_db_t *audio_ubus = (struct mbtk_audio_ubus_db_t *)h_audio;
+
+    mbtk_audio_log("%s \n", __FUNCTION__);
+    if(h_audio == NULL || mbtk_audio_ubus_db == NULL)
+    {
+        printf("ARG error or not inited.");
+        return -1;
+    }
+    LOGI("%s %d:%x", __FUNCTION__, __LINE__, audio_ubus);
+    ret = pthread_cancel(audio_ubus->dtmf_pthread);
+    mbtk_audio_log("kill pthread : %d \n", ret);
+    pthread_join(audio_ubus->dtmf_pthread, NULL);
+    do{
+        ret = pthread_kill(audio_ubus->dtmf_pthread, 0);
+        mbtk_audio_log("kill pthread: %d \n", ret);
+        if(ret == ESRCH)
+            mbtk_audio_log("The specified thread does not exist or has terminated\n");
+        else if(ret == EINVAL)
+            mbtk_audio_log("Useless signal\n");
+        else
+            mbtk_audio_log("The thread exists\n");
+        usleep(100000);
+    }while(0 == ret);
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+
+    mbtk_switch_dtmf_detection(2, 0, 0, 0);
+    /*unregister uloop*/
+    /*thread will get here only if uloop stopped*/
+    ubus_free(mbtk_audio_ubus_db->ctx);
+    uloop_done();
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    free(h_audio);
+    mbtk_audio_ubus_db = NULL;
+
+    return 0;
+}
+
+/**********************************************************************\
+*   Function:      APP_Audio_VolumeSet
+*   Description:   This function is called to send command into audio_if.
+*   unsigned int volume(0~100)
+*   Returns:        0 on success
+\**********************************************************************/
+void mbtk_audio_ubus_volume_set(unsigned int volume)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db)
+    {
+        printf("mbtk_dtmf_ubus not init!\n");
+        return;
+    }
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+    blobmsg_add_u32(&audio_cm_b, "param0", volume);
+
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_VOLUME_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
+
+static void audio_volume_get_data_cb (struct ubus_request *req, int type, struct blob_attr *msg)
+{
+    UNUSEDPARAM(req);
+    UNUSEDPARAM(type);
+    struct blob_attr *tb[1];
+    unsigned int volume = 888;
+    int rc = 0;
+
+    rc = blobmsg_parse(int_policy, 1, tb, blob_data(msg), blob_len(msg));
+    if (rc < 0)
+    {
+    	printf("[%s] parsing blobmsg failed\n", __FUNCTION__);
+    	return;
+    }
+
+    if(tb[0])
+        volume = blobmsg_get_u32(tb[0]);
+    if (mbtk_audio_ubus_db->audio_volume_get_cb)
+        mbtk_audio_ubus_db->audio_volume_get_cb(volume);
+    mbtk_audio_log("%s; volume:%d\n", __FUNCTION__, volume);
+}
+
+void mbtk_audio_ubus_volume_get(mbtk_volume_cb cb)
+{
+    int rc = 0;
+    struct ubus_request *req = NULL;
+
+    if(NULL == mbtk_audio_ubus_db ||  NULL == cb)
+    {
+        printf("mbtk_dtmf_ubus not init or callback invalid!\n");
+        return;
+    }
+    mbtk_audio_ubus_db->audio_volume_get_cb = cb;
+    req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+    if (req == NULL)
+    {
+        printf("leave %s: lack of memory\n", __FUNCTION__);
+        return;
+    }
+    memset(req, 0, sizeof(struct ubus_request));
+    blob_buf_init(&audio_cm_b, 0);
+
+    if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+                                mbtk_audio_ubus_db->audioif_request_id,
+                                AUDIO_UBUS_VOLUME_GET,
+                                audio_cm_b.head, req)) != UBUS_STATUS_OK)
+    {
+        free(req);
+        printf("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__,  ubus_strerror(rc));
+    }
+    else
+    {
+        mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+        req->data_cb = audio_volume_get_data_cb;
+        req->complete_cb = mbtk_ubus_complete_cb;
+        ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+    }
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_audio_alsa.c b/mbtk/mbtk_lib/src/mbtk_audio_alsa.c
new file mode 100755
index 0000000..405ceda
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_audio_alsa.c
@@ -0,0 +1,826 @@
+/**
+ *   \file mbtk_audio_alsa.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2020-09-21
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include "audio_if_types.h"
+#include "audio_if_ubus.h"
+#include "audio_if_parameter.h"
+#include "audio_if.h"
+#include "audio_if_api.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include "audio_if_audio_hw_mrvl.h"
+#include "audio_hw_mrvl.h"
+#include <cutils/str_parms.h>
+#include "vcm.h"
+#include "voice_control.h"
+#include "mbtk_audio.h"
+
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+	#define mbtk_audio_log(...)                    printf(__VA_ARGS__)
+#else
+	#define mbtk_audio_log(...)
+#endif
+
+typedef int (*_play_callback)(int hdl, int result);
+
+#define FAILURE -1
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT  0x20746d66
+#define ID_DATA 0x61746164
+#define FORMAT_PCM 1
+
+
+
+struct mopen_audio_t
+{
+    int device;
+    audio_hw_device_t *audio_ahw_dev_ubus;
+    struct audio_stream_in *stream_in;
+    struct audio_stream_out *stream_out;
+    int pcm_packet_size;     //320:NB, 640:WB
+    int pipe_data;
+    int fd[2];
+    pthread_t pid;
+    mbtk_audio_state_enum state;
+    pthread_mutex_t _cond_mutex;
+    pthread_mutex_t _stream_mutex;
+    void *usrData;
+};
+struct record_cb_s
+{
+    mbtk_audio_record_cb_func _cb;
+    void *cb_data;
+};
+
+static struct mopen_audio_t *internal_hdl = NULL;
+
+
+int mbtk_wav_pcm16Le_check(int fd)
+{
+    printf("MBTK_wav_pcm16Le_check()----------strart5, fd:%d\n", fd);
+    struct wav_header hdr;
+
+    if (fd <= 0)
+        return -1;
+
+    if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+    {
+        printf("\n%s: cannot read header\n", __FUNCTION__);
+        return -1;
+    }
+
+        printf("hdr.riff_id:%X, hdr.riff_fmt:%X, hdr.fmt_id:%X", hdr.riff_id, hdr.riff_fmt, hdr.fmt_id);
+
+    if ((hdr.riff_id != ID_RIFF)
+            || (hdr.riff_fmt != ID_WAVE)
+            || (hdr.fmt_id != ID_FMT))
+    {
+        printf("\n%s: is not a riff/wave file\n", __FUNCTION__);
+        return -1;
+    }
+
+    if ((hdr.audio_format != FORMAT_PCM) || (hdr.fmt_sz != 16)) {
+        printf("\n%s: is not pcm format\n", __FUNCTION__);
+        return -1;
+    }
+
+    if (hdr.bits_per_sample != 16) {
+        printf("\n%s: is not 16bit per sample\n", __FUNCTION__);
+        return -1;
+    }
+
+    printf("audio_format: %d,num_channels: %d,sample_rate: %d,byte_rate: %d,bits_per_sample:  %d data_sz: %d\n",
+           hdr.audio_format, hdr.num_channels, hdr.sample_rate, hdr.byte_rate, hdr.bits_per_sample, hdr.data_sz);
+
+    return hdr.data_sz;
+}
+
+
+static void simulateOffhook(struct mopen_audio_t *aud_hdl, unsigned int onoff)
+{
+    unsigned int pcm_on;
+    unsigned int DTMFDetectiononoff;
+    unsigned int dialToneToOthersTones;
+    unsigned int dialTonesToOthersDialTones;
+    unsigned int dialVadDuration;
+
+    pcm_on = onoff;
+    //send the command of "AUDIOSTUB_PCMCTL"
+    aud_hdl->audio_ahw_dev_ubus->switch_pcm(aud_hdl->audio_ahw_dev_ubus, pcm_on);
+
+    DTMFDetectiononoff = onoff;
+    dialToneToOthersTones = 50;
+    dialTonesToOthersDialTones = 4;
+    dialVadDuration = 3;
+    //send the command of "AUDIOSTUB_DTMFDETECTIONCTL"
+    //vcm_DTMFDetection(1, 50, 4, 3);
+    vcm_DTMFDetection(DTMFDetectiononoff, dialToneToOthersTones, dialTonesToOthersDialTones, dialVadDuration);
+
+    return;
+}
+static int config_parameters(int in_out, int NBWB)
+{
+    unsigned int direction = 0xFF, type, srcdst, priority, dest;
+    char kvpair[128];
+    struct str_parms *param = NULL;
+    int data[5];
+    const char *key = NULL;
+    bool update_vcm = false;
+
+    direction = in_out;/* 0-play, 1-record */
+    type = NBWB; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
+    srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+    priority = 1;/* 0-Do not combine(override), 1-Combine */
+    dest = 1;/* 0-Near codec, 1-Near Vocoder */
+
+    memset(kvpair, 0x00, sizeof(kvpair));
+    sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
+            VCM_CONFIG_TYPE, type, VCM_CONFIG_SRC_DST, srcdst,
+            VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
+
+    mbtk_audio_log("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair);
+
+    //extract the parameter and config from string
+    param = str_parms_create_str(kvpair);
+    if (!param) {
+        printf("%s: param create str is null!", __FUNCTION__);
+        return -1;
+    }
+
+    //set vcm configurations
+    key = VCM_CONFIG_DIRECTION;
+    if (str_parms_get_int(param, key, &data[0]) == 0) {
+        update_vcm = true;
+        str_parms_del(param, key);
+    }
+    key = VCM_CONFIG_TYPE;
+    if (str_parms_get_int(param, key, &data[1]) == 0) {
+        update_vcm = true;
+        str_parms_del(param, key);
+    }
+    key = VCM_CONFIG_SRC_DST;
+    if (str_parms_get_int(param, key, &data[2]) == 0) {
+        update_vcm = true;
+        str_parms_del(param, key);
+    }
+    key = VCM_CONFIG_PRIORITY;
+    if (str_parms_get_int(param, key, &data[3]) == 0) {
+        update_vcm = true;
+        str_parms_del(param, key);
+    }
+    key = VCM_CONFIG_DEST;
+    if (str_parms_get_int(param, key, &data[4]) == 0) {
+        update_vcm = true;
+        str_parms_del(param, key);
+    }
+
+    //printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]);
+
+    if (update_vcm) {
+        configure_vcm(data);   /*TODO check if all inputs got all values successfully*/
+    }
+
+    return 0;
+}
+
+void mbtk_audio_set_status(void* hdl, mbtk_audio_state_enum _status)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+    if (NULL == hdl || NULL == internal_hdl)
+        return 0;
+    pthread_mutex_lock(&pcxt->_cond_mutex);
+    pcxt->state = _status;
+    pthread_mutex_unlock(&pcxt->_cond_mutex);
+}
+
+static void* mbtk_record_pthread(void* hdl)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+    struct record_cb_s *_usrData = (struct record_cb_s *)pcxt->usrData;
+    unsigned bufsize = 0;
+    char *data = NULL;
+    int len;
+
+    if (NULL == hdl)
+        return NULL;
+
+    bufsize = pcxt->pcm_packet_size;
+    data = calloc(1, bufsize);
+    if (!data) {
+        fprintf(stderr, "\n%s:could not allocate %d bytes\n", __FUNCTION__, bufsize);
+        return NULL;
+    }
+
+    mbtk_audio_set_status(hdl, AUDIO_RUNNING);
+
+    while (pcxt->state != AUDIO_STOP)
+    {
+        len = pcxt->stream_in->read(pcxt->stream_in, data, bufsize);
+        if (len < 0) {
+            printf("%s: error reading!\n", __FUNCTION__);
+            break;
+        }
+        if ((bufsize > 0) && (NULL != _usrData->_cb))
+        {
+            _usrData->_cb(2, data, bufsize);
+        }
+    }
+    pcxt->pid = 0;
+    if(pcxt->usrData)
+    {
+        free(pcxt->usrData);
+        pcxt->usrData = NULL;
+    }
+    free(data);
+    mbtk_audio_log("pcm pthread end-\n");
+    return NULL;
+}
+
+static void* mbtk_play_pthread(void* hdl)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+    _play_callback audio_play_cb = (_play_callback)pcxt->usrData;
+    unsigned bufsize = 0;
+    char *data = NULL;
+    int first_set = 0;
+    int ret = 0;
+    int rc;
+
+    pthread_detach(pthread_self());
+    if (NULL == hdl)
+        return NULL;
+
+    bufsize = pcxt->pcm_packet_size;
+    data = calloc(1, bufsize);
+    if (!data) {
+        fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+        pthread_exit(NULL);
+    }
+
+    while (pcxt->state != AUDIO_STOP && 0 != pcxt->pipe_data)
+    {
+        ret = read(pcxt->fd[0], data, bufsize);
+        // printf("%s:read : %d bytes\n", __FUNCTION__, ret);
+        if(ret == 0) {
+            mbtk_audio_log("%s %d [%d]", __FUNCTION__, __LINE__, ret);
+            continue;
+        }
+        if(ret < 0) {
+            mbtk_audio_log("%s %d [%d]", __FUNCTION__, __LINE__, ret);
+            break;
+        }
+        if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+        {
+            first_set = 1;
+            mbtk_audio_set_status(hdl, AUDIO_RUNNING);
+        }
+
+        pthread_mutex_lock(&pcxt->_stream_mutex);
+        pcxt->pipe_data -= ret;
+        pthread_mutex_unlock(&pcxt->_stream_mutex);
+        if(pcxt->pipe_data < 0)
+            pcxt->pipe_data = 0;
+        if(ret < pcxt->pcm_packet_size)
+            printf("pcm %d - %d\n", pcxt->pipe_data, ret);
+
+        rc = pcxt->stream_out->write(pcxt->stream_out, data, ret);
+        if (rc < 0) {
+            printf("%s: error writing (child).\n", __FUNCTION__);
+            break;
+        } else if (rc < (signed int)pcxt->pcm_packet_size) {
+            printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, rc);
+            break;
+        }
+    }
+
+    if (pcxt->fd[0] != 0 && pcxt->fd[1] != 0)
+    {
+        close(pcxt->fd[0]);
+        close(pcxt->fd[1]);
+        pcxt->fd[0] = 0;
+        pcxt->fd[1] = 0;
+        /* printf("close pcxt->fd!\n"); */
+    }
+    if (audio_play_cb)
+        audio_play_cb(pcxt, 5);
+    pcxt->pid = 0;
+//    mbtk_audio_set_status(hdl, AUDIO_STOP);
+    mbtk_audio_set_status(hdl, AUDIO_OPEN);
+    free(data);
+    mbtk_audio_log("\n%s:exit!\n", __FUNCTION__);
+    pthread_exit(NULL);
+
+    return NULL;
+}
+
+static int audio_init_play_pthread(void* hdl)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+    _play_callback audio_play_cb = (_play_callback)pcxt->usrData;
+    int ret;
+
+    if (pcxt->fd[0] == 0 && pcxt->fd[1] == 0) {
+        if(pipe(pcxt->fd) == 0) {
+
+            pcxt->pipe_data = 0;
+            fcntl(pcxt->fd[0], F_SETFL, O_NONBLOCK);
+            fcntl(pcxt->fd[1], F_SETFL, O_NONBLOCK);
+        } else {
+            fprintf(stderr, "\n%d: create pipe error\n", __LINE__);
+            return -1;
+        }
+    }
+    if (pcxt->pid == 0) {
+        if (audio_play_cb)
+            audio_play_cb(pcxt, 0);
+        mbtk_audio_set_status(pcxt, AUDIO_RUNNING);
+        ret = pthread_create(&pcxt->pid, NULL, mbtk_play_pthread, hdl);
+        if (ret != 0)
+        {
+            fprintf(stderr, "\n%s: Failed create pthread\n",__FUNCTION__);
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+int  mbtk_audio_play_wait_end(void* hdl)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+
+    if (NULL == hdl)
+    {
+        fprintf(stderr, "\n%s: intput invalid params\n",__FUNCTION__);
+        return -1;
+    }
+
+    if(pcxt->pid != 0)
+    {
+        do{
+            usleep(10000);
+        }
+        while(pcxt->state != AUDIO_STOP);
+        pcxt->pid = 0;
+    }
+
+    return 0;
+}
+
+static int audio_open_pcm(void *dev_hdl, int num_channels, int rate, int in_out)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+    int nb_wb;
+
+    //Support 8k/16k & mono wave file
+    if (((rate != 8000) && (rate != 16000))
+            || (num_channels != 1) ) {
+        printf("%s: error wave file:rate = %d, num_channels = %d!! \n",
+                __FUNCTION__,rate, num_channels);
+        return -1;
+    }
+
+    printf("%s: success open, rate = %d, num_channels = %d.\n",
+            __FUNCTION__, rate, num_channels);
+
+    if ((8000 == rate) && (1 == num_channels)) {
+        nb_wb = 0;//NB
+        pcxt->pcm_packet_size = PCM_NB_BUF_SIZE;
+    } else if ((16000 == rate) && (1 == num_channels)) {
+        nb_wb = 1;//WB
+        pcxt->pcm_packet_size = PCM_WB_BUF_SIZE;
+    }
+
+    //config playback parameters.
+    config_parameters(in_out, nb_wb);
+    pcxt->device = in_out;
+    return 0;
+}
+
+mbtk_audio_handle mbtk_audio_open(mbtk_audio_dev_enum dev, int flag, int rate, void *usrData)
+{
+    int value = 1;
+    struct mopen_audio_t *aud_hdl = NULL;
+    int ret;
+
+    // if (dev <= AUDIO_NULL || dev >= AUDIO_MAX)
+    // {
+    //     printf("invaild PCM dev\n");
+    //     return NULL;
+    // }
+    if(internal_hdl)
+    {
+        printf("Audio device inited\n");
+        return internal_hdl;
+    }
+    aud_hdl = (struct mopen_audio_t *) calloc(1, sizeof(struct mopen_audio_t));
+    if (!aud_hdl)
+    {
+        fprintf(stderr, "\n%s:Failed to allocate audio hdl!, errno=%d\n", __FUNCTION__, errno);
+        return NULL;
+    }
+    memset(aud_hdl, 0, sizeof(struct mopen_audio_t));
+
+    //init global variables
+    aud_hdl->audio_ahw_dev_ubus = audio_hal_install();
+    if (aud_hdl->audio_ahw_dev_ubus == NULL) {
+        printf("%s: audio_hal_install failed!\n", __FUNCTION__);
+        goto error;
+    }
+
+    if(1 == dev)
+    {
+        //send the command of "AUDIOSTUB_PCMCTL" and "AUDIOSTUB_DTMFDETECTIONCTL" to simulate telephone offhook.
+            // ASR Question #80497  Using it causes the recording to crash
+    //    simulateOffhook(aud_hdl, 1);
+        //config playback parameters.
+        config_parameters(0, 0);
+    }
+    ret = audio_open_pcm(aud_hdl, flag, rate, dev);
+    if (ret)
+    {
+        printf("\n%s: pcm open error, errno=%d\n", __FUNCTION__, errno);
+        goto error;
+    }
+    if(1 == dev)
+    {
+        //open the audiostub_ctl, prepare for record and playback
+        VCMInit();
+        //open record stream
+        ret = aud_hdl->audio_ahw_dev_ubus->open_input_stream(aud_hdl->audio_ahw_dev_ubus, 0,
+                aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus),
+                NULL, &aud_hdl->stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL);
+    }
+    else
+    {
+        ret = aud_hdl->audio_ahw_dev_ubus->open_output_stream(aud_hdl->audio_ahw_dev_ubus, 0,
+                aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus),
+                AUDIO_OUTPUT_FLAG_DIRECT, NULL, &aud_hdl->stream_out, 0);
+    }
+
+    if (ret < 0) {
+        printf("%s: error opening output device. rc = %d\n", __FUNCTION__, ret);
+        goto error;
+    }
+    pthread_mutex_init(&aud_hdl->_cond_mutex, NULL);
+    pthread_mutex_init(&aud_hdl->_stream_mutex, NULL);
+    aud_hdl->usrData = usrData;
+    aud_hdl->state = AUDIO_OPEN;
+    /* printf("Mbtk_Audio_Open aud_hdl[%x][%x][%x]\n", aud_hdl, aud_hdl->_mixer_ctl, aud_hdl->_pcm); */
+    internal_hdl = aud_hdl;
+
+    return (void *)aud_hdl;
+
+error:
+    value = 0;
+    free(aud_hdl);
+    return NULL;
+}
+
+
+int mbtk_audio_play_stream_old(void *dev_hdl, const void *pData, int len)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+
+    if (NULL == pcxt || NULL == internal_hdl)
+        return -1;
+
+    if (len > 1024) {
+        printf("audio play stream max size ( < 1024): %d\n", len);
+        return -2;
+    }
+
+    if (pcxt->state == AUDIO_STOP) {
+        return 0;
+	}
+    audio_init_play_pthread(pcxt);
+
+    pthread_mutex_lock(&pcxt->_stream_mutex);
+    pcxt->pipe_data += len;
+    pthread_mutex_unlock(&pcxt->_stream_mutex);
+    while(pcxt->state != AUDIO_STOP && (pcxt->pipe_data > 40960 || pcxt->fd[1] < 0 || pcxt->fd[1] == 0)) {
+        // printf("%s:wait %d %d\n", __FUNCTION__, pcxt->pipe_data, pcxt->fd[1]);
+        usleep(50000);
+    }
+
+    if(pcxt->fd[1] > 0) {
+        if (len != write(pcxt->fd[1], pData, len)) {
+            fprintf(stderr, "\n%s: pcm_write failed [%d %d]\n", __FUNCTION__, pcxt->fd[1], errno);
+            return -errno;
+        }
+    }
+
+    return 0;
+}
+
+int mbtk_audio_play_stream(void *dev_hdl, const void *pData, int len)
+{
+//    printf("%s,--len:%d\n", __func__, len);
+    unsigned bufsize = 0;
+    char *data = NULL;
+    int first_set = 0;
+    int res = 0;
+    int ret = 0;
+    int read_size = 0;
+    char *p = (char *)pData;
+
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+
+    if (NULL == dev_hdl || NULL == internal_hdl || pData == NULL)
+        return -1;
+
+    if(AUDIO_RUNNING == pcxt->state)
+        return -2;
+
+    bufsize = pcxt->pcm_packet_size;
+    data = calloc(1, bufsize);
+    if (!data) {
+        fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+        pthread_exit(NULL);
+    }
+
+    mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+//    if(bufsize > len )
+//    {
+//        bufsize = len;
+//    }
+    
+    while (pcxt->state != AUDIO_STOP)
+    {
+
+        memcpy(data,p+read_size, bufsize );
+        read_size += bufsize;
+
+        if(read_size > len)
+        {
+         //    printf(">[%d]\n", read_size); 
+            break;
+        }
+
+        while(AUDIO_PAUSE == pcxt->state)
+        {
+            usleep(80000);
+        }
+
+        if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+        {
+            first_set = 1;
+            mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+        }
+
+        ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize);
+        if (ret < 0) {
+            printf("%s: error writing (child).\n", __FUNCTION__);
+            break;
+        } else if (ret < (signed int)pcxt->pcm_packet_size) {
+            printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret);
+            break;
+        }
+
+        if(read_size == len)
+        {
+         //    printf("=[%d]", read_size); 
+            break;
+        }
+
+    }
+
+    mbtk_audio_set_status(dev_hdl, AUDIO_OPEN);
+    free(data);
+    return 0;
+
+}
+
+
+int mbtk_audio_play_file(void *dev_hdl, int file_fd, int offset)
+{
+    unsigned bufsize = 0;
+    char *data = NULL;
+    int first_set = 0;
+    int file_data_sz = 0;
+    int res = 0;
+    int ret;
+
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+
+    if (NULL == dev_hdl || NULL == internal_hdl)
+        return -1;
+
+    if(AUDIO_RUNNING == pcxt->state)
+        return -2;
+
+    file_data_sz = mbtk_wav_pcm16Le_check(file_fd);
+
+    bufsize = pcxt->pcm_packet_size;
+    data = calloc(1, bufsize);
+    if (!data) {
+        fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+        pthread_exit(NULL);
+    }
+    if(offset)
+    {
+        lseek(file_fd, offset, SEEK_SET);
+    }
+
+    mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+    int all_size = 0;
+    
+    while (pcxt->state != AUDIO_STOP)
+    {
+        res = read(file_fd, data, bufsize);
+      //   printf("%s:read : %d bytes\n", __FUNCTION__, res);
+        if(res == 0 || res < 0)
+        {
+         //    printf("[%d]", res); 
+            break;
+        }
+
+        all_size += res;
+        if (file_data_sz < all_size || file_data_sz == all_size) {
+            printf("aplay size :%d - %d\n", file_data_sz, all_size);
+            break;
+        }
+
+        while(AUDIO_PAUSE == pcxt->state)
+        {
+            usleep(80000);
+        }
+
+        if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+        {
+            first_set = 1;
+            mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+        }
+
+        ret = pcxt->stream_out->write(pcxt->stream_out, data, res);
+        if (ret < 0) {
+            printf("%s: error writing (child).\n", __FUNCTION__);
+            break;
+        } else if (ret < (signed int)pcxt->pcm_packet_size) {
+            printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret);
+            break;
+        }
+    }
+
+    mbtk_audio_set_status(dev_hdl, AUDIO_OPEN);
+    free(data);
+
+    return 0;
+}
+
+int mbtk_audio_record(void *dev_hdl, mbtk_audio_record_cb_func cb_func, void *cb_data)
+{
+    struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+    int res = -1;
+    struct record_cb_s *_usrData = NULL;
+
+    if (NULL == pcxt || NULL == internal_hdl || NULL == cb_func)
+        return -1;
+
+    if(AUDIO_RUNNING == pcxt->state)
+        return -2;
+
+    _usrData = malloc(sizeof(struct record_cb_s));
+    _usrData->_cb = cb_func;
+    _usrData->cb_data = cb_data;
+    pcxt->usrData = (void *)_usrData;
+    res = pthread_create(&pcxt->pid, NULL, mbtk_record_pthread, dev_hdl);
+    if (res != 0)
+    {
+        if(pcxt->usrData)
+        {
+            free(pcxt->usrData);
+            pcxt->usrData = NULL;
+        }
+        fprintf(stderr, "\n%s: Failed to create pthread\n", __FUNCTION__);
+    }
+    // 防止重复录音
+    usleep(500);
+
+    return res;
+}
+
+int mbtk_audio_close(void *dev_hdl)
+{
+    printf("mbtk_audio_close()\n");
+    int value = 0;
+    struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl;
+
+    if (NULL == _hdl || NULL == internal_hdl )
+    {
+        printf("mbtk_audio_close() fail dev_hdl is NULL\n");
+        return -1;
+    }
+
+    mbtk_audio_set_status(_hdl, AUDIO_STOP);
+    if(0 == _hdl->device) {
+        while (_hdl->pid != 0) {
+            usleep(10000);
+        }
+
+        vcm_playback_drain(0);//wait for drain the AP audiostub queue.
+        usleep(80000);//delay 80ms until DSP play out its buffered data.
+        _hdl->stream_out->common.standby(&_hdl->stream_out->common);
+        _hdl->audio_ahw_dev_ubus->close_output_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_out);
+    } else {
+
+        while (_hdl->pid != 0) {
+            sleep(1);
+        }
+        _hdl->stream_in->common.standby(&_hdl->stream_in->common);
+        _hdl->audio_ahw_dev_ubus->close_input_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_in);
+        VCMDeinit();//close the fd of audiostub_ctl when exit the thread.
+    }
+
+    audio_hal_uninstall();
+    pthread_mutex_destroy(&_hdl->_cond_mutex);
+    pthread_mutex_destroy(&_hdl->_stream_mutex);
+    free(_hdl);
+    _hdl = NULL;
+    internal_hdl = NULL;
+
+    return 0;
+}
+
+int mbtk_audio_pause(void* dev_hdl)
+{
+    // struct pcm *_pcm = ((struct mopen_audio_t *)dev_hdl)->_pcm;
+
+    if (NULL == dev_hdl || NULL == internal_hdl)
+        return -1;
+
+    if (((struct mopen_audio_t *)dev_hdl)->state != AUDIO_RUNNING)
+    {
+        return -1;
+    }
+
+    // if (ioctl(_pcm->fd, SNDRV_PCM_IOCTL_PAUSE, 1))
+    // {
+    //     printf("\n%s: cannot pause channel: errno =%d\n",__FUNCTION__,-errno);
+    //     return -errno;
+    // }
+    mbtk_audio_set_status(dev_hdl, AUDIO_PAUSE);
+    return 0;
+}
+
+int mbtk_audio_resume(void* dev_hdl)
+{
+    if (NULL == dev_hdl || NULL == internal_hdl)
+        return -1;
+
+    if (((struct mopen_audio_t *)dev_hdl)->state != AUDIO_PAUSE)
+    {
+        return -1;
+    }
+
+    // if (ioctl(_pcm->fd, SNDRV_PCM_IOCTL_PAUSE, 0))
+    // {
+    //     printf("\n%s: cannot Resume channel: errno =%d\n", __FUNCTION__, -errno);
+    //     return -errno;
+    // }
+    mbtk_audio_set_status(dev_hdl, AUDIO_RESUME);
+    return 0;
+}
+
+int mbtk_audio_stop(void* dev_hdl)
+{
+    struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl;
+
+    if (NULL == dev_hdl || NULL == internal_hdl)
+        return -1;
+
+    // if (ioctl(_hdl->_pcm->fd, SNDRV_PCM_IOCTL_DROP))
+    // {
+    //     printf("\n%s: cannot Resume channel: errno =%d\n",__FUNCTION__,-errno);
+    //     return -errno;
+    // }
+
+    mbtk_audio_set_status(dev_hdl, AUDIO_STOP);
+    _hdl->pid = 0;
+
+    return 0;
+}
+
+mbtk_audio_state_enum mbtk_audio_state_get(void *hdl)
+{
+    return ((struct mopen_audio_t *)hdl)->state;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_basic_at_wrapper.c b/mbtk/mbtk_lib/src/mbtk_basic_at_wrapper.c
new file mode 100755
index 0000000..43fb606
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_basic_at_wrapper.c
@@ -0,0 +1,11 @@
+#include "mbtk_adc.h"
+
+int mbtk_at_adc(const char *args)
+{
+    int value = (int)args;
+
+    if(0 != value && 1 != value){
+        return -1;
+    }
+    return mbtk_adc_get((mbtk_adc_enum)value);
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_bs_position.c b/mbtk/mbtk_lib/src/mbtk_bs_position.c
new file mode 100755
index 0000000..0119ae5
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_bs_position.c
@@ -0,0 +1,317 @@
+/**
+ *   \file mbtk_bs_position.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-17
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include "mbtk_type.h"
+#include <telephony/ril.h>
+#include <telephony/ril_ext.h>
+#include "rilutil.h"
+#include "mbtk_log.h"
+
+#define RIL_UBUS_REQ		"ril_request"
+#define RIL_UBUS_ID		"ril"
+#define IMSI_SIZE 15
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+	#define bs_log(...)                    printf(__VA_ARGS__)
+#else
+	#define bs_log(...)
+#endif
+
+struct bs_ril_cellinfo {
+	int type;
+	int mcc;
+	int mnc;
+	int lac;
+	int cid;
+	int reg_state;
+};
+
+struct mbtk_bs_ubus_t
+{
+    struct ubus_context     *ctx;
+
+    /* RIL */
+    struct ubus_subscriber 	ril_ind_event;
+    uint32_t	 		    ril_subscriber_id;
+    uint32_t	 		    ril_request_id;
+    pthread_t  call_status_pthread;
+    struct bs_ril_cellinfo cellinfo;
+};
+struct mbtk_bs_ubus_t *mbtk_bs_ubus = NULL;
+static struct blob_buf b;
+
+static inline int radio_tech_2_act(int radio_tech)
+{
+	switch(radio_tech)
+	{
+		case RADIO_TECH_GPRS: return 0; /* ACT could have been either 1 or 0 !! */
+		case RADIO_TECH_UMTS: return 2;
+		case RADIO_TECH_EDGE: return 3;
+		case RADIO_TECH_HSDPA: return 4;
+		case RADIO_TECH_HSUPA: return 5;
+		case RADIO_TECH_HSPA: return 6;
+		case RADIO_TECH_LTE: return 7;
+		case RADIO_TECH_LTEP: return 7; /* temporary set it to 7, in future we may need to set to a number for 4G+ */
+		case RADIO_TECH_HSPAP: return 8;
+		case RADIO_TECH_UNKNOWN:
+		default: break;
+	}
+
+	return 0;
+}
+static void cellid_cb(void *response)
+{
+	rilutilstrings *resp = NULL;
+
+    resp = (rilutilstrings *) response;
+    bs_log("response num : %d\n", resp->num);
+
+    sscanf(resp->str[0], "%d", &mbtk_bs_ubus->cellinfo.reg_state);
+    sscanf(resp->str[1], "%x", &mbtk_bs_ubus->cellinfo.lac);
+    sscanf(resp->str[2], "%x", &mbtk_bs_ubus->cellinfo.cid);
+    sscanf(resp->str[3], "%d", &mbtk_bs_ubus->cellinfo.type); /* converted ACT value */
+    bs_log("cellinfo (%p): reg_state before=%d",
+        &mbtk_bs_ubus->cellinfo,
+        mbtk_bs_ubus->cellinfo.reg_state);
+    bs_log("lac:%x, cid:%x\n",
+        mbtk_bs_ubus->cellinfo.lac,
+           mbtk_bs_ubus->cellinfo.cid);
+    bs_log("reg_state:%d, lac:%d, cid:%d, type:%d\n",
+        mbtk_bs_ubus->cellinfo.reg_state, mbtk_bs_ubus->cellinfo.lac,
+           mbtk_bs_ubus->cellinfo.cid, mbtk_bs_ubus->cellinfo.type);
+    mbtk_bs_ubus->cellinfo.type = radio_tech_2_act(mbtk_bs_ubus->cellinfo.type);
+    // bs_log("mcc:%d, mnc:%d, type:%d\n",
+    //     mbtk_bs_ubus->cellinfo.mcc, mbtk_bs_ubus->cellinfo.mnc, mbtk_bs_ubus->cellinfo.type);
+    bs_log("cellinfo (%p): reg_state=%d, lac=%d, cid=%d, type=%d, mcc=%d, mnc=%d\n",
+    	 &mbtk_bs_ubus->cellinfo,
+    	 mbtk_bs_ubus->cellinfo.reg_state, mbtk_bs_ubus->cellinfo.lac, mbtk_bs_ubus->cellinfo.cid,
+    	 mbtk_bs_ubus->cellinfo.type, mbtk_bs_ubus->cellinfo.mcc, mbtk_bs_ubus->cellinfo.mnc);
+}
+
+
+static void setid_cb(char *resp)
+{
+	char mcc[4] = { 0 }, mnc[4] = { 0};
+    char *imsi = NULL;
+
+	imsi = malloc(IMSI_SIZE + 1);
+	if (!imsi) {
+		printf("Memory allocation failed\n");
+		return;
+	}
+    memset(imsi, 0, IMSI_SIZE + 1);
+	/* update imsi and cellinfo mcc & mnc */
+	strncpy(imsi, resp, IMSI_SIZE);
+    bs_log("imsi: %s\n", imsi);
+	memcpy(mcc, imsi, 3);
+	memcpy(mnc, (char *)imsi + 3, 2);
+	mbtk_bs_ubus->cellinfo.mcc = atoi(mcc);
+	mbtk_bs_ubus->cellinfo.mnc = atoi(mnc);
+
+    bs_log("reg_stat, mcc:%d, mnc:%d, \n",
+            mbtk_bs_ubus->cellinfo.mcc, mbtk_bs_ubus->cellinfo.mnc);
+    free(imsi);
+}
+
+static void bs_complete_cb(struct ubus_request *req, int ret)
+{
+	bs_log("ubus_request = %08X\n", req);
+	free(req);
+}
+
+static void bs_requset_cb(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+    unsigned int requestid = 0;
+    unsigned int rilerrno;
+    void *response = NULL;
+    int responselen = 0;
+    int ret = 0;
+
+    ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &response, &responselen);
+    if(ret)
+    {
+        fprintf(stderr, "parse blob error\n");
+        goto done;
+    }
+
+    if(rilerrno)
+    {
+        fprintf(stderr, "unsolicited id %d, error code %d\n", requestid, rilerrno);
+        goto done;
+    }
+    bs_log("requestid : %d\n", requestid);
+    if(requestid == RIL_REQUEST_GET_IMSI)
+    {
+        setid_cb((char *)response);
+    }
+    else if(requestid == RIL_REQUEST_DATA_REGISTRATION_STATE)
+    {
+        cellid_cb(response);
+    }
+done:
+    if(response)
+        rilutil_freeResponseData(requestid, response, responselen);
+
+    return;
+}
+
+
+int bs_get_cell_info(struct mbtk_bs_ubus_t *bs)
+{
+	int ret_val;
+	struct ubus_request *req = NULL;
+
+	if(!bs) {
+		printf("ril module not running\n");
+		return 0;
+	}
+	blob_buf_init(&b, 0);
+
+	rilutil_makeRequestBlob(&b, RIL_REQUEST_DATA_REGISTRATION_STATE, NULL, 0);
+
+	req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+
+	if ((ret_val =
+	     ubus_invoke_async(bs->ctx, bs->ril_request_id, RIL_UBUS_REQ, b.head, req)) != UBUS_STATUS_OK) {
+		printf("mubus_invoke_async failed\n");
+		free(req);
+		return -1;
+	} else {
+        req->data_cb = bs_requset_cb;
+        req->complete_cb = bs_complete_cb;
+		ubus_complete_request_async(bs->ctx, req);
+	}
+		return 0;
+}
+
+int bs_get_setid_info(struct mbtk_bs_ubus_t *bs)
+{
+	int ret_val;
+	struct ubus_request *req = NULL;
+
+	if(!bs) {
+		printf("ril module not running\n");
+		return 0;
+	}
+	blob_buf_init(&b, 0);
+
+	rilutil_makeRequestBlob(&b, RIL_REQUEST_GET_IMSI, NULL, 0);
+
+	req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+
+	if ((ret_val =
+	     ubus_invoke_async(bs->ctx, bs->ril_request_id, RIL_UBUS_REQ, b.head, req)) != UBUS_STATUS_OK) {
+		printf("mubus_invoke_async failed\n");
+		free(req);
+		return -1;
+	} else {
+        req->data_cb = bs_requset_cb;
+        req->complete_cb = bs_complete_cb;
+		ubus_complete_request_async(bs->ctx, req);
+	}
+		return 0;
+}
+
+static void bs_register_ril(void* hdl)
+{
+    pthread_detach(pthread_self());
+    uloop_run();
+    bs_log("%s uloop_run!\n", __FUNCTION__);
+    pthread_exit(NULL);
+}
+
+struct mbtk_bs_ubus_t *bs_ril_init(struct mbtk_bs_ubus_t *bs)
+{
+	int ret;
+
+	mbtk_bs_ubus = malloc(sizeof(struct mbtk_bs_ubus_t));
+	if (!mbtk_bs_ubus) {
+		printf("memory allocation failed\n");
+		return NULL;
+	}
+
+	memset(mbtk_bs_ubus, 0, sizeof(*mbtk_bs_ubus));
+    uloop_init();
+    mbtk_bs_ubus->ctx = ubus_connect(NULL);
+    if(!mbtk_bs_ubus->ctx)
+    {
+        LOGE("Failed to connect to ubus");
+        goto out_error;
+    }
+
+    ubus_add_uloop(mbtk_bs_ubus->ctx);
+    if (ubus_lookup_id(mbtk_bs_ubus->ctx, RIL_UBUS_ID, &mbtk_bs_ubus->ril_request_id)) {
+    	fprintf(stderr, "%s, Failed to look up test object\n", __FUNCTION__);
+        goto out_error;
+    }
+
+    pthread_create(&mbtk_bs_ubus->call_status_pthread, NULL, (void *)bs_register_ril, NULL);
+
+	return mbtk_bs_ubus;
+
+out_error:
+	free(mbtk_bs_ubus);
+	return NULL;
+}
+
+int bs_ril_exit(struct mbtk_bs_ubus_t *bs)
+{
+    int ret;
+
+	if(!bs) {
+		printf("ril module not running\n");
+		return 0;
+	}
+
+    ret = pthread_cancel(bs->call_status_pthread);
+    pthread_join(bs->call_status_pthread, NULL);
+    do{
+        ret = pthread_kill(bs->call_status_pthread, 0);
+        bs_log("kill pthread: %d \n", ret);
+        if(ret == ESRCH)
+            bs_log("The specified thread does not exist or has terminated\n");
+        else if(ret == EINVAL)
+            printf("Useless signal\n");
+        else
+            printf("The thread exists\n");
+        usleep(100000);
+    }while(0 == ret);
+
+	free(bs);
+	return 0;
+}
+int mbtk_bs_position(void)
+{
+    struct mbtk_bs_ubus_t *bs_hdl;
+    bs_hdl = bs_ril_init(NULL);
+    bs_get_setid_info(bs_hdl);
+    bs_get_cell_info(bs_hdl);
+
+    sleep(1);
+    bs_ril_exit(bs_hdl);
+
+    return 0;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_coap.c b/mbtk/mbtk_lib/src/mbtk_coap.c
new file mode 100755
index 0000000..186255e
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_coap.c
@@ -0,0 +1,1381 @@
+/*************************************************************

+Description:

+    C file for L620 coap.

+Author:

+    LuoJian

+Date:

+    2019/3/25 9:23:29

+*************************************************************/

+#include <stdlib.h>

+#include <string.h>

+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/in.h>
+#include <unistd.h>

+

+#include "mbtk_coap.h"

+#include "mbtk_type.h"

+#include "mbtk_log.h"

+#include "mbtk_sock2.h"

+

+

+/*************************************************************

+    Variables:public

+*************************************************************/

+

+

+#define MBTK_ECOAP_TIMEOUT (15 * 1000)

+#define MBTK_ECOAP_WAIT_CLOSE_TIMEOUT (5 * 60 * 1000)

+#define MBTK_ECOAP_STACK_SIZE                (12 * 1024)        // task stack size

+

+#define ECOAPVER 1

+#define EOCAPTYPE 2

+#define ECOAPCODE 3

+#define ECOAPMSGID 4

+#define ECOAPTOKEN 5

+

+

+/*param--------------------*/

+// Point the first item.

+static mbtk_ecoap_package_s *mbtk_ecoap_head = NULL;

+static mbtk_ecoap_package_ver mbth_ecoap_package_ver={1,0,1,1};

+

+

+struct sockaddr_in serveraddr = {0};

+int socket_id;

+int addrlen;

+

+static mbtk_init_info *coap_init_info = NULL;

+static int coap_handle = -1;

+static bool coap_sock_inited = FALSE;

+static int coap_fd = -1;

+

+

+

+// Point the last item.

+static mbtk_ecoap_package_s *mbtk_ecoap_tail = NULL;

+static mbtk_ecoap_net_s mbtk_ecoap_net;

+static mbtk_ecoap_state_e mbtk_ecoap_state = MBTK_ECOAP_STATE_NON;

+

+//static uint16 mbtk_ecoap_curr_coap_id = 0;

+static char mbtk_ecoap_host[MBTK_ECOAP_NEW_MAX+1] = {'\0'};

+

+static int mbtk_ecoap_port;

+static int mbtk_ecoap_is_dtls;

+static mbtk_ecoap_opt_2 mbtk_ecoap_option_2;

+static mbtk_ecoap_opt_3 mbtk_ecoap_option_3;

+static int mbtk_ecoap_recv = -1;

+static int mbtk_ecoap_cur_time =0;

+

+/*func------------------------*/

+void mbtk_ecoap_option_add(mbtk_ecoap_option_s *option);

+int mbtk_ecoap_list_del(uint16 message_id,int optDel);

+

+

+#define HEXCHAR(x) ((x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F'))

+

+

+#if 1

+

+#define toupper(a)  ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))

+

+void HexToStr(byte *pbDest, byte *pbSrc, int nLen)

+{

+	char   ddl,ddh;

+	int i;

+

+	for (i=0; i<nLen; i++)

+	{

+		ddh = 48 + pbSrc[i] / 16;

+		ddl = 48 + pbSrc[i] % 16;

+		if (ddh > 57)

+		{

+			ddh = ddh + 7;

+		}

+		if (ddl > 57)

+		{

+			ddl = ddl + 7;

+		}

+		pbDest[i*2] = ddh;

+		pbDest[i*2+1] = ddl;

+	}

+	pbDest[nLen*2] = '\0';

+}

+

+uint8_t StrToHex(byte *pbDest, byte *pbSrc, int nLen)

+{

+	char h1,h2;

+	byte s1,s2;

+	uint8_t i;

+

+	for (i=0; i<nLen; i++)

+	{

+		h1 = pbSrc[2*i];

+		h2 = pbSrc[2*i+1];

+		s1 = toupper(h1) - 0x30;

+		if (s1 > 9)

+		{

+			s1 -= 7;

+		}

+		s2 = toupper(h2) - 0x30;

+		if (s2 > 9)

+		{

+			s2 -= 7;

+		}

+		pbDest[i] = s1*16 + s2;

+		//DS_MBTK_MSG1_HIGH("StrToHex:%.2X",pbDest[i]);

+	}

+	return i;

+}

+

+void coap_log(int is_ascii,const char* data,int len)

+{

+    if(len <= 0) {

+        return;

+    }

+

+    if(is_ascii) { // Is ASCII

+        int i = 0;

+        int count = len / 100 + 1;

+

+        // Has '\0'

+        if(len != strlen(data)) {

+            return;

+        }

+

+        while(i < count) {

+            printf("%s\n",data + i * 100);

+            i++;

+        }

+    } else { // Is hex

+        int index = 0;

+        int i = 0;

+        char buf_temp[100];

+        while(index % 16 == 0 && index < len) {

+            memset(buf_temp,0,100);

+            for(i = 0;i < 16 && index + i < len;i++) {

+                snprintf(buf_temp + i * 3,100 - i,"%.2x ",((char*)data)[index + i]);

+            }

+            index += 16;

+            printf("%s\n", buf_temp);

+        }

+    }

+}

+

+

+

+static void

+mbtk_ecoap_show_error

+(

+    int rsp_errno

+)

+{

+    char temp[50] = {0};

+    memset(temp, 0, 50);

+    snprintf(temp,50,"\r\n+MCOAPERROR:%d\r\n",rsp_errno);

+    printf("%s\n",temp);

+}

+

+int ecoap_recv_buffer(char * dest,const char* data,int len)

+{

+    if( len <= 0) {

+        return -1;

+    }

+    int buffer_len = 0;

+    char Payload[MBTK_ECOAP_DATA_MAX*2+1] ={'\0'};

+	int pud_lenth = mbtk_coap_get_pdu_Length();

+	int type = mbtk_ecoap_get_message_type();

+	char code[12];

+    memset(code,0x00,sizeof(code));

+	mbtk_ecoap_get_code(code);

+	uint16_t mesageId = coapGetRecvMessageID();

+	memset(Payload,0x00,MBTK_ECOAP_DATA_MAX*2+1);

+	snprintf(dest,MBTK_ECOAP_DATA_MAX,

+			"+COAPNMI:%d\r\nMessage Type:%d\r\nCode:\"%s\"\r\nMessage ID:%d\r\nPayload:",

+			pud_lenth,

+			type,

+			code,

+			mesageId);	

+

+

+    int i = 0;

+	for(i = 0; i < len; i++)

+	{

+		if(data[i] == 0xFF && i> 3)   //BUG 46397

+		{

+			LOGE("data[i] == 0xFF\n");

+			memcpy(Payload, data+i+1, len - i-1);

+			Payload[len-i -1]='\0';

+			break;

+		}

+	}

+

+    LOGE("len:%d, i :%d\n",len,i);

+	if(Payload[len-i -1] == '\0' )

+	{

+		LOGE("==\0-------------------\n");		

+	//	coap_log(-1,(char*)Payload,len - i-1);

+	}else{

+		LOGE("!=\0--------------------\n");

+		Payload[0]='\0';

+	}

+

+    buffer_len = strlen(dest) + strlen(Payload); 

+    strcat(dest,Payload);

+	LOGE("2---------buffer_len:%d,coap_recv_buffer_dest:%s,Payload:%s\n",buffer_len,dest,Payload);

+    return buffer_len;

+}

+

+int mbtk_ecoap_get_message_type(void)

+{

+    switch(coapGetRecvType())

+    {

+        case COAP_CONFIRMABLE:

+            return 0;

+        break;

+

+        case COAP_NON_CONFIRMABLE:

+            return 1;

+        break;

+

+        case COAP_ACKNOWLEDGEMENT:

+            return 2;

+        break;

+

+        case COAP_RESET:

+            return 3;

+        break;

+    }

+	return 0;

+}

+

+void mbtk_ecoap_get_code(char *ptr)

+{

+	switch(coapGetRecvCode()) {

+		case COAP_EMPTY:

+			memcpy(ptr,"0.00",4);

+		break;

+		case COAP_GET:

+			memcpy(ptr,"0.01",4);

+		break;

+		case COAP_POST:

+			memcpy(ptr,"0.02",4);

+		break;

+		case COAP_PUT:

+			memcpy(ptr,"0.03",4);

+		break;

+		case COAP_DELETE:

+			memcpy(ptr,"0.04",4);

+		break;

+		case COAP_CREATED:

+			memcpy(ptr,"2.01",4);

+		break;

+		case COAP_DELETED:

+			memcpy(ptr,"2.02",4);

+		break;

+		case COAP_VALID:

+			memcpy(ptr,"2.03",4);

+		break;

+		case COAP_CHANGED:

+			memcpy(ptr,"2.04",4);

+		break;

+		case COAP_CONTENT:

+			memcpy(ptr,"2.05",4);

+		break;

+		case COAP_CONTINUE:

+			memcpy(ptr,"2.31",4);

+		break;

+		case COAP_BAD_REQUEST:

+			memcpy(ptr,"4.00",4);

+		break;

+		case COAP_UNAUTHORIZED:

+			memcpy(ptr,"4.01",4);

+		break;

+		case COAP_BAD_OPTION:

+			memcpy(ptr,"4.02",4);

+		break;

+		case COAP_FORBIDDEN:

+			memcpy(ptr,"4.03",4);

+		break;

+		case COAP_NOT_FOUND:

+			memcpy(ptr,"4.04",4);

+		break;

+		case COAP_METHOD_NOT_ALLOWED:

+			memcpy(ptr,"4.05",4);

+		break;

+		case COAP_NOT_ACCEPTABLE:

+			memcpy(ptr,"4.06",4);

+		break;

+		case COAP_PRECONDITION_FAILED:

+			memcpy(ptr,"4.12",4);

+		break;

+		case COAP_REQUEST_ENTITY_TOO_LARGE:

+			memcpy(ptr,"4.13",4);

+		break;

+		case COAP_UNSUPPORTED_CONTENT_FORMAT:

+			memcpy(ptr,"4.15",4);

+		break;

+		case COAP_INTERNAL_SERVER_ERROR:

+			memcpy(ptr,"5.00 ",4);

+		break;

+		case COAP_NOT_IMPLEMENTED:

+			memcpy(ptr,"5.01",4);

+		break;

+		case COAP_BAD_GATEWAY:

+			memcpy(ptr,"5.02",4);

+		break;

+		case COAP_SERVICE_UNAVAILABLE:

+			memcpy(ptr,"5.03",4);

+		break;

+		case COAP_GATEWAY_TIMEOUT:

+			memcpy(ptr,"5.04",4);

+		break;

+		case COAP_PROXYING_NOT_SUPPORTED:

+			memcpy(ptr,"5.05",4);

+		break;

+		default:

+			sprintf(ptr, "UndefCod%u",(unsigned)(coapGetRecvCode()));			

+	}

+}

+

+

+static int

+mbtk_ecoap_is_open()

+{

+    if(mbtk_ecoap_state >= MBTK_ECOAP_STATE_OPENED)

+        return 0;

+

+    return -1;

+}

+

+

+static void mbtk_ecoap_reset()

+{

+    memset(&mbtk_ecoap_net,0x0,sizeof(mbtk_ecoap_net_s));

+    mbtk_ecoap_net.message_id = 1;   //change mbtk_ecoap_net.message_id = 0;

+    memset(&mbtk_ecoap_option_2, 0x0, sizeof(mbtk_ecoap_opt_2));

+    memset(&mbth_ecoap_package_ver, 0x0,sizeof(mbtk_ecoap_package_ver));

+    mbth_ecoap_package_ver.version = 1;

+    mbth_ecoap_package_ver.type = 0;

+    mbth_ecoap_package_ver.code = 1;

+    mbth_ecoap_package_ver.message_id = 1;

+    mbtk_ecoap_recv = -1;

+

+    mbtk_ecoap_package_s *coap = mbtk_ecoap_head;

+	mbtk_ecoap_package_s *coap_next = NULL;

+	mbtk_ecoap_option_s * option_ptr = NULL;

+	mbtk_ecoap_option_s * option_ptr_next = NULL;

+	

+    while(coap != NULL)

+    {

+		coap_next = coap->next;

+		if(coap->payload != NULL)

+			free(coap->payload);

+

+		if(coap->options != NULL)

+		{

+			option_ptr = coap->options;

+			while(option_ptr != NULL)

+			{

+				option_ptr_next = option_ptr->next;

+				free(option_ptr);

+				option_ptr = NULL;

+				option_ptr = option_ptr_next;

+			}

+			

+		}

+		

+		free(coap);

+		coap = NULL;

+		coap = coap_next;

+

+    }

+

+    mbtk_ecoap_head = mbtk_ecoap_tail = NULL;

+}

+

+

+static void mbtk_ecoap_close()

+{

+

+}

+

+

+

+

+

+mbtk_ecoap_package_s *mbtk_ecoap_get_by_msg_id(uint16 message_id)

+{

+    if(mbtk_ecoap_head == NULL)

+    {

+    }

+    else

+    {

+        mbtk_ecoap_package_s *coap_ptr = mbtk_ecoap_head;

+        while(coap_ptr != NULL)

+        {

+            if(coap_ptr->message_id == message_id)

+            {

+                return coap_ptr;;

+            }

+            coap_ptr = coap_ptr->next;

+        }

+    }

+    return NULL;

+}

+

+static void mbtk_ecoap_list_item_init(unsigned int  sig,mbtk_ecoap_package_s *coap,uint16 message_id)

+{

+    switch(sig)

+    {

+        case ECOAPVER:

+            coap->version = message_id;

+            break;

+        case EOCAPTYPE:

+            coap->type = message_id;

+            break;

+        case ECOAPCODE:

+            coap->code = message_id;

+            break;

+        case ECOAPMSGID:

+            coap->message_id = message_id;

+            break;

+        case ECOAPTOKEN:

+            coap->token_len = message_id;

+            break;

+        default:

+            break;

+    }

+    coap->next = NULL;  //change delete this code

+}

+

+

+mbtk_ecoap_package_s* mbtk_ecoap_list_add(uint16 message_id)

+{

+    LOGE("mbtk_ecoap_list_add-----memssage_id:%d\n",message_id);

+    if(mbtk_ecoap_head == NULL)

+    {

+        mbtk_ecoap_head = (mbtk_ecoap_package_s*)malloc(sizeof(mbtk_ecoap_package_s));

+        memset(mbtk_ecoap_head, 0,sizeof(mbtk_ecoap_package_s));

+        mbtk_ecoap_list_item_init(ECOAPMSGID,mbtk_ecoap_head,message_id);

+        mbtk_ecoap_tail = mbtk_ecoap_head;

+        return mbtk_ecoap_head;

+    }

+    else

+    {

+        mbtk_ecoap_package_s *coap_ptr = mbtk_ecoap_head;

+        while(coap_ptr != NULL)

+        {

+            if(coap_ptr->message_id == message_id)

+            {

+                printf("Coap %d exist.\n",message_id);

+                return NULL;

+            }

+            coap_ptr = coap_ptr->next;

+        }

+        mbtk_ecoap_tail->next = (mbtk_ecoap_package_s*)malloc(sizeof(mbtk_ecoap_package_s));

+        mbtk_ecoap_list_item_init(ECOAPMSGID,mbtk_ecoap_tail->next,message_id);

+        mbtk_ecoap_tail = mbtk_ecoap_tail->next;

+        return mbtk_ecoap_tail;

+    }

+}

+

+static void mbtk_ecoap_free(mbtk_ecoap_package_s *coap)

+{

+    if(coap != NULL)

+    {

+        if(coap->payload != NULL)

+            free(coap->payload);

+

+        if(coap->options != NULL)

+        {

+            mbtk_ecoap_option_s *option_ptr = coap->options;

+            while(option_ptr != NULL)

+            {

+                free(option_ptr);

+                option_ptr = option_ptr->next;

+            }

+        }

+

+        free(coap);

+        coap = NULL;

+    }

+}

+

+int mbtk_ecoap_list_del(uint16 message_id,int optDel)

+{

+    LOGE("mbtk_ecoap_list_del:message_id:%d\n",message_id);

+    if(mbtk_ecoap_head == NULL)

+    {

+    	printf("mbtk_ecoap_head == NULL\n");

+	return -1;

+    }

+

+    mbtk_ecoap_recv = -1;

+    if(optDel)

+    {

+        memset(&mbtk_ecoap_option_2, 0x0, sizeof(mbtk_ecoap_opt_2));

+        memset(&mbtk_ecoap_option_3, 0x0, sizeof(mbtk_ecoap_opt_3));

+        memset(&mbth_ecoap_package_ver,0x0,sizeof(mbth_ecoap_package_ver));

+        mbth_ecoap_package_ver.version = 1;

+        mbth_ecoap_package_ver.type = 0;

+        mbth_ecoap_package_ver.code = 1;

+        mbth_ecoap_package_ver.message_id = 1;

+    }

+    mbtk_ecoap_package_s *coap = mbtk_ecoap_head;

+    if(mbtk_ecoap_head->message_id == message_id) // Is first item.

+    {

+        mbtk_ecoap_head = mbtk_ecoap_head->next;

+

+        mbtk_ecoap_free(coap);

+        return 0;

+    }

+    else     // Not first item.

+    {

+        while(coap->next != NULL)  

+        {

+            if(message_id == coap->next->message_id)   // delete

+            {

+                mbtk_ecoap_package_s *coap_tmp = coap->next;

+                if(mbtk_ecoap_tail == coap_tmp)

+                {

+                    mbtk_ecoap_tail = coap;

+                }

+                coap->next = coap_tmp->next;

+                mbtk_ecoap_free(coap_tmp);

+                return 0;;

+            }

+            coap = coap->next;

+        }

+        return -1;

+    }

+}

+

+void mbtk_ecoap_option_add(mbtk_ecoap_option_s *option)

+{

+    if(option != NULL)

+    {

+        switch(option->type)

+        {

+            case COAP_OPTION_IF_MATCH:

+            case COAP_OPTION_URI_HOST:

+            case COAP_OPTION_ETAG:

+            case COAP_OPTION_IF_NONE_MATCH:

+            case COAP_OPTION_LOCATION_PATH:

+            case COAP_OPTION_LOCATION_QUERY:

+            case COAP_OPTION_PROXY_URI:

+            case COAP_OPTION_PROXY_SCHEME:

+            case COAP_OPTION_URI_PORT:

+            case COAP_OPTION_ACCEPT:

+            case COAP_OPTION_SIZE2:

+            case COAP_OPTION_SIZE1:

+            {

+                break;

+            }

+            case COAP_OPTION_BLOCK2:

+            case COAP_OPTION_BLOCK1:

+            {

+                LOGE("option->opt.opt_block.number = %d\n",option->opt.opt_block.number);

+                if(option->opt.opt_block.number <= 0x0F)

+                {

+                    uint8_t temp[1];

+                    temp[0] = (uint8_t)(((option->opt.opt_block.number << 4) & 0xF0)

+                                        | ((option->opt.opt_block.more_flag << 3) & 0x08)

+                                        | (option->opt.opt_block.size & 0x07));

+                    coapAddOption(option->type,1,temp);

+                }

+                else if(option->opt.opt_block.number <= 0x0FFF)

+                {

+                    uint8_t temp[2];

+                    temp[0] = (uint8_t)(option->opt.opt_block.number >> 4);

+                    temp[1] = (uint8_t)(((option->opt.opt_block.number << 4) & 0xF0)

+                                        | ((option->opt.opt_block.more_flag << 3) & 0x08)

+                                        | (option->opt.opt_block.size & 0x07));

+                    coapAddOption(option->type,2,temp);

+

+                }

+                else

+                {

+                    uint8_t temp[3];

+                    temp[0] = (uint8_t)(option->opt.opt_block.number >> 12);

+                    temp[1] = (uint8_t)(option->opt.opt_block.number >> 4);

+                    temp[2] = (uint8_t)(((option->opt.opt_block.number << 4) & 0xF0)

+                                        | ((option->opt.opt_block.more_flag << 3) & 0x08)

+                                        | (option->opt.opt_block.size & 0x07));

+                    coapAddOption(option->type,3,temp);

+

+                }

+                break;

+            }

+            case COAP_OPTION_MAX_AGE:

+            {

+                uint8_t temp[1];

+                temp[0] = (uint8_t)option->opt.opt_int;

+                coapAddOption(option->type,1,temp);

+                break;

+            }

+            case COAP_OPTION_OBSERVE:

+            {

+                uint8_t temp[1];

+                temp[0] = (uint8_t)option->opt.opt_int;

+                coapAddOption(option->type,1,temp);

+                break;

+            }

+            case COAP_OPTION_URI_QUERY:

+            {

+                coapAddURIQuery((char*)option->opt.opt_str);

+                break;

+            }

+            case COAP_OPTION_URI_PATH:

+            {

+                coapSetURI((char*)option->opt.opt_str);

+                break;

+            }

+            case COAP_OPTION_CONTENT_FORMAT:

+            {

+                coapSetContentFormat(option->opt.opt_content_format);

+                break;

+            }

+            default:

+                printf("No such type:%s\n",option->type);

+                break;

+        }

+    }

+}

+

+static void mbtk_ecoap_set_option(mbtk_ecoap_package_s *coap,

+                                 mbtk_coap_option_type type,void *str,

+                                 int int0,int int1,int int2)

+{

+    if(coap != NULL)

+    {

+/*        if(coap->options == NULL)

+        {

+            coap->options = (mbtk_ecoap_option_s*)malloc(sizeof(mbtk_ecoap_option_s));

+            memset(coap->options,0x0,sizeof(mbtk_ecoap_option_s));

+            coap->options->type = type;

+            coap->options->next = NULL;

+        }

+*/

+        mbtk_ecoap_option_s *option = coap->options;

+        while(option != NULL)

+        {

+            LOGE("1option != NULL\n");

+            if(option->type == type)

+            {

+                break;

+            }

+            option = option->next;

+        }

+

+        LOGE("----------------------\n");

+        if(option == NULL) // Now option

+        {

+            LOGE("option == NULL\n");

+            option = (mbtk_ecoap_option_s*)malloc(sizeof(mbtk_ecoap_option_s));

+            memset(option,0x0,sizeof(mbtk_ecoap_option_s));

+//            option->type = type;

+

+            option->next = coap->options;

+            coap->options = option;

+            option->type = type;

+        }

+        else // Change option

+        {

+            // Do noting.

+        }

+

+        switch(type)

+        {

+            case COAP_OPTION_IF_MATCH:

+            case COAP_OPTION_URI_HOST:

+            case COAP_OPTION_ETAG:

+            case COAP_OPTION_IF_NONE_MATCH:

+            case COAP_OPTION_LOCATION_PATH:

+            case COAP_OPTION_URI_QUERY:

+            case COAP_OPTION_LOCATION_QUERY:

+            case COAP_OPTION_PROXY_URI:

+            case COAP_OPTION_PROXY_SCHEME:

+            case COAP_OPTION_URI_PATH:

+            {

+                memset(option->opt.opt_str,0x0,128);

+                memcpy(option->opt.opt_str,str,strlen((char*)str));

+                break;

+            }

+            case COAP_OPTION_OBSERVE:

+            case COAP_OPTION_MAX_AGE:

+            case COAP_OPTION_URI_PORT:

+            case COAP_OPTION_SIZE2:

+            case COAP_OPTION_SIZE1:

+            {

+                option->opt.opt_int = (int)int0;

+                break;

+            }

+            case COAP_OPTION_BLOCK2:

+            case COAP_OPTION_BLOCK1:

+            {

+                option->opt.opt_block.size = (mbtk_ecoap_option_block_e)int0;

+                option->opt.opt_block.number = (int)int1;

+                option->opt.opt_block.more_flag = (uint8)int2;

+                break;

+            }

+            case COAP_OPTION_CONTENT_FORMAT:

+			{

+                option->opt.opt_content_format = (mbtk_content_format_type)int0;

+                break;

+            }

+            case COAP_OPTION_ACCEPT:

+            {

+                option->opt.opt_content_format = (mbtk_content_format_type)int0;

+                break;

+            }

+            default:

+                printf("No such type:%s\n",type);

+                break;

+        }

+    }

+}

+

+

+static void mbtk_ecoap_send_ack(mbtk_coap_code_type code,

+                               uint16_t message_id,uint8 token_len,uint8 *token)

+{

+    coapReset();

+    coapSetVersion(1);

+    coapSetType(COAP_ACKNOWLEDGEMENT);

+    coapSetMessageID(message_id);

+

+    if(code == COAP_POST || code == COAP_PUT)

+        coapSetCode(COAP_CHANGED);

+    else

+        coapSetCode(COAP_EMPTY);

+

+    if(token_len > 0)

+    {

+        coapSetToken(token, token_len);

+    }

+

+    uint8_t* pduPointer = coapGetPDUPointer();

+    int pduLen = coapGetPDULength();

+	int err;

+	int res = mbtk_sock_write(coap_handle, coap_fd, pduPointer, pduLen, 300, &err);

+    if(res != pduLen)

+    {

+        printf("Send ACK fail.[res:%d,pduLen:%d],err:%d\n",res,pduLen,err);

+    }

+    else

+    {

+        printf("Send ACK to server success.\n");

+    }

+}

+

+

+

+static int mbtk_ecoap_handle_sock_init(char *ip_addr, int port, bool is_support_ssl, bool ingnore_cert)

+{

+    mbtk_sock_info *sock_info = NULL;

+    int rc = 0;

+    int errno;

+	

+    sock_info = (mbtk_sock_info *)malloc(sizeof(mbtk_sock_info));

+    if(sock_info == NULL)

+    {

+        rc = -1;

+        return rc;

+    }

+    memcpy(sock_info->address, ip_addr, strlen(ip_addr));

+    sock_info->port = port;

+    sock_info->is_support_ssl = is_support_ssl;

+    sock_info->ingnore_cert = ingnore_cert;

+	sock_info->type = MBTK_SOCK_UDP;

+	

+    printf("host %s\nport %d\nis_support_ssl %d\ningnore_cert %d\n",sock_info->address,sock_info->port,sock_info->is_support_ssl,sock_info->ingnore_cert);

+

+	if(!coap_sock_inited)

+	{

+		coap_handle = mbtk_sock_init(coap_init_info);

+	    if (coap_handle < 0 )

+	    {

+	        rc = -1;

+	        return rc;

+	    }

+		coap_sock_inited = TRUE;

+	}

+

+

+    coap_fd  = mbtk_sock_open(coap_handle, sock_info, 3000, &errno);

+    if(coap_fd < 0)

+    {

+    	printf("creat socket fail, errno:%d\n",errno);

+        rc = -1;

+        return rc;

+    }

+    mbtk_ecoap_state = MBTK_ECOAP_STATE_READY;

+	return rc;

+}

+

+

+

+int mbtk_ecoap_ecoap_send(mbtk_ecoap_package_s* coap)

+{

+    if(coap != NULL)

+    {

+        coapReset();

+        coapSetVersion(coap->version);

+        coapSetType(coap->type);

+        coapSetCode(coap->code);

+        coapSetMessageID(coap->message_id);

+

+        if(coap->token_len > 0)

+        {

+            coapSetToken(coap->token, coap->token_len);

+        }

+

+        mbtk_ecoap_option_s *option = coap->options;

+        while(option != NULL)

+        {

+            mbtk_ecoap_option_add(option);

+            option = option->next;

+        }

+

+        if(coap->payload_len > 0)

+        {

+            coapSetPayload((uint8_t*)coap->payload, coap->payload_len);

+        }

+

+        uint8_t *pduPointer = coapGetPDUPointer();

+        int pduLen = coapGetPDULength();

+        uint8_t pduPointer2[MBTK_ECOAP_DATA_MAX*2];

+		int err;

+        memset ( pduPointer2,0x00,MBTK_ECOAP_DATA_MAX*2 );

+        if((mbtk_ecoap_option_2.optlen + pduLen) > MBTK_ECOAP_DATA_MAX*2)

+        {

+            printf("This length is too long\n");

+            return -1;

+        }

+

+        LOGE("pduLen:%d, optlen:%d\n",pduLen ,mbtk_ecoap_option_2.optlen);

+   //     printf("pduPointer:\n");

+   //     coap_log(-1,(char*)pduPointer,pduLen);

+        int j=0,k=0;

+        LOGE("pduPointer-----------end\n");

+//        int optflag = 0;

+        pduPointer2[0]= *pduPointer++;

+        pduPointer2[1]= *pduPointer++;

+        pduPointer2[2]= *pduPointer++;

+        pduPointer2[3]= *pduPointer++;

+        for(j = 0; j < mbtk_ecoap_option_2.optlen; j++)

+        {

+            pduPointer2[4+j] = mbtk_ecoap_option_2.optVal[j];

+			LOGE("j:%d, %X",j, mbtk_ecoap_option_2.optVal[j]);

+            k++;

+        }

+        int pduLen2 = 4;

+        while(pduLen > pduLen2 )

+        {

+        	LOGE("\r\npduLen > pduLen2 \r\n");

+            LOGE("pduLen:%d,pduPointer:%X,k:%d\n",pduLen2,*pduPointer,k);

+            pduPointer2[pduLen2+k] = *pduPointer++;

+            pduLen2++;

+        }

+

+        pduLen += mbtk_ecoap_option_2.optlen;

+

+        printf("sendpdu:--------pduLen:%d\n",pduLen);

+		coap_log(FALSE,(char*)pduPointer2,pduLen);

+		int send_len = 0;

+

+		if((send_len = mbtk_sock_write(coap_handle, coap_fd, pduPointer2, pduLen, 300, &err)) != pduLen)

+//        if((send_len = sendto(socket_id, pduPointer2, pduLen, 0, (struct sockaddr*)&serveraddr, addrlen)) != pduLen)

+        {

+            printf("coap_udp_sendto complate.[%d/%d]\n",send_len,pduLen);

+

+            coap->send_count++;

+			return -1;

+        }

+

+        if(coap->type != COAP_CONFIRMABLE)

+        {

+            mbtk_ecoap_list_del(coap->message_id,0);

+        }

+

+    }

+	return 0;

+}

+

+void mbtk_ecoap_recv_buffer(char * dest)

+{

+	int pud_lenth = mbtk_coap_get_pdu_Length();

+	int type = mbtk_ecoap_get_message_type();

+	char code[12];

+    memset(code,0x00,sizeof(code));

+	mbtk_ecoap_get_code(code);

+	uint16_t mesageId = coapGetRecvMessageID();

+	memset(dest,0x00,129);

+	snprintf(dest,128,

+			"+COAPNMI:%d\r\nMessage Type:%d\r\nCode:\"%s\"\r\nMessage ID:%d\r\nPayload:",

+			pud_lenth,

+			type,

+			code,

+			mesageId);	

+

+	return 0;

+}

+

+

+static void mbtk_ecoap_recv_resolve(const void *data,uint16 data_len)

+{

+    if(coapCreateRecv((uint8_t*)data, data_len) <= 0)

+    {

+        printf("coapCreateRecv fail.\n");

+    }

+    else

+    {

+        LOGE("coapCreateRecv() success.\n");

+

+        uint8_t version = coapGetRecvVersion();

+        mbtk_coap_type type = coapGetRecvType();

+        mbtk_coap_code_type code = coapGetRecvCode();

+        uint16_t message_id = coapGetRecvMessageID();

+        int pud_lenth = mbtk_coap_get_pdu_Length();

+        LOGE("version:%d;type:%d\n",version,type);

+        LOGE("code:%d;message_id:%d,pud_lenth:%d\n",code,message_id,pud_lenth);

+

+        uint8 token_len = coapGetRecvTokenLength();

+        char token[9] = {0};

+        memcpy(token,coapGetRecvTokenPointer(),token_len);

+        LOGE("token[%d]:%s\n",token_len,token);

+

+        uint16 playload_len = coapGetRecvPayloadLength();

+        uint8 *playload = coapGetRecvPayloadPointer();

+//        printf("----------------payload-----------------\n");

+//        coap_log(0,(char*)playload,playload_len);

+//        printf("--------------payload end----------------\n");

+

+

+		char buff_data[MBTK_ECOAP_DATA_MAX*2+1];

+		memset ( buff_data,0x00,MBTK_ECOAP_DATA_MAX*2+1 );

+        int buffer_len = ecoap_recv_buffer(buff_data, data, data_len);

+		printf("recv buff_len:%d\n",buffer_len);

+        printf("buf:\n%s\r\n",buff_data);

+		

+        LOGE("type:%X\n",type);

+        if(type == COAP_CONFIRMABLE) // Should ACK

+        {

+            mbtk_ecoap_send_ack(code,message_id,token_len,(uint8*)token);

+        }

+        else if(type == COAP_NON_CONFIRMABLE)

+        {

+            // Do nothing.

+        }

+        else if(type == COAP_ACKNOWLEDGEMENT)

+        {

+            mbtk_ecoap_package_s * coap_send = mbtk_ecoap_get_by_msg_id(message_id);

+            if(coap_send != NULL)

+            {

+                int number;

+                uint8_t more_flag;

+                uint8_t size;

+                LOGE("Get message(%d) ack.\n",message_id);

+                if(coapGetRecvOptionBlock2(&number, &more_flag, &size))

+                {

+                    LOGE("Block2 (size:%d; more_flag:%d; number:%d)\n",size,more_flag,number);

+                    if(more_flag) // Has data no read.

+                    {

+                        coap_send->message_id = ++mbtk_ecoap_net.message_id ;

+                        mbtk_ecoap_set_option(coap_send, COAP_OPTION_BLOCK2, NULL,

+                                             size,number + 1,0);

+

+                        mbtk_ecoap_ecoap_send(coap_send);

+                    }

+                    else

+                    {

+                        mbtk_ecoap_list_del(message_id,0);

+                    }

+                }

+                else

+                {

+                    printf("coapGetRecvOptionBlock2() fail.\n");

+                    mbtk_ecoap_list_del(message_id,0);

+                }

+            }

+            else

+            {

+                printf("Coap not match.\n");

+            }

+        }

+        else     // COAP_RESET

+        {

+            printf("Coap type error.\n");

+        }

+    }

+	coapDeleteRecv();

+

+}

+

+

+static int ecoap_sig_recv_handle(void)

+{

+    LOGE("coap_sig_recv_handle----------start\n");

+

+    uint8_t buffer[MBTK_ECOAP_DATA_MAX*2+1];

+    memset ( buffer,0x00,MBTK_ECOAP_DATA_MAX*2+1 );

+    int ret=-1;

+	int err = -1;

+	while(TRUE)

+	{

+		ret = mbtk_sock_read(coap_handle, coap_fd, buffer, MBTK_ECOAP_DATA_MAX*2, 1000*10, &err);

+		if(ret <= 0)

+		{

+            printf("read fail, err:%d",err);

+			break;

+		}

+        printf("recv_from ret:%d\n",ret);

+        coap_log(FALSE,(char*)buffer,ret);

+        mbtk_ecoap_recv_resolve(buffer,ret);

+	}

+

+    return ret;

+}

+

+static int ecoap_sig_send_complete_handle(void )

+{

+    int ret=-1;

+    mbtk_ecoap_package_s *coap = mbtk_ecoap_get_by_msg_id(mbtk_ecoap_net.message_id);

+    if(coap == NULL)

+    {

+        mbtk_ecoap_show_error(MBTK_ECOAP_ERR_MSG_ID);

+        return -1;

+    }

+

+    ret = mbtk_ecoap_ecoap_send(coap);

+

+    return ret;

+

+}

+

+static int mbtk_ecoap_open(int open);

+

+

+

+#endif

+

+

+/*************************************************************

+    Public Function Definitions

+*************************************************************/

+

+/*************************************************************

+	ip_addr: url

+	port

+

+*************************************************************/

+int mbtk_coap_ecoapnew_exec_cmd

+(

+    char *ip_addr,

+    int port,

+    bool is_support_ssl, 

+    bool ingnore_cert

+)

+{

+    printf("mbtk_coap_ecoapnew_exec_cmd()------start1\n");

+	int ret = 0;

+	if( !ip_addr)

+	{

+	    mbtk_ecoap_show_error(MBTK_ECOAP_ERR_NO_READY);

+	    return -1;

+	}

+

+	ret = mbtk_ecoap_handle_sock_init(ip_addr, port, is_support_ssl, ingnore_cert);

+	

+    return ret;

+}

+

+int mbtk_coap_ecoaprxmod_exec_cmd

+(

+	int mode

+)

+{

+    int result = 0;

+	int rx_mod = mode;

+	

+    return result;

+}

+

+int mbtk_coap_ecoappr_exec_cmd

+(

+	int format

+)

+{

+    int result = 0;

+	uint16 ecoappr = format;

+    return result;

+}

+

+int mbtk_coap_ecoaprxget_exec_cmd

+(

+    int len

+)

+{

+    int result = 0;

+	int get_len = len;

+	

+    return result;

+

+}

+

+int mbtk_coap_ecoapver_exec_cmd

+(

+    int version

+)

+{

+    int result = 0;

+	mbth_ecoap_package_ver.version = version;

+    return result;

+

+}

+

+int mbtk_coap_ecoaptype_exec_cmd

+(

+    mbtk_coap_type type

+)

+{

+    int result = 0;

+	mbth_ecoap_package_ver.type = type;

+	

+    return result;

+

+}

+

+

+int mbtk_coap_ecoapcode_exec_cmd

+(

+    mbtk_coap_code_type code

+)

+{

+    int  result = 0;

+	mbth_ecoap_package_ver.code = code;

+        LOGE("ver:%d,type:%d,code:%d,msg:%d\n",

+            mbth_ecoap_package_ver.version,

+            mbth_ecoap_package_ver.type,

+            mbth_ecoap_package_ver.code,

+            mbth_ecoap_package_ver.message_id);

+    return result;

+

+}

+

+int mbtk_coap_ecoaptoken_exec_cmd

+(

+    char *token_buf, int len

+)

+{

+    int result = 0;

+	uint16 token_length = len;

+	char * token = token_buf;	

+	if(strlen(token) != token_length)

+	{

+		return -1;

+	}

+	

+	mbth_ecoap_package_ver.token_len = token_length;

+	memcpy(mbth_ecoap_package_ver.token, token, strlen(token));

+

+	return result;

+}

+

+int mbtk_coap_ecoapmsgid_exec_cmd

+(

+    int msg_id

+)

+{

+    int result = 0;

+	 mbth_ecoap_package_ver.message_id = msg_id;        

+

+	return result;

+}

+

+int mbtk_coap_ecoapopt_exec_cmd

+(

+    char *value_buf, int buf_len

+)

+{

+    int result = 0;

+	int opt = buf_len;

+    char* value = value_buf;

+

+    if(value == NULL)

+    {

+        return -1;

+    }

+    if(opt != strlen(value))

+    {

+        return -1;

+    }

+

+    memset(&mbtk_ecoap_option_2, 0x0, sizeof(mbtk_ecoap_opt_2));

+    memset(&mbtk_ecoap_option_3, 0x0, sizeof(mbtk_ecoap_opt_3));

+

+    mbtk_ecoap_option_3.optlen = opt;

+    mbtk_ecoap_option_2.optlen = opt / 2;

+

+    if(mbtk_ecoap_option_2.optlen > 0)

+    {

+        memcpy(mbtk_ecoap_option_3.optVal, value, opt);

+        mbtk_ecoap_option_3.optVal[opt] = '\0';

+        StrToHex((byte*)mbtk_ecoap_option_2.optVal, (byte*)value, strlen(value));

+//		printf("\r\nopt2---------option_len,option_data");

+//		coap_log(FALSE,(char*)mbtk_ecoap_option_2.optVal,mbtk_ecoap_option_2.optlen);

+    }

+    return result;

+

+}

+

+int mbtk_coap_ecoapsend_exec_cmd

+(

+    int message_id, int Data_len, char *data

+)

+{

+    int data_len = Data_len;

+    char * send_data = NULL;

+	int err = -1;

+    if(data_len != 0 )

+    {

+        send_data = data;

+    }

+    int coap_id = message_id;

+

+	LOGE("send---------coap_id:%d,data_len:%d\n",coap_id,data_len);

+

+     if(mbtk_ecoap_state <= MBTK_ECOAP_STATE_CLOSING )

+    {

+        mbtk_ecoap_show_error(MBTK_ECOAP_ERR_NO_OPEN);

+        return -1;

+    }

+

+    if(coap_id != mbth_ecoap_package_ver.message_id)

+    {

+        mbtk_ecoap_show_error(MBTK_ECOAP_ERR_MSG_ID);

+        return -1;

+    }

+

+    if(coap_id != mbtk_ecoap_net.message_id)

+    {

+        printf("send_cmd del message_id:%d\n",mbtk_ecoap_net.message_id);

+        mbtk_ecoap_list_del(mbtk_ecoap_net.message_id,-1);

+    }

+

+    if(send_data)

+    {

+        if(data_len != strlen(send_data) || data_len > 1024)

+        {

+            mbtk_ecoap_show_error(MBTK_ECOAP_ERR_PAYLOAD_LENGTH);

+            return -1;

+        }

+    }

+

+    mbtk_ecoap_package_s *coap = mbtk_ecoap_get_by_msg_id(coap_id);

+    if( !coap)

+    {

+        mbtk_ecoap_net.message_id = mbth_ecoap_package_ver.message_id;

+        coap = mbtk_ecoap_list_add(mbtk_ecoap_net.message_id);

+        if(coap != NULL)

+        {

+            mbtk_ecoap_list_item_init(ECOAPVER,coap,mbth_ecoap_package_ver.version);

+            mbtk_ecoap_list_item_init(EOCAPTYPE,coap,mbth_ecoap_package_ver.type);

+            mbtk_ecoap_list_item_init(ECOAPCODE,coap,mbth_ecoap_package_ver.code);

+            if(mbth_ecoap_package_ver.token_len > 0)

+            {

+                coap->token_len = mbth_ecoap_package_ver.token_len;

+                memcpy(coap->token, mbth_ecoap_package_ver.token, strlen((char *)mbth_ecoap_package_ver.token));

+            }

+            

+            if(data_len > 0)

+            {

+                coap->payload_len = data_len;

+                if(coap->payload != NULL)

+                {

+                    free(coap->payload);

+                    coap->payload = NULL;

+                }

+                coap->payload = (uint8*)malloc(data_len + 1);

+                memset(coap->payload,0x00,data_len + 1);

+                memcpy(coap->payload,send_data,data_len);

+            }

+

+        }

+        else{

+            printf("coap new error\n");

+        }

+

+    }

+    else

+    {

+		printf("coap is NULL\n");

+    }

+

+    mbtk_ecoap_recv = 0;

+	if(mbtk_ecoap_state < MBTK_ECOAP_STATE_READY)

+	{

+	    printf("State[%d] error,not ready...\n",mbtk_ecoap_state);

+	    return -1;

+	}

+

+	if( !ecoap_sig_send_complete_handle() )

+	{

+		ecoap_sig_recv_handle();

+	}

+

+	if(mbtk_sock_close(coap_handle, coap_fd,1000, &err)) {

+        return -1;

+    }

+

+    coap_fd = -1;

+    return 0;

+

+}

+

+int mbtk_coap_ecoapdel_exec_cmd( int del_id )

+{

+

+    int result = 0;

+	LOGE("del---------del_id:%d\n",del_id);

+	if(del_id != 1)

+	{

+		return -1;

+	}

+	

+	 if(mbtk_ecoap_state <= MBTK_ECOAP_STATE_CLOSING )

+	{

+		mbtk_ecoap_show_error(MBTK_ECOAP_ERR_NO_OPEN);

+		return -1;

+	}

+			

+	LOGE("del---------del_id:%d\n",del_id);

+

+    return result;

+

+}

+

+int mbtk_coap_ecoapclose_exec_cmd( void )

+{

+    int result = 0;

+	if(!coap_sock_inited) {

+        LOGE("HTTP not inited.");

+        return -1;

+    }

+

+    int err = mbtk_sock_deinit(coap_handle);

+    if(err != MBTK_SOCK_SUCCESS) {

+        LOGE("mbtk_sock_deinit() fail.");

+        return -1;

+    }

+

+    coap_handle = -1;

+    coap_sock_inited = FALSE;

+    return 0;

+

+    return result;

+}

+

+

diff --git a/mbtk/mbtk_lib/src/mbtk_coap_api.cpp b/mbtk/mbtk_lib/src/mbtk_coap_api.cpp
new file mode 100755
index 0000000..0a6dc19
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_coap_api.cpp
@@ -0,0 +1,906 @@
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*

+

+

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

+

+

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

+

+                     INCLUDE FILES FOR MODULE

+

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

+

+#include <string.h>

+#include <stdio.h>

+#include <stdlib.h>

+#include "mbtk_coap_pdu.h"

+#include "mbtk_coap_api.h"

+

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

+

+                        LOCAL DATA STRUCTURES

+

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

+//extern "C"

+//{

+

+static CoapPDU * g_CoapPDU = NULL;

+static CoapPDU * g_CoapRecvPointer = NULL;

+

+static void createCoapPDU()

+{

+    if(g_CoapPDU == NULL)

+        g_CoapPDU = new CoapPDU();

+}

+

+void coapReleaseCoapPUD()

+{

+    if(g_CoapPDU)

+    {

+        delete g_CoapPDU;

+        g_CoapPDU = NULL;

+    }

+}

+

+int coapReset()

+{

+    createCoapPDU();

+    return g_CoapPDU->reset();

+}

+

+int coapValidate()

+{

+    createCoapPDU();

+    return g_CoapPDU->validate();

+}

+

+

+uint8_t* coapGetPDUPointer()

+{

+    return g_CoapPDU->getPDUPointer();

+}

+

+void coapSetPDULength(int len)

+{

+    createCoapPDU();

+    g_CoapPDU->setPDULength(len);

+}

+

+int coapSetURI(char *uri)

+{

+    createCoapPDU();

+    return g_CoapPDU->setURI(uri);

+}

+

+int coapAddURIQuery(char *query)

+{

+    createCoapPDU();

+    return g_CoapPDU->addURIQuery(query);

+}

+

+int coapGetURI(char *dst, int dstlen, int *outLen)

+{

+    createCoapPDU();

+    return  g_CoapPDU->getURI(dst, dstlen, outLen);

+}

+

+int coapSetVersion(uint8_t version)

+{

+    createCoapPDU();

+    return g_CoapPDU->setVersion(version);

+}

+

+uint8_t coapGetVersion()

+{

+    createCoapPDU();

+    return g_CoapPDU->getVersion();

+}

+

+void coapSetType(mbtk_coap_type mt)

+{

+    createCoapPDU();

+    g_CoapPDU->setType(mt);

+}

+

+mbtk_coap_type coapGetType()

+{

+    createCoapPDU();

+    return (mbtk_coap_type)g_CoapPDU->getType();

+}

+

+int GetTokenLength(uint8_t tokenLength)

+{

+    createCoapPDU();

+    return g_CoapPDU->setTokenLength(tokenLength);

+}

+

+int coapGetTokenLength()

+{

+    createCoapPDU();

+    return g_CoapPDU->getTokenLength();

+}

+

+uint8_t* coapGetTokenPointer()

+{

+    createCoapPDU();

+    return g_CoapPDU->getTokenPointer();

+}

+

+int coapSetToken(uint8_t *token, uint8_t tokenLength)

+{

+    createCoapPDU();

+    return g_CoapPDU->setToken(token, tokenLength) ;

+}

+

+void coapSetCode(mbtk_coap_code_type code)

+{

+    createCoapPDU();

+    g_CoapPDU->setCode(code);

+}

+

+mbtk_coap_code_type coapGetCode()

+{

+    createCoapPDU();

+    return (mbtk_coap_code_type)g_CoapPDU->getCode();

+}

+

+mbtk_coap_code_type coapHttpStatusToCode(int httpStatus)

+{

+    createCoapPDU();

+    return (mbtk_coap_code_type)g_CoapPDU->httpStatusToCode(httpStatus);

+}

+

+int coapSetMessageID(uint16_t messageID)

+{

+    createCoapPDU();

+    return g_CoapPDU->setMessageID(messageID);

+}

+

+uint16_t coapGetMessageID()

+{

+    createCoapPDU();

+    return g_CoapPDU->getMessageID();

+}

+

+/// Returns the length of the PDU.

+int coapGetPDULength()

+{

+    createCoapPDU();

+    return g_CoapPDU->getPDULength();

+}

+

+/// Return the number of options that the PDU has.

+int coapGetNumOptions()

+{

+    createCoapPDU();

+    return  g_CoapPDU->getNumOptions();

+}

+

+//CoapOption* getOptions() {

+//  return g_CoapPDU->getOptions();

+//}

+

+

+int coapAddOption(uint16_t insertedOptionNumber, uint16_t optionValueLength, uint8_t *optionValue)

+{

+    createCoapPDU();

+    return  g_CoapPDU->addOption(insertedOptionNumber, optionValueLength, optionValue);

+}

+

+uint8_t* coapMallocPayload(int len)

+{

+    createCoapPDU();

+    return g_CoapPDU->mallocPayload(len);

+}

+

+int coapSetPayload(uint8_t *payload, int len)

+{

+    createCoapPDU();

+    return g_CoapPDU->setPayload(payload, len);

+}

+

+/// Returns a pointer to the payload buffer.

+uint8_t* coapGetPayloadPointer()

+{

+    createCoapPDU();

+    return g_CoapPDU->getPayloadPointer();

+}

+

+/// Gets the length of the payload buffer.

+int coapGetPayloadLength()

+{

+    createCoapPDU();

+    return g_CoapPDU->getPayloadLength();

+}

+

+/// Returns a pointer to a buffer which is a copy of the payload buffer (dynamically allocated).

+uint8_t* coapGetPayloadCopy()

+{

+    createCoapPDU();

+    return g_CoapPDU->getPayloadCopy();

+}

+

+int coapSetContentFormat(mbtk_content_format_type format)

+{

+    createCoapPDU();

+    return g_CoapPDU->setContentFormat(format);

+}

+

+int coapHasOption(uint16_t optionNumber )

+{

+    createCoapPDU();

+    return g_CoapPDU->hasOption(optionNumber);

+}

+void coapDeleteRecv()

+{

+    if(g_CoapRecvPointer != NULL)

+    {

+        delete g_CoapRecvPointer;

+        g_CoapRecvPointer = NULL;

+    }

+

+}

+int coapCreateRecv(uint8_t *pdu, int pduLength)

+{

+    coapDeleteRecv();

+    g_CoapRecvPointer = new CoapPDU(pdu, pduLength, pduLength);

+    if(g_CoapRecvPointer != NULL)

+    {

+        if(g_CoapRecvPointer->validate())

+            return g_CoapRecvPointer->getPDULength();

+        else

+        {

+            coapDeleteRecv();

+            return 0;

+        }

+    }

+    else

+        return 0;

+

+}

+

+void coapPrintHuman(char * outBuffer)

+{

+    char type[20];

+    switch(g_CoapRecvPointer->getType())

+    {

+        case COAP_CONFIRMABLE:

+            strcpy(type, "Confirmable");

+            break;

+

+        case COAP_NON_CONFIRMABLE:

+            strcpy(type, "Non-Confirmable");

+            break;

+

+        case COAP_ACKNOWLEDGEMENT:

+            strcpy(type, "Acknowledgement");

+            break;

+

+        case COAP_RESET:

+            strcpy(type, "Reset");

+            break;

+    }

+    char code[30];

+    switch(g_CoapRecvPointer->getCode())

+    {

+        case COAP_EMPTY:

+            strcpy(code, "0.00 Empty");

+            break;

+        case COAP_GET:

+            strcpy(code, "0.01 GET");

+            break;

+        case COAP_POST:

+            strcpy(code, "0.02 POST");

+            break;

+        case COAP_PUT:

+            strcpy(code, "0.03 PUT");

+            break;

+        case COAP_DELETE:

+            strcpy(code, "0.04 DELETE");

+            break;

+        case COAP_CREATED:

+            strcpy(code, "2.01 Created");

+            break;

+        case COAP_DELETED:

+            strcpy(code, "2.02 Deleted");

+            break;

+        case COAP_VALID:

+            strcpy(code, "2.03 Valid");

+            break;

+        case COAP_CHANGED:

+            strcpy(code, "2.04 Changed");

+            break;

+        case COAP_CONTENT:

+            strcpy(code, "2.05 Content");

+            break;

+        case COAP_BAD_REQUEST:

+            strcpy(code, "4.00 Bad Request");

+            break;

+        case COAP_UNAUTHORIZED:

+            strcpy(code, "4.01 Unauthorized");

+            break;

+        case COAP_BAD_OPTION:

+            strcpy(code, "4.02 Bad Option");

+            break;

+        case COAP_FORBIDDEN:

+            strcpy(code, "4.03 Forbidden");

+            break;

+        case COAP_NOT_FOUND:

+            strcpy(code, "4.04 Not Found");

+            break;

+        case COAP_METHOD_NOT_ALLOWED:

+            strcpy(code, "4.05 Method Not Allowed");

+            break;

+        case COAP_NOT_ACCEPTABLE:

+            strcpy(type, "4.06 Not Acceptable");

+            break;

+        case COAP_PRECONDITION_FAILED:

+            strcpy(code, "4.12 Precondition Failed");

+            break;

+        case COAP_REQUEST_ENTITY_TOO_LARGE:

+            strcpy(code, "4.13 Request Entity Too Large");

+            break;

+        case COAP_UNSUPPORTED_CONTENT_FORMAT:

+            strcpy(code, "4.15 Unsupported Content-Format");

+            break;

+        case COAP_INTERNAL_SERVER_ERROR:

+            strcpy(code, "5.00 Internal Server Error");

+            break;

+        case COAP_NOT_IMPLEMENTED:

+            strcpy(code, "5.01 Not Implemented");

+            break;

+        case COAP_BAD_GATEWAY:

+            strcpy(code, "5.02 Bad Gateway");

+            break;

+        case COAP_SERVICE_UNAVAILABLE:

+            strcpy(code, "5.03 Service Unavailable");

+            break;

+        case COAP_GATEWAY_TIMEOUT:

+            strcpy(code, "5.04 Gateway Timeout");

+            break;

+        case COAP_PROXYING_NOT_SUPPORTED:

+            strcpy(code, "5.05 Proxying Not Supported");

+            break;

+        default:

+        {

+            sprintf(code, "Undefined Code %u", g_CoapRecvPointer->getCode());

+        }

+    }

+

+    sprintf(outBuffer,"PDU is %d bytes long\r\n"

+            "CoAP Version: %d\r\n"

+            "Message Type: %s\r\n"

+            "Code: %s\r\n"

+            "Message ID: %u\r\n",

+            g_CoapRecvPointer->getPDULength(),

+            g_CoapRecvPointer->getVersion(),

+            type,

+            code,

+            g_CoapRecvPointer->getMessageID());

+

+    // print token value

+    int tokenLength = g_CoapRecvPointer->getTokenLength();

+    uint8_t *tokenPointer = g_CoapRecvPointer->getPDUPointer()+COAP_HDR_SIZE;

+    if(tokenLength==0)

+    {

+        sprintf(outBuffer,"%sNo token\r\n",outBuffer);

+    }

+    else

+    {

+        sprintf(outBuffer,"%sToken of %d bytes.\r\n"

+                "Value: %s\r\n",

+                outBuffer,tokenLength, (char*)tokenPointer);

+        for(int j=0; j<tokenLength; j++)

+        {

+            sprintf(outBuffer,"%s%.2x",outBuffer, tokenPointer[j]);

+        }

+    }

+    // print options

+    CoapPDU::CoapOption* options = g_CoapRecvPointer->getOptions();

+    if(options==NULL)

+    {

+        sprintf(outBuffer,"\r\n%sNO options\r\n", outBuffer);

+    }

+

+    for(int i=0; i<g_CoapRecvPointer->getNumOptions(); i++)

+    {

+        char optionNumberBuffer[20];

+        switch(options[i].optionNumber)

+        {

+            case COAP_OPTION_IF_MATCH:

+                strcpy(optionNumberBuffer, "IF_MATCH");

+                break;

+            case COAP_OPTION_URI_HOST:

+                strcpy(optionNumberBuffer, "URI_HOST");

+                break;

+            case COAP_OPTION_ETAG:

+                strcpy(optionNumberBuffer, "ETAG");

+                break;

+            case COAP_OPTION_IF_NONE_MATCH:

+                strcpy(optionNumberBuffer, "IF_NONE_MATCH");

+                break;

+            case COAP_OPTION_OBSERVE:

+                strcpy(optionNumberBuffer, "OBSERVE");

+                break;

+            case COAP_OPTION_URI_PORT:

+                strcpy(optionNumberBuffer, "URI_PORT");

+                break;

+            case COAP_OPTION_LOCATION_PATH:

+                strcpy(optionNumberBuffer, "LOCATION_PATH");

+                break;

+            case COAP_OPTION_URI_PATH:

+                strcpy(optionNumberBuffer, "URI_PATH");

+                break;

+            case COAP_OPTION_CONTENT_FORMAT:

+                strcpy(optionNumberBuffer, "CONTENT_FORMAT");

+                break;

+            case COAP_OPTION_MAX_AGE:

+                strcpy(optionNumberBuffer, "MAX_AGE");

+                break;

+            case COAP_OPTION_URI_QUERY:

+                strcpy(optionNumberBuffer, "URI_QUERY");

+                break;

+            case COAP_OPTION_ACCEPT:

+                strcpy(optionNumberBuffer, "ACCEPT");

+                break;

+            case COAP_OPTION_LOCATION_QUERY:

+                strcpy(optionNumberBuffer, "LOCATION_QUERY");

+                break;

+            case COAP_OPTION_PROXY_URI:

+                strcpy(optionNumberBuffer, "PROXY_URI");

+                break;

+            case COAP_OPTION_PROXY_SCHEME:

+                strcpy(optionNumberBuffer, "PROXY_SCHEME");

+                break;

+            case COAP_OPTION_BLOCK1:

+                strcpy(optionNumberBuffer, "BLOCK1");

+                break;

+            case COAP_OPTION_BLOCK2:

+                strcpy(optionNumberBuffer, "BLOCK2");

+                break;

+            case COAP_OPTION_SIZE1:

+                strcpy(optionNumberBuffer, "SIZE1");

+                break;

+            case COAP_OPTION_SIZE2:

+                strcpy(optionNumberBuffer, "SIZE2");

+                break;

+            default:

+                sprintf(optionNumberBuffer, "Unknown option %u",(unsigned)options[i].optionNumber);

+                break;

+        }

+

+        /*char optionValue[options[i].optionValueLength + 1];

+        for(int j=0; j<options[i].optionValueLength; j++) {

+            char c = options[i].optionValuePointer[j];

+            if((c>='!'&&c<='~')||c==' ') {

+                sprintf(optionValue, "%s%c",optionValue,c);

+            } else {

+                sprintf(optionValue,"%s\\%.2d",optionValue,c);

+            }

+        }

+        sprintf(optionValue,"%s\"\r\n",optionValue);*/

+        sprintf(outBuffer,"\r\n%sOPTION (%d/%d)\r\n"

+                "Option number (delta): %hu (%hu)\r\n"

+                "Name: %s\r\n"

+                "Value length: %u\r\n"

+                "Value: \"%s",

+                outBuffer,

+                i + 1,g_CoapRecvPointer->getNumOptions(),

+                options[i].optionNumber,options[i].optionDelta,

+                optionNumberBuffer,

+                options[i].optionValueLength,

+                (char *)options[i].optionValuePointer);

+

+    }

+    if(options)

+        free(options);

+    // print payload

+    if(g_CoapRecvPointer->getPayloadLength() == 0)

+    {

+        sprintf(outBuffer,"%sNo payload\r\n", outBuffer);

+    }

+    else

+    {

+        sprintf(outBuffer, "%sPayload of %d bytes\r\n"

+                "Value: \"%s\"\r\n", outBuffer,

+                g_CoapRecvPointer->getPayloadLength(),

+                (char *)g_CoapRecvPointer->getPayloadPointer());

+        /*sprintf(outBuffer,"%sPayload of %d bytes\r\n", outBuffer,g_CoapRecvPointer->getPayloadLength());

+        sprintf(outBuffer, "%sValue: \"", outBuffer);

+        uint8_t* _payloadPointer = g_CoapRecvPointer->getPayloadPointer();

+        for(int j=0; j<g_CoapRecvPointer->getPayloadLength(); j++) {

+            char c = _payloadPointer[j];

+            if((c>='!'&&c<='~')||c==' ') {

+                sprintf(outBuffer, "%s%c", outBuffer,c);

+            } else {

+                sprintf(outBuffer, "%s\\%.2x",outBuffer,c);

+            }

+        }

+        sprintf(outBuffer, "%s\"\r\n", outBuffer);*/

+    }

+

+}

+

+void coapGetOptionValueById(uint16_t optionNumber, uint16_t * optionValueLength, uint8_t * optionValuePointer)

+{

+    if(g_CoapRecvPointer)

+        g_CoapRecvPointer->getOptionValueById(optionNumber, optionValueLength, optionValuePointer);

+}

+

+uint16_t coapGetRecvMessageID()

+{

+    return g_CoapRecvPointer->getMessageID();

+}

+

+mbtk_coap_type coapGetRecvType()

+{

+    return (mbtk_coap_type)g_CoapRecvPointer->getType();

+}

+

+mbtk_coap_code_type coapGetRecvCode()

+{

+    return (mbtk_coap_code_type)g_CoapRecvPointer->getCode();

+}

+

+int mbtk_coap_get_pdu_Length()

+{

+    return g_CoapRecvPointer->getPDULength();

+}

+

+

+int coapGetRecvTokenLength()

+{

+    return g_CoapRecvPointer->getTokenLength();

+}

+

+uint8_t* coapGetRecvTokenPointer()

+{

+    return g_CoapRecvPointer->getTokenPointer();

+}

+

+/// Returns a pointer to the payload buffer.

+uint8_t* coapGetRecvPayloadPointer()

+{

+    return g_CoapRecvPointer->getPayloadPointer();

+}

+

+/// Gets the length of the payload buffer.

+int coapGetRecvPayloadLength()

+{

+    return g_CoapRecvPointer->getPayloadLength();

+}

+

+uint8_t coapGetRecvVersion()

+{

+    return g_CoapRecvPointer->getVersion();

+}

+

+// Return If-Match length,or 0 if fail.

+uint16_t coapGetRecvOptionIfMatch(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_IF_MATCH,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Uri-Host length,or 0 if fail.

+uint16_t coapGetRecvOptionUriHost(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_URI_HOST,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return ETag length,or 0 if fail.

+uint16_t coapGetRecvOptionETag(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_ETAG,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return If-None-Match length,or 0 if fail.

+uint16_t coapGetRecvOptionIfNoneMatch(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_IF_NONE_MATCH,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Location-Path length,or 0 if fail.

+uint16_t coapGetRecvOptionLocationPath(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_LOCATION_PATH,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Location-Query length,or 0 if fail.

+uint16_t coapGetRecvOptionLocationQuery(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_LOCATION_QUERY,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Proxy-Uri length,or 0 if fail.

+uint16_t coapGetRecvOptionProxyUri(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_PROXY_URI,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Proxy-Scheme length,or 0 if fail.

+uint16_t coapGetRecvOptionProxyScheme(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_PROXY_SCHEME,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Uri-Path length,or 0 if fail.

+uint16_t coapGetRecvOptionUriPath(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_URI_PATH,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return Uri-Query length,or 0 if fail.

+uint16_t coapGetRecvOptionUriQuery(uint16_t *optionValueLength, uint8_t *optionValuePointer)

+{

+    *optionValueLength = 0;

+    coapGetOptionValueById(COAP_OPTION_URI_QUERY,optionValueLength,optionValuePointer);

+    return *optionValueLength;

+}

+

+// Return 1 if get Observe success,or 0 if fail.

+uint16_t coapGetRecvOptionObserve(uint16_t *observe)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_OBSERVE,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *observe = (uint16_t)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Max-Age success,or 0 if fail.

+uint16_t coapGetRecvOptionMaxAge(uint16_t *max_age)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_MAX_AGE,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *max_age = (uint16_t)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Uri-Port success,or 0 if fail.

+uint16_t coapGetRecvOptionUriPort(uint16_t *uri_port)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_URI_PORT,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *uri_port = (uint16_t)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Size2 success,or 0 if fail.

+uint16_t coapGetRecvOptionSize2(uint16_t *size2)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_SIZE2,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *size2 = (uint16_t)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Size1 success,or 0 if fail.

+uint16_t coapGetRecvOptionSize1(uint16_t *size1)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_SIZE1,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *size1 = (uint16_t)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Block2 success,or 0 if fail.

+uint16_t coapGetRecvOptionBlock2(uint32_t *number,uint8_t *more_flag,uint8_t *size)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_BLOCK2,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        if(buff_len == 1)

+        {

+            *size = (uint8_t)(buff[0] & 0x07);

+            *more_flag = (uint8_t)((buff[0] & 0x08) >> 3);

+            *number = (uint32_t)((buff[0] & 0xF0) >> 4);

+        }

+        else if(buff_len == 2)

+        {

+            *size = (uint8_t)(buff[1] & 0x07);

+            *more_flag = (uint8_t)((buff[1] & 0x08) >> 3);

+            *number = (uint32_t)(((buff[0] << 8) | (buff[1] & 0xF0)) >> 4);

+        }

+        else if(buff_len == 3)

+        {

+            *size = (uint8_t)(buff[2] & 0x07);

+            *more_flag = (uint8_t)((buff[2] & 0x08) >> 3);

+            *number = (uint32_t)(((buff[0] << 16) | (buff[1] << 8) | (buff[2] & 0xF0)) >> 4);

+        }

+        else

+        {

+            return 0;

+        }

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Block1 success,or 0 if fail.

+uint16_t coapGetRecvOptionBlock1(uint32_t *number,uint8_t *more_flag,uint8_t *size)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_BLOCK1,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *size = (uint8_t)(buff[0] & 0x07);

+        *more_flag = (uint8_t)(buff[0] & 0x08);

+        if(buff_len == 1)

+        {

+            *number = (uint32_t)(buff[0] & 0xF0);

+        }

+        else if(buff_len == 2)

+        {

+            *number = (uint32_t)((buff[1] << 8) | (buff[0] & 0xF0));

+        }

+        else if(buff_len == 3)

+        {

+            *number = (uint32_t)((buff[2] << 16) | (buff[1] << 8) | (buff[0] & 0xF0));

+        }

+        else

+        {

+            return 0;

+        }

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Content-Format success,or 0 if fail.

+uint16_t coapGetRecvOptionContentFormat(mbtk_content_format_type *type)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_CONTENT_FORMAT,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *type = (mbtk_content_format_type)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+// Return 1 if get Accept success,or 0 if fail.

+uint16_t coapGetRecvOptionAccept(mbtk_content_format_type *type)

+{

+    uint8_t buff[10];

+    uint16_t buff_len = 0;

+    memset(buff,0x0,10);

+    coapGetOptionValueById(COAP_OPTION_ACCEPT,&buff_len,buff);

+    if(buff_len > 0)

+    {

+        *type = (mbtk_content_format_type)atoi((char*)buff);

+        return 1;

+    }

+    else

+    {

+        return 0;

+    }

+}

+

+

+int coapPrintRecvPayload(char *out)

+{

+    // print payload

+    int payloadLength = g_CoapRecvPointer->getPayloadLength();

+    if(payloadLength==0)

+    {

+        return 0;

+    }

+    else

+    {

+        uint8_t* payloadPointer = g_CoapRecvPointer->getPayloadPointer();

+        sprintf(out,"%s:%d\r\n",out, payloadLength*2);

+        for(int j=0; j<payloadLength; j++)

+        {

+            sprintf(out,"%s%.2X",out,payloadPointer[j]);

+        }

+        sprintf(out,"%s\r\n",out);

+        return 1;

+    }

+}

+

+const char* coapPrintHumanByIndex(int index)

+{

+    if(index == 0)

+    {

+        createCoapPDU();

+        return g_CoapPDU->printHuman();

+    }

+    else if(index == 1)

+        return g_CoapRecvPointer->printHuman();

+    return NULL;

+}

+

+const char* coapPrintHexByIndex(int index)

+{

+    if(index == 0)

+    {

+        createCoapPDU();

+        return g_CoapPDU->printHex();

+    }

+    else if(index == 1)

+        return g_CoapRecvPointer->printHex();

+    return NULL;

+}

+

+//}

+

+

diff --git a/mbtk/mbtk_lib/src/mbtk_coap_pdu.cpp b/mbtk/mbtk_lib/src/mbtk_coap_pdu.cpp
new file mode 100755
index 0000000..c9f046d
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_coap_pdu.cpp
@@ -0,0 +1,2065 @@
+/*

+Copyright (c) 2013, Ashley Mills.

+All rights reserved.

+

+Redistribution and use in source and binary forms, with or without

+modification, are permitted provided that the following conditions are met:

+

+1. Redistributions of source code must retain the above copyright notice, this

+   list of conditions and the following disclaimer.

+2. Redistributions in binary form must reproduce the above copyright notice,

+   this list of conditions and the following disclaimer in the documentation

+   and/or other materials provided with the distribution.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND

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

+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND

+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ */

+

+// version, 2 bits

+// type, 2 bits

+// 00 Confirmable

+// 01 Non-confirmable

+// 10 Acknowledgement

+// 11 Reset

+

+// token length, 4 bits

+// length of token in bytes (only 0 to 8 bytes allowed)

+

+#include <stdio.h>

+#include <stdlib.h>

+#include <stdint.h>

+#include <string.h>

+

+#include "mbtk_coap_pdu.h"

+

+//#include "mbtk_log.h"

+//#ifdef FEATURE_MBTK_ECOAP

+/// Memory-managed constructor. Buffer for PDU is dynamically sized and allocated by the object.

+/**

+ * When using this constructor, the CoapPDU class will allocate space for the PDU.

+ * Contrast this with the parameterized constructors, which allow the use of an external buffer.

+ *

+ * Note, the PDU container and space can be reused by issuing a CoapPDU::reset(). If the new PDU exceeds the

+ * space of the previously allocated memory, then further memory will be dynamically allocated.

+ *

+ * Deleting the object will free the Object container and all dynamically allocated memory.

+ *

+ * \note It would have been nice to use something like UDP_CORK or MSG_MORE, to allow separate buffers

+ * for token, options, and payload but these FLAGS aren't implemented for UDP in LwIP so stuck with one buffer for now.

+ *

+ * CoAP version defaults to 1.

+ *

+ * \sa CoapPDU::CoapPDU(uint8_t *pdu, int pduLength), CoapPDU::CoapPDU::(uint8_t *buffer, int bufferLength, int pduLength),

+ * CoapPDU:CoapPDU()~

+ *

+ */

+

+//#define printf(fmtstr) LOGD(fmtstr)

+//#define printf(fmtstr ,arg1) LOGD(fmtstr, arg1)

+//#define printf(fmtstr, arg1, arg2) LOGD(fmtstr , arg1, arg2)

+//#define printf(fmtstr, arg1, arg2, arg3) LOGD(fmtstr , arg1, arg2, arg3)

+

+/*

+void* operator new(unsigned int size, void* alloc, ds_appsrv_mem_e_type mem_type) throw()

+{

+// Do nothing

+    return alloc;

+}

+

+void operator delete(void* obj, void* alloc, ds_appsrv_mem_e_type mem_type) throw()

+{

+// Do nothing

+}

+

+*/

+

+CoapPDU::CoapPDU()

+{

+    // pdu

+    _pdu = (uint8_t*)calloc(4,sizeof(uint8_t));

+    _pduLength = 4;

+    _bufferLength = _pduLength;

+

+    //options

+    _numOptions = 0;

+    _maxAddedOptionNumber = 0;

+

+    // payload

+    _payloadPointer = NULL;

+    _payloadLength = 0;

+

+    _constructedFromBuffer = 0;

+

+    setVersion(1);

+}

+

+/// Construct object from external buffer that may be larger than actual PDU.

+/**

+ * This differs from CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) in that the buffer may be larger

+ * than the actual CoAP PDU contained int the buffer. This is typically used when a large buffer is reused

+ * multiple times. Note that \b pduLength can be 0.

+ *

+ * If an actual CoAP PDU is passed in the buffer, \b pduLength should match its length. CoapPDU::validate() must

+ * be called to initiate the object before member functions can be used.

+ *

+ * A PDU constructed in this manner must be validated with CoapPDU::validate() before the member variables will be accessible.

+ *

+ * \warning The validation call parses the PDU structure to set some internal parameters. If you do

+ * not validate the PDU, then the behaviour of member access functions will be undefined.

+ *

+ * The buffer can be reused by issuing a CoapPDU::reset() but the class will not change the size of the buffer. If the

+ * newly constructed PDU exceeds the size of the buffer, the function called (for example CoapPDU::addOption) will fail.

+ *

+ * Deleting this object will only delete the Object container and will not delete the PDU buffer.

+ *

+ * \param buffer A buffer which either contains a CoAP PDU or is intended to be used to construct one.

+ * \param bufferLength The length of the buffer

+ * \param pduLength If the buffer contains a CoAP PDU, this specifies the length of the PDU within the buffer.

+ *

+ * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)

+ */

+CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)

+{

+    	printf("CoapPDU(),bufferLength:%d, pduLength;%d\n",bufferLength,pduLength);

+    // sanity

+    if(pduLength<4&&pduLength!=0)

+    {

+        printf("PDU cannot have a length less than 4");

+    }

+

+    // pdu

+    _pdu = buffer;

+    _bufferLength = bufferLength;

+    if(pduLength==0)

+    {

+        // this is actually a fresh pdu, header always exists

+        _pduLength = 4;

+        // make sure header is zeroed

+        _pdu[0] = 0x00;

+        _pdu[1] = 0x00;

+        _pdu[2] = 0x00;

+        _pdu[3] = 0x00;

+        setVersion(1);

+    }

+    else

+    {

+        _pduLength = pduLength;

+    }

+

+    _constructedFromBuffer = 1;

+

+    // options

+    _numOptions = 0;

+    _maxAddedOptionNumber = 0;

+

+    // payload

+    _payloadPointer = NULL;

+    _payloadLength = 0;

+}

+

+/// Reset CoapPDU container so it can be reused to build a new PDU.

+/**

+ * This resets the CoapPDU container, setting the pdu length, option count, etc back to zero. The

+ * PDU can then be populated as if it were newly constructed.

+ *

+ * Note that the space available will depend on how the CoapPDU was originally constructed:

+ * -# CoapPDU::CoapPDU()

+ *

+ *  Available space initially be \b _pduLength. But further space will be allocated as needed on demand,

+ *    limited only by the OS/environment.

+ *

+ * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)

+ *

+ *      Space is limited by the variable \b pduLength. The PDU cannot exceed \b pduLength bytes.

+ *

+ * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)

+ *

+ *      Space is limited by the variable \b bufferLength. The PDU cannot exceed \b bufferLength bytes.

+ *

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::reset()

+{

+    // pdu

+    memset(_pdu,0x00,_bufferLength);

+    // packet always has at least a header

+    _pduLength = 4;

+

+    // options

+    _numOptions = 0;

+    _maxAddedOptionNumber = 0;

+    // payload

+    _payloadPointer = NULL;

+    _payloadLength = 0;

+    content.clear();

+    return 0;

+}

+

+/// Validates a PDU constructed using an external buffer.

+/**

+ * When a CoapPDU is constructed using an external buffer, the programmer must call this function to

+ * check that the received PDU is a valid CoAP PDU.

+ *

+ * \warning The validation call parses the PDU structure to set some internal parameters. If you do

+ * not validate the PDU, then the behaviour of member access functions will be undefined.

+ *

+ * \return 1 if the PDU validates correctly, 0 if not. XXX maybe add some error codes

+ */

+int CoapPDU::validate()

+{

+    if(_pduLength<4)

+    {

+        printf("PDU has to be a minimum of 4 bytes. This: %d bytes",_pduLength);

+        return 0;

+    }

+

+    // check header

+    //   0                   1                   2                   3

+    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+    // |Ver| T |  TKL  |      Code     |          Message ID           |

+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+    // |   Token (if any, TKL bytes) ...

+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+    // |   Options (if any) ...

+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+    // |1 1 1 1 1 1 1 1|    Payload (if any) ...

+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

+

+    // version must be 1

+    int version = getVersion();

+    if (version != 1)

+    {

+        printf("Invalid version: %d", version);

+        return 0;

+    }

+    printf("Version: %d", version);

+    printf("Type: %d", getType());

+

+    // token length must be between 0 and 8

+    int tokenLength = getTokenLength();

+    if(tokenLength<0||tokenLength>8)

+    {

+        printf("Invalid token length: %d",tokenLength);

+        return 0;

+    }

+    printf("Token length: %d",tokenLength);

+    // check total length

+    if((COAP_HDR_SIZE+tokenLength)>_pduLength)

+    {

+        printf("Token length would make pdu longer than actual length.");

+        return 0;

+    }

+

+    // check that code is valid

+    int code = getCode();

+    if(code<COAP_EMPTY ||

+       (code>COAP_LASTMETHOD&&code<COAP_CREATED) ||

+       (code>COAP_CONTENT&&code<COAP_CONTINUE) ||

+       (code>COAP_CONTINUE&&code<COAP_BAD_REQUEST) ||

+       (code>COAP_NOT_ACCEPTABLE&&code<COAP_PRECONDITION_FAILED) ||

+       (code==0x8E) ||

+       (code>COAP_UNSUPPORTED_CONTENT_FORMAT&&code<COAP_INTERNAL_SERVER_ERROR) ||

+       (code>COAP_PROXYING_NOT_SUPPORTED) )

+    {

+        printf("Invalid CoAP code: %d",code);

+        return 0;

+    }

+    printf("CoAP code: %d",code);

+

+    // token can be anything so nothing to check

+

+    // check that options all make sense

+    uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0;

+    int totalLength = 0;

+

+    // first option occurs after token

+    int optionPos = COAP_HDR_SIZE + getTokenLength();

+

+    // may be 0 options

+    if(optionPos==_pduLength)

+    {

+        printf("No options. No payload.");

+        _numOptions = 0;

+        _payloadLength = 0;

+        return 1;

+    }

+

+    int bytesRemaining = _pduLength-optionPos;

+    int numOptions = 0;

+    uint8_t upperNibble = 0x00, lowerNibble = 0x00;

+

+    // walk over options and record information

+    while(1)

+    {

+        // check for payload marker

+        if(bytesRemaining>0)

+        {

+            uint8_t optionHeader = _pdu[optionPos];

+            if(optionHeader==0xFF)

+            {

+                // payload

+                if(bytesRemaining>1)

+                {

+                    _payloadPointer = &_pdu[optionPos+1];

+                    _payloadLength = (bytesRemaining-1);

+                    _numOptions = numOptions;

+                    printf("Payload found, length: %d",_payloadLength);

+                    return 1;

+                }

+                // payload marker but no payload

+                _payloadPointer = NULL;

+                _payloadLength = 0;

+                printf("Payload marker but no payload.");

+                return 0;

+            }

+

+            // check that option delta and option length are valid values

+            upperNibble = (optionHeader & 0xF0) >> 4;

+            lowerNibble = (optionHeader & 0x0F);

+            if(upperNibble==0x0F||lowerNibble==0x0F)

+            {

+                printf("Expected option header or payload marker, got: 0x%x%x",upperNibble,lowerNibble);

+                return 0;

+            }

+            printf("Option header byte appears sane: 0x%x%x",upperNibble,lowerNibble);

+        }

+        else

+        {

+            printf("No more data. No payload.");

+            _payloadPointer = NULL;

+            _payloadLength = 0;

+            _numOptions = numOptions;

+            return 1;

+        }

+

+        // skip over option header byte

+        bytesRemaining--;

+

+        // check that there is enough space for the extended delta and length bytes (if any)

+        int headerBytesNeeded = computeExtraBytes(upperNibble);

+        printf("%d extra bytes needed for extended delta",headerBytesNeeded);

+        if(headerBytesNeeded>bytesRemaining)

+        {

+            printf("Not enough space for extended option delta, needed %d, have %d.",headerBytesNeeded,bytesRemaining);

+            return 0;

+        }

+        headerBytesNeeded += computeExtraBytes(lowerNibble);

+        if(headerBytesNeeded>bytesRemaining)

+        {

+            printf("Not enough space for extended option length, needed %d, have %d.",

+                   (headerBytesNeeded-computeExtraBytes(upperNibble)),bytesRemaining);

+            return 0;

+        }

+        printf("Enough space for extended delta and length: %d, continuing.",headerBytesNeeded);

+

+        // extract option details

+        optionDelta = getOptionDelta(&_pdu[optionPos]);

+        optionNumber += optionDelta;

+        optionValueLength = getOptionValueLength(&_pdu[optionPos]);

+        printf("Got option: %d with length %d",optionNumber,optionValueLength);

+        // compute total length

+        totalLength = 1; // mandatory header

+        totalLength += computeExtraBytes(optionDelta);

+        totalLength += computeExtraBytes(optionValueLength);

+        totalLength += optionValueLength;

+        // check there is enough space

+        if(optionPos+totalLength>_pduLength)

+        {

+            printf("Not enough space for option payload, needed %d, have %d.",(totalLength-headerBytesNeeded-1),_pduLength-optionPos);

+            return 0;

+        }

+        printf("Enough space for option payload: %d %d",optionValueLength,(totalLength-headerBytesNeeded-1));

+

+        // recompute bytesRemaining

+        bytesRemaining -= totalLength;

+        bytesRemaining++; // correct for previous --

+

+        // move to next option

+        optionPos += totalLength;

+

+        // inc number of options XXX

+        numOptions++;

+    }

+

+    return 1;

+}

+

+/// Destructor. Does not free buffer if constructor passed an external buffer.

+/**

+ * The destructor acts differently, depending on how the object was initially constructed (from buffer or not):

+ *

+ * -# CoapPDU::CoapPDU()

+ *

+ *  Complete object is destroyed.

+ *

+ * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)

+ *

+ *      Only object container is destroyed. \b pdu is left intact.

+ *

+ * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)

+ *

+ *      Only object container is destroyed. \b pdu is left intact.

+ *

+ */

+CoapPDU::~CoapPDU()

+{

+    if(!_constructedFromBuffer)

+    {

+        free(_pdu);

+    }

+}

+

+/// Returns a pointer to the internal buffer.

+uint8_t* CoapPDU::getPDUPointer()

+{

+    return _pdu;

+}

+

+/// Set the PDU length to the length specified.

+/**

+ * This is used when re-using a PDU container before calling CoapPDU::validate() as it

+ * is not possible to deduce the length of a PDU since the payload has no length marker.

+ * \param len The length of the PDU

+ */

+void CoapPDU::setPDULength(int len)

+{

+    _pduLength = len;

+}

+

+/// Shorthand function for setting a resource URI.

+/**

+ * Calls CoapPDU::setURI(uri,strlen(uri).

+ */

+int CoapPDU::setURI(char *uri)

+{

+    return setURI(uri,strlen(uri));

+}

+

+/// Shorthand function for setting a resource URI.

+/**

+ * This will parse the supplied \b uri and construct enough URI_PATH and URI_QUERY options to encode it.

+ * The options are added to the PDU.

+ *

+ * At present only simple URI formatting is handled, only '/','?', and '&' separators, and no port or protocol specificaiton.

+ *

+ * The function will split on '/' and create URI_PATH elements until it either reaches the end of the string

+ * in which case it will stop or if it reaches '?' it will start splitting on '&' and create URI_QUERY elements

+ * until it reaches the end of the string.

+ *

+ * Here is an example:

+ *

+ * /a/b/c/d?x=1&y=2&z=3

+ *

+ * Will be broken into four URI_PATH elements "a", "b", "c", "d", and three URI_QUERY elements "x=1", "y=2", "z=3"

+ *

+ * TODO: Add protocol extraction, port extraction, and some malformity checking.

+ *

+ * \param uri The uri to parse.

+ * \param urilen The length of the uri to parse.

+ *

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setURI(char *uri, int urilen)

+{

+    // only '/', '?', '&' and ascii chars allowed

+

+    // sanitation

+    if(urilen<=0||uri==NULL)

+    {

+        printf("Null or zero-length uri passed.");

+        return 1;

+    }

+

+    // single character URI path (including '/' case)

+    if(urilen==1)

+    {

+        addOption(COAP_OPTION_URI_PATH,1,(uint8_t*)uri);

+        return 0;

+    }

+

+    // TODO, queries

+    // extract ? to mark where to stop processing path components

+    // and then process the query params

+

+    // local vars

+    char *startP=uri,*endP=NULL;

+    int oLen = 0;

+    char splitChar = '/';

+    int queryStageTriggered = 0;

+    uint16_t optionType = COAP_OPTION_URI_PATH;

+    while(1)

+    {

+        // stop at end of string or query

+        if(*startP==0x00||*(startP+1)==0x00)

+        {

+            break;

+        }

+

+        // ignore leading slash

+        if(*startP==splitChar)

+        {

+            printf("Skipping leading slash");

+            startP++;

+        }

+

+        // find next split point

+        endP = strchr(startP,splitChar);

+

+        // might not be another slash

+        if(endP==NULL)

+        {

+            printf("Ending out of slash");

+            // check if there is a ?

+            endP = strchr(startP,'?');

+            // done if no queries

+            if(endP==NULL)

+            {

+                endP = uri+urilen;

+            }

+            else

+            {

+                queryStageTriggered = 1;

+            }

+        }

+

+        // get length of segment

+        oLen = endP-startP;

+

+#ifdef DEBUG

+        char *b = (char*)malloc(oLen+1);

+        memcpy(b,startP,oLen);

+        b[oLen] = 0x00;

+        printf("Adding URI_PATH %s",b);

+        free(b);

+#endif

+

+        // add option

+        if(addOption(optionType,oLen,(uint8_t*)startP)!=0)

+        {

+            printf("Error adding option");

+            return 1;

+        }

+        startP = endP;

+

+        if(queryStageTriggered)

+        {

+            splitChar = '&';

+            optionType = COAP_OPTION_URI_QUERY;

+            startP++;

+            queryStageTriggered = false;

+        }

+    }

+

+    return 0;

+}

+

+/// Shorthand for adding a URI QUERY to the option list.

+/**

+ * Adds a new option to the CoAP PDU that encodes a URI_QUERY.

+ *

+ * \param query The uri query to encode.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::addURIQuery(char *query)

+{

+    return addOption(COAP_OPTION_URI_QUERY,strlen(query),(uint8_t*)query);

+}

+

+/// Concatenates any URI_PATH elements and URI_QUERY elements into a single string.

+/**

+ * Parses the PDU options and extracts all URI_PATH and URI_QUERY elements,

+ * concatenating them into a single string with slash and amphersand separators accordingly.

+ *

+ * The produced string will be NULL terminated.

+ *

+ * \param dst Buffer into which to copy the concatenated path elements.

+ * \param dstlen Length of buffer.

+ * \param outLen Pointer to integer, into which URI length will be placed.

+ *

+ * \return 0 on success, 1 on failure. \b outLen will contain the length of the concatenated elements.

+ */

+int CoapPDU::getURI(char *dst, int dstlen, int *outLen)

+{

+    if(outLen==NULL)

+    {

+        printf("Output length pointer is NULL");

+        return 1;

+    }

+

+    if(dst==NULL)

+    {

+        printf("NULL destination buffer");

+        *outLen = 0;

+        return 1;

+    }

+

+    // check destination space

+    if(dstlen<=0)

+    {

+        *dst = 0x00;

+        *outLen = 0;

+        printf("Destination buffer too small (0)!");

+        return 1;

+    }

+    // check option count

+    if(_numOptions==0)

+    {

+        *dst = 0x00;

+        *outLen = 0;

+        return 0;

+    }

+    // get options

+    CoapPDU::CoapOption *options = getOptions();

+    if(options==NULL)

+    {

+        *dst = 0x00;

+        *outLen = 0;

+        return 0;

+    }

+    // iterate over options to construct URI

+    CoapOption *o = NULL;

+    int bytesLeft = dstlen-1; // space for 0x00

+    int oLen = 0;

+    // add slash at beggining

+    if(bytesLeft>=1)

+    {

+        *dst = '/';

+        dst++;

+        bytesLeft--;

+    }

+    else

+    {

+        printf("No space for initial slash needed 1, got %d",bytesLeft);

+        free(options);

+        return 1;

+    }

+

+    char separator = '/';

+    int firstQuery = 1;

+

+    for(int i=0; i<_numOptions; i++)

+    {

+        o = &options[i];

+        oLen = o->optionValueLength;

+        if(o->optionNumber==COAP_OPTION_URI_PATH||o->optionNumber==COAP_OPTION_URI_QUERY)

+        {

+            // if the option is a query, change the separator to &

+            if(o->optionNumber==COAP_OPTION_URI_QUERY)

+            {

+                if(firstQuery)

+                {

+                    // change previous '/' to a '?'

+                    *(dst-1) = '?';

+                    firstQuery = 0;

+                }

+                separator = '&';

+            }

+

+            // check space

+            if(oLen>bytesLeft)

+            {

+                printf("Destination buffer too small, needed %d, got %d",oLen,bytesLeft);

+                free(options);

+                return 1;

+            }

+

+            // case where single '/' exists

+            if(oLen==1&&o->optionValuePointer[0]=='/')

+            {

+                *dst = 0x00;

+                *outLen = 1;

+                free(options);

+                return 0;

+            }

+

+            // copy URI path or query component

+            memcpy(dst,o->optionValuePointer,oLen);

+

+            // adjust counters

+            dst += oLen;

+            bytesLeft -= oLen;

+

+            // add separator following (don't know at this point if another option is coming)

+            if(bytesLeft>=1)

+            {

+                *dst = separator;

+                dst++;

+                bytesLeft--;

+            }

+            else

+            {

+                printf("Ran out of space after processing option");

+                free(options);

+                return 1;

+            }

+        }

+    }

+

+    // remove terminating separator

+    dst--;

+    bytesLeft++;

+    // add null terminating byte (always space since reserved)

+    *dst = 0x00;

+    *outLen = (dstlen-1)-bytesLeft;

+    free(options);

+    return 0;

+}

+

+/// Sets the CoAP version.

+/**

+ * \param version CoAP version between 0 and 3.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setVersion(uint8_t version)

+{

+    if(version>3)

+    {

+        return 0;

+    }

+

+    _pdu[0] &= 0x3F;

+    _pdu[0] |= (version << 6);

+    return 1;

+}

+

+/**

+ * Gets the CoAP Version.

+ * @return The CoAP version between 0 and 3.

+ */

+uint8_t CoapPDU::getVersion()

+{

+    return (_pdu[0]&0xC0)>>6;

+}

+

+/**

+ * Sets the type of this CoAP PDU.

+ * \param mt The type, one of:

+ * - COAP_CONFIRMABLE

+ * - COAP_NON_CONFIRMABLE

+ * - COAP_ACKNOWLEDGEMENT

+ * - COAP_RESET.

+ */

+void CoapPDU::setType(int mt)

+{

+    _pdu[0] &= 0xCF;

+    _pdu[0] |= mt;

+}

+

+/// Returns the type of the PDU.

+int CoapPDU::getType()

+{

+    return (int)(_pdu[0]&0x30);

+}

+

+

+/// Set the token length.

+/**

+ * \param tokenLength The length of the token in bytes, between 0 and 8.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setTokenLength(uint8_t tokenLength)

+{

+    if(tokenLength>8)

+        return 1;

+

+    _pdu[0] &= 0xF0;

+    _pdu[0] |= tokenLength;

+    return 0;

+}

+

+/// Returns the token length.

+int CoapPDU::getTokenLength()

+{

+    return _pdu[0] & 0x0F;

+}

+

+/// Returns a pointer to the PDU token.

+uint8_t* CoapPDU::getTokenPointer()

+{

+    if(getTokenLength()==0)

+    {

+        return NULL;

+    }

+    return &_pdu[4];

+}

+

+/// Set the PDU token to the supplied byte sequence.

+/**

+ * This sets the PDU token to \b token and sets the token length to \b tokenLength.

+ * \param token A sequence of bytes representing the token.

+ * \param tokenLength The length of the byte sequence.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setToken(uint8_t *token, uint8_t tokenLength)

+{

+    printf("Setting token");

+    if(token==NULL)

+    {

+        printf("NULL pointer passed as token reference");

+        return 1;

+    }

+

+    if(tokenLength==0)

+    {

+        printf("Token has zero length");

+        return 1;

+    }

+

+    // if tokenLength has not changed, just copy the new value

+    uint8_t oldTokenLength = getTokenLength();

+    if(tokenLength==oldTokenLength)

+    {

+        memcpy((void*)&_pdu[4],token,tokenLength);

+        return 0;

+    }

+

+    // otherwise compute new length of PDU

+    uint8_t oldPDULength = _pduLength;

+    _pduLength -= oldTokenLength;

+    _pduLength += tokenLength;

+

+    // now, have to shift old memory around, but shift direction depends

+    // whether pdu is now bigger or smaller

+    if(_pduLength>oldPDULength)

+    {

+        // new PDU is bigger, need to allocate space for new PDU

+        if(!_constructedFromBuffer)

+        {

+            uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);

+            if(newMemory==NULL)

+            {

+                // malloc failed

+                printf("Failed to allocate memory for token");

+                _pduLength = oldPDULength;

+                return 1;

+            }

+            _pdu = newMemory;

+            _bufferLength = _pduLength;

+        }

+        else

+        {

+            // constructed from buffer, check space

+            if(_pduLength>_bufferLength)

+            {

+                printf("Buffer too small to contain token, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);

+                _pduLength = oldPDULength;

+                return 1;

+            }

+        }

+

+        // and then shift everything after token up to end of new PDU

+        // memory overlaps so do this manually so to avoid additional mallocs

+        int shiftOffset = _pduLength-oldPDULength;

+        int shiftAmount = _pduLength-tokenLength-COAP_HDR_SIZE; // everything after token

+        shiftPDUUp(shiftOffset,shiftAmount);

+

+        // now copy the token into the new space and set official token length

+        memcpy((void*)&_pdu[4],token,tokenLength);

+        setTokenLength(tokenLength);

+

+        // and return success

+        return 0;

+    }

+

+    // new PDU is smaller, copy the new token value over the old one

+    memcpy((void*)&_pdu[4],token,tokenLength);

+    // and shift everything after the new token down

+    int startLocation = COAP_HDR_SIZE+tokenLength;

+    int shiftOffset = oldPDULength-_pduLength;

+    int shiftAmount = oldPDULength-oldTokenLength-COAP_HDR_SIZE;

+    shiftPDUDown(startLocation,shiftOffset,shiftAmount);

+    // then reduce size of buffer

+    if(!_constructedFromBuffer)

+    {

+        uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);

+        if(newMemory==NULL)

+        {

+            // malloc failed, PDU in inconsistent state

+            printf("Failed to shrink PDU for new token. PDU probably broken");

+            return 1;

+        }

+        _pdu = newMemory;

+        _bufferLength = _pduLength;

+    }

+

+    // and officially set the new tokenLength

+    setTokenLength(tokenLength);

+    return 0;

+}

+

+/// Sets the CoAP response code

+void CoapPDU::setCode(int code)

+{

+    _pdu[1] = code;

+    // there is a limited set of response codes

+}

+

+/// Gets the CoAP response code

+int CoapPDU::getCode()

+{

+    return (int)_pdu[1];

+}

+

+

+/// Converts a http status code as an integer, to a CoAP code.

+/**

+ * \param httpStatus the HTTP status code as an integer (e.g 200)

+ * \return The correct corresponding int on success,

+ * CoapPDU::COAP_UNDEFINED_CODE on failure.

+ */

+int CoapPDU::httpStatusToCode(int httpStatus)

+{

+    switch(httpStatus)

+    {

+        case 1:

+            return CoapPDU::COAP_GET;

+        case 2:

+            return CoapPDU::COAP_POST;

+        case 3:

+            return CoapPDU::COAP_PUT;

+        case 4:

+            return CoapPDU::COAP_DELETE;

+        case 201:

+            return CoapPDU::COAP_CREATED;

+        case 202:

+            return CoapPDU::COAP_DELETED;

+        case 203:

+            return CoapPDU::COAP_VALID;

+        case 204:

+            return CoapPDU::COAP_CHANGED;

+        case 205:

+            return CoapPDU::COAP_CONTENT;

+        case 400:

+            return CoapPDU::COAP_BAD_REQUEST;

+        case 401:

+            return CoapPDU::COAP_UNAUTHORIZED;

+        case 402:

+            return CoapPDU::COAP_BAD_OPTION;

+        case 403:

+            return CoapPDU::COAP_FORBIDDEN;

+        case 404:

+            return CoapPDU::COAP_NOT_FOUND;

+        case 405:

+            return CoapPDU::COAP_METHOD_NOT_ALLOWED;

+        case 406:

+            return CoapPDU::COAP_NOT_ACCEPTABLE;

+        case 412:

+            return CoapPDU::COAP_PRECONDITION_FAILED;

+        case 413:

+            return CoapPDU::COAP_REQUEST_ENTITY_TOO_LARGE;

+        case 415:

+            return CoapPDU::COAP_UNSUPPORTED_CONTENT_FORMAT;

+        case 500:

+            return CoapPDU::COAP_INTERNAL_SERVER_ERROR;

+        case 501:

+            return CoapPDU::COAP_NOT_IMPLEMENTED;

+        case 502:

+            return CoapPDU::COAP_BAD_GATEWAY;

+        case 503:

+            return CoapPDU::COAP_SERVICE_UNAVAILABLE;

+        case 504:

+            return CoapPDU::COAP_GATEWAY_TIMEOUT;

+        case 505:

+            return CoapPDU::COAP_PROXYING_NOT_SUPPORTED;

+        default:

+            return CoapPDU::COAP_UNDEFINED_CODE;

+    }

+}

+

+/// Set messageID to the supplied value.

+/**

+ * \param messageID A 16bit message id.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setMessageID(uint16_t messageID)

+{

+    // message ID is stored in network byte order

+    uint8_t *to = &_pdu[2];

+    endian_store16(to, messageID);

+    return 0;

+}

+

+/// Returns the 16 bit message ID of the PDU.

+uint16_t CoapPDU::getMessageID()

+{

+    // mesasge ID is stored in network byteorder

+    uint8_t *from = &_pdu[2];

+    uint16_t messageID = endian_load16(uint16_t, from);

+    return messageID;

+}

+

+/// Returns the length of the PDU.

+int CoapPDU::getPDULength()

+{

+    return _pduLength;

+}

+

+/// Return the number of options that the PDU has.

+int CoapPDU::getNumOptions()

+{

+    return _numOptions;

+}

+

+

+/**

+ * This returns the options as a sequence of structs.

+ */

+CoapPDU::CoapOption* CoapPDU::getOptions()

+{

+    printf("getOptions() called, %d options.",_numOptions);

+

+    uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0;

+    int totalLength = 0;

+

+    if(_numOptions==0)

+    {

+        return NULL;

+    }

+

+    // malloc space for options

+    CoapOption *options = (CoapOption*)malloc(_numOptions*sizeof(CoapOption));

+    if(options==NULL)

+    {

+        printf("Failed to allocate memory for options.");

+        return NULL;

+    }

+

+    // first option occurs after token

+    int optionPos = COAP_HDR_SIZE + getTokenLength();

+

+    // walk over options and record information

+    for(int i=0; i<_numOptions; i++)

+    {

+        // extract option details

+        optionDelta = getOptionDelta(&_pdu[optionPos]);

+        optionNumber += optionDelta;

+        optionValueLength = getOptionValueLength(&_pdu[optionPos]);

+        // compute total length

+        totalLength = 1; // mandatory header

+        totalLength += computeExtraBytes(optionDelta);

+        totalLength += computeExtraBytes(optionValueLength);

+        totalLength += optionValueLength;

+        // record option details

+        options[i].optionNumber = optionNumber;

+        options[i].optionDelta = optionDelta;

+        options[i].optionValueLength = optionValueLength;

+        options[i].totalLength = totalLength;

+        options[i].optionPointer = &_pdu[optionPos];

+        options[i].optionValuePointer = &_pdu[optionPos+totalLength-optionValueLength];

+        // move to next option

+        optionPos += totalLength;

+    }

+

+    return options;

+}

+

+/// Add an option to the PDU.

+/**

+ * Unlike other implementations, options can be added in any order, and in-memory manipulation will be

+ * performed to ensure the correct ordering of options (they use a delta encoding of option numbers).

+ * Re-ordering memory like this incurs a small performance cost, so if you care about this, then you

+ * might want to add options in ascending order of option number.

+ * \param optionNumber The number of the option, see the enum CoapPDU::Option for shorthand notations.

+ * \param optionLength The length of the option payload in bytes.

+ * \param optionValue A pointer to the byte sequence that is the option payload (bytes will be copied).

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::addOption(uint16_t insertedOptionNumber, uint16_t optionValueLength, uint8_t *optionValue)

+{

+    // this inserts the option in memory, and re-computes the deltas accordingly

+    // prevOption <-- insertionPosition

+    // nextOption

+

+    // find insertion location and previous option number

+    uint16_t prevOptionNumber = 0; // option number of option before insertion point

+    int insertionPosition = findInsertionPosition(insertedOptionNumber,&prevOptionNumber);

+    printf("inserting option at position %d, after option with number: %hu",insertionPosition,prevOptionNumber);

+

+    // compute option delta length

+    uint16_t optionDelta = insertedOptionNumber-prevOptionNumber;

+    uint8_t extraDeltaBytes = computeExtraBytes(optionDelta);

+

+    // compute option length length

+    uint16_t extraLengthBytes = computeExtraBytes(optionValueLength);

+

+    // compute total length of option

+    uint16_t optionLength = COAP_OPTION_HDR_BYTE + extraDeltaBytes + extraLengthBytes + optionValueLength;

+

+    // if this is at the end of the PDU, job is done, just malloc and insert

+    if(insertionPosition==_pduLength)

+    {

+        printf("Inserting at end of PDU");

+        // optionNumber must be biggest added

+        _maxAddedOptionNumber = insertedOptionNumber;

+

+        // set new PDU length and allocate space for extra option

+        int oldPDULength = _pduLength;

+        _pduLength += optionLength;

+        if(!_constructedFromBuffer)

+        {

+            uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);

+            if(newMemory==NULL)

+            {

+                printf("Failed to allocate memory for option.");

+                _pduLength = oldPDULength;

+                // malloc failed

+                return 1;

+            }

+            _pdu = newMemory;

+            _bufferLength = _pduLength;

+        }

+        else

+        {

+            // constructed from buffer, check space

+            if(_pduLength>_bufferLength)

+            {

+                printf("Buffer too small for new option: needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);

+                _pduLength = oldPDULength;

+                return 1;

+            }

+        }

+

+        // insert option at position

+        insertOption(insertionPosition,optionDelta,optionValueLength,optionValue);

+        _numOptions++;

+        return 0;

+    }

+    // XXX could do 0xFF pdu payload case for changing of dynamically allocated application space SDUs < yeah, if you're insane

+

+    // the next option might (probably) needs it's delta changing

+    // I want to take this into account when allocating space for the new

+    // option, to avoid having to do two mallocs, first get info about this option

+    int nextOptionDelta = getOptionDelta(&_pdu[insertionPosition]);

+    int nextOptionNumber = prevOptionNumber + nextOptionDelta;

+    int nextOptionDeltaBytes = computeExtraBytes(nextOptionDelta);

+    printf("nextOptionDeltaBytes: %d",nextOptionDeltaBytes);

+    // recompute option delta, relative to inserted option

+    int newNextOptionDelta = nextOptionNumber-insertedOptionNumber;

+    int newNextOptionDeltaBytes = computeExtraBytes(newNextOptionDelta);

+    printf("newNextOptionDeltaBytes: %d",newNextOptionDeltaBytes);

+    // determine adjustment

+    int optionDeltaAdjustment = newNextOptionDeltaBytes-nextOptionDeltaBytes;

+

+    // create space for new option, including adjustment space for option delta

+    printf("Creating space");

+    int mallocLength = optionLength+optionDeltaAdjustment;

+    int oldPDULength = _pduLength;

+    _pduLength += mallocLength;

+

+    if(!_constructedFromBuffer)

+    {

+        uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);

+        if(newMemory==NULL)

+        {

+            printf("Failed to allocate memory for option");

+            _pduLength = oldPDULength;

+            return 1;

+        }

+        _pdu = newMemory;

+        _bufferLength = _pduLength;

+    }

+    else

+    {

+        // constructed from buffer, check space

+        if(_pduLength>_bufferLength)

+        {

+            printf("Buffer too small to contain option, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);

+            _pduLength = oldPDULength;

+            return 1;

+        }

+    }

+

+    // move remainder of PDU data up to create hole for new option

+    printf("Shifting PDU.");

+    shiftPDUUp(mallocLength,_pduLength-(insertionPosition+mallocLength));

+

+    // adjust option delta bytes of following option

+    // move the option header to the correct position

+    int nextHeaderPos = insertionPosition+mallocLength;

+    _pdu[nextHeaderPos-optionDeltaAdjustment] = _pdu[nextHeaderPos];

+    nextHeaderPos -= optionDeltaAdjustment;

+    // and set the new value

+    setOptionDelta(nextHeaderPos, newNextOptionDelta);

+

+    // new option shorter

+    // p p n n x x x x x

+    // p p n n x x x x x -

+    // p p - n n x x x x x

+    // p p - - n x x x x x

+    // p p o o n x x x x x

+

+    // new option longer

+    // p p n n x x x x x

+    // p p n n x x x x x - - -

+    // p p - - - n n x x x x x

+    // p p - - n n n x x x x x

+    // p p o o n n n x x x x x

+

+    // note, it can only ever be shorter or the same since if an option was inserted the delta got smaller

+    // but I'll leave that little comment in, just to show that it would work even if the delta got bigger

+

+    // now insert the new option into the gap

+    printf("Inserting new option...");

+    insertOption(insertionPosition,optionDelta,optionValueLength,optionValue);

+    printf("done\r\n");

+

+    // done, mark it with B!

+    _numOptions++;

+    return 0;

+}

+

+/// Allocate space for a payload.

+/**

+ * For dynamically constructed PDUs, this will allocate space for a payload in the object

+ * and return a pointer to it. If the PDU was constructed from a buffer, this doesn't

+ * malloc anything, it just changes the _pduLength and returns the payload pointer.

+ *

+ * \note The pointer returned points into the PDU buffer.

+ * \param len The length of the payload buffer to allocate.

+ * \return Either a pointer to the payload buffer, or NULL if there wasn't enough space / allocation failed.

+ */

+uint8_t* CoapPDU::mallocPayload(int len)

+{

+    printf("Entering mallocPayload");

+    // sanity checks

+    if(len==0)

+    {

+        printf("Cannot allocate a zero length payload");

+        return NULL;

+    }

+

+    // further sanity

+    if(len==_payloadLength)

+    {

+        printf("Space for payload of specified length already exists");

+        if(_payloadPointer==NULL)

+        {

+            printf("Garbage PDU. Payload length is %d, but existing _payloadPointer NULL",_payloadLength);

+            return NULL;

+        }

+        return _payloadPointer;

+    }

+

+    printf("_bufferLength: %d, _pduLength: %d, _payloadLength: %d",_bufferLength,_pduLength,_payloadLength);

+

+    // might be making payload bigger (including bigger than 0) or smaller

+    int markerSpace = 1;

+    int payloadSpace = len;

+    // is this a resizing?

+    if(_payloadLength!=0)

+    {

+        // marker already exists

+        markerSpace = 0;

+        // compute new payload length (can be negative if shrinking payload)

+        payloadSpace = len-_payloadLength;

+    }

+

+    // make space for payload (and payload marker if necessary)

+    int newLen = _pduLength+payloadSpace+markerSpace;

+    if(!_constructedFromBuffer)

+    {

+        uint8_t* newPDU = (uint8_t*)realloc(_pdu,newLen);

+        if(newPDU==NULL)

+        {

+            printf("Cannot allocate (or shrink) space for payload");

+            return NULL;

+        }

+        _pdu = newPDU;

+        _bufferLength = newLen;

+    }

+    else

+    {

+        // constructed from buffer, check space

+        printf("newLen: %d, _bufferLength: %d",newLen,_bufferLength);

+        if(newLen>_bufferLength)

+        {

+            printf("Buffer too small to contain desired payload, needed %d, got %d.",newLen-_pduLength,_bufferLength-_pduLength);

+            return NULL;

+        }

+    }

+

+    // deal with fresh allocation case separately

+    if(_payloadPointer==NULL)

+    {

+        // set payload marker

+        _pdu[_pduLength] = 0xFF;

+        // payload at end of old PDU

+        _payloadPointer = &_pdu[_pduLength+1];

+        _pduLength = newLen;

+        _payloadLength = len;

+        return _payloadPointer;

+    }

+

+    // otherwise, just adjust length of PDU

+    _pduLength = newLen;

+    _payloadLength = len;

+    printf("Leaving mallocPayload");

+    return _payloadPointer;

+}

+

+/// Set the payload to the byte sequence specified. Allocates memory in dynamic PDU if necessary.

+/**

+ * This will set the payload to \b payload. It will allocate memory in the case where the PDU was

+ * constructed without an external buffer.

+ *

+ * This will fail either if the fixed buffer isn't big enough, or if memory could not be allocated

+ * in the non-external-buffer case.

+ *

+ * \param payload Pointer to payload byte sequence.

+ * \param len Length of payload byte sequence.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setPayload(uint8_t *payload, int len)

+{

+    if(payload==NULL)

+    {

+        printf("NULL payload pointer.");

+        return 1;

+    }

+

+    uint8_t *payloadPointer = mallocPayload(len);

+    if(payloadPointer==NULL)

+    {

+        printf("Allocation of payload failed");

+        return 1;

+    }

+

+    // copy payload contents

+    memcpy(payloadPointer,payload,len);

+

+    return 0;

+}

+

+/// Returns a pointer to the payload buffer.

+uint8_t* CoapPDU::getPayloadPointer()

+{

+    return _payloadPointer;

+}

+

+/// Gets the length of the payload buffer.

+int CoapPDU::getPayloadLength()

+{

+    return _payloadLength;

+}

+

+/// Returns a pointer to a buffer which is a copy of the payload buffer (dynamically allocated).

+uint8_t* CoapPDU::getPayloadCopy()

+{

+    if(_payloadLength==0)

+    {

+        return NULL;

+    }

+

+    // malloc space for copy

+    uint8_t *payload = (uint8_t*)malloc(_payloadLength);

+    if(payload==NULL)

+    {

+        printf("Unable to allocate memory for payload");

+        return NULL;

+    }

+

+    // copy and return

+    memcpy(payload,_payloadPointer,_payloadLength);

+    return payload;

+}

+

+/// Shorthand for setting the content-format option.

+/**

+ * Sets the content-format to the specified value (adds an option).

+ * \param format The content format, one of:

+ *

+ * - COAP_CONTENT_FORMAT_TEXT_PLAIN

+ * - COAP_CONTENT_FORMAT_APP_LINK

+ * - COAP_CONTENT_FORMAT_APP_XML

+ * - COAP_CONTENT_FORMAT_APP_OCTET

+ * - COAP_CONTENT_FORMAT_APP_EXI

+ * - COAP_CONTENT_FORMAT_APP_JSON

+ *

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::setContentFormat(int format)

+{

+    if(format==0)

+    {

+        // minimal representation means null option value

+        if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,0,NULL)!=0)

+        {

+            printf("Error setting content format");

+            return 1;

+        }

+        return 0;

+    }

+

+    uint8_t c[2];

+

+    // just use 1 byte if can do it

+    //if((uint16_t)format <= 0xffu) {

+    if(1)

+    {

+        c[0] = format;

+        if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,1,c)!=0)

+        {

+            printf("Error setting content format");

+            return 1;

+        }

+        return 0;

+    }

+

+    uint8_t *to = c;

+    endian_store16(to, format);

+    if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,2,c)!=0)

+    {

+        printf("Error setting content format");

+        return 1;

+    }

+    return 0;

+}

+

+// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE

+// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE

+

+/// Moves a block of bytes to end of PDU from given offset.

+/**

+ * This moves the block of bytes _pdu[_pduLength-1-shiftOffset-shiftAmount] ... _pdu[_pduLength-1-shiftOffset]

+ * to the end of the PDU.

+ * \param shiftOffset End of block to move, relative to end of PDU (-1).

+ * \param shiftAmount Length of block to move.

+ */

+void CoapPDU::shiftPDUUp(int shiftOffset, int shiftAmount)

+{

+    printf("shiftOffset: %d, shiftAmount: %d",shiftOffset,shiftAmount);

+    int destPointer = _pduLength-1;

+    int srcPointer  = destPointer-shiftOffset;

+    while(shiftAmount--)

+    {

+        _pdu[destPointer] = _pdu[srcPointer];

+        destPointer--;

+        srcPointer--;

+    }

+}

+

+/// Moves a block of bytes down a specified number of steps.

+/**

+ * Moves the block of bytes _pdu[startLocation+shiftOffset] ... _pdu[startLocation+shiftOffset+shiftAmount]

+ * down to \b startLocation.

+ * \param startLocation Index where to shift the block to.

+ * \param shiftOffset Where the block starts, relative to start index.

+ * \param shiftAmount Length of block to shift.

+ */

+void CoapPDU::shiftPDUDown(int startLocation, int shiftOffset, int shiftAmount)

+{

+    printf("startLocation: %d, shiftOffset: %d, shiftAmount: %d",startLocation,shiftOffset,shiftAmount);

+    int srcPointer = startLocation+shiftOffset;

+    while(shiftAmount--)

+    {

+        _pdu[startLocation] = _pdu[srcPointer];

+        startLocation++;

+        srcPointer++;

+    }

+}

+

+/// Gets the payload length of an option.

+/**

+ * \param option Pointer to location of option in PDU.

+ * \return The 16 bit option-payload length.

+ */

+uint16_t CoapPDU::getOptionValueLength(uint8_t *option)

+{

+    uint16_t delta = (option[0] & 0xF0) >> 4;

+    uint16_t length = (option[0] & 0x0F);

+    // no extra bytes

+    if(length<13)

+    {

+        return length;

+    }

+

+    // extra bytes skip header

+    int offset = 1;

+    // skip extra option delta bytes

+    if(delta==13)

+    {

+        offset++;

+    }

+    else if(delta==14)

+    {

+        offset+=2;

+    }

+

+    // process length

+    if(length==13)

+    {

+        return (option[offset]+13);

+    }

+    else

+    {

+        uint8_t *from = &option[offset];

+        uint16_t value = endian_load16(uint16_t, from);

+        return value+269;

+    }

+

+}

+

+/// Gets the delta of an option.

+/**

+ * \param option Pointer to location of option in PDU.

+ * \return The 16 bit delta.

+ */

+uint16_t CoapPDU::getOptionDelta(uint8_t *option)

+{

+    uint16_t delta = (option[0] & 0xF0) >> 4;

+    if(delta<13)

+    {

+        return delta;

+    }

+    else if(delta==13)

+    {

+        // single byte option delta

+        return (option[1]+13);

+    }

+    else if(delta==14)

+    {

+        uint8_t *from = &option[1];

+        uint16_t value = endian_load16(uint16_t, from);

+        return value+269;

+    }

+    else

+    {

+        // should only ever occur in payload marker

+        return delta;

+    }

+}

+

+/// Finds the insertion position in the current list of options for the specified option.

+/**

+ * \param optionNumber The option's number.

+ * \param prevOptionNumber A pointer to a uint16_t which will store the option number of the option previous

+ * to the insertion point.

+ * \return 0 on success, 1 on failure. \b prevOptionNumber will contain the option number of the option

+ * before the insertion position (for example 0 if no options have been inserted).

+ */

+int CoapPDU::findInsertionPosition(uint16_t optionNumber, uint16_t *prevOptionNumber)

+{

+    // zero this for safety

+    *prevOptionNumber = 0x00;

+

+    printf("_pduLength: %d",_pduLength);

+

+    // if option is bigger than any currently stored, it goes at the end

+    // this includes the case that no option has yet been added

+    if( (optionNumber >= _maxAddedOptionNumber) || (_pduLength == (COAP_HDR_SIZE+getTokenLength())) )

+    {

+        *prevOptionNumber = _maxAddedOptionNumber;

+        return _pduLength;

+    }

+

+    // otherwise walk over the options

+    int optionPos = COAP_HDR_SIZE + getTokenLength();

+    uint16_t optionDelta = 0, optionValueLength = 0;

+    uint16_t currentOptionNumber = 0;

+    while(optionPos<_pduLength && _pdu[optionPos]!=0xFF)

+    {

+        optionDelta = getOptionDelta(&_pdu[optionPos]);

+        currentOptionNumber += optionDelta;

+        optionValueLength = getOptionValueLength(&_pdu[optionPos]);

+        // test if this is insertion position

+        if(currentOptionNumber>optionNumber)

+        {

+            return optionPos;

+        }

+        // keep track of the last valid option number

+        *prevOptionNumber = currentOptionNumber;

+        // move onto next option

+        optionPos += computeExtraBytes(optionDelta);

+        optionPos += computeExtraBytes(optionValueLength);

+        optionPos += optionValueLength;

+        optionPos++; // (for mandatory option header byte)

+    }

+    return optionPos;

+

+}

+

+/// CoAP uses a minimal-byte representation for length fields. This returns the number of bytes needed to represent a given length.

+int CoapPDU::computeExtraBytes(uint16_t n)

+{

+    if(n<13)

+    {

+        return 0;

+    }

+

+    if(n<269)

+    {

+        return 1;

+    }

+

+    return 2;

+}

+

+/// Set the option delta to the specified value.

+/**

+ * This assumes space has been made for the option delta.

+ * \param optionPosition The index of the option in the PDU.

+ * \param optionDelta The option delta value to set.

+ */

+void CoapPDU::setOptionDelta(int optionPosition, uint16_t optionDelta)

+{

+    int headerStart = optionPosition;

+    // clear the old option delta bytes

+    _pdu[headerStart] &= 0x0F;

+

+    // set the option delta bytes

+    if(optionDelta<13)

+    {

+        _pdu[headerStart] |= (optionDelta << 4);

+    }

+    else if(optionDelta<269)

+    {

+        // 1 extra byte

+        _pdu[headerStart] |= 0xD0; // 13 in first nibble

+        _pdu[++optionPosition] &= 0x00;

+        _pdu[optionPosition] |= (optionDelta-13);

+    }

+    else

+    {

+        // 2 extra bytes, network byte order uint16_t

+        _pdu[headerStart] |= 0xE0; // 14 in first nibble

+        optionDelta -= 269;

+        uint8_t *to = &_pdu[++optionPosition];

+        endian_store16(to, optionDelta);

+    }

+}

+

+/// Insert an option in-memory at the specified location.

+/**

+ * This assumes that there is enough space at the location specified.

+ * \param insertionPosition Position in the PDU where the option should be placed.

+ * \param optionDelta The delta value for the option.

+ * \param optionValueLength The length of the option value.

+ * \param optionValue A pointer to the sequence of bytes representing the option value.

+ * \return 0 on success, 1 on failure.

+ */

+int CoapPDU::insertOption(

+    int insertionPosition,

+    uint16_t optionDelta,

+    uint16_t optionValueLength,

+    uint8_t *optionValue)

+{

+

+    int headerStart = insertionPosition;

+

+    // clear old option header start

+    _pdu[headerStart] &= 0x00;

+

+    // set the option delta bytes

+    if(optionDelta<13)

+    {

+        _pdu[headerStart] |= (optionDelta << 4);

+    }

+    else if(optionDelta<269)

+    {

+        // 1 extra byte

+        _pdu[headerStart] |= 0xD0; // 13 in first nibble

+        _pdu[++insertionPosition] &= 0x00;

+        _pdu[insertionPosition] |= (optionDelta-13);

+    }

+    else

+    {

+        // 2 extra bytes, network byte order uint16_t

+        _pdu[headerStart] |= 0xE0; // 14 in first nibble

+        optionDelta -= 269;

+        uint8_t *to = &_pdu[++insertionPosition];

+        endian_store16(to, optionDelta);

+        insertionPosition += 1;

+    }

+

+    // set the option value length bytes

+    if(optionValueLength<13)

+    {

+        _pdu[headerStart] |= (optionValueLength & 0x000F);

+    }

+    else if(optionValueLength<269)

+    {

+        _pdu[headerStart] |= 0x0D; // 13 in second nibble

+        _pdu[++insertionPosition] &= 0x00;

+        _pdu[insertionPosition] |= (optionValueLength-13);

+    }

+    else

+    {

+        _pdu[headerStart] |= 0x0E; // 14 in second nibble

+        // this is in network byte order

+        printf("optionValueLength: %u",optionValueLength);

+        uint8_t *to = &_pdu[++insertionPosition];

+        optionValueLength -= 269;

+        endian_store16(to, optionValueLength);

+        insertionPosition += 1;

+    }

+

+    // and finally copy the option value itself

+    memcpy(&_pdu[++insertionPosition],optionValue,optionValueLength);

+

+    return 0;

+}

+

+void CoapPDU::getOptionValueById

+(

+    uint16_t optionNumber,

+    uint16_t *optionValueLength,

+    uint8_t *optionValuePointer

+)

+{

+    if(_numOptions == 0)

+        return;

+    CoapOption* options = getOptions();

+    int i = 0;

+    for(; i < _numOptions; i++)

+    {

+        if(options[i].optionNumber == optionNumber)

+        {

+            *optionValueLength = options[i].optionValueLength;

+            memcpy(optionValuePointer, options[i].optionValuePointer, options[i].optionValueLength);

+        }

+    }

+    free(options);

+}

+

+int CoapPDU::hasOption

+(

+    uint16_t optionNumber

+)

+{

+    int res = 0;

+    if(_numOptions == 0)

+        return res;

+    CoapOption* options = getOptions();

+    int i = 0;

+    for(; i < _numOptions; i++)

+    {

+        if(options[i].optionNumber == optionNumber)

+        {

+            res = 1;

+            break;

+        }

+    }

+    free(options);

+    return res;

+}

+

+const char *CoapPDU::printHuman()

+{

+    content.clear();

+    char temp1[128];

+

+    sprintf(temp1,"PDU is %d bytes long\r\n",_pduLength);

+    content.append(temp1);

+

+    sprintf(temp1,"CoAP Version: %d\r\n",getVersion());

+    content.append("Message Type: ");

+    switch(getType())

+    {

+        case COAP_CONFIRMABLE:

+            content.append("Confirmable");

+            break;

+

+        case COAP_NON_CONFIRMABLE:

+            content.append("Non-Confirmable");

+            break;

+

+        case COAP_ACKNOWLEDGEMENT:

+            content.append("Acknowledgement");

+            break;

+

+        case COAP_RESET:

+            content.append("Reset");

+            break;

+    }

+

+    sprintf(temp1,"\r\nToken length: %d\r\n",getTokenLength());

+    content.append(temp1);

+    content.append("Code: ");

+    switch(getCode())

+    {

+        case COAP_EMPTY:

+            content.append("0.00 Empty");

+            break;

+        case COAP_GET:

+            content.append("0.01 GET");

+            break;

+        case COAP_POST:

+            content.append("0.02 POST");

+            break;

+        case COAP_PUT:

+            content.append("0.03 PUT");

+            break;

+        case COAP_DELETE:

+            content.append("0.04 DELETE");

+            break;

+        case COAP_CREATED:

+            content.append("2.01 Created");

+            break;

+        case COAP_DELETED:

+            content.append("2.02 Deleted");

+            break;

+        case COAP_VALID:

+            content.append("2.03 Valid");

+            break;

+        case COAP_CHANGED:

+            content.append("2.04 Changed");

+            break;

+        case COAP_CONTENT:

+            content.append("2.05 Content");

+            break;

+        case COAP_CONTINUE:

+            content.append("2.31 Continue");

+            break;

+        case COAP_BAD_REQUEST:

+            content.append("4.00 Bad Request");

+            break;

+        case COAP_UNAUTHORIZED:

+            content.append("4.01 Unauthorized");

+            break;

+        case COAP_BAD_OPTION:

+            content.append("4.02 Bad Option");

+            break;

+        case COAP_FORBIDDEN:

+            content.append("4.03 Forbidden");

+            break;

+        case COAP_NOT_FOUND:

+            content.append("4.04 Not Found");

+            break;

+        case COAP_METHOD_NOT_ALLOWED:

+            content.append("4.05 Method Not Allowed");

+            break;

+        case COAP_NOT_ACCEPTABLE:

+            content.append("4.06 Not Acceptable");

+            break;

+        case COAP_PRECONDITION_FAILED:

+            content.append("4.12 Precondition Failed");

+            break;

+        case COAP_REQUEST_ENTITY_TOO_LARGE:

+            content.append("4.13 Request Entity Too Large");

+            break;

+        case COAP_UNSUPPORTED_CONTENT_FORMAT:

+            content.append("4.15 Unsupported Content-Format");

+            break;

+        case COAP_INTERNAL_SERVER_ERROR:

+            content.append("5.00 Internal Server Error");

+            break;

+        case COAP_NOT_IMPLEMENTED:

+            content.append("5.01 Not Implemented");

+            break;

+        case COAP_BAD_GATEWAY:

+            content.append("5.02 Bad Gateway");

+            break;

+        case COAP_SERVICE_UNAVAILABLE:

+            content.append("5.03 Service Unavailable");

+            break;

+        case COAP_GATEWAY_TIMEOUT:

+            content.append("5.04 Gateway Timeout");

+            break;

+        case COAP_PROXYING_NOT_SUPPORTED:

+            content.append("5.05 Proxying Not Supported");

+            break;

+        default:

+            sprintf(temp1, "Undefined Code %u",(unsigned)(getCode()));

+            content.append(temp1);

+

+    }

+

+    // print message ID

+    sprintf(temp1,"\r\nMessage ID: %u\r\n",getMessageID());

+    content.append(temp1);

+

+    // print token value

+    int tokenLength = getTokenLength();

+    uint8_t *tokenPointer = getPDUPointer()+COAP_HDR_SIZE;

+    if(tokenLength==0)

+    {

+        content.append("No token.\r\n");

+    }

+    else

+    {

+        //memset(temp1,0,50);

+        sprintf(temp1,"Token of %d bytes.\r\n",tokenLength);

+        content.append(temp1);

+        content.append("Value: 0x");

+        char temp2[5];

+        for(int j=0; j<tokenLength; j++)

+        {

+            sprintf(temp2,"%.2X",tokenPointer[j]);

+            content.append(temp2);

+        }

+    }

+

+    // print options

+    CoapPDU::CoapOption* options = getOptions();

+    if(options==NULL)

+    {

+        content.append("\r\nNO options");

+    }

+    else

+    {

+        //memset(temp1,0,50);

+        sprintf(temp1,"\r\n%d options:",_numOptions);

+        content.append(temp1);

+    }

+

+    for(int i=0; i<_numOptions; i++)

+    {

+        char optionTemp[128];

+        sprintf(optionTemp,"\r\nOPTION (%d/%d)\r\n"

+                "Option number (delta): %hu (%hu)\r\n"

+                "Name: "

+                ,i + 1,_numOptions,

+                options[i].optionNumber,options[i].optionDelta);

+        content.append(optionTemp);

+        boolean asString = FALSE;

+        switch(options[i].optionNumber)

+        {

+            case COAP_OPTION_IF_MATCH:

+                content.append("IF_MATCH");

+                break;

+            case COAP_OPTION_URI_HOST:

+                content.append("URI_HOST");

+                asString = TRUE;

+                break;

+            case COAP_OPTION_ETAG:

+                content.append("ETAG");

+                break;

+            case COAP_OPTION_IF_NONE_MATCH:

+                content.append("IF_NONE_MATCH");

+                break;

+            case COAP_OPTION_OBSERVE:

+                content.append("OBSERVE");

+                break;

+            case COAP_OPTION_URI_PORT:

+                content.append("URI_PORT");

+                break;

+            case COAP_OPTION_LOCATION_PATH:

+                content.append("LOCATION_PATH");

+                break;

+            case COAP_OPTION_URI_PATH:

+                content.append("URI_PATH");

+                asString = TRUE;

+                break;

+            case COAP_OPTION_CONTENT_FORMAT:

+                content.append("CONTENT_FORMAT");

+                break;

+            case COAP_OPTION_MAX_AGE:

+                content.append("MAX_AGE");

+                break;

+            case COAP_OPTION_URI_QUERY:

+                content.append("URI_QUERY");

+                asString = TRUE;

+                break;

+            case COAP_OPTION_ACCEPT:

+                content.append("ACCEPT");

+                break;

+            case COAP_OPTION_LOCATION_QUERY:

+                content.append("LOCATION_QUERY");

+                asString = TRUE;

+                break;

+            case COAP_OPTION_PROXY_URI:

+                content.append("PROXY_URI");

+                asString = TRUE;

+                break;

+            case COAP_OPTION_PROXY_SCHEME:

+                content.append("PROXY_SCHEME");

+                asString = TRUE;

+                break;

+            case COAP_OPTION_BLOCK1:

+                content.append("BLOCK1");

+                break;

+            case COAP_OPTION_BLOCK2:

+                content.append("BLOCK2");

+                break;

+            case COAP_OPTION_SIZE1:

+                content.append("SIZE1");

+                break;

+            case COAP_OPTION_SIZE2:

+                content.append("SIZE2");

+                break;

+            default:

+                //memset(temp1,0,50);

+                sprintf(temp1,"Unknown option %u",(unsigned)options[i].optionNumber);

+                content.append(temp1);

+                break;

+        }

+        //memset(temp1,0,50);

+        sprintf(temp1,"\r\nValue length: %u\r\n",options[i].optionValueLength);

+        content.append(temp1);

+        if(asString)

+        {

+            content.append("Value: ");

+        }

+        else

+        {

+            content.append("Value: 0x");

+        }

+        char temp3[5];

+        for(int j=0; j<options[i].optionValueLength; j++)

+        {

+            if(asString)

+            {

+                char c = options[i].optionValuePointer[j];

+                if((c>='!'&&c<='~')||c==' ')

+                {

+                    sprintf(temp3,"%c", c);

+                }

+                else

+                {

+                    sprintf(temp3,"\\%.2d",c);

+                }

+                content.append(temp3);

+            }

+            else

+            {

+                sprintf(temp3,"%.2X",options[i].optionValuePointer[j]);

+                content.append(temp3);

+            }

+        }

+    }

+

+    // print payload

+    if(_payloadLength==0)

+    {

+        content.append("\r\nNo payload.\r\n");

+    }

+    else

+    {

+        //memset(temp1,0,50);

+        sprintf(temp1,"\r\nPayload of %d bytes\r\nValue: 0x",_payloadLength);

+        content.append(temp1);

+        char temp4[5];

+        for(int j=0; j<_payloadLength; j++)

+        {

+            sprintf(temp4,"%.2X",_payloadPointer[j]);

+            content.append(temp4);

+        }

+        content.append("\r\n");

+    }

+    if(options)

+        free(options);

+    return content.c_str();

+}

+

+const char * CoapPDU::printHex()

+{

+    content.clear();

+    char temp[5];

+    for(int i=0; i<_pduLength; i++)

+    {

+        sprintf(temp,"%.2X",_pdu[i]);

+        content.append(temp);

+    }

+    content.append("\r\n");

+    return content.c_str();

+}

+//#endif

diff --git a/mbtk/mbtk_lib/src/mbtk_dhcp.c b/mbtk/mbtk_lib/src/mbtk_dhcp.c
new file mode 100755
index 0000000..b764f34
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_dhcp.c
@@ -0,0 +1,885 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_ifc.h"
+#include "mbtk_dhcp.h"
+
+#define VERBOSE 2
+#define STATE_SELECTING  1
+#define STATE_REQUESTING 2
+
+#define TIMEOUT_INITIAL   4000
+#define TIMEOUT_MAX      32000
+
+static int verbose = 1;
+// static char errmsg[2048];
+
+static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
+{
+    uint8_t *x;
+
+    memset(msg, 0, sizeof(dhcp_msg));
+
+    msg->op = OP_BOOTREQUEST;
+    msg->htype = HTYPE_ETHER;
+    msg->hlen = 6;
+    msg->hops = 0;
+
+    msg->flags = htons(FLAGS_BROADCAST);
+
+    msg->xid = xid;
+
+    memcpy(msg->chaddr, hwaddr, 6);
+
+    x = msg->options;
+
+    *x++ = OPT_COOKIE1;
+    *x++ = OPT_COOKIE2;
+    *x++ = OPT_COOKIE3;
+    *x++ = OPT_COOKIE4;
+
+    *x++ = OPT_MESSAGE_TYPE;
+    *x++ = 1;
+    *x++ = type;
+
+    return x;
+}
+
+static int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
+{
+    uint8_t *x;
+
+    x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);
+
+    *x++ = OPT_PARAMETER_LIST;
+    *x++ = 4;
+    *x++ = OPT_SUBNET_MASK;
+    *x++ = OPT_GATEWAY;
+    *x++ = OPT_DNS;
+    *x++ = OPT_BROADCAST_ADDR;
+
+    *x++ = OPT_END;
+
+    return DHCP_MSG_FIXED_SIZE + (x - msg->options);
+}
+
+static int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
+                                 uint32_t ipaddr, uint32_t serveraddr)
+{
+    uint8_t *x;
+
+    x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
+
+    *x++ = OPT_PARAMETER_LIST;
+    *x++ = 4;
+    *x++ = OPT_SUBNET_MASK;
+    *x++ = OPT_GATEWAY;
+    *x++ = OPT_DNS;
+    *x++ = OPT_BROADCAST_ADDR;
+
+    *x++ = OPT_REQUESTED_IP;
+    *x++ = 4;
+    memcpy(x, &ipaddr, 4);
+    x +=  4;
+
+    *x++ = OPT_SERVER_ID;
+    *x++ = 4;
+    memcpy(x, &serveraddr, 4);
+    x += 4;
+
+    *x++ = OPT_END;
+
+    return DHCP_MSG_FIXED_SIZE + (x - msg->options);
+}
+
+
+static msecs_t get_msecs(void)
+{
+    struct timespec ts;
+
+    if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    {
+        return 0;
+    }
+    else
+    {
+        return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
+               (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
+    }
+}
+
+static int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
+{
+    int s;
+    struct sockaddr_ll bindaddr;
+
+    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0)
+    {
+        LOGE("socket(PF_PACKET)");
+        return -1;
+    }
+
+    memset(&bindaddr, 0, sizeof(bindaddr));
+    bindaddr.sll_family = AF_PACKET;
+    bindaddr.sll_protocol = htons(ETH_P_IP);
+    bindaddr.sll_halen = ETH_ALEN;
+    memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
+    bindaddr.sll_ifindex = if_index;
+
+    if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0)
+    {
+        LOGE("Cannot bind raw socket to interface");
+        return -1;
+    }
+
+    return s;
+}
+
+static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
+{
+    uint16_t *up = (uint16_t *)buffer;
+    uint32_t sum = startsum;
+    uint32_t upper16;
+
+    while (count > 1)
+    {
+        sum += *up++;
+        count -= 2;
+    }
+    if (count > 0)
+    {
+        sum += (uint16_t) *(uint8_t *)up;
+    }
+    while ((upper16 = (sum >> 16)) != 0)
+    {
+        sum = (sum & 0xffff) + upper16;
+    }
+    return sum;
+}
+
+static uint32_t finish_sum(uint32_t sum)
+{
+    return ~sum & 0xffff;
+}
+
+static int send_packet(int s, int if_index, dhcp_msg *msg, int size,
+                       uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
+{
+    struct iphdr ip;
+    struct udphdr udp;
+    struct iovec iov[3];
+    uint32_t udpsum;
+    uint16_t temp;
+    struct msghdr msghdr;
+    struct sockaddr_ll destaddr;
+
+    ip.version = IPVERSION;
+    ip.ihl = sizeof(ip) >> 2;
+    ip.tos = 0;
+    ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
+    ip.id = 0;
+    ip.frag_off = 0;
+    ip.ttl = IPDEFTTL;
+    ip.protocol = IPPROTO_UDP;
+    ip.check = 0;
+    ip.saddr = saddr;
+    ip.daddr = daddr;
+    ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
+
+    udp.source = htons(sport);
+    udp.dest = htons(dport);
+    udp.len = htons(sizeof(udp) + size);
+    udp.check = 0;
+
+    /* Calculate checksum for pseudo header */
+    udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
+    udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
+    temp = htons(IPPROTO_UDP);
+    udpsum = checksum(&temp, sizeof(temp), udpsum);
+    temp = udp.len;
+    udpsum = checksum(&temp, sizeof(temp), udpsum);
+
+    /* Add in the checksum for the udp header */
+    udpsum = checksum(&udp, sizeof(udp), udpsum);
+
+    /* Add in the checksum for the data */
+    udpsum = checksum(msg, size, udpsum);
+    udp.check = finish_sum(udpsum);
+
+    iov[0].iov_base = (char *)&ip;
+    iov[0].iov_len = sizeof(ip);
+    iov[1].iov_base = (char *)&udp;
+    iov[1].iov_len = sizeof(udp);
+    iov[2].iov_base = (char *)msg;
+    iov[2].iov_len = size;
+    memset(&destaddr, 0, sizeof(destaddr));
+    destaddr.sll_family = AF_PACKET;
+    destaddr.sll_protocol = htons(ETH_P_IP);
+    destaddr.sll_ifindex = if_index;
+    destaddr.sll_halen = ETH_ALEN;
+    memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
+
+    msghdr.msg_name = &destaddr;
+    msghdr.msg_namelen = sizeof(destaddr);
+    msghdr.msg_iov = iov;
+    msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
+    msghdr.msg_flags = 0;
+    msghdr.msg_control = 0;
+    msghdr.msg_controllen = 0;
+    return sendmsg(s, &msghdr, 0);
+}
+
+static int receive_packet(int s, dhcp_msg *msg)
+{
+    int nread;
+    int is_valid;
+    struct dhcp_packet
+    {
+        struct iphdr ip;
+        struct udphdr udp;
+        dhcp_msg dhcp;
+    } packet;
+    int dhcp_size;
+    uint32_t sum;
+    uint16_t temp;
+    uint32_t saddr, daddr;
+
+    nread = read(s, &packet, sizeof(packet));
+    if (nread < 0)
+    {
+        return -1;
+    }
+    /*
+     * The raw packet interface gives us all packets received by the
+     * network interface. We need to filter out all packets that are
+     * not meant for us.
+     */
+    is_valid = 0;
+    if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr)))
+    {
+#if VERBOSE
+        LOGD("Packet is too small (%d) to be a UDP datagram", nread);
+#endif
+    }
+    else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2))
+    {
+#if VERBOSE
+        LOGD("Not a valid IP packet");
+#endif
+    }
+    else if (nread < ntohs(packet.ip.tot_len))
+    {
+#if VERBOSE
+        LOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
+#endif
+    }
+    else if (packet.ip.protocol != IPPROTO_UDP)
+    {
+#if VERBOSE
+        LOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
+#endif
+    }
+    else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT))
+    {
+#if VERBOSE
+        LOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
+#endif
+    }
+    else
+    {
+        is_valid = 1;
+    }
+
+    if (!is_valid)
+    {
+        return -1;
+    }
+
+    /* Seems like it's probably a valid DHCP packet */
+    /* validate IP header checksum */
+    sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
+    if (sum != 0)
+    {
+        LOGW("IP header checksum failure (0x%x)", packet.ip.check);
+        return -1;
+    }
+    /*
+     * Validate the UDP checksum.
+     * Since we don't need the IP header anymore, we "borrow" it
+     * to construct the pseudo header used in the checksum calculation.
+     */
+    dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
+    /*
+     * check validity of dhcp_size.
+     * 1) cannot be negative or zero.
+     * 2) src buffer contains enough bytes to copy
+     * 3) cannot exceed destination buffer
+     */
+    if ((dhcp_size <= 0) ||
+        ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) ||
+        ((int)sizeof(dhcp_msg) < dhcp_size))
+    {
+#if VERBOSE
+        LOGD("Malformed Packet");
+#endif
+        return -1;
+    }
+    saddr = packet.ip.saddr;
+    daddr = packet.ip.daddr;
+    nread = ntohs(packet.ip.tot_len);
+    memset(&packet.ip, 0, sizeof(packet.ip));
+    packet.ip.saddr = saddr;
+    packet.ip.daddr = daddr;
+    packet.ip.protocol = IPPROTO_UDP;
+    packet.ip.tot_len = packet.udp.len;
+    temp = packet.udp.check;
+    packet.udp.check = 0;
+    sum = finish_sum(checksum(&packet, nread, 0));
+    packet.udp.check = temp;
+    if (!sum)
+        sum = finish_sum(sum);
+    if (temp != sum)
+    {
+        LOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
+        return -1;
+    }
+    memcpy(msg, &packet.dhcp, dhcp_size);
+    return dhcp_size;
+}
+
+static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len)
+{
+    int i;
+    char *cp = buf;
+    char *buf_end = buf + buf_size;
+    for (i = 0; i < len; i++)
+    {
+        cp += snprintf(cp, buf_end - cp, " %02x ", array[i]);
+    }
+}
+
+static const char *ipaddr(in_addr_t addr)
+{
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
+}
+
+static const char *dhcp_type_to_name(uint32_t type)
+{
+    switch(type)
+    {
+        case DHCPDISCOVER:
+            return "discover";
+        case DHCPOFFER:
+            return "offer";
+        case DHCPREQUEST:
+            return "request";
+        case DHCPDECLINE:
+            return "decline";
+        case DHCPACK:
+            return "ack";
+        case DHCPNAK:
+            return "nak";
+        case DHCPRELEASE:
+            return "release";
+        case DHCPINFORM:
+            return "inform";
+        default:
+            return "???";
+    }
+}
+
+static void dump_dhcp_msg(dhcp_msg *msg, int len)
+{
+    unsigned char *x;
+    unsigned int n,c;
+    int optsz;
+    const char *name;
+    char buf[2048];
+
+    LOGD("===== DHCP message:");
+    if (len < DHCP_MSG_FIXED_SIZE)
+    {
+        LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
+        return;
+    }
+
+    len -= DHCP_MSG_FIXED_SIZE;
+
+    if (msg->op == OP_BOOTREQUEST)
+        name = "BOOTREQUEST";
+    else if (msg->op == OP_BOOTREPLY)
+        name = "BOOTREPLY";
+    else
+        name = "????";
+    LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
+         name, msg->op, msg->htype, msg->hlen, msg->hops);
+    LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
+         ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
+    LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
+    LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
+    LOGD("siaddr = %s", ipaddr(msg->siaddr));
+    LOGD("giaddr = %s", ipaddr(msg->giaddr));
+
+    c = msg->hlen > 16 ? 16 : msg->hlen;
+    hex2str(buf, sizeof(buf), msg->chaddr, c);
+    LOGD("chaddr = {%s}", buf);
+
+    for (n = 0; n < 64; n++)
+    {
+        unsigned char x = msg->sname[n];
+        if ((x < ' ') || (x > 127))
+        {
+            if (x == 0) break;
+            msg->sname[n] = '.';
+        }
+    }
+    msg->sname[63] = 0;
+
+    for (n = 0; n < 128; n++)
+    {
+        unsigned char x = msg->file[n];
+        if ((x < ' ') || (x > 127))
+        {
+            if (x == 0) break;
+            msg->file[n] = '.';
+        }
+    }
+    msg->file[127] = 0;
+
+    LOGD("sname = '%s'", msg->sname);
+    LOGD("file = '%s'", msg->file);
+
+    if (len < 4) return;
+    len -= 4;
+    x = msg->options + 4;
+
+    while (len > 2)
+    {
+        if (*x == 0)
+        {
+            x++;
+            len--;
+            continue;
+        }
+        if (*x == OPT_END)
+        {
+            break;
+        }
+        len -= 2;
+        optsz = x[1];
+        if (optsz > len) break;
+        if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE)
+        {
+            if ((unsigned int)optsz < sizeof(buf) - 1)
+            {
+                n = optsz;
+            }
+            else
+            {
+                n = sizeof(buf) - 1;
+            }
+            memcpy(buf, &x[2], n);
+            buf[n] = '\0';
+        }
+        else
+        {
+            hex2str(buf, sizeof(buf), &x[2], optsz);
+        }
+        if (x[0] == OPT_MESSAGE_TYPE)
+            name = dhcp_type_to_name(x[2]);
+        else
+            name = NULL;
+        LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
+        len -= optsz;
+        x = x + optsz + 2;
+    }
+}
+
+static int send_message(int sock, int if_index, dhcp_msg  *msg, int size)
+{
+#if VERBOSE > 1
+    dump_dhcp_msg(msg, size);
+#endif
+    return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
+                       PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
+}
+
+// static dhcp_info last_good_info;
+static int dhcp_configure(const char *ifname, dhcp_info *info)
+{
+    //last_good_info = *info;
+    return mbtk_ifc_configure1(ifname, info->ipaddr, info->prefixLength, info->gateway, 0);
+}
+
+static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
+{
+    if (sz < DHCP_MSG_FIXED_SIZE)
+    {
+        if (verbose) LOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
+        return 0;
+    }
+    if (reply->op != OP_BOOTREPLY)
+    {
+        if (verbose) LOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
+        return 0;
+    }
+    if (reply->xid != msg->xid)
+    {
+        if (verbose) LOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
+                              ntohl(msg->xid));
+        return 0;
+    }
+    if (reply->htype != msg->htype)
+    {
+        if (verbose) LOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype);
+        return 0;
+    }
+    if (reply->hlen != msg->hlen)
+    {
+        if (verbose) LOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
+        return 0;
+    }
+    if (memcmp(msg->chaddr, reply->chaddr, msg->hlen))
+    {
+        if (verbose) LOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
+        return 0;
+    }
+    return 1;
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask)
+{
+    int prefixLength = 0;
+    uint32_t m = (uint32_t)ntohl(mask);
+    while (m & 0x80000000)
+    {
+        prefixLength++;
+        m = m << 1;
+    }
+    return prefixLength;
+}
+
+static int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
+{
+    uint8_t *x;
+    unsigned int opt;
+    int optlen;
+
+    memset(info, 0, sizeof(dhcp_info));
+    if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
+
+    len -= (DHCP_MSG_FIXED_SIZE + 4);
+
+    if (msg->options[0] != OPT_COOKIE1) return -1;
+    if (msg->options[1] != OPT_COOKIE2) return -1;
+    if (msg->options[2] != OPT_COOKIE3) return -1;
+    if (msg->options[3] != OPT_COOKIE4) return -1;
+
+    x = msg->options + 4;
+
+    while (len > 2)
+    {
+        opt = *x++;
+        if (opt == OPT_PAD)
+        {
+            len--;
+            continue;
+        }
+        if (opt == OPT_END)
+        {
+            break;
+        }
+        optlen = *x++;
+        len -= 2;
+        if (optlen > len)
+        {
+            break;
+        }
+        switch(opt)
+        {
+            case OPT_SUBNET_MASK:
+                if (optlen >= 4)
+                {
+                    in_addr_t mask;
+                    memcpy(&mask, x, 4);
+                    info->prefixLength = ipv4NetmaskToPrefixLength(mask);
+                }
+                break;
+            case OPT_GATEWAY:
+                if (optlen >= 4) memcpy(&info->gateway, x, 4);
+                break;
+            case OPT_DNS:
+                if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
+                if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
+                break;
+            case OPT_LEASE_TIME:
+                if (optlen >= 4)
+                {
+                    memcpy(&info->lease, x, 4);
+                    info->lease = ntohl(info->lease);
+                }
+                break;
+            case OPT_SERVER_ID:
+                if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
+                break;
+            case OPT_MESSAGE_TYPE:
+                info->type = *x;
+                break;
+            default:
+                break;
+        }
+        x += optlen;
+        len -= optlen;
+    }
+
+    info->ipaddr = msg->yiaddr;
+
+    return 0;
+}
+
+void dump_dhcp_info(dhcp_info *info)
+{
+    char addr[20], gway[20];
+    LOGD("--- dhcp %s (%d) ---",
+    dhcp_type_to_name(info->type), info->type);
+    strcpy(addr, ipaddr(info->ipaddr));
+    strcpy(gway, ipaddr(info->gateway));
+    LOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
+    if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
+    if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
+    LOGD("server %s, lease %d seconds",
+         ipaddr(info->serveraddr), info->lease);
+}
+
+static int dhcp_init_ifc(const char *ifname)
+{
+    dhcp_msg discover_msg;
+    dhcp_msg request_msg;
+    dhcp_msg reply;
+    dhcp_msg *msg;
+    dhcp_info info;
+    int s, r, size;
+    int valid_reply;
+    uint32_t xid;
+    unsigned char hwaddr[6];
+    struct pollfd pfd;
+    unsigned int state;
+    unsigned int timeout;
+    int if_index;
+
+    xid = (uint32_t) get_msecs();
+    if (mbtk_ifc_get_hwaddr(ifname, hwaddr))
+    {
+        LOGE("cannot obtain interface address");
+        return -1;
+    }
+    if (mbtk_ifc_get_ifindex(ifname, &if_index))
+    {
+        LOGE("cannot obtain interface index");
+        return -1;
+    }
+
+    s = open_raw_socket(ifname, hwaddr, if_index);
+
+    timeout = TIMEOUT_INITIAL;
+    state = STATE_SELECTING;
+    info.type = 0;
+    goto transmit;
+
+    for (;;)
+    {
+        pfd.fd = s;
+        pfd.events = POLLIN;
+        pfd.revents = 0;
+        r = poll(&pfd, 1, timeout);
+
+        if (r == 0)
+        {
+#if VERBOSE
+            LOGE("TIMEOUT");
+#endif
+            if (timeout >= TIMEOUT_MAX)
+            {
+                LOGE("timed out");
+                if ( info.type == DHCPOFFER )
+                {
+                    LOGE("no acknowledgement from DHCP server\nconfiguring %s with offered parameters", ifname);
+                    return dhcp_configure(ifname, &info);
+                }
+                errno = ETIME;
+                close(s);
+                return -1;
+            }
+            timeout = timeout * 2;
+
+        transmit:
+            size = 0;
+            msg = NULL;
+            switch(state)
+            {
+                case STATE_SELECTING:
+                    msg = &discover_msg;
+                    size = init_dhcp_discover_msg(msg, hwaddr, xid);
+                    break;
+                case STATE_REQUESTING:
+                    msg = &request_msg;
+                    size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
+                    break;
+                default:
+                    r = 0;
+            }
+            if (size != 0)
+            {
+                r = send_message(s, if_index, msg, size);
+                if (r < 0)
+                {
+                    LOGE("error sending dhcp msg: %s\n", strerror(errno));
+                }
+            }
+            continue;
+        }
+
+        if (r < 0)
+        {
+            if ((errno == EAGAIN) || (errno == EINTR))
+            {
+                continue;
+            }
+            LOGE("poll failed");
+            return -1;
+        }
+
+        errno = 0;
+        r = receive_packet(s, &reply);
+        if (r < 0)
+        {
+            if (errno != 0)
+            {
+                LOGD("receive_packet failed (%d): %s", r, strerror(errno));
+                if (errno == ENETDOWN || errno == ENXIO)
+                {
+                    return -1;
+                }
+            }
+            continue;
+        }
+
+#if VERBOSE > 1
+        dump_dhcp_msg(&reply, r);
+#endif
+        decode_dhcp_msg(&reply, r, &info);
+
+        if (state == STATE_SELECTING)
+        {
+            valid_reply = is_valid_reply(&discover_msg, &reply, r);
+        }
+        else
+        {
+            valid_reply = is_valid_reply(&request_msg, &reply, r);
+        }
+        if (!valid_reply)
+        {
+            LOGE("invalid reply");
+            continue;
+        }
+
+        if (verbose)
+            dump_dhcp_info(&info);
+
+        switch(state)
+        {
+            case STATE_SELECTING:
+                if (info.type == DHCPOFFER)
+                {
+                    state = STATE_REQUESTING;
+                    timeout = TIMEOUT_INITIAL;
+                    xid++;
+                    goto transmit;
+                }
+                break;
+            case STATE_REQUESTING:
+                if (info.type == DHCPACK)
+                {
+                    LOGE("configuring %s", ifname);
+                    close(s);
+                    return dhcp_configure(ifname, &info);
+                }
+                else if (info.type == DHCPNAK)
+                {
+                    LOGE("configuration request denied");
+                    close(s);
+                    return -1;
+                }
+                else
+                {
+                    LOGE("ignoring %s message in state %d",
+                         dhcp_type_to_name(info.type), state);
+                }
+                break;
+        }
+    }
+    close(s);
+    return 0;
+}
+
+
+int mbtk_do_dhcp(const char *name)
+{
+    int ret = 0;
+    if(mbtk_ifc_open())
+    {
+        LOGE("mbtk_ifc_open() fail.");
+        ret = -1;
+        goto return_result;
+    }
+
+    if (mbtk_ifc_set_addr(name, 0, 0))
+    {
+        LOGE("failed to set ip addr for %s to 0.0.0.0: %s", name, strerror(errno));
+        ret = -1;
+        goto return_result;
+    }
+
+    if (mbtk_ifc_up(name))
+    {
+        LOGE("failed to bring up interface %s: %s", name, strerror(errno));
+        ret = -1;
+        goto return_result;
+    }
+
+    if(dhcp_init_ifc(name))
+    {
+        LOGE("dhcp_init_ifc() fail.");
+        ret = -1;
+        goto return_result;
+    }
+
+return_result:
+
+    mbtk_ifc_close();
+
+    return ret;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_file.c b/mbtk/mbtk_lib/src/mbtk_file.c
new file mode 100755
index 0000000..44f3954
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_file.c
@@ -0,0 +1,128 @@
+#include "mbtk_file.h"
+
+/**
+* Return TRUE if file exist,FLASE or not.
+*/
+bool file_exist(const char *path)
+{
+    return (access(path, F_OK) == 0) ? true : false;
+}
+
+/*
+ * Return file descriptor if open file success, return -1 or not.
+ *
+ * flag : File open flag.
+ *  O_RDONLY 以只读方式打开文件
+ *  O_WRONLY 以只写方式打开文件
+ *  O_RDWR 以可读写方式打开文件
+ *      上述三种旗标是互斥
+ *
+ *  O_CREAT 若欲打开的文件不存在则自动建立该文件。
+ *  O_EXCL 如果 O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则
+ *      建立该文件,否则将导致打开文件错误。此外,若 O_CREAT 与 O_EXCL 同时设置,
+ *      并且欲打开的文件为符号连接,则会打开文件失败。
+ *  O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。
+ *  O_TRUNC 若文件存在并且以可写的方式打开时,此旗标会令文件长度清为 0,而原来存于该文件的资料也会消失。
+ *  O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
+ *  O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
+ *  O_NDELAY 同 O_NONBLOCK。
+ *  O_SYNC 以同步的方式打开文件。
+ *  O_NOFOLLOW 如果参数 pathname 所指的文件为一符号连接,则会令打开文件失败。
+ *  O_DIRECTORY 如果参数 pathname 所指的文件并非为一目录,则会令打开文件失败
+ */
+int file_open(const char *path, int flag)
+{
+    // Only for create file : rwxrw-rx-
+    int result = open(path, flag, 0766);
+    if(result == -1) {
+        LOGE("Open file[%s] fail:%d", path, errno);
+    }
+    return result;
+}
+
+/*
+* Return file size,or -1 if get file size fail.
+*/
+int file_length(int fd)
+{
+    int cur=  lseek(fd, 0, SEEK_CUR);
+    if(cur < 0)
+    {
+        LOGE("lseek(SEEK_CUR) error: %d", errno);
+        return -1;
+    }
+    int len = lseek(fd, 0, SEEK_END);
+    if (len < 0)
+    {
+        LOGE("lseek(SEEK_END) error: %d", errno);
+        return -1;
+    }
+
+    // Reset position
+    if(cur != len) {
+        if(lseek(fd, cur, SEEK_SET))
+        {
+            LOGE("lseek(SEEK_SET) error: %d", errno);
+            return -1;
+        }
+    }
+    return len;
+}
+
+// Read data of specified length.
+int file_read(int fd, void *buf, int nbyte)
+{
+    int count = 0;
+    int len = 0;
+    while (true)
+    {
+        len = read(fd, buf + count, nbyte - count);
+        if (len > 0)
+        {
+            count += len;
+        }
+        else
+        {
+            break;
+        }
+
+        if (count == nbyte)
+            break;
+    }
+
+    return count;
+}
+
+// Write data of specified length.
+int file_write(int fd, void *buf, int nbyte)
+{
+    int count = 0;
+    int len = 0;
+    while (true)
+    {
+        len = write(fd, buf + count, nbyte - count);
+        if (len > 0)
+        {
+            count += len;
+        }
+        else
+        {
+            LOGE("write() fail,ret = %d,errno = %d", len, errno);
+            break;
+        }
+
+        if (count == nbyte)
+            break;
+    }
+
+    return count;
+}
+
+int file_close(int fd)
+{
+    int result = close(fd);
+    if(result == -1) {
+        LOGE("Close file fail:%d", errno);
+    }
+    return result;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_ftp.c b/mbtk/mbtk_lib/src/mbtk_ftp.c
new file mode 100755
index 0000000..8c1340c
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_ftp.c
@@ -0,0 +1,3040 @@
+/*************************************************************
+ Description:
+ $file_description$
+ Author:
+ LiuBin
+ Date:
+ 2020/10/28 11:49:08
+ *************************************************************/
+#include "mbtk_ftp.h"
+#include "mbtk_list.h"
+#include "mbtk_sock.h"
+#include "mbtk_str.h"
+#include "mbtk_sock2.h"
+#include "mbtk_info.h"
+#include<linux/msg.h>
+
+/*************************************************************
+ Constants and Macros
+ *************************************************************/
+#define FTP_HANDLE_MAX 5
+#define FTP_ANONYMOUS_USER "Anonymous"
+#define FTP_ANONYMOUS_PASS "@"
+
+//#define FTP_RESUME_DEBUG
+
+#ifdef MBTK_PLATFORM_QCOMM
+#define FTP_TIMEOUT 60000    // 60s
+#else
+#define FTP_TIMEOUT 3000    // 3s
+#endif
+
+/*************************************************************
+ typedef struct:local at
+ *************************************************************/
+typedef struct
+{
+    char host[64];
+    uint16 port;
+    mbtk_ftp_auth_type_enum auth_type;
+    bool ftp_type;
+    bool use_cert;
+    char name[FTP_SERVER_USER_NAME_MAX+1];
+    char pass[FTP_SERVER_USER_PASS_MAX+1];
+    mbtk_ftp_handle at_ftp_handle;
+    char remote_path[MBTK_FTP_FILE_NAME_MAX+1];
+    char local_path[MBTK_FTP_FILE_NAME_MAX+1];
+    int rest_size;
+    int read_size;
+    int put_len;
+} mbtk_at_init_parameter;
+
+mbtk_at_init_parameter mbtk_at_ftp_par={0};
+
+/*************************************************************
+ Variables:local
+ *************************************************************/
+static list_node_t *ftp_client_list = NULL;
+
+/*************************************************************
+ Variables:public
+ *************************************************************/
+
+/*************************************************************
+ Local Function Declaration
+ *************************************************************/
+
+/*************************************************************
+ Local Function Definitions
+ *************************************************************/
+static bool ftp_ch_is_space(char ch)
+{
+    if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t')
+        return true;
+
+    return false;
+}
+
+static const char* ftp_str_next(const char* str, char *result, uint32 len)
+{
+    memset(result, 0x0, len);
+    const char* ptr = str;
+    const char* ptr_result;
+    while (*ptr && ftp_ch_is_space(*ptr))
+    {
+        ptr++;
+    }
+    if (*ptr == '\0')
+    {
+        return NULL;
+    }
+    // Point to first no space char.
+    ptr_result = ptr;
+    while (*ptr && !ftp_ch_is_space(*ptr))
+    {
+        ptr++;
+    }
+
+    // Point to first space char or '\0'.
+    memcpy(result, ptr_result, ptr - ptr_result);
+
+    if (*ptr == '\0')
+    {
+        return NULL;
+    }
+
+    return ptr;
+}
+
+static int ftp_cmd_handle(mbtk_ftp_info_s *info, const void *cmd, void *rsp,
+                          uint32 *rsp_len)
+{
+    int err;
+    int rsp_code;
+    int len = strlen((char*) cmd);
+    // Write cmd
+    if(info->auth_type != 0)
+    {
+        mbtk_sock_write(info->ftp_ssl_handle,info->session,cmd,len,60000,&err);
+        if(err!=0)
+        {
+            printf("\nmbtk_sock_write error:%d\n",err);
+            return err;
+        }
+    }
+    else
+    {
+        if (sock_write(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], cmd, len, 60000, &err)
+            != len)
+        {
+            LOGE("Socket write fail[err = %d].", err);
+            return -1;
+        }
+    }
+
+    // Read cmd response
+    if (rsp != NULL && *rsp_len > 0)
+    {
+    read_angin_1:
+        memset(rsp, 0x0, *rsp_len);
+        if(info->auth_type != 0)
+        {
+            unsigned char mbtk_ftp_ssl_read_buf[16384 + 1];
+            len = mbtk_sock_read(info->ftp_ssl_handle,info->session,mbtk_ftp_ssl_read_buf,sizeof(mbtk_ftp_ssl_read_buf),FTP_TIMEOUT,&err);
+            if(err != 0)
+            {
+                printf("\n mbtk_sock_read error:%d \n",err);
+            }
+            rsp_code = atoi(mbtk_ftp_ssl_read_buf);
+            printf("%s -> Code:%d; RSP:%s\n", (char*)cmd, rsp_code, (char* )mbtk_ftp_ssl_read_buf);
+            if (rsp_code == 0)
+            {
+                goto read_angin_1;
+            }
+            memcpy((char* )rsp, mbtk_ftp_ssl_read_buf, strlen(mbtk_ftp_ssl_read_buf));
+            //printf("\nrsp = %s\n",(char* )rsp);
+            return rsp_code;
+        }
+        else
+        {
+            len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], rsp, *rsp_len, FTP_TIMEOUT,&err);
+        }
+        if (len <= 0)
+        {
+            LOGE("Socket read fail[len = %d].", len);
+            return -1;
+        }
+        rsp_code = atoi(rsp);
+        LOGI("%s -> Code:%d; RSP:%s", (char*)cmd, rsp_code, (char* )rsp);
+        //log_hex("FTP_RSP",(char* )rsp,len);
+
+        if (rsp_code == 0)
+        {
+            goto read_angin_1;
+        }
+
+        *rsp_len = len;
+    }
+    else
+    {
+        char buff[1024];
+
+    read_angin_2:
+        memset(buff, 0x0, 1024);
+        if(info->auth_type != 0)
+        {
+            unsigned char mbtk_ftp_ssl_read_buf[16384 + 1];
+            len = mbtk_sock_read(info->ftp_ssl_handle,info->session,mbtk_ftp_ssl_read_buf,sizeof(mbtk_ftp_ssl_read_buf),FTP_TIMEOUT,&err);
+            if(err != 0)
+            {
+                printf("\nmbtk_sock_read error:%d\n",err);
+            }
+            rsp_code = atoi(mbtk_ftp_ssl_read_buf);
+            printf("%s -> Code:%d; RSP:%s\n", (char*)cmd, rsp_code, (char* )mbtk_ftp_ssl_read_buf);
+            char *mbtk_ftp_ssl_read_buf_p = NULL;
+            mbtk_ftp_ssl_read_buf_p = strstr(mbtk_ftp_ssl_read_buf,"\n");
+            if(mbtk_ftp_ssl_read_buf_p!=NULL);
+            {
+                if(strlen(mbtk_ftp_ssl_read_buf_p)>1)
+                {
+                    mbtk_ftp_ssl_read_buf_p++;
+                    rsp_code = atoi(mbtk_ftp_ssl_read_buf_p);
+                }
+            }
+            if (rsp_code == 0)
+            {
+                goto read_angin_2;
+            }
+            return rsp_code;
+        }
+        else
+        {
+            len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT,
+                            &err);
+        }
+        if (len <= 0)
+        {
+            LOGE("Socket read fail[len = %d].", len);
+            return -1;
+        }
+
+        rsp_code = atoi(buff);
+        LOGI("%s -> Code:%d; RSP:%s", (char*)cmd, rsp_code, buff);
+        //log_hex("FTP_RSP",buff,len);
+
+        if (rsp_code == 0)
+        {
+            goto read_angin_2;
+        }
+    }
+
+    return rsp_code;
+}
+
+// Create data socket service and waitting client connect.
+static mbtk_ftp_error_enum ftp_data_sock_service_create(mbtk_ftp_sock_s *sock)
+{
+    return FTP_ERR_SUCCESS;
+}
+
+static bool ftp_internal_ipv4_check(void *ipv4)
+{
+    char *ip = (char*) ipv4;
+    int ip1 = atoi(ip);
+    ip = strstr(ip, ".");
+    if (!ip)
+        return FALSE;
+    int ip2 = atoi(ip + 1);
+
+    if (ip1 == 10)   // 10.x.x.x
+    {
+        return TRUE;
+    }
+    else if (ip1 == 172 && (ip2 >= 16 && ip2 <= 31))     // 172.16.0.0 ~ 172.31.255.255
+    {
+        return TRUE;
+    }
+    else if (ip1 == 192 && ip2 == 168)     // 192.168.x.x
+    {
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+static mbtk_ftp_error_enum ftp_sock_set_by_port(mbtk_ftp_info_s *info,
+        mbtk_ftp_sock_s *sock)
+{
+    // port = port1 * 256 + port2
+    // "PORT ip1,ip2,ip3,ip4,port1,port2\r\n"
+    int code;
+    char cmd_buff[100];
+    memset(cmd_buff, 0x0, 100);
+    if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6 || sock->port <= 1024
+        || strlen((char*) sock->host) == 0)
+    {
+        LOGE("FTP params set error.");
+        return FTP_ERR_PARAM_SET;
+    }
+
+    if (ftp_data_sock_service_create(sock) != FTP_ERR_SUCCESS)
+    {
+        LOGE("FTP data services create fail.");
+        return FTP_ERR_UNKNOWN;
+    }
+
+    uint8 *ptr = sock->host;
+    while (*ptr)
+    {
+        if (*ptr == '.')
+            *ptr = ',';
+        ptr++;
+    }
+    // Waitting client connect.
+    snprintf(cmd_buff, 100, "PORT %s,%d,%d\r\n", sock->host, sock->port / 256,
+             sock->port % 256);
+    code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+    if (code / 100 != 2)   // Not 2xx
+    {
+        LOGE("PORT rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_sock_set_by_eprt(mbtk_ftp_info_s *info,
+        mbtk_ftp_sock_s *sock)
+{
+    int code;
+    char cmd_buff[100];
+    memset(cmd_buff, 0x0, 100);
+    if (sock->port <= 1024 || strlen((char*) sock->host) == 0)
+    {
+        LOGE("FTP params set error.");
+        return FTP_ERR_PARAM_SET;
+    }
+    if (ftp_data_sock_service_create(sock) != FTP_ERR_SUCCESS)
+    {
+        LOGE("FTP data services create fail.");
+        return FTP_ERR_UNKNOWN;
+    }
+
+    // "EPRT |2|1080::8:800:200C:417A|5282|"
+    if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6)
+    {
+        uint8 *ptr = NULL;
+        if (sock->host[strlen((char*) sock->host) - 1] == ']')
+            sock->host[strlen((char*) sock->host) - 1] = '\0';
+
+        if (sock->host[0] == '[')
+            ptr = sock->host + 1;
+        else
+            ptr = sock->host;
+        snprintf(cmd_buff, 100, "EPRT |2|%s|%d|\r\n", ptr, sock->port);
+    }
+    else       // IPV4 "EPRT |1|132.235.1.2|6275|"
+    {
+        snprintf(cmd_buff, 100, "EPRT |1|%s|%d|\r\n", sock->host, sock->port);
+    }
+
+    code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+    if (code / 100 != 2)   // Not 2xx
+    {
+        LOGE("PORT rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_sock_get_by_pasv(mbtk_ftp_info_s *info,
+        mbtk_ftp_sock_s *sock)
+{
+    int code;
+    uint8 rsp[1024];
+    uint32 rsp_len = 1024;
+    memset(sock, 0x0, sizeof(mbtk_ftp_sock_s));
+    code = ftp_cmd_handle(info, "PASV\r\n", rsp, &rsp_len);
+    /* Found reply-strings include:
+     * "227 Entering Passive Mode (127,0,0,1,4,51)"
+     * "227 Data transfer will passively listen to 127,0,0,1,4,51"
+     * "227 Entering passive mode. 127,0,0,1,4,51"
+     */
+    if (code != 227)
+    {
+        LOGE("PASV rsp error[code = %d].", code);
+        if(code == 421)
+        {
+            printf("\n code:%d\n",code);
+            return FTP_ERR_UNKNOWN+1;
+        }
+        return FTP_ERR_UNKNOWN;
+    }
+
+    // Get IPv4 and port
+    uint8 *ptr = rsp + 4;
+    while (*ptr)
+    {
+        if (isdigit(*ptr))
+            break;
+        ptr++;
+    }
+    // ptr point to first digit.
+    memcpy(sock->host, ptr, strlen((char*) ptr));
+    ptr = sock->host;
+    int count = 0;
+    while (*ptr)
+    {
+        if (*ptr == ',')
+        {
+            *ptr = '.';
+            count++;
+        }
+        if (count == 4)
+        {
+            *ptr = '\0';
+            break;
+        }
+        ptr++;
+    }
+    ptr++;
+
+    // ptr point to first port digit.
+    int port1 = atoi((char*) ptr);
+    while (*ptr)
+    {
+        if (*ptr == ',')
+            break;
+        ptr++;
+    }
+    ptr++;
+
+    // ptr point to second port digit.
+    int port2 = atoi((char*) ptr);
+    sock->port = port1 * 256 + port2;
+
+    LOGI("PASV: %s:%d", sock->host, sock->port);
+
+    if(ftp_internal_ipv4_check(sock->host))
+    {
+        memset(sock->host,0x0,MBTK_FTP_IP_MAX + 1);
+        memcpy(sock->host,info->sock_info[FTP_SOCK_CTRL].host,strlen(info->sock_info[FTP_SOCK_CTRL].host));
+        LOGI("This is internal ipv4,so use IP - %s:%d",sock->host, sock->port);
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_sock_get_by_epsv(mbtk_ftp_info_s *info,
+        mbtk_ftp_sock_s *sock)
+{
+    int code;
+    char rsp[1024];
+    uint32 rsp_len = 1024;
+    memset(sock, 0x0, sizeof(mbtk_ftp_sock_s));
+    // |||6446|
+    code = ftp_cmd_handle(info, "EPSV\r\n", rsp, &rsp_len);
+    if (code != 229)
+    {
+        LOGE("EPSV rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    /* positive EPSV response */
+    char *ptr = strchr(rsp, '(');
+    if (ptr)
+    {
+        unsigned int num;
+        char separator[4];
+        ptr++;
+        if (5
+            == sscanf(ptr, "%c%c%c%u%c", &separator[0], &separator[1],
+                      &separator[2], &num, &separator[3]))
+        {
+            const char sep1 = separator[0];
+            int i;
+
+            /* The four separators should be identical, or else this is an oddly
+             formatted reply and we bail out immediately. */
+            for (i = 1; i < 4; i++)
+            {
+                if (separator[i] != sep1)
+                {
+                    ptr = NULL; /* set to NULL to signal error */
+                    break;
+                }
+            }
+            if (num > 0xffff)
+            {
+                LOGE("Illegal port number in EPSV reply");
+                return FTP_ERR_UNKNOWN;
+            }
+            if (ptr)
+            {
+                sock->port = (uint32) (num & 0xffff);
+                memcpy(sock->host, info->sock_info[FTP_SOCK_CTRL].host,
+                       strlen(info->sock_info[FTP_SOCK_CTRL].host));
+            }
+        }
+        else
+        {
+            ptr = NULL;
+        }
+    }
+    if (!ptr)
+    {
+        LOGE("Weirdly formatted EPSV reply");
+        return FTP_ERR_UNKNOWN;
+    }
+
+    LOGI("PASV: %s:%d", sock->host, sock->port);
+
+    return FTP_ERR_SUCCESS;
+}
+
+/*
+ * 04-26-20  02:13PM               379193 audio_0426.zip
+ * 09-10-20  02:31PM              4660645 Log.zip
+ * 10-28-20  01:53PM       <DIR>          PicLibs
+ */
+
+ /*
+ *-rw-r--r-- 1 ftp ftp     2097152000 Feb 18 17:28 ASR1803_Linux.tar.gz_aa
+ *-rw-r--r-- 1 ftp ftp     2097152000 Feb 18 17:21 ASR1803_Linux.tar.gz_ab
+ *-rw-r--r-- 1 ftp ftp     1198057917 Feb 18 17:29 ASR1803_Linux.tar.gz_ac
+ *-rw-r--r-- 1 ftp ftp         445043 Apr 06  2021 data
+ *drwxr-xr-x 1 ftp ftp              0 Apr 10  2021 L306
+ */
+static mbtk_ftp_error_enum ftp_cmd_list_parse(mbtk_ftp_info_s *info,
+        mbtk_ftp_file_info_s *file_list)
+{
+    char line[1024];
+    char line_buf[1024];
+    int len, err;
+    mbtk_ftp_file_info_s file_ptr;
+    memset(file_list, 0x0, sizeof(mbtk_ftp_file_info_s)-sizeof(void *));
+
+    // Save file number.
+    file_list->size = 0;
+    len = 1;
+    int read_line_count=0;
+    while (len > 0)
+    {
+        if(info->auth_type!=0)
+        {
+            len = mbtk_sock_readline(info->ftp_ssl_handle,info->session_data,line_buf,1024,FTP_TIMEOUT,&err,&read_line_count,line);
+        }
+        else
+        {
+            len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_DATA], line, 1024,FTP_TIMEOUT, &err);
+        }
+        LOGD("Line:%s", line);
+        if(len <= 0)
+            {
+                if (err == MBTK_SOCK_SUCCESS)
+                    return FTP_ERR_SUCCESS;
+                break;
+            }
+        else
+            len = strlen(line) - 1;
+        if (line[0] >= '0' && line[0] <= '9')
+        {
+            /*
+             * 04-26-20  02:13PM               379193 audio_0426.zip
+             * 09-10-20  02:31PM              4660645 Log.zip
+             * 10-28-20  01:53PM       <DIR>          PicLibs
+             */
+            line[len] = '\0';
+            /*
+            file_ptr = (mbtk_ftp_file_info_s*) malloc(
+                           sizeof(mbtk_ftp_file_info_s));
+            if (!file_ptr)
+            {
+                LOGE("malloc() fail.");
+                return FTP_ERR_UNKNOWN;
+            }
+            */
+            memset(&file_ptr, 0x0, sizeof(mbtk_ftp_file_info_s));
+
+            char str[MBTK_FTP_FILE_NAME_MAX];
+            const char *temp = line;
+            // Data
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            if (strlen(str) > 0)
+            {
+                LOGV("Data:%s", str);
+            }
+
+            // Time
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            if (strlen(str) > 0)
+            {
+                LOGV("Time:%s", str);
+            }
+
+            // <DIR> or file size
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            if (strlen(str) > 0)
+            {
+                LOGV("<DIR>/size:%s", str);
+                if (!strcmp("<DIR>", str))
+                {
+                    file_ptr.is_file = false;
+                    file_ptr.size = 0;
+                }
+                else
+                {
+                    file_ptr.is_file = true;
+                    file_ptr.size = atoi(str);
+                }
+            }
+
+            const char *name = temp;
+            while (*name && ftp_ch_is_space(*name))
+            {
+                name++;
+            }
+
+            // Name
+            if (strlen(name) > 0)
+            {
+                LOGV("Name:%s",name);
+                memset(file_ptr.name,0,strlen(file_ptr.name)+1);
+                memcpy(file_ptr.name, name, strlen(name));
+                char *temp = (char*) file_ptr.name
+                             + strlen((char*) file_ptr.name) - 1;
+                while (ftp_ch_is_space(*temp))
+                {
+                    *temp = '\0';
+                    temp--;
+                }
+            }
+            else
+            {
+                LOGE("Can not get name[%s].", line);
+                return FTP_ERR_UNKNOWN;
+            }
+
+            (file_list->ftp_ls_cb_typedef)(&file_ptr);
+            //file_ptr->next = file_list->next;
+            //file_list->next = file_ptr;
+            //file_list->size++;
+            //free(file_ptr);
+        } else if(!ftp_ch_is_space(line[0])) {
+             /*
+             *-rw-r--r-- 1 ftp ftp     2097152000 Feb 18 17:28 ASR1803_Linux.tar.gz_aa
+             *-rw-r--r-- 1 ftp ftp     2097152000 Feb 18 17:21 ASR1803_Linux.tar.gz_ab
+             *-rw-r--r-- 1 ftp ftp     1198057917 Feb 18 17:29 ASR1803_Linux.tar.gz_ac
+             *-rw-r--r-- 1 ftp ftp         445043 Apr 06  2021 data
+             *drwxr-xr-x 1 ftp ftp              0 Apr 10  2021 L306
+             */
+            line[len] = '\0';
+             /*
+            file_ptr = (mbtk_ftp_file_info_s*) malloc(
+                           sizeof(mbtk_ftp_file_info_s));
+            if (!file_ptr)
+            {
+                LOGE("malloc() fail.");
+                return FTP_ERR_UNKNOWN;
+            }
+            */
+            memset(&file_ptr, 0x0, sizeof(mbtk_ftp_file_info_s));
+
+            char str[MBTK_FTP_FILE_NAME_MAX];
+            const char *temp = line;
+            // rwx
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            if (strlen(str) > 0)
+            {
+                LOGV("rwx:%s", str);
+                file_ptr.is_file = (str[0] == '-' ? true : false);
+            }
+
+            // 1 ftp ftp
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+
+            // size
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            if (strlen(str) > 0)
+            {
+                LOGV("Size:%s", str);
+                file_ptr.size = atoi(str);
+            }
+
+            // Feb 18 17:28
+            // or
+            // Apr 10  2021
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+            temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+
+            const char *name = temp;
+            while (*name && ftp_ch_is_space(*name))
+            {
+                name++;
+            }
+
+            // Name
+            if (strlen(name) > 0)
+            {
+                LOGV("Name:%s",name);
+                memset(file_ptr.name,0,strlen(file_ptr.name)+1);
+                memcpy(file_ptr.name, name, strlen(name));
+                char *temp = (char*) file_ptr.name
+                             + strlen((char*) file_ptr.name) - 1;
+                while (ftp_ch_is_space(*temp))
+                {
+                    *temp = '\0';
+                    temp--;
+                }
+            }
+            else
+            {
+                LOGE("Can not get name[%s].", line);
+                return FTP_ERR_UNKNOWN;
+            }
+
+            (file_list->ftp_ls_cb_typedef)(&file_ptr);
+            //file_ptr->next = file_list->next;
+            //file_list->next = file_ptr;
+            //file_list->size++;
+            //free(file_ptr);
+        }else {
+            LOGE("Data error.");
+            return FTP_ERR_UNKNOWN;
+        }
+    }
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_download_process(mbtk_ftp_info_s *info)
+{
+#define READ_BUF_SIZE 2048
+    char buff[READ_BUF_SIZE];
+    int len, err, len_read;
+    int read_count = info->file_trans.size_send;
+
+#ifdef FTP_RESUME_DEBUG
+    int count = 0;
+#endif
+
+    if (info->file_trans.size_count - read_count > READ_BUF_SIZE)
+        len_read = READ_BUF_SIZE;
+    else
+        len_read = info->file_trans.size_count - read_count;
+
+    if(info->auth_type != 0)
+        len = mbtk_sock_read(info->ftp_ssl_handle,info->session_data,buff,len_read,FTP_TIMEOUT,&err);
+    else
+        len = sock_read(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_read,FTP_TIMEOUT, &err);
+    /*
+    while (len_read > 0 && (len = sock_read(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_read,
+                                    FTP_TIMEOUT, &err)) > 0)
+    */
+    while (len_read > 0 && len > 0)
+    {
+        read_count += len;
+
+#ifdef FTP_RESUME_DEBUG
+        count++;
+        if (count <= 1000)
+        {
+#endif
+            if (info->file_trans.data_cb)
+            {
+                info->file_trans.data_cb(buff, len);
+            }
+            else     // Write to efs.
+            {
+                if (len != file_write(info->file_trans.fd, buff, len))
+                {
+                    LOGE("EFS write fail.");
+                    return FTP_ERR_EFS_FILE;
+                }
+            }
+            memset(buff,0,sizeof(buff));
+            info->file_trans.size_send = read_count;
+#ifdef FTP_RESUME_DEBUG
+        }
+#endif
+
+        if (info->file_trans.size_count - read_count > READ_BUF_SIZE)
+            len_read = READ_BUF_SIZE;
+        else
+            len_read = info->file_trans.size_count - read_count;
+
+        if(info->auth_type != 0)
+            len = mbtk_sock_read(info->ftp_ssl_handle,info->session_data,buff,len_read,FTP_TIMEOUT,&err);
+        else
+            len = sock_read(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_read,FTP_TIMEOUT, &err);
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_update_process(mbtk_ftp_info_s *info)
+{
+#define READ_BUF_SIZE 2048
+    char buff[READ_BUF_SIZE];
+    int len, err, len_write;
+	int file_total_size = 0;
+    int write_count = 0;
+
+	if(info->file_trans.fd > 0)
+	{
+		file_total_size = file_length(info->file_trans.fd);
+        info->file_trans.size_count = file_total_size;
+		while((len_write = file_read(info->file_trans.fd, buff, READ_BUF_SIZE)) > 0 )
+		{
+			LOGE("file_read.len:%d, buf;%s", len_write, buff);
+            if(info->auth_type != 0)
+                len = mbtk_sock_write(info->ftp_ssl_handle,info->session_data,buff,len_write,FTP_TIMEOUT,&err);
+            else
+			    len = sock_write(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_write,
+                                    FTP_TIMEOUT, &err);
+			if(len < 0)
+			{
+				LOGE("EFS write fail.len:%d, err;%d", len, err);
+                return FTP_ERR_EFS_FILE;
+			}
+
+			write_count += len;
+		}
+
+        info->file_trans.size_send = write_count;
+		if( write_count != file_total_size)
+		{
+			LOGE("socket write fail.,file_total_size:%d, write_count:%d", file_total_size,write_count);
+            return FTP_ERR_NET_WRITE;
+		}
+		else{
+			LOGE("socket write success.,file_total_size:%d, write_count:%d", file_total_size, write_count);
+		}
+
+	}
+	else
+	{
+		LOGE("EFS write fail.");
+        return FTP_ERR_EFS_FILE;
+	}
+
+	return FTP_ERR_SUCCESS;
+}
+
+
+/*
+ * audio_0426.zip
+ * Log.zip
+ * PicLibs
+ */
+static mbtk_ftp_error_enum ftp_cmd_nlst_parse(mbtk_ftp_info_s *info,
+        mbtk_ftp_file_info_s *file_list)
+{
+    char line[1024];
+    int len, err;
+    mbtk_ftp_file_info_s *file_ptr = NULL;
+    while ((len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_DATA], line, 1024,
+                                FTP_TIMEOUT, &err)) > 0)
+    {
+        if (!ftp_ch_is_space(line[0]))
+        {
+            file_ptr = (mbtk_ftp_file_info_s*) malloc(
+                           sizeof(mbtk_ftp_file_info_s));
+            if (!file_ptr)
+            {
+                LOGE("malloc() fail.");
+                return FTP_ERR_UNKNOWN;
+            }
+            memset(file_ptr, 0x0, sizeof(mbtk_ftp_file_info_s));
+            memcpy(file_ptr->name, line, strlen(line));
+            char *temp = (char*) file_ptr->name + strlen((char*) file_ptr->name)
+                         - 1;
+            while (ftp_ch_is_space(*temp))
+            {
+                *temp = '\0';
+                temp--;
+            }
+
+            file_ptr->next = file_list->next;
+            file_list->next = file_ptr;
+        }
+    }
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_data_sock_read(mbtk_ftp_info_s *info,
+        mbtk_ftp_cmd_enum cmd, void *req, void *rsp)
+{
+    int err, len, code;
+    mbtk_ftp_error_enum result = FTP_ERR_SUCCESS;
+    char buff[1024];
+    if (info->is_data_sock_busy)
+    {
+        LOGW("Data socket is busy!");
+        return FTP_ERR_DATA_SOCK_BUSY;
+    }
+
+    info->is_data_sock_busy = true;
+    // Connect to service by data socket.
+    if (info->data_mode == FTP_MODE_PASSIVE)
+    {
+        mbtk_ftp_sock_s sock;
+        if(info->auth_type != FTP_AUTH_TYPE_NON) {
+            // PROT P
+            char cmd_ssl[50];
+            memset(cmd_ssl,0,50);
+            snprintf(cmd_ssl, 50, "PROT P\r\n");
+            code = ftp_cmd_handle(info, cmd_ssl, NULL,NULL);
+            if (code/100 != 2)
+            {
+                LOGE("PROT P error[code = %d].", code);
+                goto end;
+            }
+        }
+
+        if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6)
+        {
+            if ((result = ftp_sock_get_by_epsv(info, &sock))
+                != FTP_ERR_SUCCESS)
+            {
+                goto end;
+            }
+        }
+        else
+        {
+            if ((result = ftp_sock_get_by_pasv(info, &sock))
+                != FTP_ERR_SUCCESS)
+            {
+                printf("\nftp_sock_get_by_pasv end.result=%d\n",result);
+            }
+            else
+            {
+                printf("\nftp_sock_get_by_pasv ok!\n");
+            }
+        }
+
+        if(info->auth_type != FTP_AUTH_TYPE_NON)
+        {
+            info->ftp_ssl_handle_data = mbtk_sock_init(&info->ftp_ssl_info_data);
+            if(info->ftp_ssl_handle_data == -1)
+            {
+                printf("mbtk_sock_init error\n");
+            }
+            info->ftp_sock_ssl_info_data = (mbtk_sock_info*) malloc(sizeof(mbtk_sock_info));
+            memset(info->ftp_sock_ssl_info_data, 0x0, sizeof(mbtk_sock_info));
+            info->ftp_sock_ssl_info_data->is_support_ssl = info->auth_type;
+            info->ftp_sock_ssl_info_data->ftp_ssl_support=1;
+            info->ftp_sock_ssl_info_data->port = sock.port;
+            info->ftp_sock_ssl_info_data->type = MBTK_SOCK_TCP;
+            info->ftp_sock_ssl_info_data->ingnore_cert = ~(info->sock_info[FTP_SOCK_CTRL].use_cert);
+            memcpy(info->ftp_sock_ssl_info_data->address, sock.host, strlen(sock.host));
+            if(info->ftp_sock_ssl_info_data->is_support_ssl != 0)
+            {
+                info->ftp_sock_ssl_info_data->is_support_ssl = 0;
+            }
+            info->session_data = mbtk_sock_open(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data,60000,&err);
+            if(err!=0)
+            {
+                printf("mbtk_sock_open error : %d\n",err);
+            }
+            else
+            {
+                info->ftp_sock_ssl_info_data->is_support_ssl = info->auth_type;
+                //printf("\ninfo->session_data = %d \n",info->session_data);
+            }
+        }
+        else
+        {
+            memcpy(info->sock_info[FTP_SOCK_DATA].host, sock.host, strlen((char*)sock.host));
+            info->sock_info[FTP_SOCK_DATA].port = sock.port;
+            info->sock_info[FTP_SOCK_DATA].is_ssl = (info->auth_type != FTP_AUTH_TYPE_NON);
+            info->sock_info[FTP_SOCK_DATA].addr_family = info->sock_info[FTP_SOCK_CTRL].addr_family;
+            info->sock_info[FTP_SOCK_DATA].use_cert = info->sock_info[FTP_SOCK_CTRL].use_cert;
+            info->net_info.keep_alive = FALSE;
+            info->net_info.recv_buff_size = 32 * 1024; // 32K
+            info->sock_info[FTP_SOCK_DATA].fd = sock_open(&info->net_info, &info->sock_info[FTP_SOCK_DATA],
+                                                    FTP_TIMEOUT, &err);
+        }
+
+    }
+    else    // Active mode
+    {
+        if (req == NULL)
+        {
+            result = FTP_ERR_PARAM_SET;
+            goto end;
+        }
+        mbtk_ftp_sock_s *sock = (mbtk_ftp_sock_s*) req;
+
+        if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6)
+        {
+            if ((result = ftp_sock_set_by_eprt(info, sock))
+                != FTP_ERR_SUCCESS)
+            {
+                goto end;
+            }
+        }
+        else
+        {
+            if ((result = ftp_sock_set_by_port(info, sock))
+                != FTP_ERR_SUCCESS)
+            {
+                goto end;
+            }
+        }
+
+        // Wait for client[service] connect.
+
+    }
+    if(info->auth_type != FTP_AUTH_TYPE_NON)
+    {
+        if(info->session_data < 0)
+        {
+               //printf("Socket open/connect ssl fail[err = %d].", err);
+               result = FTP_ERR_NET_CONN;
+               goto read_end;
+        }
+    }
+    else
+    {
+        if (info->sock_info[FTP_SOCK_DATA].fd < 0)
+        {
+            LOGE("Socket open/connect fail[err = %d].", err);
+            result = FTP_ERR_NET_CONN;
+            goto read_end;
+        }
+
+        if(info->auth_type == FTP_AUTH_TYPE_IMPLICIT) {
+            info->sock_info[FTP_SOCK_DATA].is_ssl = true;
+        }
+    }
+
+    if (cmd == FTP_CMD_GET)   // Is download
+    {
+        char cmd[100];
+        if (info->file_trans.size_send > 0)   // Resume transmission
+        {
+            // REST size
+            memset(cmd, 0x0, 100);
+            snprintf(cmd, 100, "REST %ld\r\n", info->file_trans.size_send);
+            code = ftp_cmd_handle(info, cmd, NULL, NULL);
+            if (code != 350)
+            {
+                LOGE("REST rsp error[code = %d].", code);
+                result = FTP_ERR_UNKNOWN;
+                goto end;
+            }
+        }
+
+        memset(cmd, 0x0, 100);
+        snprintf(cmd, 100, "RETR %s\r\n", info->file_trans.remote_name);
+        code = ftp_cmd_handle(info, cmd, NULL, NULL);
+        if (code != 125 && code != 150)
+        {
+            LOGE("RETR %s rsp error[code = %d].", info->file_trans.remote_name,
+                 code);
+            result = FTP_ERR_UNKNOWN;
+            goto end;
+        }
+        
+        int mbtk_errno;
+        if(info->auth_type != 0)
+        {
+            mbtk_errno = mbtk_ssl_init_func(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data->ingnore_cert,info->session_data);
+            if(mbtk_errno != 0)
+            {
+                printf("\nmbtk_ssl_init_func error = %d",mbtk_errno);
+                goto end;
+            }
+            
+        }
+        result = ftp_download_process(info);
+        if(info->auth_type != 0)
+        {
+            char mbtk_ftp_ssl_read_buf[256];
+            memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+            mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                                       mbtk_ftp_ssl_read_buf,
+                                       sizeof(mbtk_ftp_ssl_read_buf),
+                                       6000,
+                                       &mbtk_errno);
+            printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf);
+        }
+        if(info->auth_type != 0)
+            goto read_end;
+    }
+	else if (cmd == FTP_CMD_PUT)   // Is download
+    {
+        if(info->auth_type != 0)
+        {
+                int mbtk_errno;
+                char cmd[100];
+                memset(cmd, 0x0, 100);
+                snprintf(cmd, 100, "STOR %s\r\n", info->file_trans.remote_name);
+        		LOGE("STOR %s .name:%s ", cmd, info->file_trans.remote_name);
+                code = ftp_cmd_handle(info, cmd, NULL, NULL);
+                if (code != 125 && code != 150)
+                {
+                    LOGE("RETR %s rsp error[code = %d].", info->file_trans.remote_name,
+                         code);
+                    //printf("RETR %s rsp error[code = %d].\n", info->file_trans.remote_name,code);
+                    result = FTP_ERR_UNKNOWN;
+                    goto end;
+                }
+                
+                mbtk_errno = mbtk_ssl_init_func(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data->ingnore_cert,info->session_data);
+                if(mbtk_errno != 0)
+                {
+                    printf("\nmbtk_ssl_init_func error = %d",mbtk_errno);
+                    goto end;
+                }
+                if(info->file_trans.size_count == 0)
+            	{
+            	    result = ftp_update_process(info);
+            	    goto read_end;
+            	}
+            	else 
+            	{
+                    //printf("FTP_SOCK_DATA,fd:%d\n",info->file_trans.size_count);
+            	    return FTP_ERR_SUCCESS;
+            	}
+            goto end;
+        }
+        else
+        {
+            char cmd[100];
+            memset(cmd, 0x0, 100);
+            snprintf(cmd, 100, "STOR %s\r\n", info->file_trans.remote_name);
+    		LOGE("STOR %s .name:%s ", cmd, info->file_trans.remote_name);
+            code = ftp_cmd_handle(info, cmd, NULL, NULL);
+            if (code != 125 && code != 150)
+            {
+                LOGE("RETR %s rsp error[code = %d].", info->file_trans.remote_name,
+                     code);
+                result = FTP_ERR_UNKNOWN;
+                goto end;
+            }
+    		
+        	if(info->file_trans.size_count == 0)
+        	{
+        	    result = ftp_update_process(info);
+        	    goto read_end;
+        	}
+        	else 
+        	{
+                    LOGE("FTP_SOCK_DATA,fd:%d", info->sock_info[FTP_SOCK_DATA].fd);
+        	    return FTP_ERR_SUCCESS;
+        	}
+        }
+    }
+    else if (cmd == FTP_CMD_LIST)
+    {
+        if(info->auth_type != 0)
+        {
+        	int mbtk_errno;
+        	code = ftp_cmd_handle(info, "LIST\r\n", NULL, NULL);
+        	if (code != 125 && code != 150)
+            {
+            	LOGE("LIST rsp error[code = %d].", code);
+                result = FTP_ERR_UNKNOWN;
+                goto read_end;
+            }
+
+            mbtk_errno = mbtk_ssl_init_func(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data->ingnore_cert,info->session_data);
+            if(mbtk_errno != 0)
+            {
+            	printf("\nmbtk_ssl_init_func error = %d",mbtk_errno);
+                goto read_end;
+            }
+
+            result = ftp_cmd_list_parse(info, (mbtk_ftp_file_info_s*) rsp);
+            char mbtk_ftp_ssl_read_buf[1024];
+            memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+            mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                                mbtk_ftp_ssl_read_buf,
+                                sizeof(mbtk_ftp_ssl_read_buf),
+                                6000,
+                                &mbtk_errno);
+            printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf);
+            int rsp_code = atoi(mbtk_ftp_ssl_read_buf);
+            if(rsp_code / 200)
+            	result = FTP_ERR_SUCCESS;
+            goto read_end;
+        }
+        else
+        {
+            code = ftp_cmd_handle(info, "LIST\r\n", NULL, NULL);
+            if (code != 125 && code != 150)
+            {
+                LOGE("LIST rsp error[code = %d].", code);
+                result = FTP_ERR_UNKNOWN;
+                goto end;
+            }
+
+            result = ftp_cmd_list_parse(info, (mbtk_ftp_file_info_s*) rsp);
+        }
+    }
+    else if (cmd == FTP_CMD_NLST)
+    {
+        code = ftp_cmd_handle(info, "NLST\r\n", NULL, NULL);
+        if (code != 125 && code != 150)
+        {
+            LOGE("LIST rsp error[code = %d].", code);
+            result = FTP_ERR_UNKNOWN;
+            goto end;
+        }
+
+        result = ftp_cmd_nlst_parse(info, (mbtk_ftp_file_info_s*) rsp);
+    }
+    else
+    {
+        LOGE("No support this cmd[%d].", cmd);
+        result = FTP_ERR_UNKNOWN;
+        goto read_end;
+    }
+
+    // Read [226 Transfer complete.]
+read_code:
+    memset(buff, 0x0, 1024);
+    len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT,
+                    &err);
+    if (len <= 0)
+    {
+        LOGE("Socket read fail[len = %d].", len);
+        result = FTP_ERR_NET_READ;
+        goto sock_error;
+    }
+    LOGI("RSP[len-%d]:%s",len,buff);
+    //log_hex("FTP_RSP",buff,len);
+    code = atoi(buff);
+    if (code == 0)
+    {
+        goto read_code;
+    }
+#if 1
+    // 426 Connection closed; aborted transfer of "/files/test"
+    else if (code == 426)
+    {
+        LOGE("Connection closed,restart download...");
+        result = FTP_ERR_UNKNOWN;
+        goto sock_error;
+    }
+#endif
+    else if (code != 226)
+    {
+        LOGE("Code not be 226[%s].", buff);
+        result = FTP_ERR_UNKNOWN;
+        goto read_end;
+    }
+
+    goto read_end;
+sock_error:
+    {
+        if (info->sock_info[FTP_SOCK_CTRL].fd > 0)
+        {
+            if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err))
+            {
+                LOGE("Close ctrl socket fail[%d].", err);
+            }
+        }
+        info->state = FTP_STATE_NON;
+        info->sock_info[FTP_SOCK_CTRL].fd = -1;
+    }
+read_end:
+    // Close data socket.
+    if (info->sock_info[FTP_SOCK_DATA].fd > 0)
+    {
+        if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+        {
+            LOGE("Close data socket fail[%d].", err);
+            result = FTP_ERR_NET_CLOSE;
+        }
+        else
+        {
+            info->sock_info[FTP_SOCK_DATA].fd = -1;
+        }
+    }
+    if(info->auth_type != 0)
+    {
+        if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+        {
+            LOGE("Close ssl data socket fail[%d].", err);
+            result = FTP_ERR_NET_CLOSE;
+        }
+        else
+        {
+        //    info->sock_info[FTP_SOCK_DATA].fd = -1;
+        }
+    }
+    if (info->data_mode == FTP_MODE_PASSIVE)
+    {
+
+    }
+    else
+    {
+
+    }
+
+end:
+    // Default is passive.
+    info->data_mode = FTP_MODE_PASSIVE;
+    info->is_data_sock_busy = false;
+
+    return result;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_pwd(mbtk_ftp_info_s *info,
+        char *path)
+{
+    int code;
+    char rsp[100];
+    uint32 rsp_len = 100;
+    code = ftp_cmd_handle(info, "PWD\r\n", rsp, &rsp_len);
+    if (code != 257)
+    {
+        LOGE("PWD rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    // "path" is current ....
+    char *ptr = strchr(rsp, '"');
+    if (!ptr)
+    {
+        LOGE("PWD rsp error[%d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    ptr++;
+    char *ptr_temp = ptr;
+    while (*ptr_temp)
+    {
+        if (*ptr_temp == '"')
+        {
+            *ptr_temp = '\0';
+            break;
+        }
+        ptr_temp++;
+    }
+    memcpy(path, ptr, strlen(ptr));
+    path[strlen(ptr)] = '\0';
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_cwd(mbtk_ftp_info_s *info,
+        const char *path)
+{
+    int code;
+    char cmd[100] = { 0 };
+    snprintf(cmd, 100, "CWD %s\r\n", path);
+    code = ftp_cmd_handle(info, cmd, NULL, NULL);
+    if (code != 250)
+    {
+        LOGE("CWD rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_mkd(mbtk_ftp_info_s *info,
+        const char *path)
+{
+    int code;
+    char cmd[100] = { 0 };
+    snprintf(cmd, 100, "MKD %s\r\n", path);
+    code = ftp_cmd_handle(info, cmd, NULL, NULL);
+    if (code == 257)
+    {
+        return FTP_ERR_SUCCESS;
+    }
+    else if (code == 550)
+    {
+        LOGE("Dir has exist[%s].", path);
+        return FTP_ERR_FILE_EXIST;
+    }
+    else
+    {
+        LOGE("MKD rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_rmd(mbtk_ftp_info_s *info,
+        const char *path)
+{
+    int code;
+    char cmd[100] = { 0 };
+    snprintf(cmd, 100, "RMD %s\r\n", path);
+    code = ftp_cmd_handle(info, cmd, NULL, NULL);
+    if (code == 250)
+    {
+        return FTP_ERR_SUCCESS;
+    }
+    else if (code == 550)
+    {
+        LOGE("Dir not exist or not empty[%s].", path);
+        return FTP_ERR_FILE_NO_FOUND;
+    }
+    else
+    {
+        LOGE("RMD rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_stat(mbtk_ftp_info_s *info,
+        void *status)
+{
+    int code;
+    char rsp[1024];
+    uint32 rsp_len = 1024;
+    code = ftp_cmd_handle(info, "STAT\r\n", rsp, &rsp_len);
+    if (code != 211)
+    {
+        LOGE("STAT rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    memcpy(status, rsp, rsp_len);
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_type(mbtk_ftp_info_s *info,
+        mbtk_ftp_data_type_enum type)
+{
+    int code;
+    if (type == FTP_DATA_TYPE_I)
+        code = ftp_cmd_handle(info, "TYPE I\r\n", NULL, NULL);
+    else if (type == FTP_DATA_TYPE_E)
+        code = ftp_cmd_handle(info, "TYPE E\r\n", NULL, NULL);
+    else
+        code = ftp_cmd_handle(info, "TYPE A\r\n", NULL, NULL);
+
+    if (code != 200)
+    {
+        LOGE("TYPE rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_size(mbtk_ftp_info_s *info,
+        const char *path, uint32 *size)
+{
+    int code;
+    char cmd[100] = { 0 };
+    char rsp[100];
+    uint32 rsp_len = 100;
+    snprintf(cmd, 100, "SIZE %s\r\n", path);
+    code = ftp_cmd_handle(info, cmd, rsp, &rsp_len);
+
+    if (code == 213)
+    {
+        // "213 4660645"
+        *size = atoi(rsp + 4);
+    }
+    else if (code == 550)
+    {
+        LOGW("No found file[%s].", path);
+        return FTP_ERR_FILE_NO_FOUND;
+    }
+    else
+    {
+        LOGE("SIZE rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_mdtm(mbtk_ftp_info_s *info,
+        const char *path, char *time)
+{
+    int code;
+    char cmd[100] = { 0 };
+    char rsp[100];
+    uint32 rsp_len = 100;
+    snprintf(cmd, 100, "MDTM %s\r\n", path);
+    code = ftp_cmd_handle(info, cmd, rsp, &rsp_len);
+
+    if (code == 213)
+    {
+        // "213 20181017014716"
+        memcpy(time, rsp + 4, 14);
+    }
+    else if (code == 550)
+    {
+        LOGW("No found file[%s].", path);
+        return FTP_ERR_FILE_NO_FOUND;
+    }
+    else
+    {
+        LOGE("MDTM rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_dele(mbtk_ftp_info_s *info,
+        const char *path)
+{
+    int code;
+    char cmd[100] = { 0 };
+    snprintf(cmd, 100, "DELE %s\r\n", path);
+    code = ftp_cmd_handle(info, cmd, NULL, NULL);
+    if (code == 250)
+    {
+        return FTP_ERR_SUCCESS;
+    }
+    else if (code == 550)
+    {
+        LOGW("No found file[%s].", path);
+        return FTP_ERR_FILE_NO_FOUND;
+    }
+    else
+    {
+        LOGE("DELE rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_quit(mbtk_ftp_info_s *info)
+{
+    int code;
+    code = ftp_cmd_handle(info, "QUIT\r\n", NULL, NULL);
+    if (code != 221)
+    {
+        LOGE("CWD rsp error[code = %d].", code);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process(mbtk_ftp_info_s *info,
+        mbtk_ftp_cmd_enum cmd, void *req, void *rsp)
+{
+    mbtk_ftp_error_enum result = FTP_ERR_SUCCESS;
+    if (info->state == FTP_STATE_READY)   // FTP login
+    {
+        info->state = FTP_STATE_CMD_PROCESS;
+        switch (cmd)
+        {
+            case FTP_CMD_LIST:
+            {
+                result = ftp_data_sock_read(info, FTP_CMD_LIST, req, rsp);
+                break;
+            }
+            case FTP_CMD_NLST:
+            {
+                result = ftp_data_sock_read(info, FTP_CMD_NLST, req, rsp);
+                break;
+            }
+            case FTP_CMD_PWD:
+            {
+                result = ftp_cmd_process_pwd(info, rsp);
+                break;
+            }
+            case FTP_CMD_CWD:
+            {
+                result = ftp_cmd_process_cwd(info, (char*) req);
+                break;
+            }
+            case FTP_CMD_MKD:
+            {
+                result = ftp_cmd_process_mkd(info, (char*) req);
+                break;
+            }
+            case FTP_CMD_RMD:
+            {
+                result = ftp_cmd_process_rmd(info, (char*) req);
+                break;
+            }
+            case FTP_CMD_STAT:
+            {
+                result = ftp_cmd_process_stat(info, rsp);
+                break;
+            }
+            case FTP_CMD_TYPE:
+            {
+                mbtk_ftp_data_type_enum *type = (mbtk_ftp_data_type_enum*) req;
+                result = ftp_cmd_process_type(info, *type);
+                break;
+            }
+            case FTP_CMD_SIZE:
+            {
+                result = ftp_cmd_process_size(info, (char*) req, (uint32*) rsp);
+                break;
+            }
+            case FTP_CMD_MDTM:
+            {
+                result = ftp_cmd_process_mdtm(info, (char*) req, (char*) rsp);
+                break;
+            }
+            case FTP_CMD_DELE:
+            {
+                result = ftp_cmd_process_dele(info, (char*) req);
+                break;
+            }
+            case FTP_CMD_QUIT:
+            {
+                result = ftp_cmd_process_quit(info);
+                break;
+            }
+            default:
+            {
+                LOGE("Unknown cmd:%d", cmd);
+                result = FTP_ERR_UNKNOWN;
+                break;
+            }
+        }
+        info->state = FTP_STATE_READY;
+    }
+    else
+    {
+        LOGW("FTP state error[%d].", info->state);
+        result = FTP_ERR_UNKNOWN;
+    }
+
+    return result;
+}
+
+static mbtk_ftp_error_enum ftp_login(mbtk_ftp_info_s *info,mbtk_ftp_user_info_s *user)
+{
+    // Open net in the first.
+    if(info->net_info.net_id <= 0) {
+        if(sock_net_open(&info->net_info,info->sock_info[FTP_SOCK_CTRL].addr_family))
+        {
+            LOGE("sock_net_open() fail.");
+            return FTP_ERR_NET_CONN;
+        }
+    }
+
+    int err;
+    mbtk_ftp_error_enum ftp_err = FTP_ERR_SUCCESS;
+    info->state = FTP_STATE_CONNECTING;
+    info->net_info.keep_alive = TRUE;
+    info->net_info.recv_buff_size = 0; // Default
+    info->sock_info[FTP_SOCK_CTRL].fd = sock_open(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err);
+    if (info->sock_info[FTP_SOCK_CTRL].fd < 0)   // Fail
+    {
+        LOGE("Socket open/connect fail[err = %d].", err);
+        ftp_err = FTP_ERR_NET_CONN;
+        goto login_fail;
+    }
+
+    if(info->auth_type == FTP_AUTH_TYPE_IMPLICIT)
+        info->sock_info[FTP_SOCK_CTRL].is_ssl = true;
+
+    // Ctrl socket connect success.
+    info->state = FTP_STATE_CONNECTED;
+    LOGI("FTP ctrl socket connected.");
+
+    char buff[1024];
+    int len;
+    char *ptr = NULL;
+
+    // 220-FileZilla Server version 0.9.43 beta
+    // 220-written by Tim Kosse (tim.kosse@filezilla-project.org)
+    // 220 Please visit http://sourceforge.net/projects/filezilla/
+    while(TRUE) {
+        memset(buff, 0x0, 1024);
+        len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT,
+                            &err);
+        if (len <= 0)
+        {
+            LOGE("Socket read fail[err = %d].", err);
+            ftp_err = FTP_ERR_NET_READ;
+            goto login_fail;
+        } else {// xxx yyyyyy
+            if((ptr = strstr(buff,"220 ")) || (ptr = strstr(buff,"230 "))) {
+                LOGI("RSP:%s",ptr);
+                break;
+            }
+        }
+    }
+
+    int code = atoi(ptr);
+    if (code == 230)   // Has logged in.
+    {
+        info->state = FTP_STATE_READY;
+        LOGI("FTP Has logged in.");
+        return FTP_ERR_SUCCESS;
+    }
+    else if (code == 220)       // Should logn in.
+    {
+        int len;
+        char cmd_buff[50];
+
+#if 0
+        // Read other data.
+        char buff[1024];
+        memset(buff,0x0,1024);
+        while((len = sock_read(&info->net_info,info->ctrl_sock.fd, buff, 1024, info->ssl_enable, 1000,
+                                &err)) > 0)
+        {
+            LOGI("RSP[%d]:%s",len,buff);
+            memset(buff,0x0,1024);
+        }
+#endif
+
+        if(info->auth_type == FTP_AUTH_TYPE_EXPLICIT_SSL
+            || info->auth_type == FTP_AUTH_TYPE_EXPLICIT_TLS) {
+            if(info->auth_type == FTP_AUTH_TYPE_EXPLICIT_SSL) {
+                len = snprintf(cmd_buff, 50, "AUTH SSL\r\n");
+            } else {
+                len = snprintf(cmd_buff, 50, "AUTH TLS\r\n");
+            }
+            cmd_buff[len] = '\0';
+            code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+            if (code != 234 && code != 334)
+            {
+                LOGE("AUTH SSL/TLS fail[code = %d].", code);
+                ftp_err = FTP_ERR_LOGIN_DENIED;
+                goto login_fail;
+            }
+
+#if 0
+            if(sock_ssl_enable(&info->net_info,info->ctrl_sock.fd
+                ,info->ctrl_sock.host,info->ctrl_sock.port,info->use_cert,FTP_TIMEOUT)){
+                LOGE("sock_ssl_enable() fail.");
+                ftp_err = FTP_ERR_LOGIN_DENIED;
+                goto login_fail;
+            }
+#endif
+            info->sock_info[FTP_SOCK_CTRL].is_ssl = true;
+        }
+
+        if(info->auth_type != FTP_AUTH_TYPE_NON) {
+            len = snprintf(cmd_buff, 50, "PBSZ 0\r\n");
+            cmd_buff[len] = '\0';
+            code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+            if (code != 200 && code != 220)
+            {
+                LOGE("PBSZ 0 fail[code = %d].", code);
+                ftp_err = FTP_ERR_LOGIN_DENIED;
+                goto login_fail;
+            }
+        }
+
+        len = snprintf(cmd_buff, 50, "USER %s\r\n", user->name);
+        cmd_buff[len] = '\0';
+        code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+        if (code == 331) // USER is 331
+        {
+            len = snprintf(cmd_buff, 50, "PASS %s\r\n", user->pass);
+            cmd_buff[len] = '\0';
+            code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+        }
+
+        if (code / 100 == 2)   // USER/PASS is 2xx
+        {
+            info->state = FTP_STATE_READY;
+            LOGI("FTP logn in success.");
+            return FTP_ERR_SUCCESS;
+        }
+        else if (code == 332)   // // USER/PASS is 332
+        {
+            LOGW("Should set ACCT.");
+            ftp_err = FTP_ERR_UNKNOWN;
+            goto login_fail;
+        }
+        else
+        {
+            LOGE("FTP login denied[code = %d].", code);
+            ftp_err = FTP_ERR_LOGIN_DENIED;
+            goto login_fail;
+        }
+    }
+    else
+    {
+        LOGE("FTP code error[%d].", code);
+        ftp_err = FTP_ERR_UNKNOWN;
+        goto login_fail;
+    }
+
+login_fail:
+    info->state = FTP_STATE_NON;
+    return ftp_err;
+}
+
+static mbtk_ftp_info_s* ftp_info_find(mbtk_ftp_handle handle)
+{
+    if (!ftp_client_list)
+    {
+        LOGE("FTP Client List not init.");
+        return NULL;
+    }
+
+    mbtk_ftp_info_s *result = NULL;
+    list_first(ftp_client_list);
+    while ((result = (mbtk_ftp_info_s*) list_next(ftp_client_list)))
+    {
+        if (result->handle == handle)
+            break;
+    }
+
+    return result;
+}
+
+mbtk_ftp_handle mbtk_ftp_upload_end(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        printf("No such FTP handle:%d\n", handle);
+    }
+    
+    char buff[1024]={0};
+    int err=0;
+    int len=0;
+    int result;
+
+    if (info->sock_info[FTP_SOCK_DATA].fd > 0)
+    {
+        if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+        {
+            LOGE("Close data socket fail[%d].", err);
+            result = FTP_ERR_NET_CLOSE;
+        }
+        else
+        {
+        //    info->sock_info[FTP_SOCK_DATA].fd = -1;
+        }
+    }
+    if(info->auth_type != 0)
+    {
+        if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+        {
+            LOGE("Close ssl data socket fail[%d].", err);
+            result = FTP_ERR_NET_CLOSE;
+        }
+        else
+        {
+        //    info->sock_info[FTP_SOCK_DATA].fd = -1;
+        }
+    }
+    info->data_mode = FTP_MODE_PASSIVE;
+    info->is_data_sock_busy = false;
+    info->file_trans.size_count = 0;
+    info->file_trans.size_send = 0;
+    
+    char line_buf[1024];
+    if(info->auth_type != 0)
+        len = mbtk_sock_read(info->ftp_ssl_handle,info->session,buff,sizeof(buff),FTP_TIMEOUT,&err);
+    else
+        len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT, &err);
+    if(len > 0)
+    {
+        printf("\n%s\n",buff);
+        if(err != 0)
+            printf("socket read error: %d\n",err);
+    }
+    else
+    {
+        printf("socket_read error:%d\n",err);
+        result = -1;
+    }
+
+    return result;
+}
+
+static mbtk_ftp_handle ftp_next_handle()
+{
+    if (!ftp_client_list)
+    {
+        LOGE("FTP Client List not init.");
+        return -1;
+    }
+
+    mbtk_ftp_info_s *info = NULL;
+    mbtk_ftp_handle handle = 1;
+    bool used;
+    while (handle <= FTP_HANDLE_MAX)
+    {
+        used = false;
+        // This handle used?
+        list_first(ftp_client_list);
+        while ((info = (mbtk_ftp_info_s*) list_next(ftp_client_list)))
+        {
+            if (handle == info->handle)
+            {
+                used = true;
+                break;
+            }
+        }
+
+        if (!used)
+        {
+            break;
+        }
+
+        handle++;
+    }
+
+    LOGI("Get free handle:%d", handle);
+
+    return handle;
+}
+
+static void ftp_free_func(void *data)
+{
+    if (data)
+    {
+        mbtk_ftp_info_s *info = (mbtk_ftp_info_s*) data;
+        LOGI("Free FTP client[handle = %d].", info->handle);
+        free(info);
+    }
+}
+
+/*************************************************************
+ Public Function Definitions
+ *************************************************************/
+mbtk_ftp_handle mbtk_ftp_init(const void* host, uint16 port, mbtk_ftp_auth_type_enum auth_type,
+                              bool is_ipv6, bool use_cert)
+{
+    if (!ftp_client_list)
+        ftp_client_list = list_create(ftp_free_func);
+
+    if (!ftp_client_list)
+    {
+        LOGE("FTP Client List not init.");
+        return -1;
+    }
+
+    if (list_size(ftp_client_list) > FTP_HANDLE_MAX)
+    {
+        LOGE("FTP client is full.");
+        return -1;
+    }
+
+    if (host == NULL || strlen(host) == 0)
+    {
+        LOGE("Host error.");
+        return -1;
+    }
+
+    if (port == 0)
+    {
+        port = FTP_SERVICE_PORT_DEF;
+    }
+
+    mbtk_ftp_info_s *info = (mbtk_ftp_info_s*) malloc(sizeof(mbtk_ftp_info_s));
+    if (!info)
+    {
+        LOGE("malloc() fail.");
+        return -1;
+    }
+    memset(info, 0x0, sizeof(mbtk_ftp_info_s));
+    list_add(ftp_client_list, info);
+    memcpy(info->sock_info[FTP_SOCK_CTRL].host, host, strlen(host));
+    info->sock_info[FTP_SOCK_CTRL].port = port;
+    // info->auth_type == FTP_AUTH_TYPE_IMPLICIT, info->is_ipv6 ? MBTK_ADDR_IPV6 : MBTK_ADDR_IPV4,info->use_cert,
+    info->sock_info[FTP_SOCK_CTRL].is_ssl = (auth_type == FTP_AUTH_TYPE_IMPLICIT);
+    info->sock_info[FTP_SOCK_CTRL].addr_family = is_ipv6 ? MBTK_ADDR_IPV6: MBTK_ADDR_IPV4;
+    info->sock_info[FTP_SOCK_CTRL].use_cert = use_cert;
+
+    info->handle = ftp_next_handle();
+    info->state = FTP_STATE_NON;
+    info->data_mode = FTP_MODE_PASSIVE;
+    info->sock_info[FTP_SOCK_CTRL].fd = -1;
+    info->sock_info[FTP_SOCK_DATA].fd = -1;
+    //info->is_ipv6 = is_ipv6;
+    info->auth_type = auth_type;
+    //info->use_cert = use_cert;
+
+    LOGI("FTP info#host:%s,port:%d,ipv6:%d,ssl:%d,cert:%d",info->sock_info[FTP_SOCK_CTRL].host,
+            info->sock_info[FTP_SOCK_CTRL].port,
+            is_ipv6,info->auth_type,use_cert);
+
+    if(auth_type != FTP_AUTH_TYPE_NON)
+    {
+        info->ftp_ssl_handle = mbtk_sock_init(&info->ftp_ssl_info);
+        if(info->ftp_ssl_handle == -1)
+        {
+            printf("mbtk_sock_init error\n");
+        }
+        
+        info->ftp_sock_ssl_info = (mbtk_sock_info*) malloc(sizeof(mbtk_sock_info));
+        memset(info->ftp_sock_ssl_info, 0x0, sizeof(mbtk_sock_info));
+        info->ftp_sock_ssl_info->is_support_ssl = (auth_type != FTP_AUTH_TYPE_NON);
+        info->ftp_sock_ssl_info->ftp_ssl_support = 1;
+        info->ftp_sock_ssl_info->port = port;
+        info->ftp_sock_ssl_info->type = MBTK_SOCK_TCP;
+        info->ftp_sock_ssl_info->ingnore_cert = ~use_cert;
+        memcpy(info->ftp_sock_ssl_info->address, host, strlen(host));
+    }
+    return info->handle;
+}
+
+mbtk_ftp_error_enum mbtk_ftp_reconfig(mbtk_ftp_handle handle,const void* host, uint16 port, mbtk_ftp_auth_type_enum auth_type,
+                                      bool is_ipv6, bool use_cert)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+    if(auth_type != FTP_AUTH_TYPE_NON)
+    {
+        info->ftp_sock_ssl_info = (mbtk_sock_info*) malloc(sizeof(mbtk_sock_info));
+        memset(info->ftp_sock_ssl_info, 0x0, sizeof(mbtk_sock_info));
+        if(host && strlen(host) > 0)
+        {
+            memcpy(info->ftp_sock_ssl_info->address, host, strlen(host));
+            info->ftp_sock_ssl_info->address[strlen(host)] = '\0';
+        }
+        info->ftp_sock_ssl_info->is_support_ssl = (auth_type != FTP_AUTH_TYPE_NON);
+        info->ftp_sock_ssl_info->ftp_ssl_support = 1;
+        info->ftp_sock_ssl_info->port = port;
+        info->ftp_sock_ssl_info->ingnore_cert = ~use_cert;
+        info->ftp_sock_ssl_info->type = MBTK_SOCK_TCP;
+    }
+    if(info->state == FTP_STATE_NON)
+    {
+        if(host && strlen(host) > 0)
+        {
+            memcpy(info->sock_info[FTP_SOCK_CTRL].host, host, strlen(host));
+            info->sock_info[FTP_SOCK_CTRL].host[strlen(host)] = '\0';
+        }
+        info->sock_info[FTP_SOCK_CTRL].port = port;
+        info->sock_info[FTP_SOCK_CTRL].addr_family = is_ipv6 ? MBTK_ADDR_IPV6 : MBTK_ADDR_IPV4;
+        info->auth_type = auth_type;
+        info->sock_info[FTP_SOCK_CTRL].use_cert = use_cert;
+
+        return FTP_ERR_SUCCESS;
+    }
+    else
+    {
+        LOGE("Not reset FTP config.The state is %d", info->state);
+        return FTP_ERR_UNKNOWN;
+    }
+}
+
+mbtk_ftp_error_enum mbtk_ftp_user_set(mbtk_ftp_handle handle,void* user,void* pass)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    if(info->state == FTP_STATE_NON && !str_empty(user) && !str_empty(pass))
+    {
+        memset(&info->user,0x0,sizeof(mbtk_ftp_user_info_s));
+        memcpy(info->user.name, user, strlen(user));
+        memcpy(info->user.pass, pass, strlen(pass));
+        return FTP_ERR_SUCCESS;
+    }
+    else
+    {
+        LOGE("Not reset FTP config.The state is %d", info->state);
+        return FTP_ERR_UNKNOWN;
+    }
+}
+
+mbtk_ftp_error_enum mbtk_ftp_deinit(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    if (list_remove(ftp_client_list, info))
+    {
+        int err;
+        sock_close(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err);
+        sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err);
+        ftp_free_func(info);
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+/*
+ * Quit FTP service.
+ */
+mbtk_ftp_error_enum mbtk_ftp_quit(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    int err = 0;
+    if(info->sock_info[FTP_SOCK_CTRL].fd > 0) {
+        mbtk_ftp_error_enum ftp_err = ftp_cmd_process(info, FTP_CMD_QUIT, NULL,
+                                      NULL);
+        if (ftp_err != FTP_ERR_SUCCESS)
+        {
+            LOGE("FTP QUIT fail[%d].", ftp_err);
+            //return ftp_err;
+        }
+
+        // FTP quit success.
+        info->state = FTP_STATE_CONNECTED;
+    }
+
+    if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err))
+    {
+        LOGE("Close ctrl socket fail[%d].", err);
+        return FTP_ERR_NET_CLOSE;
+    }
+
+    if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+    {
+        LOGE("Close data socket fail[%d].", err);
+        return FTP_ERR_NET_CLOSE;
+    }
+
+    info->state = FTP_STATE_NON;
+    info->data_mode = FTP_MODE_PASSIVE;
+    memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+    info->sock_info[FTP_SOCK_CTRL].fd = -1;
+    info->sock_info[FTP_SOCK_DATA].fd = -1;
+
+    return FTP_ERR_SUCCESS;
+}
+
+mbtk_ftp_error_enum mbtk_ftp_net_close(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    if(info->net_info.net_id > 0) {
+        int err;
+        if(sock_net_close(&info->net_info, FTP_TIMEOUT,&err))
+        {
+            LOGE("sock_net_close() fail[%ld].",err);
+            return FTP_ERR_NET_CLOSE;
+        }
+
+        info->net_info.net_id = -1;
+    }
+
+    return FTP_ERR_SUCCESS;
+}
+
+
+mbtk_ftp_info_s* mbtk_ftp_info_get(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return NULL;
+    }
+
+    return info;
+}
+
+/*
+ * Login specified FTP service.
+ */
+mbtk_ftp_error_enum mbtk_ftp_login(mbtk_ftp_handle handle, void *name,
+                                   void *pass)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    if (info->state == FTP_STATE_NON)
+    {
+        mbtk_ftp_user_info_s user;
+        memset(&user,0x0,sizeof(mbtk_ftp_user_info_s));
+        if (!str_empty(name) && !str_empty(pass))
+        {
+            memcpy(user.name, name, strlen(name));
+            memcpy(user.pass, pass, strlen(pass));
+            memcpy(info->user.name, name, strlen(name));
+            memcpy(info->user.pass, pass, strlen(pass));
+        }
+        else
+        {
+            memcpy(user.name, FTP_ANONYMOUS_USER, strlen(FTP_ANONYMOUS_USER));
+            memcpy(user.pass, FTP_ANONYMOUS_PASS, strlen(FTP_ANONYMOUS_PASS));
+            memcpy(info->user.name, FTP_ANONYMOUS_USER, strlen(FTP_ANONYMOUS_USER));
+            memcpy(info->user.pass, FTP_ANONYMOUS_PASS, strlen(FTP_ANONYMOUS_PASS));
+        }
+
+        LOGI("FTP login#user:%s,pass:%s",user.name,user.pass);
+        
+        if(info->auth_type != 0)
+        {
+            int mbtk_errno=-1;
+            info->session = mbtk_sock_open(info->ftp_ssl_handle,info->ftp_sock_ssl_info,60000,&mbtk_errno);
+            if(mbtk_errno!=0)
+            {
+                printf("mbtk_sock_open error : %d\n",mbtk_errno);
+            }
+            else
+            {
+                unsigned char mbtk_ftp_ssl_read_buf[16384 + 1];
+                char cmd[50];
+                memset(cmd,0,50);
+                int len_ssl;
+                
+
+                memset(cmd,0,50);
+                snprintf(cmd, 50, "PBSZ 0\r\n");
+                mbtk_sock_write(info->ftp_ssl_handle,info->session,
+                                    cmd,
+                                    sizeof(cmd),
+                                    60000,
+                                    &mbtk_errno);
+                memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+                mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                            mbtk_ftp_ssl_read_buf,
+                            sizeof(mbtk_ftp_ssl_read_buf),
+                            60000,
+                            &mbtk_errno);
+                printf("\nmbtk_sock_read PBSZ 0:\n%s\n",mbtk_ftp_ssl_read_buf);
+                memset(cmd,0,50);
+                snprintf(cmd, 50, "PROT P\r\n");
+                mbtk_sock_write(info->ftp_ssl_handle,info->session,
+                                    cmd,
+                                    sizeof(cmd),
+                                    60000,
+                                    &mbtk_errno);
+                memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+                mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                            mbtk_ftp_ssl_read_buf,
+                            sizeof(mbtk_ftp_ssl_read_buf),
+                            60000,
+                            &mbtk_errno);
+                printf("\nmbtk_sock_read PROT P:\n%s\n",mbtk_ftp_ssl_read_buf);
+                memset(cmd,0,50);
+                snprintf(cmd, 50, "USER %s\r\n",info->user.name);
+                mbtk_sock_write(info->ftp_ssl_handle,info->session,
+                                    cmd,
+                                    sizeof(cmd),
+                                    60000,
+                                    &mbtk_errno);
+                memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+                mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                            mbtk_ftp_ssl_read_buf,
+                            sizeof(mbtk_ftp_ssl_read_buf),
+                            60000,
+                            &mbtk_errno);
+                printf("\nmbtk_sock_read USER:\n%s\n",mbtk_ftp_ssl_read_buf);
+                memset(cmd,0,50);
+                snprintf(cmd, 50, "PASS %s\r\n",info->user.pass);
+                mbtk_sock_write(info->ftp_ssl_handle,info->session,
+                                    cmd,
+                                    sizeof(cmd),
+                                    60000,
+                                    &mbtk_errno);
+                memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+                mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                            mbtk_ftp_ssl_read_buf,
+                            sizeof(mbtk_ftp_ssl_read_buf),
+                            60000,
+                            &mbtk_errno);
+                printf("\nmbtk_sock_read PASS:\n%s\n",mbtk_ftp_ssl_read_buf);
+                char *ptr = NULL;
+                if((ptr = strstr(mbtk_ftp_ssl_read_buf,"220 ")) || (ptr = strstr(mbtk_ftp_ssl_read_buf,"230 "))) {
+                    LOGI("RSP:%s",ptr);
+                    printf("RSP:%s\n",ptr);
+                }
+                else
+                {
+                    printf("\nptr error.\n");
+                    return FTP_ERR_UNKNOWN;
+                }
+                int code = atoi(ptr);
+                if (code / 100 == 2)   // USER/PASS is 2xx
+                {
+                    info->state = FTP_STATE_READY;
+                    LOGI("FTP logn in success.");
+                    printf("FTP logn in success.\n");
+                }
+                else if (code == 332)   // // USER/PASS is 332
+                {
+                    LOGW("Should set ACCT.");
+                    printf("Should set ACCT.\n");
+                    return FTP_ERR_UNKNOWN;
+                }
+                else
+                {
+                    LOGE("FTP login denied[code = %d].", code);
+                    printf("FTP login denied[code = %d].\n", code);
+                    return FTP_ERR_UNKNOWN;
+                }
+                
+                memset(cmd,0,50);
+                snprintf(cmd, 50, "PWD\r\n");
+                mbtk_sock_write(info->ftp_ssl_handle,info->session,
+                                    cmd,
+                                    sizeof(cmd),
+                                    60000,
+                                    &mbtk_errno);
+                memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+                mbtk_sock_read(info->ftp_ssl_handle,info->session,
+                            mbtk_ftp_ssl_read_buf,
+                            sizeof(mbtk_ftp_ssl_read_buf),
+                            60000,
+                            &mbtk_errno);
+                printf("\nmbtk_sock_read PWD:\n%s\n",mbtk_ftp_ssl_read_buf);
+            }
+            return mbtk_errno;
+        }
+        
+        return ftp_login(info,&user);
+    }
+    else
+    {
+        LOGD("Has login.");
+        return FTP_ERR_SUCCESS;
+    }
+}
+
+/*
+ * Get current directory's path.
+ */
+mbtk_ftp_error_enum mbtk_ftp_pwd(mbtk_ftp_handle handle, void *path)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return FTP_ERR_PARAM_SET;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_PWD, NULL, path);
+}
+
+/*
+ * Go to specified directory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_cd(mbtk_ftp_handle handle, void *path)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return FTP_ERR_PARAM_SET;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_CWD, path, NULL);
+}
+
+/*
+ * Get the native ip and free port.
+ */
+mbtk_ftp_error_enum mbtk_ftp_get_ip_and_port(char *ipBuf_out,
+                                    int *port,int iptype)
+{
+    char psz_port_cmd[128];
+    int i=0;
+
+    *port = rand() % (60000 - 50000 + 1) + 50000;
+    sprintf(psz_port_cmd, "netstat -an | grep :%d > /dev/null", *port);
+
+        char ipBuf[32] = "";
+        FILE *fstream=NULL;
+
+        char buff[1024];  
+        char iptype_str[8];
+        memset(buff,0,sizeof(buff));    
+        /*eth0可以换成eth1、docker0、em1、lo等*/
+        if(iptype == MBTK_ADDR_IPV6)
+        {
+            
+            if(NULL==(fstream=popen("ifconfig ccinet0 | grep \"inet6 addr: 2\" | awk '{print $3}'","r")))    
+            {   
+                snprintf(ipBuf, 39, "%s","0:0:0:0:0:0:0:0");  
+            }       
+            if(NULL!=fgets(buff, sizeof(buff), fstream))   
+            {   
+                snprintf(ipBuf, 39, "%s",buff);  
+            }   
+            else  
+            {  
+                snprintf(ipBuf, 39, "%s","0:0:0:0:0:0:0:0");  
+                pclose(fstream);  
+            }
+        }
+        else
+        {
+            if(NULL==(fstream=popen("ifconfig ccinet0 | grep \"inet addr:\" | awk \'{print $2}\' | cut -c 6-","r")))    
+            {   
+                snprintf(ipBuf, 18, "%s","0.0.0.0");  
+            }       
+            if(NULL!=fgets(buff, sizeof(buff), fstream))   
+            {   
+                snprintf(ipBuf, 18, "%s",buff);  
+            }   
+            else  
+            {  
+                snprintf(ipBuf, 18, "%s","0.0.0.0");  
+                pclose(fstream);  
+            }  
+        }
+            pclose(fstream);  
+            
+        printf("ip:%s\n", ipBuf);
+        memcpy(ipBuf_out, ipBuf, 32);
+        return 0;
+}
+/*
+ * Get current directory's subdirectory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_dir_ls(mbtk_ftp_handle handle,
+                                    mbtk_ftp_file_info_s *list_head)
+{
+    if (!list_head)
+    {
+        LOGE("No set file list.");
+        return FTP_ERR_PARAM_SET;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_LIST, NULL, list_head);
+}
+
+/*
+ * Get specified file's size.
+ */
+uint32 mbtk_ftp_file_size(mbtk_ftp_handle handle, void *path)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return 0;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return 0;
+    }
+    uint32 size = 0;
+    if (ftp_cmd_process(info, FTP_CMD_SIZE, path, &size) != FTP_ERR_SUCCESS)
+        return 0;
+
+    return size;
+}
+
+/*
+ * Get specified file's modify time.
+ */
+mbtk_ftp_error_enum mbtk_ftp_file_time(mbtk_ftp_handle handle, void *path,
+                                       void *time)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return FTP_ERR_PARAM_SET;
+    }
+
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_MDTM, path, time);
+}
+
+/*
+ * Delete specified file.
+ */
+mbtk_ftp_error_enum mbtk_ftp_file_del(mbtk_ftp_handle handle, void *path)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return FTP_ERR_PARAM_SET;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_DELE, path, NULL);
+}
+
+/*
+ * Create specified directory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_dir_mkdir(mbtk_ftp_handle handle, void *path)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return FTP_ERR_PARAM_SET;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_MKD, path, NULL);
+}
+
+/*
+ * Delete specified directory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_dir_rmdir(mbtk_ftp_handle handle, void *path)
+{
+    if (!path)
+    {
+        LOGE("No set path");
+        return FTP_ERR_PARAM_SET;
+    }
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_RMD, path, NULL);
+}
+
+/*
+ * Set data type.
+ */
+mbtk_ftp_error_enum mbtk_ftp_data_type_set(mbtk_ftp_handle handle,
+        mbtk_ftp_data_type_enum data_type)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    return ftp_cmd_process(info, FTP_CMD_TYPE, &data_type, NULL);
+}
+
+/*
+ * Set FTP mode.
+ */
+mbtk_ftp_error_enum mbtk_ftp_mode_set(mbtk_ftp_handle handle,
+                                      mbtk_ftp_mode_enum mode)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    info->data_mode = mode;
+
+    return FTP_ERR_SUCCESS;
+}
+
+uint32 mbtk_ftp_download_start(mbtk_ftp_handle handle, void *remote_path,
+                               void *local_path, mbtk_data_cb_func data_cb)
+{
+    if (!remote_path || (local_path && data_cb) || (!local_path && !data_cb))
+    {
+        LOGE("Param set error.");
+        return 0;
+    }
+
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return 0;
+    }
+
+    if (info->state >= FTP_STATE_READY && !info->is_trans)
+    {
+        int retry_time = 0;
+        memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+
+        // Set data type to "I"
+        if (FTP_ERR_SUCCESS
+            != mbtk_ftp_data_type_set(handle, FTP_DATA_TYPE_I))
+        {
+            LOGE("Set data type to I fail.");
+            return 0;
+        }
+
+        // Get file size.
+        info->file_trans.size_count = mbtk_ftp_file_size(handle, remote_path);
+        if (info->file_trans.size_count > 0)
+        {
+            LOGI("File size:%d", info->file_trans.size_count);
+        }
+        else
+        {
+            LOGE("File not exist.");
+            return 0;
+        }
+
+        //Get file modify time.
+        if (FTP_ERR_SUCCESS
+            != mbtk_ftp_file_time(handle, remote_path,
+                                  (char*) info->file_trans.modify_time))
+        {
+            LOGE("Get file modify time fail.");
+            return 0;
+        }
+
+        memcpy(info->file_trans.remote_name, remote_path,
+               strlen((char*) remote_path));
+        if (local_path)
+        {
+            memcpy(info->file_trans.local_name, local_path,
+                   strlen((char*) local_path));
+            info->file_trans.data_cb = NULL;
+        }
+        else
+        {
+            info->file_trans.data_cb = data_cb;
+        }
+        info->file_trans.size_send = 0;
+        info->file_trans.is_download = true;
+        info->file_trans.fd = -1;
+        info->is_trans = true;
+
+        if (!info->file_trans.data_cb)   // Save to efs
+        {
+            info->file_trans.fd = file_open((const char*)info->file_trans.local_name,
+                                            O_WRONLY | O_CREAT | O_TRUNC);
+            if (info->file_trans.fd <= 0)
+            {
+                LOGE("Can not open EFS file[%s].", info->file_trans.local_name);
+                return 0;
+            }
+        }
+
+        do {
+            // Start download file.
+            if (FTP_ERR_SUCCESS
+                != ftp_data_sock_read(info, FTP_CMD_GET, NULL, NULL))
+            {
+                LOGW("ftp_data_sock_read() fail.");
+            }
+
+            if(info->sock_info[FTP_SOCK_CTRL].fd <= 0) {
+                // Download fail.
+                LOGW("Ctrl socket error,should login angin.");
+                break;
+            } else if (info->file_trans.size_send == info->file_trans.size_count) {
+                // Download success
+                break;
+            }
+
+            // Should redownload without quit.
+            char time[20] = { 0 };
+            if (FTP_ERR_SUCCESS
+                != mbtk_ftp_file_time(handle, info->file_trans.remote_name,
+                                      time))
+            {
+                LOGE("Get file modify time fail.");
+                break;
+            }
+
+            if (strcmp(time, (char*) info->file_trans.modify_time))
+            {
+                LOGW("Service file changed.");
+                break;
+            }
+
+            retry_time++;
+        } while(retry_time < 5);
+
+
+        if (!info->file_trans.data_cb && info->file_trans.fd > 0)   // Save to efs
+        {
+            if (file_close(info->file_trans.fd))
+            {
+                LOGE("EFS close fail.");
+                return 0;
+            }
+        }
+
+        // Download success.
+        if (info->file_trans.size_send == info->file_trans.size_count)
+        {
+            LOGI("Download %s success[%d].", (char* )remote_path,
+                 info->file_trans.size_count);
+
+            // Reset download configs.
+            info->is_trans = false;
+            // memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+        }
+        else
+        {
+            LOGW("Download %s fail[%d / %d].", (char* )remote_path,
+                 info->file_trans.size_send, info->file_trans.size_count);
+        }
+
+        return info->file_trans.size_send;
+    }
+    else
+    {
+        LOGE("FTP state error[%d].", info->state);
+        return 0;
+    }
+}
+
+uint32 mbtk_ftp_download_continue(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return 0;
+    }
+
+    if(info->state == FTP_STATE_NON) {
+        if(FTP_ERR_SUCCESS != ftp_login(info,&info->user)) {
+            LOGE("FTP login fail.");
+            return 0;
+        }
+    }
+
+    if (info->state >= FTP_STATE_READY && info->is_trans
+        && info->file_trans.is_download
+        && info->file_trans.size_send < info->file_trans.size_count)
+    {
+        // Set data type to "I"
+        if (FTP_ERR_SUCCESS
+            != mbtk_ftp_data_type_set(handle, FTP_DATA_TYPE_I))
+        {
+            LOGE("Set data type to I fail.");
+            return 0;
+        }
+
+        // Get file size.
+        uint32 size = mbtk_ftp_file_size(handle, info->file_trans.remote_name);
+        if (size > 0)
+        {
+            LOGI("File size:%d", size);
+        }
+        else
+        {
+            LOGE("File not exist.");
+            return 0;
+        }
+        if (size != info->file_trans.size_count)
+        {
+            LOGW("Service file changed.");
+            return 0;
+        }
+
+        //Get file modify time.
+        char time[20] = { 0 };
+        if (FTP_ERR_SUCCESS
+            != mbtk_ftp_file_time(handle, info->file_trans.remote_name,
+                                  time))
+        {
+            LOGE("Get file modify time fail.");
+            return 0;
+        }
+        if (strcmp(time, (char*) info->file_trans.modify_time))
+        {
+            LOGW("Service file changed.");
+            return 0;
+        }
+
+        if (!info->file_trans.data_cb)   // Save to efs
+        {
+            info->file_trans.fd = file_open((const char*)info->file_trans.local_name,
+                                            O_WRONLY | O_CREAT | O_APPEND);
+            if (info->file_trans.fd <= 0)
+            {
+                LOGE("Can not open EFS file[%s].", info->file_trans.local_name);
+                return FTP_ERR_EFS_FILE;
+            }
+        }
+
+        uint32 size_last = info->file_trans.size_send;
+        // Start download file.
+        if (FTP_ERR_SUCCESS
+            != ftp_data_sock_read(info, FTP_CMD_GET, NULL, NULL))
+        {
+            LOGW("Data download fail.");
+        }
+
+        if (!info->file_trans.data_cb && info->file_trans.fd > 0)
+        {
+            if (file_close(info->file_trans.fd))
+            {
+                LOGE("EFS close fail.");
+                return 0;
+            }
+        }
+
+        // Download success.
+        if (info->file_trans.size_send == info->file_trans.size_count)
+        {
+            LOGI("Download %s success[%d].", info->file_trans.remote_name,
+                 info->file_trans.size_count);
+
+            // Reset download configs.
+            info->is_trans = false;
+            //memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+        }
+        else
+        {
+            LOGW("Download %s fail[%d / %d].", info->file_trans.remote_name,
+                 info->file_trans.size_send, info->file_trans.size_count);
+        }
+
+        return info->file_trans.size_send - size_last;
+    }
+    else
+    {
+        LOGE("FTP state error[%d].", info->state);
+        return 0;
+    }
+}
+
+/*
+* Upload EFS:  local_path is efs path;size_byte is 0.
+* Upload data: local_path is NULL;size_byte is data size.
+*/
+int mbtk_ftp_upload_start(mbtk_ftp_handle handle, const void *remote_path,
+                          const void *local_path, uint32 size_byte)
+{
+    if (!remote_path || (size_byte == 0 && !local_path)
+        || (size_byte > 0 && local_path))
+    {
+        LOGE("Param set error.");
+        return -1;
+    }
+
+	int result = 0;
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return -1;
+    }
+
+    LOGE("info->state:%d, info->is_trans:%d", info->state,info->is_trans);
+
+    if (info->state >= FTP_STATE_READY && !info->is_trans)
+    {
+		        // Set data type to "I"
+        if (FTP_ERR_SUCCESS
+            != mbtk_ftp_data_type_set(handle, FTP_DATA_TYPE_I))
+        {
+            LOGE("Set data type to I fail.");
+            return -1;
+        }
+	
+        memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+        info->file_trans.is_download = false;
+
+        memcpy(info->file_trans.remote_name, remote_path,
+               strlen((char*) remote_path));
+
+        if (local_path)
+        {
+            memcpy(info->file_trans.local_name, local_path,
+                   strlen((char*) local_path));
+            info->file_trans.fd = file_open((const char*)info->file_trans.local_name,
+                                            O_RDONLY);
+            if (info->file_trans.fd <= 0)
+            {
+                LOGE("Can not open EFS file[%s].", info->file_trans.local_name);
+                return -1;
+            }
+		
+        }
+        info->file_trans.size_count = size_byte;
+        info->file_trans.size_send = 0;
+        // Start upload data.
+
+
+	    // Start update file.
+        if (FTP_ERR_SUCCESS != ftp_data_sock_read(info, FTP_CMD_PUT, NULL, NULL))
+        {
+            LOGW("ftp_data_sock_read() fail.");
+			if(info->file_trans.size_count == info->file_trans.size_send && info->file_trans.size_send != 0)
+			{
+				result = FTP_ERR_SUCCESS;
+			}
+			else
+			{
+			    mbtk_at_ftp_par.rest_size = info->file_trans.size_send;
+				result = FTP_ERR_UNKNOWN;
+			} 
+        }
+
+		if (info->file_trans.fd > 0 )   // Save to efs
+		{
+            info->file_trans.size_count = 0;
+			info->file_trans.size_send = 0;
+			if (file_close(info->file_trans.fd))
+			{
+				LOGE("EFS close fail.");
+				return -1;
+			}
+		}
+
+    }
+    else
+    {
+        LOGE("FTP state error[%d].", info->state);
+        return -1;
+    }
+
+    return result;
+}
+
+/*
+* This only for upload data(No for upload efs).
+*/
+int mbtk_ftp_upload_send(mbtk_ftp_handle handle, const void *data,uint16 data_len)
+{
+    if (!data || data_len == 0)
+    {
+        LOGE("Param set error.");
+        return -1;
+    }
+
+    int err;
+	int result = 0;
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return -1;
+    }
+
+    if(info->file_trans.fd > 0)   // Is upload from efs.
+    {
+        LOGE("Not upload from EFS.");
+        return -1;
+    }
+
+//LOGE("1socket:%d, data:%s, data_len:%d", info->sock_info[FTP_SOCK_DATA].fd, data, data_len );
+    if((info->file_trans.size_send + data_len) > info->file_trans.size_count)
+	{
+		printf("send over set length\n");
+        result = FTP_ERR_UNKNOWN;
+        goto overlong;
+    }
+    int len;
+    if(info->auth_type != 0)
+        len = mbtk_sock_write(info->ftp_ssl_handle,info->session_data,data,data_len,FTP_TIMEOUT,&err);
+    else
+	    len = sock_write(&info->net_info, &info->sock_info[FTP_SOCK_DATA], data, data_len,
+                            FTP_TIMEOUT, &err);
+	if(len < 0)
+	{
+		LOGE("EFS write fail.len:%d, err;%d", len, err);
+        return FTP_ERR_EFS_FILE;
+	}
+
+	info->file_trans.size_send += len;
+    mbtk_at_ftp_par.rest_size = info->file_trans.size_send;
+    
+    LOGE("size_count:%d, size_send:%d.", info->file_trans.size_count,info->file_trans.size_send);
+
+    if((info->file_trans.size_count <= info->file_trans.size_send) )
+	{
+	    printf("\nClose data socket begin!\n ");
+			    // Close data socket.
+overlong:    if (info->sock_info[FTP_SOCK_DATA].fd > 0)
+	    {
+	        if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+	        {
+	            LOGE("Close data socket fail[%d].", err);
+                printf("\nClose data socket fail[%d].\n", err);
+	            result = FTP_ERR_NET_CLOSE;
+	        }
+	        else
+	        {
+	            printf("\nClose data socket ok[%d].\n", err);
+	        //    info->sock_info[FTP_SOCK_DATA].fd = -1;
+	        }
+	    }
+        if(info->auth_type != 0)
+        {
+            if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+            {
+	            LOGE("Close ssl data socket fail[%d].", err);
+                printf("\nClose ssl data socket fail[%d].\n", err);
+	            result = FTP_ERR_NET_CLOSE;
+	        }
+	        else
+	        {
+	            printf("\nClose ssl data socket ok[%d].\n", err);
+	        //    info->sock_info[FTP_SOCK_DATA].fd = -1;
+	        }
+        }
+        info->data_mode = FTP_MODE_PASSIVE;
+        info->is_data_sock_busy = false;
+        info->file_trans.size_count = 0;
+        info->file_trans.size_send = 0;
+	}
+	else
+	{
+		LOGE("size_count:%d, size_send:%d.", info->file_trans.size_count,info->file_trans.size_send);
+	}
+
+
+    // Start update data.
+
+    return result;
+}
+
+mbtk_ftp_error_enum mbtk_ftp_trans_reset(mbtk_ftp_handle handle)
+{
+    mbtk_ftp_info_s *info = ftp_info_find(handle);
+    if (!info)
+    {
+        LOGE("No such FTP handle:%d", handle);
+        return FTP_ERR_UNKNOWN;
+    }
+
+    info->is_trans = false;
+    memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+
+    return FTP_ERR_SUCCESS;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_ftp_at.c b/mbtk/mbtk_lib/src/mbtk_ftp_at.c
new file mode 100755
index 0000000..58c2d07
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_ftp_at.c
@@ -0,0 +1,594 @@
+/*************************************************************
+ Description:
+ $file_description$
+ Author:
+ LiuBin
+ Date:
+ 2020/10/28 11:49:08
+ *************************************************************/
+#include "mbtk_ftp.h"
+#include "mbtk_list.h"
+#include "mbtk_sock.h"
+#include "mbtk_str.h"
+#include "mbtk_sock2.h"
+#include "mbtk_info.h"
+#include<linux/msg.h>
+
+/*************************************************************
+ typedef struct:local at
+ *************************************************************/
+typedef struct
+{
+    char host[64];
+    uint16 port;
+    mbtk_ftp_auth_type_enum auth_type;
+    bool ftp_type;
+    bool use_cert;
+    char name[FTP_SERVER_USER_NAME_MAX+1];
+    char pass[FTP_SERVER_USER_PASS_MAX+1];
+    mbtk_ftp_handle at_ftp_handle;
+    char remote_path[MBTK_FTP_FILE_NAME_MAX+1];
+    char local_path[MBTK_FTP_FILE_NAME_MAX+1];
+    int rest_size;
+    int read_size;
+    int put_len;
+} mbtk_at_init_parameter;
+
+mbtk_at_init_parameter mbtk_at_ftp_par_at={0};
+
+/*************************************************************
+ Variables:local
+ *************************************************************/
+static list_node_t *ftp_client_list = NULL;
+
+/*************************************************************
+ Variables:public
+ *************************************************************/
+
+/*************************************************************
+ Local Function Declaration
+ *************************************************************/
+
+/*************************************************************
+ Local Function Definitions
+ *************************************************************/
+
+//at
+struct my_msg   //消息队列结构体
+{
+	long int my_msg_type;
+    char *ptr;
+}mbtk_at_msg;
+
+int msgid;
+
+int mbtk_at_msgid(int *at_msgid)
+{
+    msgid = *at_msgid;
+    return 0;
+}
+
+void mbtk_at_printf(void *data)
+{
+    char *ptr = malloc(strlen(data)+1);
+    memset(ptr,0,strlen(data)+1);
+    memcpy(ptr, data, strlen(data)+1);
+    mbtk_at_msg.ptr = ptr;
+	mbtk_at_msg.my_msg_type=3;
+	msgsnd(msgid,&mbtk_at_msg,sizeof(&mbtk_at_msg),0);   //发送数据到缓冲区
+}
+
+int mbtk_at_ftp(int parameter,int port,char *addr, char *pass, char *name,int at_auth_type ,bool ftp_type, bool use_cert)
+{
+    int at_ftp_ret = 0;
+
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    switch (parameter) {
+    case 0: {
+        mbtk_at_ftp_par_at.port = port;
+        break;
+        }
+    case 1: {
+        memset(mbtk_at_ftp_par_at.host, 0, strlen(mbtk_at_ftp_par_at.host)+1);
+        memcpy(mbtk_at_ftp_par_at.host, addr, strlen(addr)+1);
+        break;
+        }
+    case 2: {
+        memset(mbtk_at_ftp_par_at.pass, 0, strlen(mbtk_at_ftp_par_at.pass)+1);
+        memcpy(mbtk_at_ftp_par_at.pass, pass, strlen(pass)+1);
+        break;
+        }
+    case 3: {
+        memset(mbtk_at_ftp_par_at.name, 0, strlen(mbtk_at_ftp_par_at.name)+1);
+        memcpy(mbtk_at_ftp_par_at.name, name, strlen(name)+1);
+        break;
+        }
+    case 4: {
+        mbtk_at_ftp_par_at.auth_type = at_auth_type;
+        mbtk_at_ftp_par_at.use_cert = use_cert;
+        break;
+        }
+    case 5: {
+        mbtk_at_ftp_par_at.ftp_type = ftp_type;
+        break;
+        }
+    default :
+        at_ftp_ret = -1;
+        return at_ftp_ret;
+    }
+    return at_ftp_ret;
+}
+
+int mbtk_at_get_ftp_info(int parameter,int *port,char *addr, char *pass, char *name, int *at_auth_type ,int *ftp_type, int *use_cert)
+{
+    int at_ftp_ret = 0;
+
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    switch (parameter) {
+    case 0: {
+        *port = mbtk_at_ftp_par_at.port;
+        break;
+        }
+    case 1: {
+        memset(addr, 0, strlen(addr)+1);
+        memcpy(addr, mbtk_at_ftp_par_at.host, strlen(mbtk_at_ftp_par_at.host)+1);
+        break;
+        }
+    case 2: {
+        memset(pass, 0, strlen(pass)+1);
+        memcpy(pass, mbtk_at_ftp_par_at.pass, strlen(mbtk_at_ftp_par_at.pass)+1);
+        break;
+        }
+    case 3: {
+        memset(name, 0, strlen(name)+1);
+        memcpy(name, mbtk_at_ftp_par_at.name, strlen(mbtk_at_ftp_par_at.name)+1);
+        break;
+        }
+    case 4: {
+        *at_auth_type = mbtk_at_ftp_par_at.auth_type;
+        *use_cert = mbtk_at_ftp_par_at.use_cert;
+        break;
+        }
+    case 5: {
+        *ftp_type = mbtk_at_ftp_par_at.ftp_type;
+        break;
+        }
+    default :
+        at_ftp_ret = -1;
+    }
+    return at_ftp_ret;
+}
+
+int mbtk_at_ftp_mkrmdel(int cmd,char *dir)
+{
+    int at_ftp_ret = 0;
+
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+
+    char send_buf[1024];
+    
+    mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+                                    0, mbtk_at_ftp_par_at.use_cert);
+    mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+    if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+            at_ftp_ret = -1;
+    
+    at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+    if(at_ftp_ret != 0)
+    {
+        printf("ftp_login err:%d\n",at_ftp_ret);
+    }
+    memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+    memcpy(mbtk_at_ftp_par_at.remote_path,dir,strlen(dir)+1);
+    switch (cmd)
+    {
+        case 0:
+        {
+            at_ftp_ret = mbtk_ftp_dir_mkdir(mbtk_at_ftp_par_at.at_ftp_handle,dir);
+            if(at_ftp_ret != 0)
+            {
+                printf("+CFTPMKD: FAIL,<%d>\n",at_ftp_ret);
+                sprintf(send_buf,"+CFTPMKD: FAIL,<%d>\n",at_ftp_ret);
+            }
+            else
+            {
+                printf("+CFTPMKD: SUCCESS\n");
+                sprintf(send_buf,"+CFTPMKD: SUCCESS\n");
+            }
+            break;
+        }
+        case 1:
+        {
+            at_ftp_ret = mbtk_ftp_dir_rmdir(mbtk_at_ftp_par_at.at_ftp_handle,dir);
+            if(at_ftp_ret != 0)
+            {
+                printf("+CFTPRMD: FAIL,<%d>\n",at_ftp_ret);
+                sprintf(send_buf,"+CFTPRMD: FAIL,<%d>\n",at_ftp_ret);
+            }
+            else
+            {
+                printf("+CFTPRMD: SUCCESS\n");
+                sprintf(send_buf,"+CFTPRMD: SUCCESS\n");
+            }
+            break;
+        }
+        case 2:
+        {
+            at_ftp_ret = mbtk_ftp_file_del(mbtk_at_ftp_par_at.at_ftp_handle,dir);
+            if(at_ftp_ret != 0)
+            {
+                printf("+CFTPDELE: FAIL,<%d>\n",at_ftp_ret);
+                sprintf(send_buf,"+CFTPDELE: FAIL,<%d>\n",at_ftp_ret);
+            }
+            else
+            {
+                printf("+CFTPDELE: SUCCESS\n");
+                sprintf(send_buf,"+CFTPDELE: SUCCESS\n");
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    
+    mbtk_at_printf(send_buf);
+    mbtk_at_printf("end");
+    mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+    mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+    return at_ftp_ret;
+}
+
+int mbtk_at_ftp_upload(char *remote_path,char *local_path, int size_byte, int rest_size)
+{
+    int at_ftp_ret=-1;
+    int len_size;
+    char send_buf[1024];
+    
+    mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+                                    0, mbtk_at_ftp_par_at.use_cert);
+    mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+    if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+        at_ftp_ret = -1;
+    
+    at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+    if(at_ftp_ret != 0)
+    {
+        printf("ftp_login err:%d\n",at_ftp_ret);
+    }
+    
+    memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+    memcpy(mbtk_at_ftp_par_at.remote_path, remote_path, strlen(remote_path)+1);
+    if(local_path!=NULL)
+    {
+        memset(mbtk_at_ftp_par_at.local_path, 0, strlen(mbtk_at_ftp_par_at.local_path)+1);
+        memcpy(mbtk_at_ftp_par_at.local_path, local_path, strlen(local_path)+1);
+    }
+    mbtk_at_ftp_par_at.put_len = size_byte;
+    mbtk_at_ftp_par_at.rest_size = rest_size;
+
+    {
+        FILE *fp;
+        fp=fopen(local_path,"r");
+        if(NULL==fp)
+            printf("Read file error\n");
+        else
+        {
+            printf("Open file success\n");
+            fseek(fp,0,SEEK_END); //将文件读写指针移动到文件尾
+            len_size=ftell(fp); //ftell函数获取从文件尾移动到文件开头的偏移量
+            pclose(fp);
+        }
+    }
+    if(local_path == NULL)
+    {
+        at_ftp_ret = mbtk_ftp_upload_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path,
+                          NULL, size_byte);
+        if(at_ftp_ret != 0)
+        {
+            printf("+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+            sprintf(send_buf,"+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+        }
+        else 
+        {
+            at_ftp_ret = mbtk_ftp_upload_send(mbtk_at_ftp_par_at.at_ftp_handle,"" ,size_byte);
+            if(at_ftp_ret != 0)
+            {
+                printf("+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+                sprintf(send_buf,"+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+            }
+            else
+            {
+                printf("+CFTPPUT: SUCCESS,<%d>\n",len_size);
+                sprintf(send_buf,"+CFTPPUT: SUCCESS,<%d>\n",len_size);
+            }
+        }
+        mbtk_ftp_upload_end(mbtk_at_ftp_par_at.at_ftp_handle);
+    }
+    else
+    {
+        at_ftp_ret = mbtk_ftp_upload_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path,
+                          local_path, size_byte);
+        if(at_ftp_ret != 0)
+        {
+            printf("+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+            sprintf(send_buf,"+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+        }
+        else
+        {
+            printf("+CFTPPUT: SUCCESS,<%d>\n",len_size);
+            sprintf(send_buf,"+CFTPPUT: SUCCESS,<%d>\n",len_size);
+        }
+    }
+    mbtk_at_printf(send_buf);
+    mbtk_at_printf("end");
+    mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+    mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+    return at_ftp_ret;
+}
+
+void mbtk_at_ftp_data_cb(void *data, uint32 data_len)
+{
+    char resp_buf[2150];
+    printf("\n=====data_cb data[%s]=====\n=====data_cb data_len[%d]=====\n",data, data_len);
+
+    memset(resp_buf,0,2150);
+    sprintf(resp_buf, "+CFTPGET:");
+    mbtk_at_printf(resp_buf);
+
+    if(data_len > 1021)
+    {
+        memset(resp_buf,0,2150);
+        memcpy(resp_buf,data,1021);
+        mbtk_at_printf(resp_buf);
+        memset(resp_buf,0,2150);
+        sprintf(resp_buf, "<%d>", 1021);
+        mbtk_at_printf(resp_buf);
+
+        memset(resp_buf,0,2150);
+        sprintf(resp_buf, "+CFTPGET:");
+        mbtk_at_printf(resp_buf);
+        memset(resp_buf,0,2150);
+        memcpy(resp_buf,data+1021,data_len-1021);
+        mbtk_at_printf(resp_buf);
+        memset(resp_buf,0,2150);
+        sprintf(resp_buf, "<%d>", data_len-1021);
+        mbtk_at_printf(resp_buf);
+    }
+    else
+    {
+        memset(resp_buf,0,2150);
+        memcpy(resp_buf,data,data_len);
+        mbtk_at_printf(resp_buf);
+        
+        memset(resp_buf,0,2150);
+        sprintf(resp_buf, "<%d>", data_len);
+        mbtk_at_printf(resp_buf);
+    }
+
+}
+
+int mbtk_at_ftp_download(void *remote_path, void *local_path, int data_cbc, int rest_size, int read_size)
+{
+
+    int at_ftp_ret=-1;
+    int len_size;
+    
+    mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+                                    0, mbtk_at_ftp_par_at.use_cert);
+    mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+    if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+        at_ftp_ret = -1;
+    
+    at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+    if(at_ftp_ret != 0)
+    {
+        printf("ftp_login err:%d\n",at_ftp_ret);
+    }
+
+    memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+    memcpy(mbtk_at_ftp_par_at.remote_path, remote_path, strlen(remote_path)+1);
+    if(local_path!=NULL)
+    {
+        memset(mbtk_at_ftp_par_at.local_path, 0, strlen(mbtk_at_ftp_par_at.local_path)+1);
+        memcpy(mbtk_at_ftp_par_at.local_path, local_path, strlen(local_path)+1);
+    }
+    mbtk_at_ftp_par_at.rest_size = rest_size;
+    mbtk_at_ftp_par_at.read_size = read_size;
+    
+    // Download file: /data
+    uint32 len_count = 0;
+    uint32 len;
+    int download_time = 0;
+    char resp_buf[1024];
+    int ret;
+    
+    uint32 file_size = mbtk_ftp_file_size(mbtk_at_ftp_par_at.at_ftp_handle, remote_path);
+    if(file_size > 0)
+    {
+        if(rest_size > file_size)
+        {
+            printf("+CTPGETFILE: FAIL,<err>");
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d>\r\n",901);
+            mbtk_at_printf(resp_buf);
+            //ret = ATRESP(30163, 0, 0, resp_buf);
+            goto exit;
+        }
+        printf("Will download file:/data[%d]\n", file_size);
+        /*
+        memset(resp_buf,0,1024);
+        sprintf(resp_buf, "Will download file:/data[%d]",file_size);
+        mbtk_at_printf(resp_buf);
+        */
+        // Start download
+        if(data_cbc == 0)//to file
+        {
+            len = mbtk_ftp_download_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path, local_path, NULL);
+            /*
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf, "download size:/len[%d]",len);
+            mbtk_at_printf(resp_buf);
+            */
+        }
+        else if(data_cbc == 1)
+        {
+            len = mbtk_ftp_download_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path, NULL, mbtk_at_ftp_data_cb);
+            /*
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf, "download size:/len[%d]",len);
+            mbtk_at_printf(resp_buf);
+            */
+        }
+        else
+        {
+            printf("+CTPGETFILE: FAIL,<err>");
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d>\r\n",902);
+            mbtk_at_printf(resp_buf);
+            //ret = ATRESP(30163, 0, 0, resp_buf);
+            goto exit;
+        }
+        if(len > 0)
+        {
+            len_count += len;
+            download_time++;
+            printf("Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+            /*
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf,"Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+            mbtk_at_printf(resp_buf);
+            */
+            while (len_count < file_size
+                   && download_time <= 10 // Try 10 times.
+                   && (len = mbtk_ftp_download_continue(mbtk_at_ftp_par_at.at_ftp_handle)) > 0)
+            {
+                len_count += len;
+                download_time++;
+                printf("Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+                /*
+                memset(resp_buf,0,1024);
+                sprintf(resp_buf,"Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+                mbtk_at_printf(resp_buf);
+                */
+            }
+    
+            printf("Download complete - [%d / %d].\n",len_count, file_size);
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf, "+CFTPGETFILE: SUCCESS,<%d>\r\n",len_count);
+            mbtk_at_printf(resp_buf);
+            //ret = ATRESP(30163, 0, 0, resp_buf);
+        }
+        else
+        {
+            printf("FTP download fail[%d / %d].\n",len_count, file_size);
+            memset(resp_buf,0,1024);
+            sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d / %d> len=%d",len_count, file_size,len);
+            mbtk_at_printf(resp_buf);
+            //ret = ATRESP(30163, 0, 0, resp_buf);
+            goto exit;
+        }
+    }else {
+        printf("File error.\n");
+        memset(resp_buf,0,1024);
+        sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d>\r\n",904);
+        mbtk_at_printf(resp_buf);
+        //ret = ATRESP(30163, 0, 0, resp_buf);
+        goto exit;
+    }
+
+    
+exit:
+    if(file_size != len_count)
+        mbtk_at_ftp_par_at.rest_size = len_count;
+    
+    //mbtk_at_printf(resp_buf);
+    mbtk_at_printf("end");
+    mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+    mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+    return at_ftp_ret;
+
+}
+
+void ftp_ls_at_cb_func(void *file_list_cb)
+{
+    int ret;
+    char resp_buf[1024 + 1];
+    printf("+CFTPLIST:\r\n%s\n", ((mbtk_ftp_file_info_s *)file_list_cb)->name);
+    sprintf(resp_buf, "%s",((mbtk_ftp_file_info_s *)file_list_cb)->name);
+    mbtk_at_printf(resp_buf);
+    //ret = ATRESP(30163, 0, 0, resp_buf);
+}
+
+
+int mbtk_at_ftp_list(char *ftp_path)
+{
+    int at_ftp_ret=-1;
+    int len_size;
+    char resp_buf[1024];
+    
+    mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+                                    0, mbtk_at_ftp_par_at.use_cert);
+    mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+    if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+        at_ftp_ret = -1;
+    
+    at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+    if(at_ftp_ret != 0)
+    {
+        printf("ftp_login err:%d\n",at_ftp_ret);
+    }
+
+    memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+    memcpy(mbtk_at_ftp_par_at.remote_path, ftp_path, strlen(ftp_path)+1);
+    
+    at_ftp_ret = mbtk_ftp_cd(mbtk_at_ftp_par_at.at_ftp_handle, ftp_path);
+    if(FTP_ERR_SUCCESS != at_ftp_ret) {
+        printf("mbtk_ftp_cd() fail:%d\n", at_ftp_ret);
+        sprintf(resp_buf,"+CFTPLIST: FAIL:%d\n", at_ftp_ret);
+        goto exit;
+    }
+    mbtk_at_printf("+CFTPLIST:");
+    mbtk_ftp_file_info_s list_head;
+    list_head.ftp_ls_cb_typedef = ftp_ls_at_cb_func;
+    at_ftp_ret = mbtk_ftp_dir_ls(mbtk_at_ftp_par_at.at_ftp_handle, &list_head);
+    if(FTP_ERR_SUCCESS != at_ftp_ret) {
+        printf("mbtk_ftp_dir_ls() fail:%d\n", at_ftp_ret);
+        sprintf(resp_buf,"+CFTPLIST: FAIL:%d\n", at_ftp_ret);
+        goto exit;
+    }
+    else
+    {
+        printf("+CFTPLIST: SUCCESS\r\n");
+        sprintf(resp_buf,"+CFTPLIST: SUCCESS\r\n");
+    }
+exit:
+    mbtk_at_printf(resp_buf);
+    mbtk_at_printf("end");
+    mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+    mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+    return at_ftp_ret;
+}
+
+int mbtk_at_get_ftp_data_info(char *remote_path, char *local_path, int *rest_size, int *read_size, int *put_len)
+{
+    if(remote_path != NULL)
+    {
+        memset(remote_path, 0, strlen(remote_path)+1);
+        memcpy(remote_path, mbtk_at_ftp_par_at.remote_path, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+    }
+    if(local_path != NULL)
+    {
+        memset(local_path, 0, strlen(local_path)+1);
+        memcpy(local_path, mbtk_at_ftp_par_at.local_path, strlen(mbtk_at_ftp_par_at.local_path)+1);
+    }
+    if(rest_size != NULL)
+        *rest_size = mbtk_at_ftp_par_at.rest_size;
+    if(read_size != NULL)
+        *read_size = mbtk_at_ftp_par_at.read_size;
+    if(put_len != NULL)
+        *put_len = mbtk_at_ftp_par_at.put_len;
+    return 0;
+}
+
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_gnss.c b/mbtk/mbtk_lib/src/mbtk_gnss.c
new file mode 100755
index 0000000..72c207c
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_gnss.c
@@ -0,0 +1,2214 @@
+/**
+ *   \file mbtk_gnss.c
+ *   \brief gnss module.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-16
+ */
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "mbtk_type.h"
+#include "mbtk_gnss.h"
+#include "mbtk_http.h"
+#include "mbtk_log.h"
+#include "ringbuffer.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+    #define gnss_log(...)                    printf(__VA_ARGS__)
+#else
+    #define gnss_log(...)
+#endif
+
+// 默认为 9600,打开为 115200,但是 AT+MGPSCMD 会重启。
+#define BAUDRATE_115200  1
+
+#define TTFF_TEST   0
+
+#define MBTK_GNSS_DEV  "/dev/ttyS2"
+
+#define MBTK_UART_RECV_BUFFER_SIZE 1024
+#define MBTK_UART_SEND_BUFFER_MAX 128
+
+/******************************************************************************
+ * 时间处理相关的宏
+ *****************************************************************************/
+// 获取当前时间
+#define GET_TIME()  { gettimeofday(&time_m, NULL); \
+    time_m.tv_sec += TIMEOUT_SEC;\
+}
+// 设置从循环中退出的时间
+#define SET_TIME_OUT(x)  { gettimeofday(&time_m, NULL); \
+    time_m.tv_sec += x;\
+}
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME()  { gettimeofday(&time_n, NULL); \
+    if(time_n.tv_sec > time_m.tv_sec) { \
+        printf("\ntimeout!!!\n\n");\
+        close(fd); \
+        return ret; \
+    } \
+}
+// 检测时间是否超时,超时则退出当前循环
+#define CHK_TIME_BREAK()  { gettimeofday(&time_n, NULL); \
+    if(time_n.tv_sec > time_m.tv_sec) { \
+        printf("\ntimeout!!!\n\n");\
+        break; \
+    } \
+}
+// 检测延时是否到达,到达则退出当前循环
+#define DELAY_TIME_BREAK()  { gettimeofday(&time_n, NULL); \
+    if(time_n.tv_sec > time_m.tv_sec) { \
+        break; \
+    } \
+}
+
+typedef void (*gnss_msg_func_t)
+(
+    int index,
+    char *in_data,
+    void *out_ptr
+);
+
+struct mbtk_gnss_cmd_msg_t
+{
+    int index; // 序号
+    char *cmd_str; // 匹配字符
+    gnss_msg_func_t gnss_msg_func; // 回调函数
+    int is_continue; // 是否随NEMA数据一起输出
+};
+
+typedef enum
+{
+    E_MT_LOC_MSG_ID_STATUS_INFO = 0,        /**<  pv_data = &E_QL_LOC_STATUS_VALUE_T  */
+    E_MT_LOC_MSG_ID_LOCATION_INFO,          /**<  pv_data = &QL_LOC_LOCATION_INFO_T  */
+    E_MT_LOC_MSG_ID_SV_INFO,                /**<  pv_data = &QL_LOC_SV_STATUS_T  */
+    E_MT_LOC_MSG_ID_NMEA_INFO,              /**<  pv_data = &QL_LOC_NMEA_INFO_T  */
+    E_MT_LOC_MSG_ID_CAPABILITIES_INFO,      /**<  pv_data = &E_QL_LOC_CAPABILITIES_T  */
+    E_MT_LOC_MSG_ID_AGPS_STATUS,            /**<  pv_data = &QL_LOC_AGPS_STATUS_T  */
+    E_MT_LOC_MSG_ID_NI_NOTIFICATION,        /**<  pv_data = &QL_LOC_NI_NOTIFICATION_INTO_T  */
+    E_MT_LOC_MSG_ID_XTRA_REPORT_SERVER,     /**<  pv_data = &QL_LOC_XTRA_REPORT_SERVER_INTO_T  */
+}e_mt_loc_msg_id_t;
+
+typedef struct
+{
+    int64_t     timestamp;                          /**<   System Timestamp, marked for when got the nmea data */
+    int         length;                             /**<   NMEA string length. */
+    char        nmea[255 + 1];   /**<   NMEA string.*/
+}mopen_gnss_nmea_info_t;  /* Message */
+
+struct mbtk_gnss_handle_t
+{
+    int dev_fd;
+    pthread_t  uart_pthread;
+    pthread_t  gnss_pthread;
+    mbtk_gnss_handler_func_t gnss_handler_func;
+    int mode; // 0 - stop, 1 - single, 2 - periodic, 3 - start
+    pthread_mutex_t _cond_mutex;
+    int reset_state;
+    int inited;
+    ring_buffer_t ring_buffer;
+    int getap_status;
+    char *rb;
+
+#if TTFF_TEST
+    pthread_t ttff_pid;
+    int location_state;
+#endif
+    /********************
+    存储handle的地址指针
+    phandle = &handle
+    handle  = mbtk_gnss_handle
+    *********************/
+    uint32 *phandle; // handle的地址指针
+};
+
+#if TTFF_TEST
+struct mbtk_gnss_ttff_t
+{
+    int type;
+    int timeout_sec;
+    int test_count;
+    int average_loc_time;
+};
+
+// ttff 测试 flag
+static int location_test = 0;
+static pthread_mutex_t loc_cond_mutex_r = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t loc_sync_cond = PTHREAD_COND_INITIALIZER;
+#endif
+
+struct mopen_gnss_device_info_t
+{
+    int      device_info_valid;
+    int      usrt_bandrate;
+    char     product_name[10];
+    char     dev_config[6];
+    char     hw_ver[6];
+    char     fw_ver[32];
+    char     pn[16];
+    char     sn[16];
+    char     nmea_ver[4];
+};
+
+static struct mopen_gnss_device_info_t mopen_gnss_device_info;
+static struct mbtk_gnss_handle_t *mbtk_gnss_handle = NULL;
+static int firmware_extren_state = 0;
+
+static char g_no_sv = 0;// 参与定位的卫星数量
+
+int mopen_gnss_get_nmea_config(uint32 h_gnss);
+int mopen_gnss_get_ant_state_info(uint32 h_gnss);
+
+static void get_gnss_time_info(int cmd, char *str, void *data);
+static void get_gnss_agnss_state(int cmd, char *str, void *data);
+static void get_gnss_device_info(int type, char *str, void *usr_ptr);
+static void gnss_uart_info(int cmd, char *str, void *data);
+static void gnss_gsa_info(int cmd, char *str, void *data);
+static int mopen_uart_change(int fd, int check);
+
+static int select_read( int fd, int timeout );
+ssize_t deal_read(int fd, void *buf, size_t count);
+
+static struct mbtk_gnss_cmd_msg_t mbtk_gnss_cmd_msg_map[] = {
+{ 1,     "$OK",         NULL,                 0},
+{ 2,     "$Fail",       NULL,                 0},
+{ 3,     "RMC",         get_gnss_time_info,   1},
+{ 4,     "GGA",         get_gnss_time_info,   1},
+{ 5,     "$PDTINFO",    get_gnss_device_info, 0},
+{ 6,     "$CFGNMEA",    get_gnss_device_info, 0},
+{ 7,     "$CFGPRT",     gnss_uart_info,       0},
+{ 8,     "$CFGAID",     get_gnss_agnss_state, 0},
+{ 9,     "$ANTSTAT",    NULL,                 0},
+#if TTFF_TEST
+{10,     "GSA",         gnss_gsa_info,        1},
+#endif
+};
+
+/**
+ *  \brief strstr_n
+ *
+ *  find string return number
+ *
+ *  \param param
+ *  \return return type
+ */
+int strstr_n(const char *s1, const char *s2)
+{
+    int n;
+    int strlen = 0;
+
+    if(*s2)
+    {
+        while(*s1)
+        {
+            for(n = 0; *(s1+n) == *(s2 + n); n++)
+            {
+                if(!*(s2 + n + 1))
+                {
+                    strlen++;
+                    return strlen;
+                }
+            }
+            s1++;
+            strlen++;
+        }
+        return 0;
+    }
+    else
+        return 0;
+}
+
+/**
+ * @brief      gnss_get_para_from_nmea
+ *
+ * @details    从buf里面得到第num个逗号所在的位置
+ *
+ * @param      param
+ *
+ * @return     0~0xfe,代表逗号所在位置的偏移.
+ *             0xff,代表不存在第cx个逗号
+ */
+static int gnss_get_para_from_nmea(const char *data, char *out_data, int num)
+{
+    int i = 0;
+    int n[2] = {0};
+    int tmp;
+
+    // 找到第num个",",结果放到 n[0]
+    for (i = 0; i < num; ++i) {
+        tmp = strstr_n(&data[n[0]], ",");
+        if(0 == tmp) {
+            gnss_log("%s %d : error\n", __func__, __LINE__);
+            gnss_log("error: [%d] %s\n", num, data);
+            return -1;
+        }
+        n[0] += tmp;
+    }
+    if ((n[1] = strstr_n(&data[n[0]], ",")) ||
+        (n[1] = strstr_n(&data[n[0]], "*")) &&
+        (n[1] > 1)) {
+        memcpy(out_data, &data[n[0]], n[1] - 1);
+    } else {
+        gnss_log("%s %d : error [%d]\n" , __func__, __LINE__, n[1]);
+        gnss_log("error: [%d] %s\n", num, data);
+        return -1;
+    }
+
+    return 0;
+}
+/**
+* @brief      get_timestamp
+*
+* @details
+*
+* @param      param
+*
+* @return     return type
+*/
+static time_t get_timestamp(char *time)
+{
+    char tmp_char[4] = {0};
+    struct tm* tmp_time = (struct tm*)malloc(sizeof(struct tm));
+
+    memset(tmp_time, 0, sizeof(struct tm));
+    memset(tmp_char, 0, sizeof(tmp_char));
+    memcpy(tmp_char, &time[4], 2);
+    tmp_time->tm_sec = atoi(tmp_char);
+    memcpy(tmp_char, &time[2], 2);
+    tmp_time->tm_min = atoi(tmp_char);
+    memcpy(tmp_char, &time[0], 2);
+    tmp_time->tm_hour = atoi(tmp_char);
+    memcpy(tmp_char, &time[6], 2);
+    tmp_time->tm_mday = atoi(tmp_char);
+    memcpy(tmp_char, &time[8], 2);
+    tmp_time->tm_mon = atoi(tmp_char);
+    memcpy(tmp_char, &time[10], 2);
+    tmp_time->tm_year = 100 + atoi(tmp_char);
+
+    time_t _t = mktime(tmp_time);//按当地时区解析tmp_time
+    // gnss_log("timestamp: %ld\n",_t);
+    free(tmp_time);
+
+    return _t;
+}
+/**
+ * @brief      get_gnss_device_info
+ *
+ * @details    获取设备信息
+ *
+ * @param      type: 5-从$PDTINFO获取
+ *                   6-从$CFGNMEA获取
+ *
+ * @return     return type
+ */
+static void get_gnss_device_info(int type, char *str, void *usr_ptr)
+{
+    char tmp_str[32] = {0};
+    int i, ret;
+
+    if(5 == type) // define  mbtk_gnss_cmd_msg_map
+    {
+        // $PDTINFO get product info
+        char *tmp_ptr[6] = {mopen_gnss_device_info.product_name,
+                            mopen_gnss_device_info.dev_config,
+                            mopen_gnss_device_info.hw_ver,
+                            mopen_gnss_device_info.fw_ver,
+                            mopen_gnss_device_info.pn,
+                            mopen_gnss_device_info.sn
+        };
+        for (i = 0; i < 6; ++i) {
+            memset(tmp_str, 0, sizeof(tmp_str));
+            // get product name
+            ret = gnss_get_para_from_nmea(str, tmp_str, i + 1);
+            if(ret)
+                continue;
+            memcpy(tmp_ptr[i], tmp_str, strlen(tmp_str));
+        }
+        gnss_log("*************************\n");
+        gnss_log("-Pn: %s\n dc: %s\n hv: %s\n fw: %s\n pn: %s\n sn: %s\n ",
+                            mopen_gnss_device_info.product_name,
+                            mopen_gnss_device_info.dev_config,
+                            mopen_gnss_device_info.hw_ver,
+                            mopen_gnss_device_info.fw_ver,
+                            mopen_gnss_device_info.pn,
+                            mopen_gnss_device_info.sn);
+    }
+    if(6 == type) // define  mbtk_gnss_cmd_msg_map
+    {
+        // $CFGNMEA get nmea version
+        memset(tmp_str, 0, sizeof(tmp_str));
+        ret = gnss_get_para_from_nmea(str, tmp_str, 1);
+        if(ret)
+            return;
+        memcpy(mopen_gnss_device_info.nmea_ver, tmp_str, strlen(tmp_str));
+        mopen_gnss_device_info.device_info_valid = TRUE;
+    }
+}
+
+static short int from_hex(char a)
+{
+    if (a >= 'A' && a <= 'F')
+        return a - 'A' + 10;
+    else if (a >= 'a' && a <= 'f')
+        return a - 'a' + 10;
+    else
+        return a - '0';
+}
+
+static int str_to_hex(char *str)
+{
+    unsigned char str_len = strlen(str);
+    int i;
+    int ret = 0;
+
+    for (i = 0; i < str_len; ++i) {
+        ret = ret * 16 + from_hex(str[i]);
+    }
+    return ret;
+}
+
+static void get_gnss_agnss_state(int cmd, char *str, void *data)
+{
+    int ret;
+    char tmp_str[10] = {0};
+    int agps;
+    static int count = 0;
+
+    ret = gnss_get_para_from_nmea(str, tmp_str, 2);
+    if(ret) {
+        printf("\n%s[%d] error!\n" , __FUNCTION__, __LINE__);
+    }
+    agps = str_to_hex(tmp_str);
+    gnss_log("\n%s[%d] agnss: %s[%x]\n" , __FUNCTION__, __LINE__, tmp_str, agps);
+    if(0 == agps && count < 5) {
+        mopen_gnss_get_aidinfo(mbtk_gnss_handle);
+        count++;
+    } else {
+        printf("\nagnss: %s\n", str);
+        count = 0;
+    }
+    //  $CFGAID,0,00000000,00000000,00*3E
+}
+// 1节=1海里/小时=1.852公里/小时
+/**
+ * @brief      function description
+ *
+ * @details    获取位置信息
+ *
+ * @param      type: 1-从$RMC获取
+ *                   2-从$GGA获取
+ * @return     return type
+ */
+static void get_gnss_loc_info(int type, char *str,
+                              struct mbtk_gnss_location_info_t *_mopen_location_info)
+
+{
+    char tmp_str[32] = {0};
+    int ret;
+
+    if(1 == type)
+    {
+        // $PDTINFO get product info
+        memset(tmp_str, 0, sizeof(tmp_str));
+        // get product name
+        ret = gnss_get_para_from_nmea(str, tmp_str, 7);
+        if(ret)
+            return;
+        _mopen_location_info->speed = atof(tmp_str);
+        memset(tmp_str, 0, sizeof(tmp_str));
+        // get product name
+        ret = gnss_get_para_from_nmea(str, tmp_str, 8);
+        if(ret)
+            return;
+        _mopen_location_info->bearing = atof(tmp_str);
+    }
+    else if(2 == type)
+    {
+        // $XXGGA get product info
+        memset(tmp_str, 0, sizeof(tmp_str));
+        // get product name
+        ret = gnss_get_para_from_nmea(str, tmp_str, 2);
+        if(ret)
+            return;
+        _mopen_location_info->latitude = atof(tmp_str);
+        memset(tmp_str, 0, sizeof(tmp_str));
+        // get product name
+        ret = gnss_get_para_from_nmea(str, tmp_str, 4);
+        if(ret)
+            return;
+        _mopen_location_info->longitude = atof(tmp_str);
+        memset(tmp_str, 0, sizeof(tmp_str));
+        // get product name
+        ret = gnss_get_para_from_nmea(str, tmp_str, 9);
+        if(ret)
+            return;
+        _mopen_location_info->altitude = atof(tmp_str);
+    }
+}
+
+static void get_gnss_time_info(int cmd, char *str, void *data)
+{
+    int ret;
+    char param[36] = {0};
+    struct mbtk_gnss_location_info_t *mopen_location_info_ptr = (struct mbtk_gnss_location_info_t *)data;
+
+    if (3 == cmd) {
+        memset(param, 0, sizeof(param));
+        // get time
+        ret = gnss_get_para_from_nmea(str, param, 1);
+        if(ret)
+            return;
+        // get date
+        ret = gnss_get_para_from_nmea(str, &param[6], 9);
+        if(ret)
+            return;
+
+        mopen_location_info_ptr->timestamp = get_timestamp(param);
+        get_gnss_loc_info(1, str, mopen_location_info_ptr);
+    } else if(4 == cmd) /* GGA */{
+        get_gnss_loc_info(2, str, mopen_location_info_ptr);
+        ret = gnss_get_para_from_nmea(str, param, 7);
+        if(ret)
+            return;
+        char no_sv = (char)atoi(param);
+        gnss_log("SV number: %d, %d\n", g_no_sv, no_sv);
+        /*
+          只能在临时固件下,才能获取APdata星历数据
+          在6颗卫星保存文件,每增加2颗保存一次。
+         */
+        if (1 == firmware_extren_state &&
+            g_no_sv < (no_sv - 1) && no_sv > 5) {
+
+            g_no_sv = no_sv;
+            mbtk_gnss_get_ap_data();
+        }
+    }
+}
+
+static void gnss_uart_info(int cmd, char *str, void *data)
+{
+    int ret;
+    char tmp_str[12] = {0};
+
+    // $CFGPRT,1,h0,9600,129,3*57
+    ret = gnss_get_para_from_nmea(str, tmp_str, 3);
+    if(ret)
+        return;
+    mopen_gnss_device_info.usrt_bandrate = atoi(tmp_str);
+    gnss_log("CFGPRT: %s\n", str);
+    gnss_log("Uart bandrate: %d\n" , mopen_gnss_device_info.usrt_bandrate);
+    gnss_log("*************************\n");
+}
+/**
+ *  \brief function description
+ *
+ *  Detailed 处理gnss数据
+ *
+ *  \param param
+ *  \return return type
+ */
+static void process_gnss_callback(struct mbtk_gnss_handle_t *handle,
+                                  const char *data, int data_len)
+{
+    int ret = 0;
+    int i = 0;
+    static struct mbtk_gnss_location_info_t mopen_location_info;
+    static int64_t tmp_time = 0;
+    mopen_gnss_nmea_info_t nmea_info;
+
+    memset(&nmea_info, 0, sizeof(nmea_info));
+    if(0 == tmp_time)
+        memset(&mopen_location_info, 0, sizeof(mopen_location_info));
+
+    for (i = 0;
+         i < (sizeof(mbtk_gnss_cmd_msg_map) / sizeof(struct mbtk_gnss_cmd_msg_t));
+         ++i) {
+        if(strstr_n(data, mbtk_gnss_cmd_msg_map[i].cmd_str)) {
+            if(mbtk_gnss_cmd_msg_map[i].gnss_msg_func)
+                mbtk_gnss_cmd_msg_map[i].gnss_msg_func(mbtk_gnss_cmd_msg_map[i].index,
+                                                   data, &mopen_location_info);
+            break;
+        }
+    }
+    if(0 == mbtk_gnss_cmd_msg_map[i].is_continue)
+        return;
+
+    tmp_time = mopen_location_info.timestamp;
+    nmea_info.timestamp = mopen_location_info.timestamp;
+    nmea_info.length = data_len;
+    memcpy(nmea_info.nmea, data, data_len);
+    gnss_log("nmea:[%d] %s", data_len, data);
+    if(handle->gnss_handler_func && handle->mode == 3 &&
+       nmea_info.timestamp)
+        handle->gnss_handler_func(handle, E_MT_LOC_MSG_ID_NMEA_INFO, &nmea_info, NULL);
+    if(handle->gnss_handler_func && handle->mode == 1 &&
+            mopen_location_info.latitude &&
+            mopen_location_info.longitude &&
+            mopen_location_info.altitude &&
+            mopen_location_info.timestamp &&
+            mopen_location_info.speed)
+    {
+        handle->gnss_handler_func(handle, E_MT_LOC_MSG_ID_LOCATION_INFO, &mopen_location_info, NULL);
+        memset(&mopen_location_info, 0, sizeof(mopen_location_info));
+    }
+
+    return;
+}
+
+/**
+ *  \brief get_gnss_from_str
+ *
+ *  Detailed 从串口数据解析出每条消息
+ *
+ *  \param param
+ *  \return return type
+ */
+static int get_gnss_from_str(struct mbtk_gnss_handle_t *handle,
+                             const char *data, int data_len)
+{
+    char *tail = NULL;
+    static int seek = 0;
+    // 等待 OK, 如果20条结果没有等到,就异常
+    static int reset_count = 0;
+    int i = 0, ret = -1;
+
+    if (handle->reset_state)
+    {
+        // 等待 reset 回复的 OK
+        if(0 != memcmp(data, "$OK", 3) && reset_count < 20) {
+            printf("gnss reset invalid: [%s]\n", data);
+            reset_count++;
+            return -1;
+        }
+        if (reset_count > 19) {
+            printf("%s: device reset timeout!!!\n", __FUNCTION__);
+            LOGI("%s: device reset timeout!!!\n", __FUNCTION__);
+        }
+        reset_count = 0;
+        gnss_log("reset ok: %s\n", data);
+#if BAUDRATE_115200
+        ret = mopen_uart_change(handle->dev_fd, 0);
+        if(ret) {
+            printf("reset Uart set 115200 error\n");
+        }
+#endif
+        pthread_mutex_lock(&handle->_cond_mutex);
+        handle->reset_state = 0;
+        pthread_mutex_unlock(&handle->_cond_mutex);
+    }
+
+    if((data[0] == '$' || data[0] == '#') &&
+       data[data_len - 1] == '\n' &&
+       data_len < 128) {
+        process_gnss_callback(handle, data, data_len);
+    } else {
+        gnss_log("nmea error: %s\n", data);
+    }
+
+    return 1;
+}
+
+void mopen_gnss_NonBlock(int fd, int cmd)
+{
+    int flags;
+
+    flags = fcntl(fd, F_GETFL, 0);
+    if(cmd)
+        flags |= O_NONBLOCK;
+    else
+        flags &= ~O_NONBLOCK;
+
+    fcntl(fd, F_SETFL, flags);
+}
+
+int set_baudrate(int fd, int baudrate)
+{
+    struct termios options, oldtio;
+
+    if(fcntl(fd, F_SETFL, 0) < 0) {
+        printf("fcntl failed!\n");
+        return -1;
+    }
+
+    if(tcgetattr(fd, &oldtio) != 0) {
+        printf("setup serial error!\n");
+        return -1;
+    }
+
+    /* Get the current options for the port... */
+    tcgetattr(fd, &options);
+
+    /* Set the baud rates to baudrate... */
+    cfsetispeed(&options,baudrate);
+    cfsetospeed(&options,baudrate);
+    tcsetattr(fd, TCSANOW, &options);
+
+    if (0 != tcgetattr(fd, &options))
+    {
+        printf("get options error!\n");
+        return -1;
+    }
+
+    /*
+     * 8bit Data,no partity,1 stop bit...
+     */
+    options.c_cflag &= ~PARENB;//无奇偶校验
+    options.c_cflag &= ~CSTOPB;//停止位,1位
+    options.c_cflag &= ~CSIZE; //数据位的位掩码
+    options.c_cflag |= CS8;    //数据位,8位
+
+    cfmakeraw(&options);
+
+    /*
+     * Set the new options for the port...
+     */
+    if (tcsetattr(fd, TCSANOW, &options) != 0)
+    {
+        printf("setup serial error!\n");
+        return -1 ;
+    }
+
+    return 0 ;
+}
+/*
+  自适应波特率设置
+ */
+static int auto_set_uart_baudrate(int fd)
+{
+    char rbuf[512];
+    int rByte = 0;
+    int b[3] = {B115200, B9600, 0};
+    int ret = B9600;
+    struct timeval time_m, time_n;
+    // 时间超时标志
+    int timeout_sign = 0;
+    // 先测试默认的9600波特率
+    SET_TIME_OUT(3);
+    do {
+        gettimeofday(&time_n, NULL);
+        if(time_n.tv_sec > time_m.tv_sec) {
+            printf("Baudrate--test-9600--- timeout!\n");
+            if(timeout_sign)
+                break;
+            set_baudrate(fd, B115200);
+            ret = B115200;
+            timeout_sign = 1;
+            SET_TIME_OUT(3);
+            continue;
+        }
+
+        if(select_read(fd, 1) > 0)
+            usleep(50000);
+        else
+            continue;
+
+        rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+        if(rByte > 0) {
+            gnss_log("Auto Baudrate[%d]%s\n", rByte, rbuf);
+            if(strstr(rbuf, "$"))
+                return ret;
+            memset(rbuf, 0, sizeof(rbuf));
+        } else {
+            printf("*** read error\n");
+        }
+	}while(1);
+
+    return -1;
+}
+
+int mopen_gnss_open(char *dev, int baudrate)
+{
+    int ret;
+    int fd = 0;
+
+    fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
+    if(fd < 0) {
+        return -1;
+    }
+    gnss_log("curent dev: %s, fd: %d \n", dev, fd);
+
+    if(baudrate) {
+        gnss_log("set baudrate: %d \n", baudrate);
+        ret = set_baudrate(fd, baudrate);
+        if(-1 == ret) {
+            close(fd);
+            return -1;
+        }
+    } else {
+        set_baudrate(fd, B9600);
+    }
+
+    return fd;
+}
+
+static int mopen_gnss_read(int fd, char* buf, unsigned int buf_len)
+{
+     buf_len=(buf_len > MBTK_UART_RECV_BUFFER_SIZE ? MBTK_UART_RECV_BUFFER_SIZE : buf_len);
+     return read(fd, buf, buf_len);
+}
+
+int mopen_gnss_write(int fd, const char* buf, unsigned int buf_len)
+{
+    size_t size;
+    size_t size_to_wr;
+    ssize_t size_written;
+    if(MBTK_UART_SEND_BUFFER_MAX < buf_len)
+    {
+        return -1;
+    }
+    for(size = 0; size < buf_len;)
+    {
+        size_to_wr = buf_len - size;
+        if( size_to_wr > MBTK_UART_SEND_BUFFER_MAX)
+            size_to_wr = MBTK_UART_SEND_BUFFER_MAX;
+
+        size_written = write(fd, &buf[size], size_to_wr);
+        if (size_written==-1)
+        {
+            return -1;
+        }
+        gnss_log("send cmd: %s", &buf[size]);
+        size += size_written;
+        if(size_written != size_to_wr)
+        {
+            return size;
+        }
+    }
+    return size;
+}
+
+int mopen_gnss_close(int fd)
+{
+    return close(fd);
+}
+
+static void gnss_info_pthread(void* hdl)
+{
+    struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)hdl;
+    int ret = 0, i;
+    char tmp;
+    char tmp_arr[128] = {0};
+
+    pthread_detach(pthread_self());
+
+    memset(tmp_arr, 0, sizeof(tmp_arr));
+    while(mbtk_gnss_handle->inited)
+    {
+        for (i = 0; i < 256; ++i) {
+            if (0 == mbtk_gnss_handle->inited)
+                goto exit;
+            ret = ring_buffer_peek(&gnss_handle->ring_buffer, &tmp, i);
+            if (0 == ret) {
+                usleep(300000);
+                gnss_log("ring_buffer_peek ringbuffer read error\n");
+                i--;
+                continue;
+            }
+            if (tmp == '\n') {
+                break;
+            }
+        }
+
+        if (i > (256 - 2))
+            continue;
+
+        ret = ring_buffer_dequeue_arr(&gnss_handle->ring_buffer, tmp_arr, i + 1);
+
+        if(ret > 0 && 0 == mbtk_gnss_handle->getap_status) {
+            // gnss_log("NEMA:[%d] %s", ret, tmp_arr);
+            get_gnss_from_str(gnss_handle, tmp_arr, ret);
+            memset(tmp_arr, 0, sizeof(tmp_arr));
+        } else {
+            gnss_log("ringbuffer read error\n");
+        }
+        usleep(5000);
+    }
+ exit:
+    pthread_exit(NULL);
+}
+
+static void gnss_uart_pthread(void* hdl)
+{
+    struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)hdl;
+    int ret = 0;
+    char buf[MBTK_UART_RECV_BUFFER_SIZE] = {0};
+
+    pthread_detach(pthread_self());
+
+    memset(buf, 0, sizeof(buf));
+    while(mbtk_gnss_handle->inited)
+    {
+        while(mbtk_gnss_handle->getap_status){
+            // 在读AP_DATA星历时,不能输出NMEA
+            printf("g");
+            usleep(100000);
+        }
+        ret = mopen_gnss_read(gnss_handle->dev_fd, buf, MBTK_UART_RECV_BUFFER_SIZE);
+        if(ret > 0) {
+            // gnss_log("read: [%d] %s\n", ret, buf);
+            ring_buffer_queue_arr(&gnss_handle->ring_buffer, buf, ret);
+            memset(buf, 0, sizeof(buf));
+        } else {
+            gnss_log("read error\n");
+        }
+        usleep(100000);
+    }
+
+    pthread_exit(NULL);
+}
+
+ssize_t deal_read(int fd, void *buf, size_t count)
+{
+    int ret = 0;
+
+#if 0
+    ret = read(fd, buf, count);
+    return ret;
+#else
+    while (1)
+    {
+        ret = read(fd, buf, count);
+        if (ret == 0) {
+            printf("read serial return 0, please check serial device.\n");
+            exit(-5);
+        }
+        if(ret < 0) {
+            if ((errno == EAGAIN) || (errno == EINTR)) {
+                printf("read serial return -1, errno = %d, retry.\n", errno);
+                continue;
+            } else {
+                printf("read serial return -1, errno = %d, please check serial device.\n", errno);
+                exit(-5);
+            }
+        }
+        return ret;
+    }
+#endif
+}
+
+static int select_read( int fd, int timeout ) //1ms
+{
+    fd_set set;
+    struct timeval t;
+    int ret;
+    int i = timeout;
+
+    do {
+        FD_ZERO(&set);
+        FD_SET(fd, &set);
+        t.tv_sec = 0;
+        t.tv_usec = 100;
+
+        ret = select(FD_SETSIZE, &set, NULL, NULL, &t );
+        if(ret == 0) continue;
+        if(ret < 0 && errno == EINTR)continue;
+        else return ret;
+    } while(i--);
+
+    return ret;
+}
+
+// check: 是否需要校验
+static int mopen_uart_change(int fd, int check)
+{
+    int rByte = 0, i = 20;
+    char name[32];
+    char rbuf[1024];
+
+    sprintf(name,"$CFGPRT,1,h0,115200,129,3\r\n");
+    rByte = write( fd, name, strlen(name));
+    tcdrain(fd);
+
+    set_baudrate(fd, B115200);
+    usleep(200000);
+    tcflush(fd, TCIFLUSH);
+
+    if (0 == check)
+        return 0;
+    do{
+        rByte = 0;
+        memset(rbuf, 0, sizeof(rbuf));
+        if(select_read(fd, 1) > 0) {
+            rByte = deal_read(fd, &rbuf, sizeof(rbuf) - 1);
+            rbuf[rByte] = 0;
+            gnss_log("%s: %s", __FUNCTION__, rbuf);
+        }
+        if(strstr(rbuf, "$")) {
+            return 0;
+        } else {
+            gnss_log("%d rByte = %d, [%s]\n", 20 - i, rByte, rbuf);
+        }
+        usleep(5000 * 100);
+    }while(i--);
+
+    return -1;
+}
+
+#define GPS_DEV "/sys/devices/soc.0/d4000000.apb/mbtk-dev-op/gps_power"
+
+static int mopen_open_gps(int state)
+{
+    int fd, ret;
+    char s[4] = "on";
+    fd = open(GPS_DEV, O_RDWR | O_TRUNC, 0644);
+    if(fd < 0) {
+        LOGE("[%s]  file [%s] open error\n", __FUNCTION__, GPS_DEV);
+        return -1;
+    }
+    if(0 == state)
+    {
+        memcpy(s, "off", 3);
+    }
+    ret = write(fd, s, 4);
+    if (ret < 0) {
+        LOGE("%s: error writing to file!\n", __FUNCTION__);
+        close(fd);
+        return -2;
+    }
+
+    close(fd);
+    return 0;
+}
+
+int mbtk_gnss_client_init(uint32 *ph_gnss)
+{
+    int ret;
+
+    if(ph_gnss == NULL) {
+        printf("ARG error or has inited.");
+        return -1;
+    }
+
+    if (mbtk_gnss_handle) {
+        printf("GNSS has inited.");
+        *ph_gnss = (uint32)mbtk_gnss_handle;
+        return 0;
+    }
+    mbtk_gnss_handle = malloc(sizeof(struct mbtk_gnss_handle_t));
+    if(NULL == mbtk_gnss_handle)
+    {
+        printf("malloc memory error\n");
+        return -3;
+    }
+    memset(mbtk_gnss_handle, 0, sizeof(struct mbtk_gnss_handle_t));
+    memset(&mopen_gnss_device_info, 0, sizeof(mopen_gnss_device_info));
+
+    ret = mopen_open_gps(1);
+    if(ret) {
+        printf("GNSS open init error\n");
+        return -4;
+    }
+    sleep(1);
+
+    mbtk_gnss_handle->dev_fd = mopen_gnss_open(MBTK_GNSS_DEV, 0);
+
+    printf("Gnss Config Uart Baudrate Start -> \n");
+    ret = auto_set_uart_baudrate(mbtk_gnss_handle->dev_fd);
+    if(-1 == ret) {
+        ret = -2;
+        goto err;
+    } else if (B9600 == ret) {
+        ret = mopen_uart_change(mbtk_gnss_handle->dev_fd, 1);
+        if(ret)
+        {
+            printf("GNSS Uart set B115200 error\n");
+            mopen_gnss_close(mbtk_gnss_handle->dev_fd);
+            mopen_open_gps(0);
+            return -1;
+        }
+    }
+    printf("Gnss Config Uart Baudrate Successful.\n");
+
+    mbtk_gnss_handle->rb = malloc(MBTK_UART_RECV_BUFFER_SIZE);
+    if(NULL == mbtk_gnss_handle->rb)
+    {
+        printf("malloc memory error\n");
+        return -1;
+    }
+
+    ring_buffer_init(&mbtk_gnss_handle->ring_buffer,
+                     mbtk_gnss_handle->rb,
+                     MBTK_UART_RECV_BUFFER_SIZE);
+
+    mbtk_gnss_handle->inited = 1;
+
+    pthread_mutex_init(&mbtk_gnss_handle->_cond_mutex, NULL);
+    pthread_create(&mbtk_gnss_handle->uart_pthread, NULL, (void *)gnss_uart_pthread, (void *)mbtk_gnss_handle);
+    pthread_create(&mbtk_gnss_handle->gnss_pthread, NULL, (void *)gnss_info_pthread, (void *)mbtk_gnss_handle);
+
+    mopen_gnss_get_ant_state_info((uint32)mbtk_gnss_handle);
+    mopen_gnss_get_device_info((uint32)mbtk_gnss_handle);
+    mopen_gnss_get_nmea_config((uint32)mbtk_gnss_handle);
+    mopen_gnss_get_uart((uint32)mbtk_gnss_handle);
+    mopen_gnss_get_aidinfo((uint32)mbtk_gnss_handle);
+
+    *ph_gnss = (uint32)mbtk_gnss_handle;
+    mbtk_gnss_handle->phandle = ph_gnss;
+
+    return 0;
+ err:
+    mopen_gnss_close(mbtk_gnss_handle->dev_fd);
+    mopen_open_gps(0);
+    firmware_extren_state = 0;
+    if (mbtk_gnss_handle) free(mbtk_gnss_handle);
+    mbtk_gnss_handle = NULL;
+
+    return ret;
+}
+static int _kill_pthread(pthread_t pid, int kill)
+{
+    int ret;
+
+    if (kill) {
+        ret = pthread_cancel(pid);
+        pthread_join(pid, NULL);
+    }
+    do{
+        ret = pthread_kill(pid, 0);
+        if(ret == ESRCH)
+            gnss_log("The specified thread does not exist or has terminated\n");
+        else if(ret == EINVAL)
+            gnss_log("Useless signal\n");
+        else
+            gnss_log("The thread exists\n");
+        usleep(100000);
+    }while(0 == ret);
+
+    return 0;
+}
+int mbtk_gnss_client_deinit(uint32 h_gnss)
+{
+    int ret;
+    struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+
+    if(h_gnss == NULL)
+    {
+        gnss_log("ARG error or not inited.");
+        return -1;
+    }
+    gnss_handle->inited = 0;
+#if TTFF_TEST
+    // ttff测试线程在运行,而且不是临时固件模式
+    if (gnss_handle->ttff_pid &&
+        0 == firmware_extren_state &&
+        0 == location_test) {
+        gnss_log("kill thread ttff.\n");
+        _kill_pthread(gnss_handle->ttff_pid, 1);
+    }
+#endif
+    gnss_log("kill thread info 0.\n");
+    _kill_pthread(gnss_handle->gnss_pthread, 0);
+
+    gnss_log("kill thread uart.\n");
+    _kill_pthread(gnss_handle->uart_pthread, 0);
+
+    mopen_gnss_close(gnss_handle->dev_fd);
+
+    ret = mopen_open_gps(0);
+    if(ret)
+    {
+        printf("GNSS close init error\n");
+        return -1;
+    }
+
+    firmware_extren_state = 0;
+    if (gnss_handle->rb) free(gnss_handle->rb);
+    free(h_gnss);
+    mbtk_gnss_handle = NULL;
+
+    return 0;
+}
+
+int mopen_gnss_send_cmd(uint32 h_gnss, const char *cmd, int cmd_len)
+{
+    struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+    return  mopen_gnss_write(gnss_handle->dev_fd, cmd, cmd_len);
+}
+
+/**
+ *  \brief mbtk_gnss_dev_reset
+ *
+ *  Detailed description
+ *
+ *  \param
+ *         type: 0 软件复位
+ *               1 芯片级复位(看门狗)
+ *               2 板级复位
+ *               3 接收机停止
+ *         mode :
+ *         0 : 热启动
+ *         1 : 温启动
+ *         2 : 冷启动
+ *  \return return type
+ */
+int mbtk_gnss_dev_reset(uint32 h_gnss, int type, int mode)
+{
+    int ret;
+    struct mbtk_gnss_handle_t *handle = (struct mbtk_gnss_handle_t *)h_gnss;
+    // h00 热启动
+    // h01 温启动
+    // h85 冷启动
+    char send_buf[24] = {0};
+
+    if(0 == h_gnss){
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    if (1 == handle->reset_state) {
+        printf("%s already reset_state.\n", __func__);
+        return -2;
+    }
+
+    if (0 == mode || 1 == mode) {
+        snprintf(send_buf, sizeof(send_buf), "$RESET,%d,h0%d\r\n", type, mode);
+    } else if (2 == mode) {
+        snprintf(send_buf, sizeof(send_buf), "$RESET,%d,h85\r\n", type);
+    } else if (3 == mode) {
+        snprintf(send_buf, sizeof(send_buf), "$RESET,%d,hFF\r\n", type);
+    } else {
+        printf("%s reset mode invalid.\n", __func__);
+        return -2;
+    }
+
+    if ( 1 == firmware_extren_state ) {
+        if (mode > 1) {
+            mbtk_gnss_firmware_update();
+        } else {
+            memset(send_buf, 0, sizeof(send_buf));
+            // 在有GLONASS固件的情况下,冷启动指令为: $CFGSYS,H101
+            // 只发$RESET,0,hFF, 会重置波特率,待验证
+            snprintf(send_buf, sizeof(send_buf), "$CFGSYS,H101\r\n");
+        }
+    }
+
+    gnss_log("%s : %s\n", __FUNCTION__, send_buf);
+    LOGI("%s : %s", __FUNCTION__, send_buf);
+    pthread_mutex_lock(&handle->_cond_mutex);
+    handle->reset_state = 1;
+    pthread_mutex_unlock(&handle->_cond_mutex);
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("%s %d FAIL.	ret:%d\n", __FUNCTION__, __LINE__, ret);
+        return -1;
+    }
+
+    // 加载GLONASS固件后,波特率为115200
+    if ( 0 == firmware_extren_state ) {
+        set_baudrate(handle->dev_fd, B9600);
+        gnss_log("%s : set B9600\n", __FUNCTION__);
+    }
+
+    return 0;
+}
+
+int mopen_gnss_get_device_info(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$PDTINFO\r\n";
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("mopen_gnss_client_init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+
+    return 0;
+}
+/**
+ * @brief      mopen_gnss_set_system_config
+ *
+ * @details    设置卫星系统配置
+ *
+ * @param      mode
+ *             0 -> H01(1) –GPS L1+SBAS+QZSS
+ *             1 -> H10 – BDS B1
+ *             2 -> H101 2 – GPS+GLONASS+GALILEO+SBAS+QZSS
+ *             3 -> H11 3 – GPS+BDS+GALILEO+SBAS+QZSS
+ * @return     return type
+ */
+int mbtk_gnss_set_system_config(uint32 h_gnss, int mode)
+{
+    int ret;
+    char send_buf[20] = "$CFGSYS,H10\r\n";
+    char *str_mode[4] = {"H01", "H10", "H101", "H11"};
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    if( mode > 3 )
+    {
+        printf("%s param invalid.\n", __func__);
+        return -2;
+    }
+    snprintf(send_buf, sizeof(send_buf), "$CFGSYS,%s\r\n", str_mode[mode]);
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+        return -3;
+    }
+
+    return 0;
+}
+/**
+ * @brief      mopen_gnss_set_nema_config
+ *
+ * @details    设定NMEA 配置
+ *             输出的NMEA 协议版本
+ *             h30 - 在 NMEA 标准 version 3.0 基础上扩展北斗相关的语句(NMEA 3.0)
+ *             h51 - 在标准NMEA4.1 基础上扩展北斗相关语(NMEA 4.1)
+ *             默认配置: h51
+ *
+ * @param      mode
+ *             0 -> h30
+ *             1 -> h51
+ *
+ * @return     return type
+ */
+int mbtk_gnss_set_nema_config(uint32 h_gnss, int mode)
+{
+    int ret;
+    char send_buf[16] = "$CFGNMEA,h30\r\n";
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    if (mode) {
+        send_buf[10] = '5';
+        send_buf[11] = '1';
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+        return -3;
+    }
+
+    return 0;
+}
+int mopen_gnss_aidpos(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$AIDPOS,4002.229934,N,11618.096855,E,37.254\r\n";
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("mopen_gnss_client_init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    return 0;
+}
+/**
+ * @brief      mopen_gnss_get_aidinfo
+ *
+ * @details    查询辅助数据状态
+ *             $CFGAID,0,D7FBFBDF,00000000,08*47
+ * @param      param
+ *
+ * @return     return type
+ */
+int mopen_gnss_get_aidinfo(uint32 h_gnss)
+{
+    int ret;
+    // char *send_buf = "$AIDINFO\r\n";
+    char *send_buf = "$CFGAID,0\r\n";
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+        return -1;
+    }
+    return 0;
+}
+/**
+ * @brief      mopen_gnss_get_uart
+ *
+ * @details    get uart config info.
+ *             $CFGPRT,1,h0,9600,129,3*57
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int mopen_gnss_get_uart(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$CFGPRT,1\r\n";
+    // char *send_buf = "$CFGPRT,2\r\n";
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("mopen_gnss_client_init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mopen_gnss_set_uart(uint32 h_gnss, int baudrate)
+{
+    int ret;
+    char send_buf[28] = {0};
+    // char *send_buf = "$CFGPRT,1,h0,9600,1,3\r\n";
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    sprintf(send_buf, "$CFGPRT,1,h0,%d,1,3\r\n", baudrate);
+    gnss_log("%s %s", __FUNCTION__, send_buf);
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("mopen_gnss_client_init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mopen_gnss_get_msg_output(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$CFGMSG,0,1\r\n"; // msg class, msg id
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        printf("%s FAIL. ret:%d\n", __func__, ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mopen_gnss_set_msg_output(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$CFGMSG,0,1,1\r\n";// msg class, msg id, msg switch
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mopen_gnss_set_lowpower(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$CFGLOWPOWER,0\r\n";// 0 - nomale, 1 - lowpower
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mopen_gnss_get_ant_state_info(uint32 h_gnss)
+{
+    int ret;
+    char *cmd1_buf = "$ANTSTAT,1\r\n";
+    char *cmd2_buf = "$ANTSTAT1\r\n";
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, cmd1_buf, strlen(cmd1_buf));
+    if(ret < 0)
+    {
+        gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+        return -1;
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, cmd2_buf, strlen(cmd2_buf));
+    if(ret < 0)
+    {
+        gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mopen_gnss_get_nmea_config(uint32 h_gnss)
+{
+    int ret;
+    char *send_buf = "$CFGNMEA\r\n";
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+    if(ret < 0)
+    {
+        gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+        return -1;
+    }
+    return 0;
+}
+
+int mbtk_gnss_add_rx_msg_handler(uint32 h_gnss, mbtk_gnss_handler_func_t handler_ptr)
+{
+    struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+
+    if(0 == h_gnss && NULL == handler_ptr)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    gnss_handle->gnss_handler_func = handler_ptr;
+
+    return 0;
+}
+
+#define AGNSS_TLE_FILE  "/tmp/agnss_tle"
+
+static void http_data_cb_func(
+    int session_id, mbtk_http_data_type_enum type,
+    void *data,int data_len)
+{
+    static int agnss_fd = 0;
+    int ret = 0;
+
+    if(type == MBTK_HTTP_DATA_HEADER) {
+        gnss_log("Header(%d):%s\n", data_len, (char*)data);
+        if(agnss_fd > 0)
+            return;
+        unlink(AGNSS_TLE_FILE);
+        agnss_fd = open(AGNSS_TLE_FILE, O_RDWR|O_CREAT|O_TRUNC, 0644);
+        if (agnss_fd <= 0)
+            gnss_log("file open error\n");
+        gnss_log("agnss file open: %d\n", agnss_fd);
+    } else if(type == MBTK_HTTP_DATA_CONTENT) {
+        gnss_log("http Data(%d)\n", data_len);
+
+        ret = write(agnss_fd, (char*)data, data_len);
+        if (ret < 0) {
+            gnss_log("%s: error writing to file!\n", __FUNCTION__);
+        } else if (ret < data_len) {
+            gnss_log("%s: wrote less the buffer size!\n", __FUNCTION__);
+        }
+    } else {
+        gnss_log(">>>>>Complete<<<<<\n");
+        if(agnss_fd <= 0)
+            return;
+        close(agnss_fd);
+        agnss_fd = 0;
+    }
+}
+
+static int gnss_http_requst(char *id, char *pw)
+{
+    char tmp[128] = {0};
+
+    int http_handle = mbtk_http_handle_get(TRUE, http_data_cb_func);
+    if(http_handle < 0)
+    {
+        printf("mbtk_http_handle_get() fail.");
+        return -1;
+    }
+
+    int http_session = mbtk_http_session_create(http_handle, HTTP_OPTION_POST, HTTP_VERSION_1_1);
+    if(http_handle < 0)
+    {
+        printf("mbtk_http_session_create() fail.");
+        return -2;
+    }
+
+    if(mbtk_http_session_url_set(http_handle, http_session, "http://unicore-api.rx-networks.cn/rxn-api/locationApi/rtcm")) {
+        printf("mbtk_http_session_url_set() fail.\n");
+        return -3;
+    }
+
+    char* post_data = "[{\"rtAssistance\":{\"format\":\"rtcm\",\"msgs\":[\"GPS:2NAF\",\"BDS:2NAF\",\"QZS:2NAF\"]}}]\r\n";
+
+    mbtk_http_session_head_add(http_handle, http_session, \
+    "Host", "unicore-api.rx-networks.cn");
+
+    sprintf(tmp, "RXN-BASIC cId=%s,mId=Unicore,dId=12-23-34-45-58,pw=%s", id, pw);
+    mbtk_http_session_head_add(http_handle, http_session, \
+    "Authorization", tmp);
+
+    mbtk_http_session_head_add(http_handle, http_session, \
+            "Content-Type", "application/json");
+
+    mbtk_http_session_head_add(http_handle, http_session, \
+            "Accept", "application/octet-stream");
+    mbtk_http_session_content_set(http_handle, http_session,
+                                  post_data, strlen(post_data));
+
+    if(mbtk_http_session_start(http_handle, http_session)) {
+        printf("mbtk_http_session_start() fail.\n");
+        return -4;
+    }
+
+    if(mbtk_http_handle_free(http_handle))
+    {
+        printf("mbtk_http_handle_free() fail.");
+        return -5;
+    }
+
+    return 0;
+}
+
+/**********************************
+
+ ID1: TempID1Expire20221031
+ Base 64 PW1: RlJYdkFTNE9DWXJhN2ZWTA==
+**************************************/
+#define AGNSS_CONFIG_FILE  "/etc/mbtk/gps.conf"
+
+/**
+ * @brief      mopen_gnss_download_tle
+ *
+ * @details    下载星历数据
+ *             (卫星星历,又称为两行轨道数据(TLE,Two-Line Orbital Element))
+ *             保存到文件:AGNSS_TLE_FILE
+ * @param      param
+ *
+ * @return     return type
+ */
+int mbtk_gnss_download_tle(void)
+{
+    FILE *fp;
+    char StrLine[64];
+    char _id[24] = {0};
+    char _passwd[28] = {0};
+    int i;
+    if((fp = fopen(AGNSS_CONFIG_FILE, "r")) == NULL)
+    {
+        printf("open %s error!\n", AGNSS_CONFIG_FILE);
+        return -1;
+    }
+
+    while (!feof(fp))
+    {
+        memset(StrLine, 0, 64);
+        fgets(StrLine, 64, fp);
+        gnss_log("%s\n", StrLine);
+        i = strstr_n(StrLine, ": ");
+        if(i && strstr_n(StrLine, "ID"))
+        {
+            memcpy(_id, &StrLine[i + 1], strlen(StrLine) - i - 2);
+        }
+        else if( i && strstr_n(StrLine, "Base 64"))
+        {
+            memcpy(_passwd, &StrLine[i + 1], strlen(StrLine) - i - 2);
+        }
+    }
+    fclose(fp);
+    gnss_log("%s : %s[%d], %s[%d]\n", __FUNCTION__, _id, strlen(_id), _passwd, strlen(_passwd));
+
+    return gnss_http_requst(_id, _passwd);
+}
+
+/**
+ * @brief      mopen_gnss_injects_aidpos
+ *
+ * @details    注入星历, 128 bytes
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int mbtk_gnss_injects_aidpos(uint32 h_gnss)
+{
+    int ret;
+    int agnss_fd = 0;
+    int size = 0;
+
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+
+    agnss_fd = open(AGNSS_TLE_FILE, O_RDWR);
+    if (agnss_fd <= 0)
+    {
+        printf("%s open file FAIL. errno:%d\n", __FUNCTION__, errno);
+        return -1;
+    }
+    char* databuf = (char*)malloc(128);
+    if(databuf == NULL)
+    {
+        gnss_log("%s malloc() fail.", __FUNCTION__);
+        return -1;
+    }
+    memset(databuf, 0, 128);
+    while(0 < (size = read(agnss_fd, databuf, 128)))
+    {
+        gnss_log("%s Write[%d]\r\n", __FUNCTION__, size);
+        ret = mopen_gnss_send_cmd(h_gnss, databuf, size);
+        if(ret < 0)
+        {
+            printf("%s send cmd FAIL. ret:%d\n", __FUNCTION__, ret);
+            break;
+        }
+        memset(databuf, 0, 128);
+    }
+    close(agnss_fd);
+    free(databuf);
+    mopen_gnss_get_aidinfo(h_gnss);
+
+    return 0;
+}
+/**
+ * @brief      mopen_gnss_set_mode
+ *
+ * @details    detailed description
+ *
+ * @param      mode
+ *                  0 : stop
+ *                  1 : 输出一次坐标
+ *                  2 : stop
+ *                  3 : 输出nmea数据到回调函数
+ *    0 - stop, 1 - single, 2 - periodic, 3 - start
+ *
+ * @return     return type
+ */
+int mbtk_gnss_set_mode(uint32 h_gnss, int mode)
+{
+    struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+    if(0 == h_gnss)
+    {
+        printf("%s handler invalid.\n", __func__);
+        return -1;
+    }
+    gnss_handle->mode = mode;
+
+    return 0;
+}
+
+int mbtk_gnss_print_version(uint32 h_gnss)
+{
+    printf("*************************\n");
+    printf("-Pn: %s\n dc: %s\n hv: %s\n fw: %s\n pn: %s\n sn: %s\n ",
+                        mopen_gnss_device_info.product_name,
+                        mopen_gnss_device_info.dev_config,
+                        mopen_gnss_device_info.hw_ver,
+                        mopen_gnss_device_info.fw_ver,
+                        mopen_gnss_device_info.pn,
+                        mopen_gnss_device_info.sn);
+    printf("Uart bandrate: %d\n" , mopen_gnss_device_info.usrt_bandrate);
+    printf("*************************\n");
+
+    return 0;
+}
+
+/**
+* @brief 使用popen调用终端并获取执行结果
+*
+* @param[in] cmd 命令内容
+* @param[out] result 保存结果的地址
+* @return 0或1 执行状态,成功或失败
+*/
+int exec_cmd(const char *cmd, char *result)
+{
+    FILE *pipe = popen(cmd, "r");
+    if(!pipe)
+        return -1;
+
+    char buffer[256] = {0};
+    while(!feof(pipe))
+    {
+        if(fgets(buffer, 256, pipe))
+        {
+            printf("%s", buffer);
+            memset(buffer, 0, sizeof(buffer));
+        }
+    }
+    pclose(pipe);
+    return 0;
+}
+
+#define GNSS_AP_DATA_FILE  "/etc/mbtk/rtm.bin"
+
+int mbtk_gnss_get_ap_data(void)
+{
+    int state = 0;
+    uint32 *ph_gnss = NULL;
+    mbtk_gnss_handler_func_t cb;
+    int current_mode;
+    const char* cmd = "mbtk_gnss_update getap -d /dev/ttyS2 -b 115200 -a /etc/mbtk/rtm.bin";
+
+	if(access(GNSS_AP_DATA_FILE, F_OK) != -1) {
+        unlink(GNSS_AP_DATA_FILE);
+    }
+    mbtk_gnss_handle->getap_status = 1;
+    sleep(1);
+    printf("Mopen Gnss Get Ap Data -> \n");
+    int ret = exec_cmd(cmd, NULL);
+
+    usleep(100000);
+    mbtk_gnss_handle->getap_status = 0;
+    if(0 != ret) {
+        printf("Gnss getap result: %x\n", ret);
+        return -1;
+    }
+    LOGI("%s %d: %d.\n", __FUNCTION__, __LINE__, ret);
+    return ret;
+}
+/*
+  sync : 1
+ */
+int mbtk_gnss_firmware_update(void)
+{
+    int state = 0;
+    uint32 *ph_gnss = NULL;
+    mbtk_gnss_handler_func_t cb;
+    int current_mode;
+	int fd = -1;
+	int ret = 0;
+
+    const char* cmd_1 = "mbtk_gnss_update downbl -d /dev/ttyS2 \
+                       -l /etc/mbtk/bootloader_r3.0.0_build6773_uartboot_921600.pkg";
+
+    const char* cmd_2 = "mbtk_gnss_update sendap -d /dev/ttyS2 -b 921600 -a /etc/mbtk/rtm.bin";
+
+    const char* cmd_3 = "mbtk_gnss_update downfw -d /dev/ttyS2 -b 921600\
+                       -f /etc/mbtk/UC6228CI-R3.4.21.0Build16211_G1L1E1_mfg.pkg";
+                       // /etc/mbtk/UC6228CI-R3.4.0.0Build7258_mfg.pkg
+
+    if (mbtk_gnss_handle) {
+        printf("%s gnss thread runing!!!\n", __func__);
+        if (mbtk_gnss_handle->gnss_handler_func)
+            cb = mbtk_gnss_handle->gnss_handler_func;
+
+        ph_gnss = mbtk_gnss_handle->phandle;
+        current_mode = mbtk_gnss_handle->mode;
+        // 主线程是否在运行
+        if (mbtk_gnss_handle->gnss_pthread)
+            state = 1;
+        mbtk_gnss_client_deinit(mbtk_gnss_handle);
+    }
+    printf("Mopen Gnss Bootloader Update -> \n");
+    //int ret = exec_cmd(cmd_1, NULL);
+
+	fd=initial_serialPort("/dev/ttyS2");
+	ret = downloadBL(fd, "/etc/mbtk/bootloader_r3.0.0_build6773_uartboot_921600.pkg");
+    if(0 != ret) {
+        printf("Gnss update result: %x\n", ret);
+		close(fd);
+        return -1;
+    }
+
+    if(access(GNSS_AP_DATA_FILE, F_OK) != -1)
+    {
+        printf("Mopen Gnss Send AP Data  -> \n");
+        //ret = exec_cmd(cmd_2, NULL);
+
+		set_baudrate(fd, B921600);
+		ret = sendAPData(fd, "/etc/mbtk/rtm.bin");
+		
+        if(0 != ret) {
+			close(fd);
+            printf("Gnss update result: %x\n", ret);
+        }
+    }
+
+    printf("Mopen Gnss Firmware Update -> \n");
+    //ret = exec_cmd(cmd_3, NULL);
+	set_baudrate(fd, B921600);
+	ret = downloadFW(fd, "/etc/mbtk/UC6228CI-R3.4.21.0Build16211_G1L1E1_mfg.pkg");
+	close(fd);
+
+    if(0 != ret) {
+        printf("Gnss update result: %x\n", ret);
+        return -2;
+    }
+
+    if (0 == firmware_extren_state)
+        firmware_extren_state = 1;
+    if (state && ph_gnss) {
+        ret = mbtk_gnss_client_init(ph_gnss);
+        if (cb) {
+            mbtk_gnss_handle->gnss_handler_func = cb;
+            mbtk_gnss_handle->mode = current_mode;
+        }
+    }
+
+    LOGI("%s %d: %d.\n", __FUNCTION__, __LINE__, ret);
+    return ret;
+}
+
+int mbtk_at_gnss(int start_stop, void *cb)
+{
+    static uint32 loc = 0;
+    int ret = -1;
+
+    LOGI("%s %d", __FUNCTION__, __LINE__);
+    switch (start_stop) {
+    case 0: {
+        ret = mbtk_gnss_set_mode(loc, 0);
+        if(ret)
+            return -3;
+        ret = mbtk_gnss_client_deinit(loc);
+        if(ret)
+            return -3;
+        loc = 0;
+        return 0;
+    }
+    case 1: {
+        if (0 != loc)
+            return -1;
+
+        ret = mbtk_gnss_client_init(&loc);
+        if(ret || 0 == loc)
+            return -1;
+
+        if(NULL == cb)
+            return -2;
+
+        ret = mbtk_gnss_add_rx_msg_handler(loc, (mbtk_gnss_handler_func_t)cb);
+        if(ret)
+            return -2;
+        ret = mbtk_gnss_set_mode(loc, 3);
+        break;
+    }
+    case 2: {
+        ret = mbtk_gnss_set_mode(loc, 0);
+        break;
+    }
+    case 3: {
+        ret = mbtk_gnss_set_mode(loc, 3);
+        break;
+    }
+    case 4: {
+        ret = mopen_uart_change(((struct mbtk_gnss_handle_t *)loc)->dev_fd, 1);
+        if(ret) {
+            printf("reset Uart set 115200 error\n");
+        }
+        break;
+    }
+    case 6: {
+        ret = mbtk_gnss_firmware_update();
+        if(ret) {
+            printf("gnss firmware update error!!\n");
+        }
+		break;
+    }
+	case 11:{
+		ret = mbtk_gnss_set_system_config((uint32)mbtk_gnss_handle,3);//GPS+BD
+		break;
+	}
+	case 10:{
+		ret = mbtk_gnss_set_system_config((uint32)mbtk_gnss_handle,0);// only GPS
+		break;
+	}
+	case 9:{
+		ret = mbtk_gnss_set_system_config((uint32)mbtk_gnss_handle,2);//GPS+GLONASS
+		break;
+	}	
+    default:
+        break;
+    }
+
+    return ret;
+}
+/*
+    0     热启动
+    1     冷启动
+    2     温启动
+ */
+int mbtk_at_gnss_reset(int type)
+{
+    switch (type)
+    {
+    case 0: {
+        // $RESET,0,h0
+        return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 0);
+    }
+    case 1: {
+        // $RESET,0,h85
+        return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 2);
+    }
+    case 2: {
+        // $RESET,0,h01
+        return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 1);
+    }
+    case 3: {
+        return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 3);
+    }
+    case 4: {
+        return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 3, 0);
+    }
+    case 5: {
+        return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 1, 0);
+    }
+    default:
+        break;
+    }
+    return -9;
+}
+
+#if TTFF_TEST
+static void gnss_gsa_info(int cmd, char *str, void *data)
+{
+    char tmp_str[32] = {0};
+    int ret;
+
+    gnss_log("[ GSA ]: ");
+    // $xxGSA
+    ret = gnss_get_para_from_nmea(str, tmp_str, 1);
+    if(0 == ret && ('A' == tmp_str[0])){
+        gnss_log("Smode: %s, ", tmp_str);
+        memset(tmp_str, 0, 32);
+    } else {
+        printf("%s [exit]: %s\n", __FUNCTION__, str);
+        return;
+    }
+
+    /* 定位模式:
+            1-未定位
+            2-2D 定位
+            3-3D 定位
+     */
+    ret = gnss_get_para_from_nmea(str, tmp_str, 2);
+    if(ret){
+        gnss_log("L%d %s error! \n");
+        return;
+    }
+
+    gnss_log("fs: %s - [%d]", tmp_str, atoi(tmp_str));
+    if ( atoi(tmp_str) != mbtk_gnss_handle->location_state ) {
+        mbtk_gnss_handle->location_state = atoi(tmp_str);
+        if (mbtk_gnss_handle->location_state > 1 && location_test) {
+            pthread_mutex_lock(&loc_cond_mutex_r);
+            location_test = 0;
+            pthread_cond_signal(&loc_sync_cond);
+            pthread_mutex_unlock(&loc_cond_mutex_r);
+        }
+    }
+    gnss_log(" -- \n");
+}
+
+int mbtk_gnss_test_ttff(int type, int timeout_sec)
+{
+    struct timeval tnow;
+    struct timespec tout;
+    long t_start, t_end;
+    int ret;
+
+    pthread_mutex_lock(&loc_cond_mutex_r);
+    location_test = 1;
+    pthread_mutex_unlock(&loc_cond_mutex_r);
+
+    switch (type)
+    {
+    case 0: {
+        // $RESET,0,h0
+        mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 0);
+        break;
+    }
+    case 1: {
+        // $RESET,0,hFF
+        mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 3);
+        break;
+    }
+    case 2: {
+        // $RESET,0,h01
+        mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 1);
+        break;
+    }
+    case 3: {
+        // 在有GLONASS固件的情况下,冷启动指令为: $CFGSYS,H101
+        // 只发$RESET,0,hFF, 会重置波特率,待验证
+        mopen_gnss_set_system_config((uint32)mbtk_gnss_handle, 2);
+        break;
+    }
+    case 4: {
+        if ( 0 == firmware_extren_state )
+            return -2;
+
+        ret = mopen_gnss_firmware_update();
+        if(ret) {
+            printf("gnss firmware update error!!\n");
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    if (0 == timeout_sec )
+        timeout_sec = 60 * 3;
+    gettimeofday(&tnow, NULL);
+    t_start = tnow.tv_sec * 1000 * 1000 + tnow.tv_usec;
+    tout.tv_sec = tnow.tv_sec + timeout_sec;
+    tout.tv_nsec = tnow.tv_usec;
+    if (tout.tv_nsec > 1000000000)
+    {
+        tout.tv_sec += 1;
+        tout.tv_nsec -= 1000000000;
+    }
+    pthread_mutex_lock(&loc_cond_mutex_r);
+    ret = pthread_cond_timedwait(&loc_sync_cond, &loc_cond_mutex_r, &tout);
+    pthread_mutex_unlock(&loc_cond_mutex_r);
+    gettimeofday(&tnow, NULL);
+    t_end = tnow.tv_sec * 1000 * 1000 + tnow.tv_usec;
+    gnss_log("gnss ttff time:%ld\n", t_end - t_start);
+    if(ret == ETIMEDOUT) {
+        location_test = 0;
+        return -1;
+    }
+
+    return (t_end - t_start)/1000;
+}
+
+#define GNSS_TEST_FILE  "/tmp/gnss_test"
+#define INSERT_CUT_OFF_RULE() { memset(buffer, 0, sizeof(buffer)); \
+    sprintf(buffer, "----------------------------------\r\n"); \
+    ret = write(fd, buffer, strlen(buffer)); \
+    if (ret < 0) { \
+        printf("%s write error !!\n", __func__); \
+    } \
+}
+
+void *gnss_ttff_thread(void *data)
+{
+    struct mbtk_gnss_ttff_t *handle = (struct mbtk_gnss_ttff_t *)data;
+    int fd, ret, i;
+    int index, time_ms;
+    float loc_time;
+    char buffer[128] = {0};
+
+    pthread_detach(pthread_self());
+
+	if ( !access(GNSS_TEST_FILE, F_OK) ){
+        unlink(GNSS_TEST_FILE);
+    }
+
+    pthread_cond_init(&loc_sync_cond, NULL);
+    pthread_mutex_init(&loc_cond_mutex_r, NULL);
+    fd = open(GNSS_TEST_FILE, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (fd <= 0) {
+        gnss_log("file open error\n");
+    }
+    INSERT_CUT_OFF_RULE()
+    sprintf(buffer, "type: %d, timeout: %d, count: %d\r\n", handle->type,
+                                                          handle->timeout_sec,
+                                                          handle->test_count);
+    ret = write(fd, buffer, strlen(buffer));
+    if (ret < 0) {
+        printf("%s write error !!\n", __func__);
+    }
+    INSERT_CUT_OFF_RULE()
+    for (i = 0; i < handle->test_count; ++i) {
+        memset(buffer, 0, sizeof(buffer));
+        time_ms = mbtk_gnss_test_ttff(handle->type, handle->timeout_sec);
+        if (-1 == time_ms)
+            loc_time = time_ms;
+        else
+            loc_time = ((float)time_ms) / 1000;
+        sprintf(buffer, "\t %d - [ %f s ]\r\n", i + 1, loc_time);
+        printf("\t %d - %f\n", i + 1, loc_time);
+        ret = write(fd, buffer, strlen(buffer));
+        if (ret < 0) {
+            printf("%s write error !!\n", __func__);
+        }
+    }
+
+    INSERT_CUT_OFF_RULE()
+    close(fd);
+    mbtk_gnss_handle->ttff_pid = 0;
+    pthread_cond_destroy(&loc_sync_cond);
+    pthread_mutex_destroy(&loc_cond_mutex_r);
+    pthread_exit(NULL);
+}
+#endif
+
+int mbtk_at_gnss_start_ttff(int type, int timeout_sec, int count)
+{
+#if TTFF_TEST
+    int ret;
+    static struct mbtk_gnss_ttff_t mbtk_gnss_ttff;
+
+    LOGI("%s %d, %d, %d", __FUNCTION__, type, timeout_sec, count);
+    if (NULL == mbtk_gnss_handle) {
+        printf("%s not init!!!\n", __func__);
+        return -1;
+    }
+    if (mbtk_gnss_handle->ttff_pid) {
+        printf("%s busy!!!\n", __func__);
+        return -2;
+    }
+    mbtk_gnss_ttff.type = type;
+    mbtk_gnss_ttff.timeout_sec = timeout_sec;
+    mbtk_gnss_ttff.test_count = count;
+    ret = pthread_create(&mbtk_gnss_handle->ttff_pid, NULL, (void *)gnss_ttff_thread, &mbtk_gnss_ttff);
+    if (ret != 0)
+    {
+        fprintf(stderr, "\n%s: Failed create pthread\n", __FUNCTION__);
+        return ret;
+    }
+
+#endif
+    return 0;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_gnss_update.c b/mbtk/mbtk_lib/src/mbtk_gnss_update.c
new file mode 100755
index 0000000..2c0657e
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_gnss_update.c
@@ -0,0 +1,1283 @@
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sched.h>
+#include <limits.h>
+#include <linux/serial.h>
+
+#define RTM_FILE_NAME "rtm.bin"
+
+#define PARA_ERR                -1
+#define FILE_CHECK_ERR          -2
+#define ENTER_UPDATE_MODE_ERR   -3
+#define UPDATE_ERR              -4
+#define UART_DEV_ERR            -5
+
+#define XMODEM_SOH 0x01
+#define XMODEM_STX 0x02
+#define XMODEM_EOT 0x04
+#define XMODEM_ACK 0x06
+#define XMODEM_NAK 0x15
+#define XMODEM_CAN 0x18
+#define XMODEM_CRC_CHR	'C'
+#define XMODEM_CRC_SIZE 2		/* Crc_High Byte + Crc_Low Byte */
+#define XMODEM_FRAME_ID_SIZE 2 		/* Frame_Id + 255-Frame_Id */
+#define XMODEM_DATA_SIZE_SOH 128  	/* for Xmodem protocol */
+#define XMODEM_DATA_SIZE_STX 1024 	/* for 1K xmodem protocol */
+#define USE_1K_XMODEM 1  		/* 1 for use 1k_xmodem 0 for xmodem */
+#define	TIMEOUT_USEC	0
+#define	TIMEOUT_SEC		10
+
+#if (USE_1K_XMODEM)
+#define XMODEM_DATA_SIZE 	XMODEM_DATA_SIZE_STX
+#define XMODEM_HEAD		XMODEM_STX
+#else
+#define XMODEM_DATA_SIZE 	XMODEM_DATA_SIZE_SOH
+#define XMODEM_HEAD 		XMODEM_SOH
+#endif
+
+
+/******************************************************************************
+ * 时间处理相关的宏
+ *****************************************************************************/
+// 时间超时标志
+int timeout_sign = 1;
+// 获取当前时间
+#define GET_TIME()  { gettimeofday(&time_m, NULL); \
+	time_m.tv_sec += TIMEOUT_SEC;\
+}
+// 设置从循环中退出的时间
+#define SET_TIME_OUT(x)  { gettimeofday(&time_m, NULL); \
+	time_m.tv_sec += x;\
+}
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		printf("\ntimeout!!!\n\n");\
+		close(fd); \
+		return ret; \
+	} \
+}
+// 检测时间是否超时,超时则退出当前循环
+#define CHK_TIME_BREAK()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		timeout_sign = 1; 	\
+		printf("\ntimeout!!!\n\n");\
+		break; \
+	} \
+}
+// 检测延时是否到达,到达则退出当前循环
+#define DELAY_TIME_BREAK()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		timeout_sign = 1; 	\
+		break; \
+	} \
+}
+
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME1()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		printf("\ntimeout!!!\n\n");\
+		if(datafile != NULL) \
+		fclose(datafile); \
+		return ret; \
+	} \
+}
+
+
+/******************************************************************************
+ * APData 相关定义、声明
+ *****************************************************************************/
+// APData 数据头部定义
+typedef struct {
+	unsigned int  ih_magic;		// Image Header Magic Number
+	unsigned int  ih_dcrc;		// Image Data CRC checksum
+	unsigned int  ih_time;		// Image Creation Timestamp
+	unsigned int  ih_size;		// Image Data Size
+	unsigned int  ih_compress;		// Image Header compress or not:0, not compress
+	unsigned int  pkg_flash_addr;	// flash memory offset for package
+	unsigned int  pkg_run_addr;		// Run time address for this package
+	unsigned int  ih_hcrc;		// Image Header CRC checksum
+} uc_image_header_t;
+
+// APData 数据头部长度
+#define HEADERLEN 32
+// APData 接收状态类型
+typedef enum ReceStat{
+	WAIT_FD = 1,
+	WAIT_FC,
+	WAIT_FB,
+	WAIT_FA,
+	RECE_HEADER,
+	RECE_DATA,
+} RecvStat_t;
+// APData 接收状态变量
+static RecvStat_t recvStat = WAIT_FD;
+// APData 接收状态变量
+static int isStartReceive = 0;
+// APData 开始接收
+void af_start_receive();
+// APData 停止接收,在数据接收完成或出错时调用
+void af_stop_receive();
+// 获取isStartReceive 变量值
+int af_is_start_receive();
+// APData 数据接收入口
+int af_add_char(char *file, unsigned char c);
+// 校验 APData 数据头
+int af_check_header(unsigned char *pbuf, unsigned int len);
+// 校验 APData 数据区
+int af_check_data(unsigned int * pbuf, unsigned int len);
+// 获取 APData 数据长度
+int af_get_data_len();
+// APData 数据接收缓存
+unsigned int recv_buf[1024 * 2];
+unsigned char *pbuf;
+int data_len;
+// 校验文件
+int check_file(char *fname);
+
+/******************************************************************************
+ * 与接收机串口通讯相关定义、声明
+ *****************************************************************************/
+// select功能使用变量
+static int use_select = 1;
+// 初始化串口资源
+int initial_serialPort(char * serial_device);
+// 设置串口波特率
+static int set_baudrate(int fd, int baudrate);
+// 检测串口数据
+static int select_read(int fd, int timeout);
+// 读取串口数据
+static ssize_t deal_read(int fd, void *buf, size_t count);
+// 向接收机发送串口数据
+static void gps_dev_send(int fd, char *msg);
+// 通过xmodem协议向接收机发送串口数据
+int xmodem_send(int fd, char *fname);
+
+/******************************************************************************
+ * apflash 功能函数
+ *****************************************************************************/
+// 检测接收机发送的'YC'信号,如果收到,则标志着接收机进入boot模式,并可以通过xmodem发送数据
+int check_YC(char newchar);
+// 获取 APData 数据, 应该在接收机定位且星历数据接收完整时获取
+int getAPData(int fd, char *file);
+// 向接收机发送 APData 数据,有效的APData数据可以让CI模块迅速定位
+int sendAPData(int fd, char *ap);
+// 校验 APData 数据文件
+int checkAPData(char *apFile);
+// 为接收机加载BootLoader,该流程执行时,需要根据终端提示,给接收机下电和上电,确保接收机进入boot模式
+int downloadBL(int fd, char *bl);
+// 为接收机加载Firmware,该流程必须在加载BootLoader之后进行
+int downloadFW(int fd, char *fw);
+
+void printGetapUsage(char *app)
+{
+	printf("\n%s getap -d receiverPort [-b baudrate] [-h] -a apfile \n", app);
+	printf("\tfunction: read APData from receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+}
+
+void printSendapUsage(char *app)
+{
+	printf("\n%s sendap -d receiverPort [-b baudrate] [-h] -a apfile\n", app);
+	printf("\tfunction: send APData to receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+}
+
+void printCheckapUsage(char *app)
+{
+	printf("\n%s checkap -a apfile [-h]\n", app);
+	printf("\tfunction: check APData\n");
+	printf("\tparas:\n");
+	printf("\t\tapfile: APData file\n");
+}
+
+void printDownloadblUsage(char *app)
+{
+	printf("\n%s downbl -d receiverPort [-b baudrate] -l bootloader [-h]\n", app);
+	printf("\tfunction: download bootloader to receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+	printf("\t\tbootloader: bootloader file\n");
+}
+
+void printDownloadfwUsage(char *app)
+{
+	printf("\n%s downfw -d receiverPort [-b baudrate] -f firmware [-h]\n", app);
+	printf("\tfunction: download firmware to receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+	printf("\t\tfirmware: firmware file\n");
+}
+
+void printUsage(char *app)
+{
+	printGetapUsage(app);
+	printSendapUsage(app);
+	printCheckapUsage(app);
+	printDownloadblUsage(app);
+	printDownloadfwUsage(app);
+}
+
+#define GPS_DEV "/sys/devices/soc.0/d4000000.apb/mbtk-dev-op/gps_power"
+
+static int mopen_open_gps(int state)
+{
+    int fd, ret;
+    char s[4] = "on";
+    fd = open(GPS_DEV, O_RDWR | O_TRUNC, 0644);
+    if(fd < 0) {
+        printf("[%s]  file [%s] open error\n", __FUNCTION__, GPS_DEV);
+        return -1;
+    }
+    if(0 == state)
+    {
+        memcpy(s, "off", 3);
+    }
+    ret = write(fd, s, 4);
+    if (ret < 0) {
+        printf("%s: error writing to file!\n", __FUNCTION__);
+        close(fd);
+        return -2;
+    }
+
+    close(fd);
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int c;
+	int ret = 0;
+	int fd = -1;
+	int paraMask = 0;
+	int baud = 115200;
+	char devPort[200] = {0};
+	char fw[200] = {0};
+	char bl[200] = {0};
+	char ap[200] = {0};
+	int func = 0; // 1:getap, 2:sendap, 3:downbl, 4:downfw, 5:checkap
+
+	// Verify arguments
+	if (argc < 2) {
+		printf("Usage:\n");
+		printUsage(argv[0]);
+		exit(1);
+	}
+
+	if(strcmp(argv[1], "getap") == 0) {
+		func = 1;
+		paraMask = 1;
+	} else if (strcmp(argv[1], "sendap") == 0) {
+		func = 2;
+		paraMask = 1;
+	} else if (strcmp(argv[1], "downbl") == 0) {
+		func = 3;
+		paraMask = 9;
+	} else if (strcmp(argv[1], "downfw") == 0) {
+		func = 4;
+		paraMask = 5;
+	} else if (strcmp(argv[1], "checkap") == 0) {
+		func = 5;
+		paraMask = 16;
+	} else {
+		printf("Usage:\n");
+		printUsage(argv[0]);
+		exit(1);
+	}
+
+	for(;;) {
+		opterr = 0;
+		c = getopt(argc, argv, "d:b:f:l:a:h");
+		if(c < 0)
+			break;
+		switch(c) {
+			case 'd':
+				snprintf(devPort, 200, "%s", optarg);
+				printf("receiver port: %s\n", devPort);
+				paraMask &= ~1;
+				break;
+			case 'b':
+				baud = atoi(optarg);
+				printf("baud rate: %d\n", baud);
+				break;
+			case 'f':
+				snprintf(fw, 200, "%s", optarg);
+				printf("firmware: %s\n", fw);
+				paraMask &= ~4;
+				break;
+			case 'l':
+				snprintf(bl, 200, "%s", optarg);
+				printf("bootloader: %s\n", bl);
+				paraMask &= ~8;
+				break;
+			case 'a':
+				snprintf(ap, 200, "%s", optarg);
+				printf("apdata file: %s\n", ap);
+				paraMask &= ~16;
+				break;
+			case 'h':
+			default:
+				printf("Usage:\n");
+				if (func == 1)
+					printGetapUsage(argv[0]);
+				else if (func == 2)
+					printSendapUsage(argv[0]);
+				else if (func == 3)
+					printDownloadblUsage(argv[0]);
+				else if (func == 4)
+					printDownloadfwUsage(argv[0]);
+				else if (func == 5)
+					printCheckapUsage(argv[0]);
+				else
+					printUsage(argv[0]);
+				exit(1);
+		}
+	}
+	if (paraMask) {
+		if (func == 1)
+			printGetapUsage(argv[0]);
+		else if (func == 2)
+			printSendapUsage(argv[0]);
+		else if (func == 3)
+			printDownloadblUsage(argv[0]);
+		else if (func == 4)
+			printDownloadfwUsage(argv[0]);
+		else if (func == 5)
+			printCheckapUsage(argv[0]);
+		else
+			printUsage(argv[0]);
+		exit(1);
+	}
+
+	// Open serial port
+	if (func != 5) {
+		if ((fd = initial_serialPort(devPort)) == -1)
+		{
+			printf("Can't open COM\n");
+			return UART_DEV_ERR;
+		}
+		if (baud == 115200) {
+			set_baudrate(fd, B115200);
+		} else if (baud == 921600) {
+			set_baudrate(fd, B921600);
+		} else if (baud == 1843200) {
+			set_baudrate(fd, B1500000);
+		} else {
+			printf("baudrate %d not supported\n", baud);
+			close(fd);
+			exit(1);
+		}
+	}
+
+	// execute function
+	switch(func) {
+		case 1:
+			ret = getAPData(fd, ap);
+			break;
+		case 2:
+			ret = sendAPData(fd, ap);
+			break;
+		case 3:
+			ret = downloadBL(fd, bl);
+			break;
+		case 4:
+			ret = downloadFW(fd, fw);
+			break;
+		case 5:
+			ret = checkAPData(ap);
+			break;
+		default:break;
+	}
+	close(fd);
+	return ret;
+
+}
+
+int getAPData(int fd, char *file)
+{
+	int rByte = 0;
+	char rbuf[4096];
+	int ret = 0, i;
+	struct timeval time_m, time_n;
+
+    if (NULL == file) {
+	    printf("Please input file!! \n");
+		return 1;
+    }
+	if (!fd)
+		return 1;
+	printf("Get apdata\n");
+	gps_dev_send(fd, "$ReqRecvFlash\r\n");
+	af_start_receive();
+	GET_TIME();
+	while(1) {
+		CHK_TIME();
+		if(select_read(fd,1) > 0)
+			usleep(50000);
+		else
+			continue;
+
+		rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+		if(rByte >= 1){
+			if(af_is_start_receive()) {
+				for(i = 0; i < rByte; i++)
+					af_add_char(file, rbuf[i]);
+			} else {
+				break;
+			}
+		}
+	}
+
+	checkAPData(file);
+	return 0;
+}
+
+int sendAPData(int fd, char *apFile)
+{
+	int rByte = 0;
+	char rbuf[4096];
+	int ret = 0;
+	struct timeval time_m, time_n;
+
+	if(access(apFile, F_OK) != -1)
+	{
+		// Download APData only if the file exits
+		printf("Download APData...\n");
+		if(xmodem_send(fd, apFile))
+		{
+			printf("xmodem error!\n");
+			close(fd);
+			return ENTER_UPDATE_MODE_ERR;
+		}
+		// Waiting for 'C'
+		GET_TIME();
+		while(1)
+		{
+			CHK_TIME();
+			if(select_read(fd,1) > 0)
+				usleep(500000);
+			else
+				continue;
+			rByte = deal_read(fd,&rbuf,sizeof(rbuf)-1);
+			rbuf[rByte] = 0;
+			if(rByte > 0)
+			{
+				if(rbuf[rByte - 1] == 'C')
+					break;
+			}
+		}
+		printf("download APData success\n");
+	}
+	else
+	{
+		printf("file err!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+int checkAPData(char *apFile)
+{
+	printf("Checking %s\n", apFile);
+	if(check_file(apFile))
+	{
+		printf("file error!\n");
+		return FILE_CHECK_ERR;
+
+	}
+	else
+	{
+		printf("pass\r\n");
+	}
+	return 0;
+}
+
+int downloadFW(int fd, char *fw)
+{
+    int ret;
+	struct timeval time_m, time_n;
+	char rbuf[512];
+
+    if(NULL == fw) {
+	    printf("Error: Can't find firmware.\n");
+        return -1;
+    }
+	printf("Download firmware...\n");
+	if(xmodem_send(fd, fw) < 0) {
+		printf("xmodem error! send firmware failed!\n");
+		close(fd);
+		return UPDATE_ERR;
+	}
+
+	printf("Download firmware success\n");
+	return 0;
+}
+
+int downloadBL(int fd, char *bl)
+{
+	int rByte = 0;
+	char rbuf[4096];
+	char name[128];
+	int ret = 0;
+	struct timeval time_m, time_n;
+
+    if(NULL == bl) {
+	    printf("Error: Can't find bootloader.\n");
+        return -1;
+    }
+	printf("------Please Powerdown the receiver!\n");
+    mopen_open_gps(0);
+	SET_TIME_OUT(3);
+	while(1) {
+		DELAY_TIME_BREAK(); //
+		if(select_read(fd,1) > 0)
+			usleep(50000);
+		else
+			continue;
+
+		rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+	}
+	int start = 0,finish = 0;
+
+	memset(name, 0, sizeof(name));
+	sprintf(name,"M!T");
+	printf("waiting for YC, timeout is %d s\n", TIMEOUT_SEC);
+	printf("-------Please Powerup the receiver!\n");
+    mopen_open_gps(1);
+	// Waiting for 'YC'
+	GET_TIME();
+	while(1) {
+		int finish = 0, i;
+		CHK_TIME_BREAK(); //
+		rByte = write( fd, name, strlen(name));
+		rByte = select_read(fd,1);
+		if(rByte <= 0)
+			continue;
+		rByte = deal_read(fd, rbuf, sizeof(rbuf) - 1);
+		rbuf[rByte] = 0;
+		for (i = 0 ; i < rByte; i++)
+		{
+			if (check_YC(rbuf[i])) {
+				printf("Receive 'YC'\n");
+				finish = 1;
+				break;
+			}
+		}
+		if (finish)
+			break;
+	}
+	//wait 'YC' timeout deal
+	if (timeout_sign == 1)
+	{
+		//wait NAK
+		GET_TIME();
+		while(1)
+		{
+			CHK_TIME();
+			if(select_read(fd,1) <= 0)
+				continue;
+
+			rByte = deal_read(fd, rbuf,sizeof(rbuf));
+			if (rbuf[rByte-1] == 'C')
+			{
+				printf("###read xmodem start character 'C'.\n");
+				break;
+			}
+		}
+	}
+	use_select = 1;
+	printf("download bootloader...\n");
+
+	// Transfer bootloader via xmodem protocal
+	// if(xmodem_send(fd, "./bootloader.bin")) {
+	if(xmodem_send(fd, bl)) {
+		printf("xmodem error!\n");
+		close(fd);
+		return ENTER_UPDATE_MODE_ERR;
+	}
+	printf("download bootloader success\n");
+	return 0;
+}
+
+int check_YC(char newchar)
+{
+	int static state = 0;
+	int ret = 0;
+	switch (state) {
+		case 0:
+			if (newchar == 'Y')
+				state = 1;
+			break;
+		case 1:
+			if (newchar == 'C') {
+				state = 1;
+				ret = 1;
+			}
+			break;
+		default:
+			state = 0;
+	}
+	return ret;
+}
+
+const unsigned short CRC16_Table[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+unsigned short crc16_ccitt(const unsigned char *buf, int len)
+{
+	register int counter;
+	register unsigned short crc = 0;
+	for (counter = 0; counter < len; counter++)
+		crc = (crc << 8) ^ CRC16_Table[((crc >> 8) ^ *(char *)buf++) & 0x00FF];
+	return crc;
+}
+
+
+unsigned int checksum32(unsigned int * pbuf, unsigned int len)
+{
+	unsigned int i, sumValue = 0;
+	len >>=2;
+
+	for(i=0;i<len;i++)
+	{
+		sumValue += *pbuf++;
+	}
+	return sumValue;
+}
+
+void af_start_receive()
+{
+	recvStat = WAIT_FD;
+	isStartReceive = 1;
+	return;
+}
+
+void af_stop_receive()
+{
+    int i;
+	printf("%s:%d\r\n", __FUNCTION__, __LINE__);
+	printf("%s:%d  recvStat = %d\r\n", __FUNCTION__, __LINE__, recvStat);
+	pbuf = (unsigned char *)recv_buf;
+	for(i = 0; i < 4636; i++){
+		if(i % 32 == 0)printf("\r\n");
+		printf("%02X ", pbuf[i]);
+	}
+	printf("\r\n");
+	isStartReceive = 0;
+	return;
+}
+
+int af_is_start_receive()
+{
+	return isStartReceive;
+}
+
+int af_check_header(unsigned char *pbuf, unsigned int len)
+{
+	unsigned int crc = crc16_ccitt(pbuf, len-4);
+
+	if(crc == *(unsigned int *)(pbuf + len - 4))
+		return 1;
+	else
+		return 0;
+}
+
+int af_check_data(unsigned int * pbuf, unsigned int len)
+{
+	unsigned int cs = checksum32(pbuf + 8, len);
+	if(cs == pbuf[1])
+		return 1;
+	else
+		return 0;
+}
+
+int af_get_data_len()
+{
+	int len = *(int *)(recv_buf+3);
+	return len;
+}
+
+int af_add_char(char *file, unsigned char c)
+{
+	int ret = 0;
+	switch(recvStat){
+		case WAIT_FD:
+			if(c == 0xfd){
+				pbuf = (unsigned char *)recv_buf;
+				pbuf[0] = c;
+				recvStat = WAIT_FC;
+				printf("------------received 0xfd\r\n");
+			}
+			break;
+		case WAIT_FC:
+			if(c == 0xfc){
+				pbuf[1] = c;
+				recvStat = WAIT_FB;
+				printf("------------received 0xfc\r\n");
+			}else{
+				af_stop_receive();
+			}
+			break;
+		case WAIT_FB:
+			if(c == 0xfb){
+				pbuf[2] = c;
+				recvStat = WAIT_FA;
+				printf("------------received 0xfb\r\n");
+			}else{
+				af_stop_receive();
+			}
+			break;
+		case WAIT_FA:
+			if(c == 0xfa){
+				pbuf[3] = c;
+				recvStat = RECE_HEADER;
+				pbuf += 4;
+				printf("------------received 0xfa\r\n");
+			}else{
+				af_stop_receive();
+			}
+			break;
+		case RECE_HEADER:
+			*pbuf = c;
+			pbuf++;
+			if((pbuf - (unsigned char *)recv_buf) == HEADERLEN){
+				if(af_check_header((unsigned char *)recv_buf, HEADERLEN)){
+					recvStat = RECE_DATA;
+					data_len = af_get_data_len();
+				}else{
+					af_stop_receive();
+				}
+			}
+			break;
+		case RECE_DATA:
+			*pbuf = c;
+			pbuf++;
+			if((pbuf - (unsigned char *)recv_buf) == data_len + HEADERLEN){
+				if(af_check_data(recv_buf, recv_buf[3])){
+					int fd = open(file, O_WRONLY|O_CREAT, S_IRWXU);
+					write(fd, recv_buf, pbuf - (unsigned char *)recv_buf);
+					printf("%s:%d rtm len = %ld\r\n", __FUNCTION__, __LINE__, pbuf-(unsigned char *)recv_buf);
+					close(fd);
+					printf("receive rtm\n");
+				}else{
+					printf("af_check_data false!");
+				}
+				af_stop_receive();
+			}
+			ret = 1;
+			break;
+		default:
+			printf("%s:recvStat = %d\r\n", __FUNCTION__, recvStat);
+			break;
+	}
+	return ret;
+}
+
+
+
+ssize_t deal_read(int fd, void *buf, size_t count)
+{
+	int ret = 0;
+
+	while (1)
+	{
+		ret = read(fd, buf, count);
+		if (ret == 0)
+		{
+			printf("read serial return 0, please check serial device.\n");
+			exit(UART_DEV_ERR);
+		}
+		if(ret < 0)
+		{
+			if ((errno == EAGAIN) || (errno == EINTR))
+			{
+				printf("read serial return -1, errno = %d, retry.\n", errno);
+				continue;
+			}
+			else
+			{
+				printf("read serial return -1, errno = %d, please check serial device.\n", errno);
+				exit(UART_DEV_ERR);
+			}
+		}
+		return ret;
+	}
+}
+
+unsigned short get_crc16 ( char *ptr, unsigned short count )
+{
+	unsigned short crc, i;
+
+	crc = 0;
+	while(count--)
+	{
+		crc = crc ^ (int) *ptr++ << 8;
+
+		for(i = 0; i < 8; i++)
+		{
+			if(crc & 0x8000)
+				crc = crc << 1 ^ 0x1021;
+			else
+				crc = crc << 1;
+		}
+	}
+
+	return (crc & 0xFFFF);
+}
+
+void dump_u(void *buf, int len)
+{
+	unsigned char *p = (unsigned char *)buf;
+	int i;
+
+	for(i = 0; i < len; i++) {
+		if(i % 16 == 0) printf("%04x:", i);
+		if(i % 16 == 8) printf(" -");
+		printf(" %02x", p[i]);
+		if(i % 16 == 15) printf("\n");
+	}
+	if(i % 16) printf("\n");
+}
+
+unsigned int get_file_size(const char * name)
+{
+	struct stat statbuff;
+	//unsigned int size, checksum;
+	if(stat(name, &statbuff) < 0)
+		return -1;
+	else
+		return statbuff.st_size;
+}
+
+
+int check_file(char * fname)
+{
+	FILE *fd;
+	uc_image_header_t header;
+	unsigned int buf[1024];
+	unsigned int fsize, checksum, i;
+	unsigned int len;
+	unsigned short crc;
+	size_t rByte;
+
+	if((fd=fopen(fname,"rb"))==NULL)
+	{
+		printf("\n can't open (%s) or not exist!(errno=%d:%s) \n", fname, errno, strerror(errno));
+		return -1;
+	}
+
+	fsize = get_file_size(fname);
+
+	printf("file size [%d]\n",fsize);
+
+	if(fsize == 0)
+		return -1;
+
+	while(fsize > sizeof(header)) {
+		rByte = fread((char *)&header, sizeof(char), sizeof(header), fd);
+
+		dump_u((char *)&header, sizeof(header));
+
+		crc = get_crc16 ( (char *) &header, sizeof(header)-4);
+		printf("crc16  [%08x]\n", crc);
+
+		if((header.ih_hcrc & 0xFFFF) != crc) {
+			fclose(fd);
+			return -1;
+		}
+
+		fsize -= sizeof(header);
+		fsize -= header.ih_size;
+		checksum = 0;
+		len = header.ih_size;
+		while(len > 0)
+		{
+			if(len >= 1024 )
+				rByte = 1024;
+			else
+				rByte = len;
+
+			memset(buf, 0, sizeof(buf));
+			rByte = fread((char *)buf, 1, rByte, fd);
+			for(i = 0; i < (rByte+3)/4; i++)
+				checksum += buf[i];
+
+			len -= rByte;
+		}
+		printf("checksum  [%08x]\n\n",checksum);
+
+		if( checksum != header.ih_dcrc) {
+			fclose(fd);
+			return -1;
+		}
+	}
+
+	fclose(fd);
+	return 0;
+}
+
+static int select_read(int fd, int timeout) //1ms
+{
+	fd_set set;
+	struct timeval t;
+	int ret;
+	int i = timeout;
+
+	if(use_select) {
+		do {
+			FD_ZERO(&set);
+			FD_SET(fd, &set);
+			t.tv_sec = 0;
+			t.tv_usec = 100;
+
+			ret = select(FD_SETSIZE, &set, NULL, NULL, &t );
+			if(ret == 0) continue;
+			if(ret < 0 && errno == EINTR)continue;
+			else return ret;
+		} while(i--);
+	} else {
+		struct timeval t0, t1;
+		long dt = 0;
+		int c;
+
+		gettimeofday(&t0, NULL);
+		do {
+			c = 0;
+			ret = ioctl(fd, FIONREAD, &c);
+			if(c > 0) { ret = c; break; }
+
+			gettimeofday(&t1, NULL);
+			dt = t1.tv_usec - t0.tv_usec;
+			dt += (t1.tv_sec-t0.tv_sec)*1000*1000;
+		} while(dt/1000 < timeout);
+	}
+
+	return ret;
+}
+
+int set_baudrate(int fd, int baudrate)
+{
+	struct termios options, oldtio;
+
+	if(fcntl(fd, F_SETFL, 0) < 0) {
+		printf("fcntl failed!\n");
+		return -1;
+	}
+
+	if(tcgetattr(fd, &oldtio) != 0) {
+		printf("setup serial error!\n");
+		return -1;
+	}
+
+	/* Get the current options for the port... */
+	tcgetattr(fd, &options);
+
+	/* Set the baud rates to baudrate... */
+	cfsetispeed(&options,baudrate);
+	cfsetospeed(&options,baudrate);
+	tcsetattr(fd, TCSANOW, &options);
+
+	if (0 != tcgetattr(fd, &options))
+	{
+		printf("get options error!\n");
+		return -1;
+	}
+
+	/*
+	 * 8bit Data,no partity,1 stop bit...
+	 */
+	options.c_cflag &= ~PARENB;//无奇偶校验
+	options.c_cflag &= ~CSTOPB;//停止位,1位
+	options.c_cflag &= ~CSIZE; //数据位的位掩码
+	options.c_cflag |= CS8;    //数据位,8位
+
+	cfmakeraw(&options);
+
+	/*
+	 * Set the new options for the port...
+	 */
+	if (tcsetattr(fd, TCSANOW, &options) != 0)
+	{
+		printf("setup serial error!\n");
+		return -1 ;
+	}
+
+	return 0 ;
+}
+
+int initial_serialPort(char * serial_device)
+{
+	int fd;
+	fd = open( serial_device , O_RDWR );
+	if ( fd == -1 )
+	{
+		/* open error! */
+		printf("Can't open serial port(%s)!(errno=%d:%s) \n", serial_device, errno, strerror(errno));
+		return -1;
+	}
+
+	set_baudrate(fd, B9600);
+
+	return fd ;
+}
+
+static void gps_dev_send(int fd, char *msg)
+{
+	int i, n, ret;
+
+	i = strlen(msg);
+
+	n = 0;
+
+	printf("function gps_dev_send: %s", msg);
+	do {
+
+		ret = write(fd, msg + n, i - n);
+
+		if (ret < 0 && errno == EINTR) {
+			continue;
+		}
+
+		n += ret;
+
+	} while (n < i);
+
+	// drain cmd
+	tcdrain(fd);
+
+	return;
+}
+
+int xmodem_send(int fd, char *fname)
+{
+	char packet_data[XMODEM_DATA_SIZE];
+	char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1];
+	int ret = -1;
+
+	FILE *datafile;
+	int complete,retry_num,pack_counter,read_number,write_number,i;
+	unsigned short crc_value;
+	unsigned char ack_id = 'C';
+	struct timeval time_m, time_n;
+
+	datafile = NULL;
+	pack_counter = 0;	// 包计数器清零
+	complete = 0;
+	retry_num = 0;
+
+	printf("[%s]\n",fname);
+	//只读方式打开一个准备发送的文件,如果不存在就报错,退出程序。
+	if((datafile=fopen(fname,"rb"))==NULL)
+	{
+		printf("\n can't open (%s) or not exist!(errno=%d:%s) \n", fname, errno, strerror(errno));
+		return -1;
+	}
+	else
+	{
+		printf("Ready to send the file:%s\n",fname);
+	}
+
+	printf("Waiting for signal C/NAK!\n");
+	GET_TIME();
+	while(1)
+	{
+		CHK_TIME1();
+		if(select_read(fd,1) > 0)
+			usleep(10000);
+		else
+			continue;
+
+		//read(fd,&ack_id,1);
+		deal_read(fd,&ack_id,1);
+		if(ack_id == 'C')
+			break;
+	}
+
+	printf("The signal NAK: %02x ok!!!\n",ack_id);//打印接收到的NAK信息
+
+	while(!complete)
+	{
+		switch(ack_id)
+		{
+			case XMODEM_CRC_CHR:	// 接收到字符'C'开始启动传输,并使用CRC校验
+				printf("begining to Send file %s...\n",fname);
+
+			case XMODEM_ACK:        //0x06
+				retry_num = 0;
+				pack_counter++;
+
+				read_number = fread(packet_data, sizeof(char), XMODEM_DATA_SIZE, datafile);
+				//从打开的datafile指向的文件中读取
+				//XMODEM_DATA_SIZE 个(char)数据,
+				//放到packet_data这个数组中
+				if(read_number > 0)//read_number为返回的读取实际字节数
+				{
+					//printf("test:read_number:%d\n", read_number);
+					if(read_number < XMODEM_DATA_SIZE_STX)
+					{
+						printf("Start filling the last frame!\n");
+						for(; read_number < XMODEM_DATA_SIZE; read_number++)
+							packet_data[read_number] = 0x1A;  // 不足128字节用0x1A填充
+						//printf("replenish data.\n");
+					}
+
+					frame_data[0] = XMODEM_HEAD;  // 帧开始字符
+					frame_data[1] = (char)pack_counter;  // 信息包序号
+					frame_data[2] = (char)(255 - frame_data[1]);  // 信息包序号的补码
+
+					for(i=0; i < XMODEM_DATA_SIZE; i++)  // 128字节的数据段
+						frame_data[i+3] = packet_data[i];//把收到的字符和信息头一起打包
+
+					crc_value = get_crc16(packet_data, XMODEM_DATA_SIZE); // 16位crc校验
+					frame_data[XMODEM_DATA_SIZE+3] = (unsigned char)(crc_value >> 8);// 高八位数据
+					frame_data[XMODEM_DATA_SIZE+4] = (unsigned char)(crc_value);     //低八位数据
+
+					/* 发送133字节数据 */
+					write_number = write( fd, frame_data, XMODEM_DATA_SIZE + 5);//向串口写一个包数据,即133字节数据
+					printf("."); //ADD: process
+					fflush(stdout);
+					//printf("waiting for next ACK... \n......\n");
+
+					GET_TIME();
+					while(1)
+					{
+						CHK_TIME1();
+						if(select_read(fd,1) > 0)
+							usleep(10000);
+						else
+							continue;
+
+						//read(fd,&ack_id,1);
+						deal_read(fd,&ack_id,1);
+						break;
+					}
+
+					if(ack_id == XMODEM_ACK) {
+						//printf("ACK Ok!!Ready sending next pack!\n");
+						;
+					}
+					else
+					{
+						printf("ACK Error!\n");
+						printf("0x%02X\n",ack_id);
+						//printf("pack_counter = %d\n", pack_counter);
+					}
+				}
+
+				else  // 文件发送完成
+				{
+					ack_id = XMODEM_EOT;
+					complete = 1;
+					printf("Complete ACK\n");
+
+					GET_TIME();
+					while(ack_id != XMODEM_ACK)
+					{
+						CHK_TIME1();
+						ack_id = XMODEM_EOT;
+						write_number = write(fd,&ack_id,1);
+						while((deal_read(fd, &ack_id, 1)) <= 0);
+					}
+					printf("Send file successful!!!\n");
+					fclose(datafile);
+					datafile = NULL;
+				}
+				break;
+
+			case XMODEM_NAK:
+				if( retry_num++ > 10)
+				{
+					printf("Retry too many times,Quit!\n");
+					complete = 1;
+				}
+				else //重试,发送
+				{
+					write_number = write(fd, frame_data, XMODEM_DATA_SIZE + 5);
+					printf("Retry for ACK,%d,%d...", pack_counter, write_number);
+
+					GET_TIME();
+					while(1)
+					{
+						CHK_TIME1();
+						if(select_read(fd,1) > 0)
+							usleep(100);
+						else
+							continue;
+
+						//read(fd,&ack_id,1);
+						deal_read(fd,&ack_id,1);
+						break;
+					}
+
+					if( ack_id == XMODEM_ACK )
+						printf("OK\n");
+					else
+						printf("Error!\n");
+				}
+				break;
+			default:
+				printf("Fatal Error! %d\n", ack_id);
+				complete = 1;
+				return -1;
+				break;
+		}
+	}
+
+	if( datafile != NULL )
+		fclose(datafile);
+
+	return 0;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_gpio.c b/mbtk/mbtk_lib/src/mbtk_gpio.c
new file mode 100755
index 0000000..c761476
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_gpio.c
@@ -0,0 +1,532 @@
+/**
+ *   \file gpio-test.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-04-26
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include "mbtk_log.h"
+#include <sys/mman.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include "gpio-define.h"
+
+#define gpio_log(...)     if(gpio_debug)printf(__VA_ARGS__)
+
+static int gpio_debug = 0;
+
+struct gpio_register_function gpio_func_register[128] = {
+    {GPIO_FUNC_GPIO_00, 0},
+    {GPIO_FUNC_GPIO_01, 0},
+    {GPIO_FUNC_GPIO_02, 0},
+    {GPIO_FUNC_GPIO_03, 0},
+    {GPIO_FUNC_GPIO_04, 0},
+    {GPIO_FUNC_GPIO_05, 0},
+    {GPIO_FUNC_GPIO_06, 0},
+    {GPIO_FUNC_GPIO_07, 0},
+    {GPIO_FUNC_GPIO_08, 0},
+    {GPIO_FUNC_GPIO_09, 0},
+    {GPIO_FUNC_GPIO_10, 0},
+    {GPIO_FUNC_GPIO_11, 0},
+    {GPIO_FUNC_GPIO_12, 0},
+    {GPIO_FUNC_GPIO_13, 0},
+    {GPIO_FUNC_GPIO_14, 0},
+    {GPIO_FUNC_GPIO_15, 0},
+    {GPIO_FUNC_GPIO_16, 0},
+    {GPIO_FUNC_GPIO_17, 0},
+    {GPIO_FUNC_GPIO_18, 0},
+    {GPIO_FUNC_GPIO_19, 0},
+    {GPIO_FUNC_GPIO_20, 0},
+    {GPIO_FUNC_GPIO_21, 0},
+    {GPIO_FUNC_GPIO_22, 0},
+    {GPIO_FUNC_GPIO_23, 0},
+    {GPIO_FUNC_GPIO_24, 0},
+    {GPIO_FUNC_GPIO_25, 0},
+    {GPIO_FUNC_GPIO_26, 0},
+    {GPIO_FUNC_GPIO_27, 0},
+    {GPIO_FUNC_GPIO_28, 0},
+    {GPIO_FUNC_GPIO_29, 0},
+    {GPIO_FUNC_GPIO_30, 0},
+    {GPIO_FUNC_GPIO_31, 0},
+    {GPIO_FUNC_GPIO_32, 0},
+    {GPIO_FUNC_GPIO_33, 0},
+    {GPIO_FUNC_GPIO_34, 0},
+    {GPIO_FUNC_GPIO_35, 0},
+    {GPIO_FUNC_GPIO_36,   0},
+    {GPIO_FUNC_MMC1_DAT3, 5}, // GPIO_37
+    {GPIO_FUNC_MMC1_DAT2, 5}, // GPIO_38
+    {GPIO_FUNC_MMC1_DAT1, 5}, // GPIO_39
+    {GPIO_FUNC_MMC1_DAT0, 5}, // GPIO_40
+    {GPIO_FUNC_MMC1_CMD, 5},  //GPIO_41
+    {GPIO_FUNC_MMC1_CLK, 5},  //GPIO_42
+    {GPIO_FUNC_MMC1_CD , 1},  //GPIO_43
+    {0,0},{0,0},{0,0},{0,0},
+    {GPIO_FUNC_SDIO_DAT3, 1}, //GPIO_48
+    {GPIO_FUNC_GPIO_49, 0},
+    {GPIO_FUNC_GPIO_50, 0},
+    {GPIO_FUNC_GPIO_51, 0},
+    {GPIO_FUNC_GPIO_52, 0},
+    {GPIO_FUNC_GPIO_53, 0},
+    {GPIO_FUNC_GPIO_54, 0},
+    {GPIO_FUNC_SDIO_DAT2, 1}, //GPIO_55
+    {GPIO_FUNC_SDIO_DAT1, 1}, //GPIO_56
+    {GPIO_FUNC_SDIO_DAT0, 1}, //GPIO_57
+    {GPIO_FUNC_SDIO_CMD, 1},  //GPIO_58
+    {GPIO_FUNC_SDIO_CLK, 1},  //GPIO_59
+    {GPIO_FUNC_GPIO_60, 0},
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},
+    {GPIO_FUNC_DVL_0, 1},//GPIO_67
+    {GPIO_FUNC_DVL_1, 1},//GPIO_68
+    {GPIO_FUNC_GPIO_69, 0},
+    {GPIO_FUNC_GPIO_70, 0},
+    {GPIO_FUNC_QSPI_DAT3, 1}, //GPIO_71
+    {GPIO_FUNC_QSPI_DAT2, 1}, //GPIO_72
+    {GPIO_FUNC_QSPI_DAT1, 1}, //GPIO_73
+    {GPIO_FUNC_QSPI_DAT0, 1}, //GPIO_74
+    {GPIO_FUNC_QSPI_CLK, 1},  //GPIO_75
+    {GPIO_FUNC_QSPI_CS1, 1},  //GPIO_76
+    {GPIO_FUNC_GPIO_77, 0},
+    {GPIO_FUNC_GPIO_78, 0},
+    {GPIO_FUNC_GPIO_79, 0},
+    {GPIO_FUNC_GPIO_80, 0},
+    {GPIO_FUNC_USIM_UCLK, 1},//GPIO_81
+    {GPIO_FUNC_USIM_UIO, 1},//GPIO_82
+    {GPIO_FUNC_USIM_URSTn, 1},//GPIO_83
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},{0,0},
+    {GPIO_FUNC_USB_ID, 1},//GPIO_99
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},{0,0},{0,0},{0,0},
+    {0,0},
+    {GPIO_FUNC_PRI_TDI, 1},         //GPIO_117
+    {GPIO_FUNC_PRI_TMS, 1},         //GPIO_118
+    {GPIO_FUNC_PRI_TCK, 1},         //GPIO_119
+    {GPIO_FUNC_PRI_TDO, 1},         //GPIO_120
+    {GPIO_FUNC_QSPI_VMODE_GPIO, 1}, //GPIO_121
+    {GPIO_FUNC_VBUS_DRV, 1},        //GPIO_122
+    {GPIO_FUNC_CLK_REQ, 1},         //GPIO_123
+    {0,0},
+    {GPIO_FUNC_VCXO_REQ, 1},        //GPIO_125
+    {GPIO_FUNC_VCXO_OUT, 1},        //GPIO_126
+    {0,0},
+};
+#if 0
+/**
+ *  \brief strstr_n
+ *
+ *  find string return number
+ *
+ *  \param param
+ *  \return return type
+ */
+int strstr_n(const char *s1, const char *s2)
+{
+    int n;
+    int strlen = 0;
+
+    if(*s2)
+    {
+        while(*s1)
+        {
+            for(n = 0; *(s1+n) == *(s2 + n); n++)
+            {
+                if(!*(s2 + n + 1))
+                {
+                    strlen++;
+                    return strlen;
+                }
+            }
+            s1++;
+            strlen++;
+        }
+        return 0;
+    }else
+        return 0;
+}
+static short int from_hex(char a)
+{
+    if (a >= 'A' && a <= 'F')
+        return a - 'A' + 10;
+    else if (a >= 'a' && a <= 'f')
+        return a - 'a' + 10;
+    else
+        return a - '0';
+}
+
+int str_to_hex(char *str)
+{
+    unsigned char str_len = strlen(str);
+    int i;
+    int ret = 0;
+
+    if(str[0] != '0' || (str[1] != 'x' && str[1] != 'X'))
+    {
+        printf("%s error, %s!\n", __FUNCTION__, str);
+        return ret;
+    }
+    for (i = 2; i < str_len; ++i) {
+        ret = ret * 16 + from_hex(str[i]);
+    }
+    return ret;
+}
+#endif
+
+#define HWMAP_DEVICE "/dev/hwmap"
+#define PAGE_OFFS_BITS(pgsz) ((unsigned int)(pgsz)-1)
+#define PAGE_MASK_BITS(pgsz) (~PAGE_OFFS_BITS(pgsz))
+
+static int hwacc_register(int rw, unsigned int addr, unsigned int *data)
+{
+	int fid;
+	unsigned int pagesize, len, len_aligned;
+	unsigned int addr_aligned;
+	volatile unsigned int *pa;
+	void *vpa;
+
+	len = pagesize = sysconf(_SC_PAGESIZE);
+	if((fid = open(HWMAP_DEVICE, O_RDWR)) < 0)
+	{
+		printf("Failed to open %s\n", HWMAP_DEVICE);
+		exit(-1);
+	}
+
+	// Align the length so the mapped area is page-aligned and contains the requested area
+	addr_aligned = addr & PAGE_MASK_BITS(pagesize);
+	len_aligned =((addr + len - addr_aligned) + pagesize - 1) & PAGE_MASK_BITS(pagesize);
+
+	/* Notes on flags: MAP_PRIVATE results in copy on write; MAP_SHARED allows normal write */
+	/*   MAP_SHARED required O_RDWR in open above, otherwise mmap fails with errno=EACCES   */
+	/* Notes on prot:  PROT_WRITE allows read and write; PROT_READ allows read only         */
+	/* Notes on off: an unsigned 32-bit value, should be aligned to page size according to mmap manpage */
+	if((vpa = mmap(0, len_aligned, PROT_READ|PROT_WRITE, MAP_SHARED, fid, addr_aligned)) == MAP_FAILED)
+	{
+		printf("mmap failed (%d)\n", errno);
+	}
+	else
+	{
+		pa = (volatile unsigned int *)((unsigned char *)vpa + (addr & PAGE_OFFS_BITS(pagesize)));
+		if(rw == 0)
+		{
+			*data = *pa;
+			gpio_log("Value read from 0x%.8x via MVA=0x%p is 0x%.8x\n", addr, pa, *data);
+		}
+		else if(rw == 1)
+		{
+			*pa = *data;
+			gpio_log("Value %.8x written to 0x%.8x via MVA=0x%p\n", *data, addr, pa);
+#if defined(HWACC_DEBUG)
+			{
+				unsigned int val;
+				val = *pa;
+				printf("Value read from 0x%.8x via MVA=0x%p is 0x%.8x\n", addr, pa, val);
+			}
+#endif
+		}
+		munmap(vpa, len);
+	}
+
+	close(fid);
+	return 0;
+}
+/*
+设置GPIO 模式:第一步读GPIO22默认function
+root@OpenWrt:/# hwacc r 0xd401e134
+Option = r Addr = d401e134
+Value read from 0xd401e134 via MVA=0x0xb6fc3134 is 0x0000d040   //默认GPIO功能
+Bit0~bit2值对应上面表格各function,0代表GPIO功能
+ */
+static int gpio_register_read(int reg)
+{
+    int ret = -1;
+#if 0
+    FILE * fp;
+    // "/bin/hwacc r 0xd401e134";
+    char command[36] = {0};
+    char buffer[1024];
+    int i = 0;
+
+    sprintf(command, "/bin/hwacc r 0x%x", reg);
+    fp = popen(command, "r");
+    while(1)
+    {
+        if( fgets (buffer, sizeof(buffer), fp)!=NULL ) {
+            buffer[strlen(buffer) - 1] = 0;
+            // gpio_log("out [%d]: %s\n", strlen(buffer), buffer);
+        }else{
+            break;
+        }
+        i = strstr_n(buffer, "is");
+        if(i)
+        {
+            ret = str_to_hex(&buffer[i + 2]);
+            gpio_log("read 0x%x value:%s, %x\n", reg, &buffer[i + 2], ret);
+        }
+    }
+    pclose(fp);
+#else
+    hwacc_register(0, reg, &ret);
+#endif
+    return ret;
+}
+/*
+设置输入输出状态,设置PDR寄存器GPIO22为output
+root@OpenWrt:/# hwacc w 0xD401900c 0x00c03800
+Option = w Addr = d401900c Data=00c03800
+Value 00c03800 written to 0xd401900c via MVA=0x0xb6f9f00c
+ */
+static void gpio_register_write(int reg, int value)
+{
+#if 0
+    FILE * fp;
+    //  "/bin/hwacc w 0xD401900c 0x00c03800"
+    char command[36] = {0};
+    char buffer[1024];
+
+    sprintf(command, "/bin/hwacc w 0x%x 0x%x", reg, value);
+    gpio_log("command: %s\n", command);
+    fp = popen(command, "r");
+    while(1)
+    {
+        if( fgets (buffer, sizeof(buffer), fp)!=NULL ) {
+            gpio_log("%s\n", buffer);
+        }else{
+            break;
+        }
+    }
+    pclose(fp);
+
+#else
+    hwacc_register(1, reg, &value);
+#endif
+}
+/*
+AF SEL<p>This field is used for alternate function selection for a pin.
+It selects between the eight possible alternate functions for the pin.
+Alternate function 0 is always the reset case.
+
+<p>0x0 = Alternate function 0 (primary function at reset)
+<p>0x1 = Alternate function 1
+<p>0x2 = Alternate function 2
+<p>0x3 = Alternate function 3
+<p>0x4 = Alternate function 4
+<p>0x5 = Alternate function 5
+<p>0x6 = Alternate function 6
+<p>0x7 = Alternate function 7
+ */
+static int gpio_register_set_func_0(int port)
+{
+    int ret;
+    struct gpio_register_function *reg = NULL;
+    if(port > 128)
+        return -1;
+    reg = &gpio_func_register[port];
+    if(0 == reg->reg)
+        return -1;
+    ret = gpio_register_read(reg->reg);
+    if((ret & 0x7) != reg->func_gpio)
+    {
+        gpio_log("Gpio set func [%d] [0x%x]!\n", reg->func_gpio, (ret & 0xfffffff8) | reg->func_gpio);
+        gpio_register_write(reg->reg, (ret & 0xfffffff8) | reg->func_gpio);
+    }
+    return 0;
+}
+/*
+设置GPIO  方向
+读取输入输出状态,读PDR寄存器:0x0c
+root@OpenWrt:/# hwacc r 0xD401900c
+Option = r Addr = d401900c
+Value read from 0xd401900c via MVA=0x0xb6f3900c is 0x00803800  //bit22为0,代表Input
+ */
+static void gpio_register_set_direction(int port, int dir)
+{
+    int ret;
+    int reg = 0xD4019000;
+
+    if(port > (32 - 1))
+        reg = 0xD4019004;
+    if(port > (32 * 2 - 1))
+        reg = 0xD4019008;
+    if(port > (32 * 3 - 1))
+        reg = 0xD4019100;
+
+    reg += 0x0c;
+    port = port % 0x20;
+    ret = gpio_register_read(reg);
+    // 设置 输出 0 && 1
+    if(!(ret & (0x1 << port)) && dir)
+    {
+        gpio_register_write(reg, ret | (0x1 << port));
+    }
+    // 设置 输入 1 && 0
+    if((ret & (0x1 << port)) && !dir)
+    {
+        gpio_register_write(reg, ret | !(0x1 << port));
+    }
+}
+/*
+设置GPIO 输出电平
+
+读取电平状态,先读PLR寄存器:0x00
+root@OpenWrt:/# hwacc r 0xD4019000
+Option = r Addr = d4019000
+Value read from 0xd4019000 via MVA=0x0xb6f1c000 is 0x81e82a30
+对应下面具体BIT
+1000 0001 1110 1000 0010 1010 0011 0000   BIT22默认电平高
+
+设置输出高:设置PSR寄存器:0x18(只写寄存器)
+root@OpenWrt:/# hwacc w 0xD4019018 0x400000
+Option = w Addr = d4019018 Data=00400000
+Value 00400000 written to 0xd4019018 via MVA=0x0xb6f56018 //bit22写1,输出高
+
+设置输出低:设置PCR寄存器:0x24
+root@OpenWrt:/# hwacc w 0xD4019024 0x400000
+Option = w Addr = d4019024 Data=00400000
+Value 00400000 written to 0xd4019024 via MVA=0x0xb6faa024   //Bit22写1,GPIO22输出低
+
+ */
+static void gpio_register_set_value(int port, int value)
+{
+    int ret;
+    int reg = 0xD4019000;
+
+    if(port > (32 - 1))
+        reg = 0xD4019004;
+    if(port > (32 * 2 - 1))
+        reg = 0xD4019008;
+    if(port > (32 * 3 - 1))
+        reg = 0xD4019100;
+
+    if(value)
+    {
+        reg += 0x18;
+    }
+    else
+        reg += 0x24;
+
+    port = port % 0x20;
+    ret = gpio_register_read(reg);
+    // 设置 高电平 0 && 1
+    if(value)
+    {
+        gpio_register_write(reg, ret | (0x1 << port));
+        return;
+    }
+    // 设置 低电平 1 && 0
+    if(!(ret & (0x1 << port)) && !value)
+    {
+        gpio_register_write(reg, ret | (0x1 << port));
+    }
+}
+/*
+读取电平状态,先读PLR寄存器:0x00
+root@OpenWrt:/# hwacc r 0xD4019000
+Option = r Addr = d4019000
+Value read from 0xd4019000 via MVA=0x0xb6f1c000 is 0x81e82a30
+对应下面具体BIT
+1000 0001 1110 1000 0010 1010 0011 0000   BIT22默认电平高
+ */
+static int gpio_register_get_value(int port)
+{
+    int ret = -1;
+    int reg = 0xD4019000;
+
+    if(port > (32 - 1))
+        reg = 0xD4019004;
+    if(port > (32 * 2 - 1))
+        reg = 0xD4019008;
+    if(port > (32 * 3 - 1))
+        reg = 0xD4019100;
+    port = port % 0x20;
+    ret = gpio_register_read(reg);
+    if(ret & (0x1 << port))
+    {
+        return 1;
+    }
+    return 0;
+}
+
+void gpio_debug_set(int enable)
+{
+    gpio_debug = enable;
+}
+
+int gpio_register_test_out(int port, int value)
+{
+    int ret;
+    gpio_log("Gpio port [%d] test start!\n", port);
+    ret = gpio_register_set_func_0(port);
+    if(ret)
+    {
+        printf("gpio_port can't support!\n");
+        return -1;
+    }
+
+    gpio_register_set_direction(port, 1);
+    ret = gpio_register_get_value(port);
+    gpio_log("gpio default value is : %d.\n", ret);
+
+    gpio_register_set_value(port, 1);
+    ret = gpio_register_get_value(port);
+    gpio_log("######gpio should is high: %d.######\n", ret);
+    if(1 != ret)
+        goto exit;
+    usleep(50);
+
+    gpio_register_set_value(port, 0);
+    ret = gpio_register_get_value(port);
+    gpio_log("######gpio should is low: %d.######\n", ret);
+    if(0 != ret)
+    {
+        goto exit;
+    }
+
+exit:
+    gpio_register_set_direction(port, 0);
+
+    return ret;
+}
+
+int mbtk_at_gpio(void* arg)
+{
+    int test_gpio[] = {33, 35, 36, 34, 82, 83, 81, /*41, 40, 39, 38, 37, 42,*/
+                       21, 4, 122, 123, 20, 43, 13, 12, 14, 118, 19, 120,
+                       49, 50, 32, 31, /*51, 52, */53, 54, 119, 23, 24, 27, 28, 26, 25, 5, 9,
+                       0, 1, 2, 3, 6, 7, 15, 18, 16, 17,
+                       126, 125, 56, 55, 58, 48, 57, 59, 117, 29, 30};
+
+    int i, ret, total, n = 0;
+    int *fail_io = (int *)arg;
+    total = (sizeof(test_gpio)/sizeof(int));
+    printf("Start test gpio total: %d\n", total);
+    for(i = 0; i < total; i++)
+    {
+        ret = gpio_register_test_out(test_gpio[i], 0);
+        if(-1 == ret)
+        {
+            LOGI("######gpio [%d] test failed!!!!!!######\n", test_gpio[i]);
+            fail_io[n] = test_gpio[i];
+            n++;
+        }else{
+            LOGI("######gpio [%d] test success!!!!!!######\n", test_gpio[i]);
+        }
+    }
+    return n;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_http.c b/mbtk/mbtk_lib/src/mbtk_http.c
new file mode 100755
index 0000000..e63064e
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_http.c
@@ -0,0 +1,1361 @@
+/*************************************************************
+Description:
+    MBTK HTTP c file.
+Author:
+    LiuBin
+Date:
+    2020/4/30 13:51:42
+*************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "mbtk_http_base.h"
+#include "mbtk_http.h"
+#include "mbtk_http_chunks.h"
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+
+/*************************************************************
+    Variables:local
+*************************************************************/
+static mbtk_http_handle_t http_handles[HTTP_HANDLE_MAX] =
+{
+    {
+        .id = -1,
+        .data_cb = NULL,
+        .session_cnt = 0,
+        .session = {NULL}
+    }
+};
+
+/*************************************************************
+    Variables:public
+*************************************************************/
+
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+
+/*************************************************************
+    Local Function Definitions
+*************************************************************/
+static void http_session_free(mbtk_http_session_t *session)
+{
+    if(session)
+    {
+        if(session->req.header_cnt > 0)
+        {
+            int index;
+            for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++)
+            {
+                if(session->req.req_h[index] != NULL)
+                {
+                    if(session->req.req_h[index]->value)
+                        free(session->req.req_h[index]->value);
+                    free(session->req.req_h[index]);
+                    session->req.req_h[index] = NULL;
+                }
+            }
+            session->req.header_cnt = 0;
+        }
+
+        if(session->req.content)
+        {
+            free(session->req.content);
+            session->req.content = NULL;
+        }
+
+        if(session->rsp.header_cnt > 0)
+        {
+            int index;
+            for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++)
+            {
+                if(session->rsp.rsp_h[index] != NULL)
+                {
+                    if(session->rsp.rsp_h[index]->value)
+                        free(session->rsp.rsp_h[index]->value);
+                    free(session->rsp.rsp_h[index]);
+                    session->rsp.rsp_h[index] = NULL;
+                }
+            }
+            session->rsp.header_cnt = 0;
+        }
+
+        free(session);
+    }
+}
+
+static int http_session_close(mbtk_http_session_t *session)
+{
+    if(session)
+    {
+        if(session->sock_fd > 0)
+        {
+            if(mbtk_http_close(session->sock_fd))
+            {
+                LOGE("mbtk_http_close() fail.");
+                return -1;
+            }
+            session->sock_fd = -1;
+        }
+
+        session->state = HTTP_SESSION_STATE_NON;
+
+        return 0;
+    }
+
+    return -1;
+}
+
+
+static bool http_handle_check(int handle_id)
+{
+    if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX
+       || http_handles[handle_id].id < 0)
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static bool http_session_check(int handle_id, int session_id)
+{
+    if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX
+       || http_handles[handle_id].id < 0
+       || http_handles[handle_id].id != handle_id)
+    {
+        return FALSE;
+    }
+
+    if(session_id < 0 || session_id >= HTTP_SESSION_MAX
+       || http_handles[handle_id].session[session_id] == NULL
+       || http_handles[handle_id].session[session_id]->id != session_id)
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static bool http_is_space_char(char ch)
+{
+    if(ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n')
+        return TRUE;
+
+    return FALSE;
+}
+
+static bool http_str_empty(char *str)
+{
+    if(str == NULL || strlen(str) == 0)
+        return TRUE;
+
+    return FALSE;
+}
+
+
+static int http_url_parse
+(
+    void* url,
+    void *host,
+    void *uri,
+    int *port,
+    bool *is_ssl
+)
+{
+    if(strlen(url) == 0)
+    {
+        return -1;
+    }
+    char *url_ptr = (char*)url;
+    char *host_ptr = (char*)host;
+
+    LOGI("URL[%d]:%s",strlen(url_ptr),url_ptr);
+
+    if(!memcmp(url_ptr,"https://",8))
+    {
+        *is_ssl = TRUE;
+        url_ptr += 8;
+    }
+    else if(!memcmp(url_ptr,"http://",7))
+    {
+        *is_ssl = FALSE;
+        url_ptr += 7;
+    }
+    else
+    {
+        *is_ssl = FALSE;
+    }
+
+    // ptr point to host.
+    while(*url_ptr)
+    {
+        if(*url_ptr == ':' || *url_ptr == '/') // Host end
+            break;
+        if(http_is_space_char(*url_ptr))
+        {
+            url_ptr++;
+            continue;
+        }
+        *host_ptr++ = *url_ptr++;
+    }
+
+    // "www.baidu.com"
+    if(*url_ptr == '\0')   // No port and uri
+    {
+        if(*is_ssl)
+        {
+            *port = MBTK_HTTPS_PORT_DEF;
+        }
+        else
+        {
+            *port = MBTK_HTTP_PORT_DEF;
+        }
+        memcpy(uri,"/",1);
+
+        LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
+        return 0;
+    }
+    else
+    {
+        //LOGI("Host end with:%x",*url_ptr);
+        if(*url_ptr == ':')   // Port exist.
+        {
+            *port = atoi(url_ptr + 1);
+
+            // Point to '/' or NULL
+            while(*url_ptr && *url_ptr != '/')
+            {
+                url_ptr++;
+            }
+
+            // "www.baidu.com:80"
+            if(*url_ptr == '\0')   // No uri
+            {
+                if(*port == 0)
+                {
+                    if(*is_ssl)
+                    {
+                        *port = MBTK_HTTPS_PORT_DEF;
+                    }
+                    else
+                    {
+                        *port = MBTK_HTTP_PORT_DEF;
+                    }
+                }
+                memcpy(uri,"/",1);
+
+                LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
+                return 0;
+            }
+        }
+
+        // "www.baidu.com/xxx" or "www.baidu.com:80/xxx"
+        // Now,url_ptr point to '/'
+        if(*url_ptr != '/')
+        {
+            LOGE("URI must start with '/'.");
+            return -1;
+        }
+
+        //LOGI("URL3[%d]:%s",strlen(url_ptr),url_ptr);
+
+        memcpy(uri,url_ptr,strlen(url_ptr));
+
+        if(*port == 0)
+        {
+            if(*is_ssl)
+            {
+                *port = MBTK_HTTPS_PORT_DEF;
+            }
+            else
+            {
+                *port = MBTK_HTTP_PORT_DEF;
+            }
+        }
+
+        LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
+        return 0;
+    }
+}
+
+static int http_session_req_head_add(mbtk_http_session_t *session,bool replace,
+                                     char *name, char *value)
+{
+    if(session == NULL || value == NULL)
+        return -1;
+
+    LOGI("Add request header - %s:%s",name,value);
+
+    int i = 0;
+    while(i < HTTP_REQUEST_HEADER_MAX)
+    {
+        if(session->req.req_h[i]
+           && !strncasecmp(session->req.req_h[i]->name,name,strlen(name)))   // Is change value
+        {
+            break;
+        }
+        i++;
+    }
+
+    if(i == HTTP_REQUEST_HEADER_MAX)   // Should add new header.
+    {
+        i = 0;
+        while(i < HTTP_REQUEST_HEADER_MAX)
+        {
+            if(session->req.req_h[i] == NULL)   // Find NULL request.
+            {
+                session->req.req_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t));
+                if(session->req.req_h[i] == NULL)
+                {
+                    LOGE("malloc() fail.");
+                    return -1;
+                }
+
+                memset(session->req.req_h[i],0x0,sizeof(mbtk_http_header_t));
+                memcpy(session->req.req_h[i]->name, name, strlen(name));
+                session->req.req_h[i]->value = NULL;
+                session->req.header_cnt++;
+                break;
+            }
+            i++;
+        }
+    }
+    else     // Is change value
+    {
+        if(!replace)
+        {
+            LOGW("Found this header[%s],no replace.",name);
+            return 0;
+        }
+    }
+
+    if(i == HTTP_REQUEST_HEADER_MAX)
+    {
+        LOGE("Request header is full.");
+        return -1;
+    }
+
+    if(session->req.req_h[i]->value)
+    {
+        free(session->req.req_h[i]->value);
+    }
+    session->req.req_h[i]->value = (char*)malloc(strlen(value) + 1);
+    if(session->req.req_h[i]->value == NULL)
+    {
+        LOGE("malloc() fail.");
+        return -1;
+    }
+    memset(session->req.req_h[i]->value,0x0,strlen(value) + 1);
+    memcpy(session->req.req_h[i]->value,value,strlen(value));
+
+    return 0;
+}
+
+#if 0
+static int http_session_rsp_head_add(mbtk_http_session_t *session,
+                                     char *name, char *value)
+{
+    if(session == NULL || value == NULL)
+        return -1;
+
+    int i = 0;
+    while(i < HTTP_REQUEST_HEADER_MAX)
+    {
+        if(session->rsp.rsp_h[i] == NULL)   // Find NULL request.
+        {
+            session->rsp.rsp_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t));
+            if(session->rsp.rsp_h[i] == NULL)
+            {
+                LOGE("malloc() fail.");
+                return -1;
+            }
+
+            memcpy(session->rsp.rsp_h[i]->name,name,strlen(name));
+            session->rsp.rsp_h[i]->value = (char*)malloc(strlen(value) + 1);
+            if(session->rsp.rsp_h[i]->value == NULL)
+            {
+                LOGE("malloc() fail.");
+                return -1;
+            }
+            memset(session->rsp.rsp_h[i]->value,0x0,strlen(value) + 1);
+            memcpy(session->rsp.rsp_h[i]->value,value,strlen(value));
+
+            session->rsp.header_cnt++;
+            return 0;
+        }
+        i++;
+    }
+
+    return -1;
+}
+#endif
+
+static char* http_option_str_get(mbtk_http_option_enum option)
+{
+    switch(option)
+    {
+        case HTTP_OPTION_HEAD:
+            return "HEAD";
+        case HTTP_OPTION_GET:
+            return "GET";
+        case HTTP_OPTION_POST:
+            return "POST";
+        case HTTP_OPTION_PUT:
+            return "PUT";
+        case HTTP_OPTION_DELETE:
+            return "DELETE";
+        case HTTP_OPTION_OPTIONS:
+            return "OPTIONS";
+        case HTTP_OPTION_TRACE:
+            return "TRACE";
+        case HTTP_OPTION_CONNECT:
+            return "CONNECT";
+        case HTTP_OPTION_LINK:
+            return "LINK";
+        case HTTP_OPTION_UNLINK:
+            return "UNLINK";
+        default:
+            return "";
+    }
+}
+
+static char* http_version_str_get(mbtk_http_version_enum version)
+{
+    switch(version)
+    {
+        case HTTP_VERSION_1_0:
+            return "1.0";
+        case HTTP_VERSION_1_1:
+            return "1.1";
+        case HTTP_VERSION_2:
+            return "2";
+        case HTTP_VERSION_3:
+            return "3";
+        default:
+            return "";
+    }
+}
+
+static char* http_header_find(mbtk_http_session_t *session,char* name)
+{
+    int i = 0;
+    while(i < HTTP_REQUEST_HEADER_MAX)
+    {
+        if(session->req.req_h[i] &&
+           !strncasecmp(session->req.req_h[i]->name,name,strlen(name)))
+        {
+            return session->req.req_h[i]->value;
+        }
+
+        i++;
+    }
+    return NULL;
+}
+
+static int http_header_str_get(mbtk_http_header_t *header,char *header_str,int header_str_len)
+{
+    if(header == NULL || header->value == NULL
+       || header_str == NULL)
+        return 0;
+
+    int len = 0;
+    len = snprintf(header_str,header_str_len,"%s: %s\r\n",
+                   header->name, header->value);
+
+    return len;
+}
+
+static mbtk_http_version_enum http_version_get_by_str(char *version_str)
+{
+    if(!memcmp(version_str,"1.0",3))
+        return HTTP_VERSION_1_0;
+    else if(!memcmp(version_str,"1.1",3))
+        return HTTP_VERSION_1_1;
+    else if(!memcmp(version_str,"2",1))
+        return HTTP_VERSION_2;
+    else if(!memcmp(version_str,"3",1))
+        return HTTP_VERSION_3;
+    else
+        return HTTP_VERSION_1_1;
+}
+
+static int http_header_read(mbtk_http_session_t *session)
+{
+#define BUFFER_SIZE 2048
+    char line[BUFFER_SIZE];
+    char *ptr = NULL;
+    int len = 0;
+    while((len = mbtk_http_read_line(session->sock_fd,line,BUFFER_SIZE)) > 0)
+    {
+        if(!memcmp(line,"\r\n",2))
+        {
+            LOGD("Read empty line.");
+            break;
+        }
+
+        // Delete "\r\n"
+        ptr = line + len - 1; // Point to last char.
+        while(http_is_space_char(*ptr))
+        {
+            *ptr = '\0';
+            len--;
+            ptr--;
+        }
+
+        LOGV("LINE:%s",line);
+
+        if(http_handles[session->handle_id].show_rsp_header &&
+           http_handles[session->handle_id].data_cb)
+        {
+            http_handles[session->handle_id].data_cb(session->id,
+                    MBTK_HTTP_DATA_HEADER,line,len);
+        }
+
+        if(!memcmp(line,"HTTP/",5))   // "HTTP/1.1 200 OK"
+        {
+            session->rsp.state_code = atoi(line + 9);
+            session->rsp.version = http_version_get_by_str(line + 5);
+        }
+        else     // Is response header item.
+        {
+            if(!strncasecmp(line,"Content-Length",14))
+            {
+                ptr = line + 14;
+                while(ptr && !isdigit(*ptr))
+                {
+                    ptr++;
+                }
+
+                if(ptr)
+                {
+                    session->rsp.content_length = atol(ptr);
+                }
+            }
+            else if(!strncasecmp(line,"Transfer-Encoding",17))
+            {
+                ptr = line + 17;
+                while(ptr && !isalpha(*ptr))
+                {
+                    ptr++;
+                }
+
+                if(ptr && !memcmp(ptr,"chunked",7))
+                {
+                    session->rsp.is_chunked = TRUE;
+                }
+            }
+        }
+    }
+#undef BUFFER_SIZE
+
+    LOGD("RSP:HTTP/%s %d, is_chunked:%d,Content-Length:%d",http_version_str_get(session->rsp.version),
+         session->rsp.state_code,session->rsp.is_chunked,session->rsp.content_length);
+
+    return 0;
+}
+
+static int http_session_start_write(mbtk_http_session_t *session)
+{
+    LOGI("Start HTTP write.");
+
+#define BUFFER_SIZE 1024
+    session->state = HTTP_SESSION_STATE_WRITE_HEADER;
+    char buff[BUFFER_SIZE];
+    int len = 0;
+    int index = 0;
+    len += snprintf(buff + len,BUFFER_SIZE - len,"%s %s HTTP/%s\r\n",
+                    http_option_str_get(session->option),
+                    session->uri,
+                    http_version_str_get(session->version));
+
+    // if no set "Host",should set default host.
+    char *host = http_header_find(session,"Host");
+    if(!host)
+    {
+        len += snprintf(buff + len,BUFFER_SIZE - len,"Host: %s\r\n", session->host);
+    }
+
+    if(mbtk_http_write(session->sock_fd,buff,len) != len)
+    {
+        LOGE("mbtk_http_write() fail.");
+        return -1;
+    }
+
+    char header_str[BUFFER_SIZE];
+    int header_str_len = 0;
+    while(index < HTTP_REQUEST_HEADER_MAX)
+    {
+        if(session->req.req_h[index] &&
+           (header_str_len = http_header_str_get(session->req.req_h[index], header_str, BUFFER_SIZE)) > 0)
+        {
+            if(mbtk_http_write(session->sock_fd,header_str,header_str_len) != header_str_len)
+            {
+                LOGE("mbtk_http_write() fail.");
+                return -1;
+            }
+        }
+        index++;
+    }
+
+    // Write request header success.
+    LOGI("HTTP write header complete.");
+
+#undef BUFFER_SIZE
+
+    // Write "\r\n"
+    if(mbtk_http_write(session->sock_fd,"\r\n",2) != 2)
+    {
+        LOGE("mbtk_http_write() fail.");
+        return -1;
+    }
+
+    LOGI("Start write HTTPsession->option. %d", session->option);
+    if(session->option == HTTP_OPTION_POST)
+    {
+        session->state = HTTP_SESSION_STATE_WRITE_CONTENT;
+        LOGI("Start write HTTP content data.");
+
+        if(session->req.content && session->req.content_len > 0)
+        {
+            if(mbtk_http_write(session->sock_fd,session->req.content,session->req.content_len) != session->req.content_len)
+            {
+                LOGE("mbtk_http_write() fail.");
+                return -1;
+            }
+
+            session->state = HTTP_SESSION_STATE_WRITE_END;
+        }
+    }
+    else
+    {
+        session->state = HTTP_SESSION_STATE_WRITE_END;
+
+        LOGI("HTTP write complete.");
+    }
+    return 0;
+}
+
+static int http_session_read_by_chunk(mbtk_http_session_t *session)
+{
+#undef BUFFER_SIZE
+#define BUFFER_SIZE 2048
+    http_chunk_code chunk_code;
+    http_chunker_t chunker;
+    char read_buf[BUFFER_SIZE + 1];
+    int read_len = 0;
+    char chunk_buf[BUFFER_SIZE + 1];
+    int chunk_len;
+    http_chunk_init(&chunker);
+    while(TRUE)
+    {
+        read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000);
+        //read_len = mbtk_http_read_line(session->sock_file,read_buf,BUFFER_SIZE);
+        if(read_len <= 0)
+        {
+            LOGE("Read fail.");
+            return -1;
+        }
+
+        chunk_code = http_chunk_parse(&chunker, read_buf, read_len, chunk_buf, &chunk_len);
+        if(chunk_code > CHUNKE_OK)   // Fail.
+        {
+            LOGE("http_chunk_parse() fail[err - %d].",chunk_code);
+            return -1;
+        }
+
+        LOGD("Read chunk_len:%d",chunk_len);
+        chunk_buf[chunk_len] = '\0';
+
+        if(http_handles[session->handle_id].data_cb)
+            http_handles[session->handle_id].data_cb(session->id,
+                    MBTK_HTTP_DATA_CONTENT,chunk_buf,chunk_len);
+
+        if(CHUNKE_STOP == chunk_code)
+        {
+            if(http_handles[session->handle_id].data_cb)
+                http_handles[session->handle_id].data_cb(session->id,
+                        MBTK_HTTP_DATA_COMPLETE,NULL,0);
+
+            break;
+        }
+    }
+
+    LOGV("Chunk read success.");
+
+    return 0;
+}
+
+static int http_session_read_by_length(mbtk_http_session_t *session)
+{
+#undef BUFFER_SIZE
+#define BUFFER_SIZE 2048
+    char read_buf[BUFFER_SIZE + 1];
+    int read_len = 0;
+    int64 read_count = 0;
+    while(TRUE)
+    {
+        memset(read_buf,0x0,BUFFER_SIZE + 1);
+        read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000);
+        if(read_len <= 0)
+        {
+            LOGE("Read fail.");
+            return -1;
+        }
+
+        if(read_count + read_len >= session->rsp.content_length)   // Read data complete.
+        {
+            if(http_handles[session->handle_id].data_cb)
+            {
+                http_handles[session->handle_id].data_cb(session->id,
+                        MBTK_HTTP_DATA_CONTENT,read_buf,session->rsp.content_length - read_count);
+
+                http_handles[session->handle_id].data_cb(session->id,
+                        MBTK_HTTP_DATA_COMPLETE,NULL,0);
+            }
+            break;
+        }
+
+        if(http_handles[session->handle_id].data_cb)
+            http_handles[session->handle_id].data_cb(session->id,
+                    MBTK_HTTP_DATA_CONTENT,read_buf,read_len);
+
+        read_count += read_len;
+    }
+
+    return 0;
+}
+
+static int http_session_read_by_general(mbtk_http_session_t *session)
+{
+#undef BUFFER_SIZE
+#define BUFFER_SIZE 2048
+    char read_buf[BUFFER_SIZE + 1];
+    int read_len = 0;
+    while(TRUE)
+    {
+        read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,1000);
+        if(read_len <= 0)
+        {
+            if(read_len == -2 || read_len == 0) // Timeout or end
+                break;
+
+            LOGW("Read end[read_len - %d].",read_len);
+            //return -1;
+            break;
+        }
+
+        read_buf[read_len] = '\0';
+
+        if(http_handles[session->handle_id].data_cb)
+            http_handles[session->handle_id].data_cb(session->id,
+                    MBTK_HTTP_DATA_CONTENT,read_buf,read_len);
+    }
+
+    if(http_handles[session->handle_id].data_cb)
+        http_handles[session->handle_id].data_cb(session->id,
+                MBTK_HTTP_DATA_COMPLETE,NULL,0);
+
+    return 0;
+}
+
+static int http_session_start_read(mbtk_http_session_t *session)
+{
+    LOGI("Start HTTP read.");
+    int result = 0;
+//    usleep(500000);
+    session->state = HTTP_SESSION_STATE_READ_HEADER;
+    if(http_header_read(session))
+    {
+        result = -1;
+        goto read_end;
+    }
+
+    if(session->option != HTTP_OPTION_HEAD)
+    {
+        session->state = HTTP_SESSION_STATE_READ_CONTENT;
+        if(session->rsp.is_chunked)
+        {
+            if(http_session_read_by_chunk(session))
+            {
+                result = -1;
+                goto read_end;
+            }
+        }
+        else if(session->rsp.content_length > 0)
+        {
+            if(http_session_read_by_length(session))
+            {
+                result = -1;
+                goto read_end;
+            }
+        }
+        else
+        {
+            if(http_session_read_by_general(session))
+            {
+                result = -1;
+                goto read_end;
+            }
+        }
+    }
+    else
+    {
+        if(http_handles[session->handle_id].data_cb)
+            http_handles[session->handle_id].data_cb(session->id,
+                    MBTK_HTTP_DATA_COMPLETE,NULL,0);
+    }
+
+read_end:
+    session->state = HTTP_SESSION_STATE_READ_END;
+
+    LOGI("HTTP request complete[result - %d].",result);
+    if(http_session_close(session))
+    {
+        return -1;
+    }
+
+#if 0
+    // Free session after HTTP request complete.
+    http_session_free(session);
+    http_handles[handle_id].session[session_id] = NULL;
+    http_handles[handle_id].session_cnt--;
+#endif
+
+    return result;
+}
+
+static bool http_session_req_check(mbtk_http_session_t *session)
+{
+    if(session == NULL || session->port == 0 ||
+       strlen(session->host) == 0)
+    {
+        LOGE("Session not set host or port.");
+        return FALSE;
+    }
+
+    if(session->option != HTTP_OPTION_HEAD &&
+       session->option != HTTP_OPTION_POST &&
+       session->option != HTTP_OPTION_GET)
+    {
+        LOGE("Only support HEAD/GET/POST");
+        return FALSE;
+    }
+
+#if 0
+    if(session->version != HTTP_VERSION_1_0 &&
+       session->version != HTTP_VERSION_1_1)
+    {
+        LOGE("Only support HTTP 1.0/1.1");
+        return FALSE;
+    }
+#endif
+
+    if(session->option == HTTP_OPTION_POST)
+    {
+        char *value = NULL;
+        value = http_header_find(session, "Content-Length");
+        if(!value)
+        {
+            LOGE("POST must set 'Content-Length'");
+            return FALSE;
+        }
+        if(session->req.content_len != atoi(value))
+        {
+            LOGE("POST 'Content-Length' error.");
+            return FALSE;
+        }
+
+        value = http_header_find(session, "Content-Type");
+        if(!value)
+        {
+            LOGE("POST must set 'Content-Type'");
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+/*************************************************************
+    Public Function Definitions
+*************************************************************/
+int mbtk_http_handle_get(bool show_rsp_header,mbtk_http_data_callback_func data_cb)
+{
+    int index = 0;
+    int i = 0;
+    for(; index < HTTP_HANDLE_MAX; index++)
+    {
+        if(http_handles[index].id < 0)   // Find free handle
+        {
+            break;
+        }
+    }
+
+    if(index == HTTP_HANDLE_MAX)
+    {
+        LOGE("HTTP Handle is full.");
+        return -1;
+    }
+
+    memset(&(http_handles[index]),0x0,sizeof(mbtk_http_handle_t));
+    http_handles[index].id = index;
+    http_handles[index].show_rsp_header = show_rsp_header;
+    http_handles[index].data_cb = data_cb;
+    http_handles[index].session_cnt = 0;
+    for(i = 0; i < HTTP_SESSION_MAX; i++)
+    {
+        http_handles[index].session[i] = NULL;
+    }
+
+    if(mbtk_http_init())
+    {
+        LOGE("mbtk_http_init() fail.");
+        return -1;
+    }
+
+    return http_handles[index].id;
+}
+
+int mbtk_http_handle_free(int handle_id)
+{
+    int i = 0;
+    if(!http_handle_check(handle_id))
+    {
+        LOGE("Handle error.");
+        return -1;
+    }
+
+    http_handles[handle_id].id = -1;
+    http_handles[handle_id].data_cb = NULL;
+    if(http_handles[handle_id].session_cnt > 0)
+    {
+        for(i = 0; i < HTTP_SESSION_MAX; i++)
+        {
+            if(http_handles[handle_id].session[i] != NULL)
+            {
+                if(http_handles[handle_id].session[i]->state != HTTP_SESSION_STATE_NON)
+                {
+                    if(http_session_close(http_handles[handle_id].session[i]))
+                    {
+                        return -1;
+                    }
+                }
+
+                http_session_free(http_handles[handle_id].session[i]);
+                http_handles[handle_id].session[i] = NULL;
+            }
+        }
+
+        http_handles[handle_id].session_cnt = 0;
+    }
+
+    if(mbtk_http_deinit())
+    {
+        LOGE("mbtk_http_deinit() fail.");
+        return -1;
+    }
+
+    return 0;
+}
+
+int mbtk_http_session_create(int handle_id, mbtk_http_option_enum option,
+                             mbtk_http_version_enum version)
+{
+    int handle_index = 0;
+    int session_index = 0;
+    if(!http_handle_check(handle_id))
+    {
+        LOGE("Handle error.");
+        return -1;
+    }
+
+    for(; handle_index < HTTP_HANDLE_MAX; handle_index++)
+    {
+        if(http_handles[handle_index].id == handle_id)   // Find handle
+        {
+            break;
+        }
+    }
+
+    if(handle_index == HTTP_HANDLE_MAX)
+    {
+        LOGE("No found handle[handle - %d].",handle_id);
+        return -1;
+    }
+
+    if(http_handles[handle_index].session_cnt >= HTTP_SESSION_MAX)
+    {
+        LOGE("Session is full.");
+        return -1;
+    }
+
+    for(; session_index < HTTP_SESSION_MAX; session_index++)
+    {
+        if(http_handles[handle_index].session[session_index] == NULL)   // Find first NULL session
+        {
+            break;
+        }
+    }
+
+    if(session_index == HTTP_SESSION_MAX)
+    {
+        LOGE("Session is full.");
+        return -1;
+    }
+
+    mbtk_http_session_t* session = (mbtk_http_session_t*)malloc(sizeof(mbtk_http_session_t));
+    if(session == NULL)
+    {
+        LOGE("malloc() fail.");
+        return -1;
+    }
+    memset(session,0x0,sizeof(mbtk_http_session_t));
+    session->sock_fd = -1;
+    session->sock_file = NULL;
+    session->handle_id = handle_id;
+    session->id = session_index;
+    session->state = HTTP_SESSION_STATE_NON;
+    session->is_ssl = FALSE;
+    session->version = version;
+    session->option = option;
+    session->req.content_len = 0;
+    session->req.content_len_send = 0;
+    session->rsp.is_chunked = FALSE;
+    session->rsp.content_length = 0;
+    session->rsp.header_cnt = 0;
+    http_handles[handle_index].session[session_index] = session;
+    http_handles[handle_index].session_cnt++;
+
+    return session->id;
+}
+
+int mbtk_http_session_option_reset(int handle_id, int session_id, mbtk_http_option_enum option)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state != HTTP_SESSION_STATE_NON)
+    {
+        LOGE("Session state error.[%d]",session->state);
+        return -1;
+    }
+
+    session->option = option;
+    return 0;
+}
+
+int mbtk_http_session_free(int handle_id,int session_id)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state != HTTP_SESSION_STATE_NON)
+    {
+        if(http_session_close(session))
+        {
+            return -1;
+        }
+    }
+
+    http_session_free(session);
+    http_handles[handle_id].session[session_id] = NULL;
+    http_handles[handle_id].session_cnt--;
+    return 0;
+}
+
+int mbtk_http_session_url_set(int handle_id,int session_id,void *url)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state == HTTP_SESSION_STATE_NON)
+        return http_url_parse(url, session->host,session->uri,&(session->port),&(session->is_ssl));
+    else
+    {
+        LOGE("Currenr session is process[state - %d].",session->state);
+        return -1;
+    }
+}
+
+int mbtk_http_session_head_add(int handle_id,int session_id,
+                               char *name, char *value)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    if(http_str_empty(name) || http_str_empty(value))
+    {
+        LOGE("Param error.");
+        return -1;
+    }
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state == HTTP_SESSION_STATE_NON)
+    {
+        int result = http_session_req_head_add(session,TRUE,name,value);
+        if(!result && !strncasecmp(name,"Content-Length",14))
+        {
+            session->req.content_len = atoi(value);
+        }
+        return result;
+    }
+    else
+    {
+        LOGE("Currenr session is process[state - %d].",session->state);
+        return -1;
+    }
+}
+
+int mbtk_http_session_content_set(int handle_id,int session_id,
+                                  char *content,uint32 content_len)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    if(content_len <= 0 || content_len > HTTP_CONTENT_LEN_MAX)
+    {
+        LOGE("Content lenght error[%d].",content_len);
+        return -1;
+    }
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state == HTTP_SESSION_STATE_NON)
+    {
+        if(session->option != HTTP_OPTION_POST)
+        {
+            LOGE("Content only for post.");
+            return -1;
+        }
+
+        if(session->req.content)
+        {
+            free(session->req.content);
+            session->req.content_len = 0;
+        }
+
+        session->req.content = (char*)malloc(content_len);
+        if(session->req.content == NULL)
+        {
+            LOGE("malloc() fail.");
+            return -1;
+        }
+
+        char *content_type = NULL;
+        if(strlen(content) == content_len)   //
+        {
+            content_type = "text/plain";
+        }
+        else
+        {
+            content_type = "application/octet-stream";
+        }
+
+        if(http_session_req_head_add(session, FALSE, "Content-Type", content_type))
+        {
+            LOGE("Set 'Content-Type' fail.");
+            return -1;
+        }
+
+        memcpy(session->req.content,content,content_len);
+        session->req.content_len = content_len;
+
+        char len_str[20] = {0};
+        snprintf(len_str,20,"%d",content_len);
+        if(http_session_req_head_add(session,FALSE,"Content-Length",len_str))
+        {
+            LOGE("Set 'Content-Length' fail.");
+            return -1;
+        }
+
+
+        return 0;
+    }
+    else
+    {
+        LOGE("Currenr session is process[state - %d].",session->state);
+        return -1;
+    }
+}
+
+int mbtk_http_session_start(int handle_id,int session_id)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state == HTTP_SESSION_STATE_NON)
+    {
+        if(!http_session_req_check(session))
+        {
+            LOGE("http_session_req_check() fail.");
+            return -1;
+        }
+
+        // Must set "Connection" for post.
+        if(session->option == HTTP_OPTION_POST)
+        {
+            if(http_session_req_head_add(session,FALSE,"Connection","KeepAlive"))
+            {
+                LOGE("Set 'Content-Length' fail.");
+                return -1;
+            }
+        }
+
+        LOGI("HTTP request start.");
+        LOGI("host:%s, port:%d, uri:%s",session->host,session->port,session->uri);
+        LOGI("is_ssl:%d, version:%d, option:%d, content_len:%d",session->is_ssl,
+             session->version,session->option,session->req.content_len);
+
+        int sock_fd = mbtk_http_open(session->is_ssl,TRUE,session->host,session->port);
+        if(sock_fd < 0)
+        {
+            return -1;
+        }
+        session->sock_fd = sock_fd;
+//        int fd = mbtk_sock_fd_get(sock_fd);
+//        if(fd < 0) {
+//            LOGE("mbtk_sock_fd_get() fail.");
+//            return -1;
+//        }
+        // session->sock_file = fdopen(sock_fd,"r");
+        session->state = HTTP_SESSION_STATE_CONN;
+
+//        if(!session->sock_file) {
+//            LOGE("fdopen() fail.");
+//            return -1;
+//        }
+
+        LOGI("HTTP connected.");
+
+        if(http_session_start_write(session))
+        {
+            return -1;
+        }
+
+        if(session->state == HTTP_SESSION_STATE_WRITE_END)
+        {
+            if(http_session_start_read(session))
+            {
+                return -1;
+            }
+        }
+        else
+        {
+            LOGI("Waitting post content data...");
+        }
+
+        return 0;
+    }
+    else
+    {
+        LOGE("Currenr session is process[state - %d].",session->state);
+        return -1;
+    }
+}
+
+int mbtk_http_session_content_send(int handle_id,int session_id,
+                                   char *data,int data_len)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return -1;
+    }
+
+    if(data_len <= 0 || data_len > HTTP_CONTENT_LEN_MAX)
+    {
+        LOGE("Content lenght error[%d].",data_len);
+        return -1;
+    }
+
+    LOGV("Post send:%d - %s",data_len,data);
+
+    mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+    if(session->state == HTTP_SESSION_STATE_WRITE_CONTENT)
+    {
+        if(session->option != HTTP_OPTION_POST)
+        {
+            LOGE("Content only for post.");
+            return -1;
+        }
+
+        if(session->req.content || session->req.content_len <= 0)
+        {
+            LOGE("This post not spit package.");
+            return -1;
+        }
+
+        // Discard excess data.
+        if(session->req.content_len_send + data_len > session->req.content_len)
+            data_len = session->req.content_len - session->req.content_len_send;
+
+        if(data_len != mbtk_http_write(session->sock_fd,data,data_len))
+        {
+            return -1;
+        }
+
+        session->req.content_len_send += data_len;
+
+        LOGI("HTTP post data send: %d / %d",session->req.content_len_send,
+             session->req.content_len);
+
+        // Post data send complete.
+        if(session->req.content_len_send >= session->req.content_len)
+        {
+            session->state = HTTP_SESSION_STATE_WRITE_END;
+
+            LOGI("HTTP write complete.");
+            if(http_session_start_read(session))
+            {
+                return -1;
+            }
+        }
+
+        return 0;
+    }
+    else
+    {
+        LOGE("Currenr session state error[%d].",session->state);
+        return -1;
+    }
+}
+
+const mbtk_http_session_t* mbtk_http_session_get(int handle_id,int session_id)
+{
+    if(!http_session_check(handle_id,session_id))
+    {
+        LOGE("Session error.");
+        return NULL;
+    }
+
+    return http_handles[handle_id].session[session_id];
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_http_base.c b/mbtk/mbtk_lib/src/mbtk_http_base.c
new file mode 100755
index 0000000..40a6742
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_http_base.c
@@ -0,0 +1,279 @@
+#include <sys/epoll.h>
+#include <string.h>
+
+#include "mbtk_log.h"
+#include "mbtk_http_base.h"
+
+static void http_sock_cb_func(int handle, int fd, int event);
+
+static mbtk_init_info http_init_info =
+{
+    MBTK_NET_LINUX,
+    NULL,
+    http_sock_cb_func
+};
+static bool http_sock_inited = FALSE;
+static int http_handle = -1;
+static int http_fd = -1;
+
+static void http_sock_cb_func(int handle, int fd, int event)
+{
+    if(http_handle == handle && http_fd == fd) {
+        if(event & EPOLLIN) { // READ
+
+        } else if(event & EPOLLRDHUP) { // Close
+
+        } else {
+            LOGW("Unknown event:%x",event);
+        }
+    }
+}
+
+int mbtk_http_init()
+{
+    if(http_sock_inited) {
+        LOGE("HTTP has inited.");
+        return -1;
+    }
+
+    http_handle = mbtk_sock_init(&http_init_info);
+    if(http_handle < 0) {
+        LOGE("mbtk_sock_init() fail.");
+        return -1;
+    }
+
+    http_sock_inited = TRUE;
+    return 0;
+}
+
+int mbtk_http_deinit()
+{
+    if(!http_sock_inited) {
+        LOGE("HTTP not inited.");
+        return -1;
+    }
+
+    int err = mbtk_sock_deinit(http_handle);
+    if(err != MBTK_SOCK_SUCCESS) {
+        LOGE("mbtk_sock_deinit() fail.");
+        return -1;
+    }
+
+    http_handle = -1;
+    http_sock_inited = FALSE;
+    return 0;
+}
+
+
+int mbtk_http_open
+(
+    bool is_ssl,
+    bool ingnore_cert,
+    const void *host,
+    uint16 port
+)
+{
+    int err;
+    mbtk_sock_info sock_info;
+    memset(&sock_info,0x0,sizeof(mbtk_sock_info));
+
+    sock_info.type = MBTK_SOCK_TCP;
+    sock_info.is_support_ssl = is_ssl;
+    sock_info.ingnore_cert = ingnore_cert;
+    memcpy(sock_info.address,host,strlen(host));
+    sock_info.port = port;
+
+    http_fd = mbtk_sock_open(http_handle,&sock_info, 3000, &err);
+
+    return http_fd;
+}
+
+/*=============================================
+FUNCTION
+    mbtk_http_read
+
+DESCRIPTION
+    read content from socket.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    *buf      Store read content.
+    len       the length of Content.
+    timeout   Set timeout
+
+RETURN VALUE
+    Length of read content
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_http_read
+(
+    int sock_fd,
+    void *buf,
+    uint16 len,
+    int timeout_ms
+)
+{
+    int err;
+    int read_len = mbtk_sock_read(http_handle, sock_fd, buf, len, timeout_ms, &err);
+    if(read_len < 0) {
+        if(err == MBTK_SOCK_ETIMEOUT) {
+            return -2;
+        } else {
+            return -1;
+        }
+    } else {
+        return read_len;
+    }
+}
+
+#if 0
+int mbtk_http_read_line
+(
+    FILE *file,
+    void *buf,
+    uint16 len
+)
+{
+    if(file) {
+        char *buf_ptr = (char*)buf;
+        char *line = NULL;
+read_again:
+        line = fgets(buf_ptr,len,file);
+        if(!line && errno == EWOULDBLOCK) {
+            usleep(100000);
+            goto read_again;
+        }
+        if(line && strlen(line) > 0
+            && strlen(line) <= len
+            && buf_ptr[strlen(line) - 1] == '\n') {
+            LOGV("Read-Line[%d]:%s",strlen(line),line);
+            return strlen(line);
+        }else{
+            LOGE("fgets() fail.");
+            return -1;
+        }
+    }
+
+    return -1;
+}
+#else
+int mbtk_http_read_line
+(
+    int sock_fd,
+    void *buf,
+    uint16 len
+)
+{
+#if 1
+    if(sock_fd > 0) {
+        char *buf_ptr = (char*)buf;
+        char read_buf[1];
+        int read_len = 0;
+        while(TRUE) {
+            if(mbtk_sock_read_async(http_handle, sock_fd, read_buf, 1) == 1) {
+                *buf_ptr++ = read_buf[0];
+                read_len++;
+
+                if(read_buf[0] == '\n' || read_len >= len) {
+                    return read_len;
+                }
+            } else {
+                return -1;
+            }
+        }
+    }
+#else
+    if(http_handle >= 0) {
+        char *buf_ptr = (char*)buf;
+        char read_buf[1];
+        int read_len = 0;
+        while(TRUE) {
+            if(read(http_fd, read_buf, 1) == 1) {
+                *buf_ptr++ = read_buf[0];
+                read_len++;
+
+                if(read_buf[0] == '\n' || read_len >= len) {
+                    return read_len;
+                }
+            } else {
+                if(errno == EWOULDBLOCK) {
+                    usleep(100000);
+                }
+            }
+        }
+    }
+
+#endif
+
+    return -1;
+}
+
+#endif
+
+/*=============================================
+FUNCTION
+    mbtk_http_write
+
+DESCRIPTION
+    Write content to socket.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    *buf    Content to be transferred
+    len     the length of Content.
+
+RETURN VALUE
+    Length of written content
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_http_write
+(
+    int sock_fd,
+    void *buf,
+    uint16 len
+)
+{
+    int err;
+    LOGV("Write[%d]:%s",len,(char*)buf);
+    return mbtk_sock_write(http_handle, sock_fd, buf, len, 300, &err);
+}
+
+/*=============================================
+FUNCTION
+    mbtk_http_close
+
+DESCRIPTION
+    close HTTP service.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    *err    Error number
+
+RETURN VALUE
+    TURE or FALSE
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_http_close(int sock_fd)
+{
+    int err;
+
+    if(mbtk_sock_close(http_handle, sock_fd,1000, &err)) {
+        return -1;
+    }
+
+    sock_fd = -1;
+    return 0;
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_http_chunks.c b/mbtk/mbtk_lib/src/mbtk_http_chunks.c
new file mode 100755
index 0000000..899e0c7
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_http_chunks.c
@@ -0,0 +1,131 @@
+#include <string.h>
+
+#include "mbtk_http_chunks.h"
+#include "mbtk_http_base.h"
+
+static bool http_isxdigit(char digit)
+{
+    return (digit >= 0x30 && digit <= 0x39) /* 0-9 */
+            || (digit >= 0x41 && digit <= 0x46) /* A-F */
+            || (digit >= 0x61 && digit <= 0x66); /* a-f */
+}
+
+void http_chunk_init(http_chunker_t *chunker)
+{
+    chunker->hexindex = 0;      /* start at 0 */
+    chunker->dataleft = 0;      /* no data left yet! */
+    chunker->state = CHUNK_HEX; /* we get hex first! */
+}
+
+http_chunk_code http_chunk_parse(http_chunker_t *chunker, char *src, int src_len,
+            char *dest,int *dest_len)
+{
+    int piece;
+    char *datap = src;
+    int length = src_len;
+
+    *dest_len = 0;
+
+    while(length > 0)
+    {
+        switch(chunker->state)
+        {
+            case CHUNK_HEX:
+                if(http_isxdigit(*datap))
+                {
+                    if(chunker->hexindex < MAXNUM_SIZE)
+                    {
+                        chunker->hexbuffer[chunker->hexindex] = *datap;
+                        datap++;
+                        length--;
+                        chunker->hexindex++;
+                    }
+                    else
+                    {
+                        return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
+                    }
+                }
+                else // Not hex char. ('\r')
+                {
+                    if(0 == chunker->hexindex)
+                        return CHUNKE_ILLEGAL_HEX;
+
+                    chunker->hexbuffer[chunker->hexindex] = '\0';
+                    sscanf(chunker->hexbuffer,"%x",&chunker->datasize);
+
+                    LOGD("Chunk len:%s -> %d",chunker->hexbuffer,chunker->datasize);
+
+                    chunker->state = CHUNK_LF; /* now wait for the CRLF */
+                }
+                break;
+            case CHUNK_LF:
+                if(*datap == 0x0a) // '\n'
+                {
+                    if(0 == chunker->datasize) { // Chunk lenght is '0' (Is last chunk)
+                        chunker->state = CHUNK_TRAILER;
+                    } else {
+                        chunker->state = CHUNK_DATA;
+                    }
+                }
+
+                datap++;
+                length--;
+                break;
+            case CHUNK_DATA:
+                /* We expect 'datasize' of data. We have 'length' right now, it can be
+                   more or less than 'datasize'. Get the smallest piece.
+                */
+                piece = (chunker->datasize >= length)?length:chunker->datasize;
+
+                memcpy(dest + *dest_len,datap,piece);
+                *dest_len += piece;
+
+                chunker->datasize -= piece; /* decrease amount left to expect */
+                datap += piece;    /* move read pointer forward */
+                length -= piece;   /* decrease space left in this round */
+
+                if(0 == chunker->datasize) // Next chunk
+                    chunker->state = CHUNK_POSTLF;
+                break;
+            case CHUNK_POSTLF:
+                if(*datap == 0x0a)
+                {
+                    http_chunk_init(chunker);
+                }
+                else if(*datap != 0x0d)
+                    return CHUNKE_BAD_CHUNK;
+                datap++;
+                length--;
+                break;
+            case CHUNK_TRAILER:
+                if((*datap != 0x0d) && (*datap != 0x0a))
+                {
+                    return CHUNKE_BAD_CHUNK;
+                }
+                if(*datap == 0x0d)
+                {
+                    /* skip if CR */
+                    datap++;
+                    length--;
+                }
+                chunker->state = CHUNK_STOP;
+                break;
+            case CHUNK_STOP: // Complete
+                if(*datap == 0x0a)
+                {
+                    length--;
+
+                    /* Record the length of any data left in the end of the buffer
+                       even if there's no more chunks to read */
+                    chunker->dataleft = length;
+
+                    return CHUNKE_STOP; /* return stop */
+                }
+                else
+                    return CHUNKE_BAD_CHUNK;
+        }
+    }
+    return CHUNKE_OK;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_ifc.c b/mbtk/mbtk_lib/src/mbtk_ifc.c
new file mode 100755
index 0000000..51267f5
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_ifc.c
@@ -0,0 +1,577 @@
+/*
+* MBTK Network Interface control.
+*
+* Author : lb
+* Date   : 2021/8/20 11:44:05
+*
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+//#include <net/if.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+#include <linux/sockios.h>
+//#include <cutils/properties.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <linux/route.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+#include "mbtk_ifc.h"
+
+#define IFNAMSIZ    16
+
+static int ifc_ctl_sock = -1;
+static pthread_mutex_t ifc_sock_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void ifc_init_ifr(const char *name, struct ifreq *ifr)
+{
+    memset(ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr->ifr_name, name, IFNAMSIZ);
+    ifr->ifr_name[IFNAMSIZ - 1] = 0;
+}
+
+static int ifc_set_flags(int sock, const char *name, unsigned set, unsigned clr)
+{
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
+        return -1;
+    ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
+    return ioctl(sock, SIOCSIFFLAGS, &ifr);
+}
+
+static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
+{
+    struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+    sin->sin_addr.s_addr = addr;
+}
+
+#if 1
+static const char *ipaddr_to_string(in_addr_t addr)
+{
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
+}
+#endif
+
+static in_addr_t prefixLengthToIpv4Netmask(int prefix_length)
+{
+    in_addr_t mask = 0;
+
+    // C99 (6.5.7): shifts of 32 bits have undefined results
+    if (prefix_length <= 0 || prefix_length > 32)
+    {
+        return 0;
+    }
+
+    mask = ~mask << (32 - prefix_length);
+    mask = htonl(mask);
+
+    return mask;
+}
+
+#if 1
+static int ifc_set_prefixLength(const char *name, int prefixLength)
+{
+    struct ifreq ifr;
+    // TODO - support ipv6
+//    if (prefixLength > 32 || prefixLength < 0) return -1;
+
+    in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength);
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, mask);
+
+    return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
+}
+#endif
+
+int ifc_act_on_ipv4_route(int action, const char *ifname, struct in_addr dst, int prefix_length,
+                          struct in_addr gw)
+{
+    struct rtentry rt;
+    int result;
+    in_addr_t netmask;
+
+    memset(&rt, 0, sizeof(rt));
+
+    rt.rt_dst.sa_family = AF_INET;
+    rt.rt_dev = (void*) ifname;
+
+    netmask = prefixLengthToIpv4Netmask(prefix_length);
+    init_sockaddr_in(&rt.rt_genmask, netmask);
+    init_sockaddr_in(&rt.rt_dst, dst.s_addr);
+    rt.rt_flags = RTF_UP;
+
+    if (prefix_length == 32)
+    {
+        rt.rt_flags |= RTF_HOST;
+    }
+
+    if (gw.s_addr != 0)
+    {
+        rt.rt_flags |= RTF_GATEWAY;
+        init_sockaddr_in(&rt.rt_gateway, gw.s_addr);
+    }
+
+    result = ioctl(ifc_ctl_sock, action, &rt);
+    if (result < 0)
+    {
+        if (errno == EEXIST)
+        {
+            result = 0;
+        }
+        else
+        {
+            result = -errno;
+        }
+    }
+    return result;
+}
+
+static int ifc_create_default_route1(const char *name, in_addr_t gw)
+{
+    struct in_addr in_dst, in_gw;
+
+    in_dst.s_addr = 0;
+    in_gw.s_addr = gw;
+
+    int ret = ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 0, in_gw);
+    LOGD("ifc_create_default_route(%s, %d) = %d", name, gw, ret);
+    return ret;
+}
+
+/* deprecated - v4 only */
+static int ifc_create_default_route2(const char *name, const char *gw)
+{
+    struct in_addr in_dst, in_gw;
+
+    in_dst.s_addr = 0;
+    if(gw == NULL)
+    {
+        in_gw.s_addr = 0;
+    }
+    else
+    {
+        if(inet_aton(gw,(struct in_addr *)&(in_gw.s_addr)) < 0)
+        {
+            LOGE("inet_aton error.");
+            return -1;
+        }
+    }
+
+    int ret = ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 0, in_gw);
+    LOGD("ifc_create_default_route(%s) = %d", name, ret);
+    return ret;
+}
+
+int mbtk_ifc_open(void)
+{
+    pthread_mutex_lock(&ifc_sock_mutex);
+    if (ifc_ctl_sock == -1)
+    {
+        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+        if (ifc_ctl_sock < 0)
+        {
+            LOGE("socket() failed: %s\n", strerror(errno));
+        }
+    }
+
+    return ifc_ctl_sock < 0 ? -1 : 0;
+}
+
+int mbtk_ifc_close(void)
+{
+    if (ifc_ctl_sock != -1)
+    {
+        (void)close(ifc_ctl_sock);
+        ifc_ctl_sock = -1;
+    }
+    pthread_mutex_unlock(&ifc_sock_mutex);
+
+    return 0;
+}
+
+int mbtk_ifc_set_addr(const char *name, in_addr_t addr, in_addr_t netmask)
+{
+    struct ifreq ifr, irf_mask;
+    int ret;
+
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, addr);
+
+    ret = ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
+    if(ret)
+    {
+        LOGD("set_addr(%s, %x) = %d fail.", name, addr, ret);
+    }
+
+    if(netmask)
+    {
+        ifc_init_ifr(name, &irf_mask);
+        init_sockaddr_in(&irf_mask.ifr_netmask, netmask);
+        ret = ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &irf_mask);
+        if(ret)
+        {
+            LOGD("set_netmask(%s, %x) = %d fail.", name, netmask, ret);
+        }
+    }
+
+    return ret;
+}
+
+int mbtk_ifc_ip_config(const char *ifname, const char *ipv4, const char *mask, const char *gateway)
+{
+    UNUSED(gateway);
+    struct ifreq ifr;
+
+//    struct rtentry  rt;
+    // Set IPv4
+    struct sockaddr_in *sin;
+    memset(&ifr,0,sizeof(ifr));
+    strcpy(ifr.ifr_name,ifname);
+    sin = (struct sockaddr_in*)&ifr.ifr_addr;
+    sin->sin_family = AF_INET;
+    if(ipv4) {
+        if(inet_aton(ipv4,&(sin->sin_addr)) < 0)
+        {
+            LOGE("inet_aton error.");
+            return -2;
+        }
+    } else {
+        memset(&(sin->sin_addr), 0, sizeof(struct in_addr));
+    }
+
+    if(ioctl(ifc_ctl_sock,SIOCSIFADDR,&ifr) < 0)
+    {
+        LOGE("ioctl SIOCSIFADDR error.");
+        return -3;
+    }
+
+#if 1
+#if 1
+    //netmask
+    if(mask) {
+        if(inet_aton(mask,&(sin->sin_addr)) < 0)
+        {
+            LOGE("inet_pton error.");
+            return -4;
+        }
+
+        if(ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr) < 0)
+        {
+            LOGE("ioctl error.");
+            return -5;
+        }
+    }
+#else
+
+    //struct ifreq ifr;
+    //strcpy(ifr.ifr_name, interface_name);
+    struct sockaddr_in netmask_addr;
+    bzero(&netmask_addr, sizeof(struct sockaddr_in));
+    netmask_addr.sin_family = PF_INET;
+    inet_aton(mask, &netmask_addr.sin_addr);
+    memcpy(&ifr.ifr_ifru.ifru_netmask, &netmask_addr,
+           sizeof(struct sockaddr_in));
+    if (ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr) < 0)
+    {
+        LOGE("ioctl() fail.");
+        return -1;
+    }
+#endif
+#endif
+
+#if 0
+    //gateway
+    memset(&rt, 0, sizeof(struct rtentry));
+    memset(sin, 0, sizeof(struct sockaddr_in));
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+    if(inet_aton(gateway, &sin->sin_addr)<0)
+    {
+        LOGE( "inet_aton error." );
+    }
+    memcpy ( &rt.rt_gateway, sin, sizeof(struct sockaddr_in));
+    ((struct sockaddr_in *)&rt.rt_dst)->sin_family=AF_INET;
+    ((struct sockaddr_in *)&rt.rt_genmask)->sin_family=AF_INET;
+    rt.rt_flags = RTF_GATEWAY;
+    if (ioctl(ifc_ctl_sock, SIOCADDRT, &rt)<0)
+    {
+        LOGE("ioctl(SIOCADDRT) error in set_default_route\n");
+        return -1;
+    }
+#endif
+    return 0;
+}
+
+int mbtk_ifc_set_netmask(const char *ifname, const char *netmask)
+{
+    int s;
+    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+    {
+        LOGE("Socket");
+        return -1;
+    }
+    struct ifreq ifr;
+    strcpy(ifr.ifr_name, ifname);
+    struct sockaddr_in netmask_addr;
+    bzero(&netmask_addr, sizeof(struct sockaddr_in));
+    netmask_addr.sin_family = PF_INET;
+    inet_aton(netmask, &netmask_addr.sin_addr);
+    memcpy(&ifr.ifr_ifru.ifru_netmask, &netmask_addr,
+           sizeof(struct sockaddr_in));
+    if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
+    {
+        LOGE("ioctl");
+        close(s);
+        return -1;
+    }
+    close(s);
+    return 0;
+}
+
+
+int mbtk_ifc_get_addr(const char *name, void *addr)
+{
+    int ret;
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr);
+    LOGD("ifc_get_addr(%s, %x) = %d", name, ifr.ifr_addr, ret);
+    if(ret < 0) return -1;
+
+    memcpy(addr, &ifr.ifr_addr, sizeof(struct sockaddr));
+    return 0;
+}
+
+
+int mbtk_ifc_up(const char *name)
+{
+    int ret = ifc_set_flags(ifc_ctl_sock, name, IFF_UP, 0);
+//    LOGI("mbtk_ifc_up(%s) = %d", name, ret);
+    return ret;
+}
+
+int mbtk_ifc_down(const char *name)
+{
+    int ret = ifc_set_flags(ifc_ctl_sock, name, 0, IFF_UP);
+//    LOGI("mbtk_ifc_down(%s) = %d", name, ret);
+    return ret;
+}
+
+int mbtk_ifc_get_hwaddr(const char *name, void *ptr)
+{
+    int r;
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
+    if(r < 0) return -1;
+
+    memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+    return 0;
+}
+
+int mbtk_ifc_get_ifindex(const char *name, int *if_indexp)
+{
+    int r;
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
+    if(r < 0) return -1;
+
+    *if_indexp = ifr.ifr_ifindex;
+    return 0;
+}
+
+int mbtk_ifc_configure1(const char *ifname,
+                        in_addr_t address,
+                        uint32_t prefixLength,
+                        in_addr_t gateway,
+                        in_addr_t netmask)
+{
+    if(mbtk_ifc_open())
+    {
+        LOGE("mbtk_ifc_open() fail.", strerror(errno));
+        return -1;
+    }
+
+    if (mbtk_ifc_up(ifname))
+    {
+        LOGE("failed to turn on interface %s: %s", ifname, strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+    if (mbtk_ifc_set_addr(ifname, address, netmask))
+    {
+        LOGE("failed to set ipaddr %s: %s", ipaddr_to_string(address), strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+    if (ifc_set_prefixLength(ifname, prefixLength))
+    {
+        LOGE("failed to set prefixLength %d: %s", prefixLength, strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+    if (ifc_create_default_route1(ifname, gateway))
+    {
+        LOGE("failed to set default route %s: %s", ipaddr_to_string(gateway), strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+
+    mbtk_ifc_close();
+    return 0;
+}
+
+int mbtk_ifc_configure2(const char *ifname,
+                        const char *ipv4,
+                        uint32_t prefixLength,
+                        const char *gateway,
+                        const char *netmask)
+{
+    if(mbtk_ifc_open())
+    {
+        LOGE("mbtk_ifc_open() fail.", strerror(errno));
+        return -1;
+    }
+
+    if(ipv4 == NULL) {
+        if (mbtk_ifc_down(ifname))
+        {
+            LOGE("failed to turn off interface %s: %s", ifname, strerror(errno));
+            mbtk_ifc_close();
+            return -1;
+        }
+    } else {
+        if (mbtk_ifc_up(ifname))
+        {
+            LOGE("failed to turn on interface %s: %s", ifname, strerror(errno));
+            mbtk_ifc_close();
+            return -1;
+        }
+    }
+
+    if (mbtk_ifc_ip_config(ifname, ipv4, netmask, gateway))
+    {
+        LOGE("failed to set ipaddr: %s", strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+
+//    mbtk_ifc_set_netmask(ifname, netmask);
+
+#if 0
+    if (ifc_set_prefixLength(ifname, prefixLength))
+    {
+        LOGE("failed to set prefixLength %d: %s", prefixLength, strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+#endif
+
+#if 0
+    if (ifc_create_default_route2(ifname, gateway))
+    {
+        LOGE("failed to set default route: %s", strerror(errno));
+        mbtk_ifc_close();
+        return -1;
+    }
+#endif
+
+    mbtk_ifc_close();
+
+    return 0;
+}
+
+struct in6_ifreq {
+    struct in6_addr addr;
+    uint32_t        prefixlen;
+    unsigned int    ifindex;
+};
+
+int mbtk_ipv6_config(const char *ifname, const char *ipv6, uint32_t prefixLength)
+{
+    struct ifreq ifr;
+    struct in6_ifreq ifr6;
+    int sockfd;
+    int err = 0;
+
+    // Create IPv6 socket to perform the ioctl operations on
+    sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
+    if(sockfd < 0) {
+        LOGE("socket() fail.[%d]", errno);
+        return -1;
+    }
+
+    if(ipv6) {
+        if(ifc_set_flags(sockfd, ifname, IFF_UP, 0) < 0) {
+            LOGE("if up fail[%d].", errno);
+            err = -1;
+            goto exit;
+        }
+
+        // Copy the interface name to the ifreq struct
+        strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+        // Get the ifrindex of the interface
+        if(ioctl(sockfd, SIOGIFINDEX, &ifr) < 0)
+        {
+            LOGE("ioctl SIOGIFINDEX error.");
+            err = -1;
+            goto exit;
+        }
+
+        // Prepare the in6_ifreq struct and set the address to the interface
+        if(inet_pton(AF_INET6, ipv6, &ifr6.addr) < 0) {
+            LOGE("inet_pton() fail[%d].", errno);
+            err = -1;
+            goto exit;
+        }
+    } else {
+        if(ifc_set_flags(sockfd, ifname, 0, IFF_UP) < 0) {
+            LOGE("if down fail[%d].", errno);
+            err = -1;
+            goto exit;
+        }
+
+        // Copy the interface name to the ifreq struct
+        strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+        // Get the ifrindex of the interface
+        if(ioctl(sockfd, SIOGIFINDEX, &ifr) < 0)
+        {
+            LOGE("ioctl SIOGIFINDEX error.");
+            err = -1;
+            goto exit;
+        }
+
+        // Set IPv6 to 0.
+        memset(&(ifr6.addr), 0, sizeof(struct in6_addr));
+    }
+    ifr6.ifindex = ifr.ifr_ifindex;
+    ifr6.prefixlen = prefixLength;
+    if(ioctl(sockfd, SIOCSIFADDR, &ifr6) < 0) {
+        LOGE("ioctl SIOCSIFADDR error.");
+        err = -1;
+        goto exit;
+    }
+
+    LOGD("Set IPv6 : %s success.", ipv6);
+exit:
+    close(socket);
+    return err;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_info.c b/mbtk/mbtk_lib/src/mbtk_info.c
new file mode 100755
index 0000000..7ff9345
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_info.c
@@ -0,0 +1,1068 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include "mbtk_info.h"
+#include "mbtk_list.h"
+#include "mbtk_utils.h"
+
+static int sock_read(int fd, uint8 *msg, int data_len)
+{
+    memset(msg, 0, data_len);
+    int len = 0;
+    int read_len = 0;
+    while(1)
+    {
+        len = read(fd, msg + read_len, data_len - read_len);
+        if(len > 0)
+        {
+            read_len += len;
+        }
+        else if(len == 0)
+        {
+            LOG("read() end.");
+            break;
+        }
+        else
+        {
+            if(EAGAIN == errno)
+            {
+                LOG("Read end, lenght = %d", read_len);
+            }
+            else
+            {
+                LOG("read() error[%d].", errno);
+            }
+            break;
+        }
+    }
+
+    if(read_len > 0)
+    {
+        log_hex("DATA_RECV", msg, read_len);
+        return read_len;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static int sock_write(int fd, uint8 *msg, int data_len)
+{
+    int len = 0;
+    int write_len = 0;
+    while(write_len < data_len)
+    {
+        len = write(fd, msg + write_len, data_len - write_len);
+        if(len > 0)
+        {
+            write_len += len;
+        }
+        else if(len == 0)
+        {
+            LOG("write() end.");
+            break;
+        }
+        else
+        {
+            LOG("write() error[%d].", errno);
+            break;
+        }
+    }
+
+    if(write_len > 0)
+    {
+        log_hex("DATA_SEND", msg, write_len);
+        return write_len;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+static int pack_num_check(const void* data, int data_len)
+{
+    int count = 0;
+    int pack_len;
+    const uint8* ptr = (const uint8*)data;
+    while(ptr < (const uint8*)data + data_len)
+    {
+        if(MBTK_INFO_PACKET_FLAG != byte_2_uint32(ptr, true))
+        {
+            LOG("pack_num_check() - TAG error.");
+            break;
+        }
+        ptr += sizeof(uint32);
+
+        pack_len = byte_2_uint16(ptr, false);
+        if(pack_len < SOCK_PACK_LEN_MIN - SOCK_PACK_EXTRA_LEN)
+        {
+            LOG("pack_num_check() - Packet length error.");
+            break;
+        }
+        ptr += sizeof(uint16);
+        ptr += pack_len;
+
+        count++;
+    }
+
+    return count;
+}
+
+char* type2str(mbtk_info_type_enum type)
+{
+    switch(type)
+    {
+        case MBTK_INFO_TYPE_REQ:
+            return "REQ";
+        case MBTK_INFO_TYPE_RSP:
+            return "RSP";
+        case MBTK_INFO_TYPE_IND:
+            return "IND";
+        default:
+        {
+            return "UNKNOWN";
+        }
+    }
+}
+
+char* apn2str(mbtk_ip_type_enum type)
+{
+    switch(type)
+    {
+        case MBTK_IP_TYPE_IP:
+            return "IP";
+        case MBTK_IP_TYPE_IPV6:
+            return "IPV6";
+        case MBTK_IP_TYPE_IPV4V6:
+            return "IPV4V6";
+        case MBTK_IP_TYPE_PPP:
+            return "PPP";
+        default:
+        {
+            return "UNKNOWN";
+        }
+    }
+}
+
+/*
+IPv6 : 254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239 -> uint128
+*/
+int str_2_ipv6(const void *ip_str, void *ipv6)
+{
+    const uint8 *ptr = (const uint8*)ip_str;
+    uint8 *ipv6_ptr = (uint8*)ipv6;
+    ipv6_ptr[0] = (uint8)atoi(ptr);
+    int i = 1;
+    while(i < 16) {
+        ptr = (const uint8*)strstr(ptr, ".");
+        if(ptr == NULL)
+            return -1;
+        ptr++;
+        ipv6_ptr[i] = (uint8)atoi(ptr);
+        i++;
+    }
+
+    return 0;
+}
+
+/*
+IPv6 : uint128 -> fe80::215:1dff:fe81:484c
+*/
+int ipv6_2_str(const void *ipv6, void *ipv6_str)
+{
+    const uint8 *ptr = (const uint8*)ipv6;
+    uint8 *ipv6_ptr = (uint8*)ipv6_str;
+    int i = 0;
+    int index = 0;
+    while(i < 16) {
+        index += sprintf(ipv6_ptr + index, "%02x%02x", ptr[i], ptr[i + 1]);
+        index += sprintf(ipv6_ptr + index, ":");
+        i += 2;
+    }
+
+    ipv6_ptr[index - 1] = '\0'; // Delete last ':'
+
+    return 0;
+}
+
+
+
+char* id2str(int id)
+{
+    switch(id)
+    {
+        // <string> IMEI
+        case MBTK_INFO_ID_DEV_IMEI_REQ:
+        case MBTK_INFO_ID_DEV_IMEI_RSP:
+            return "IMEI";
+        // <string> SN
+        case MBTK_INFO_ID_DEV_SN_REQ:
+        case MBTK_INFO_ID_DEV_SN_RSP:
+            return "SN";
+        // <string> MEID
+        case MBTK_INFO_ID_DEV_MEID_REQ:
+        case MBTK_INFO_ID_DEV_MEID_RSP:
+            return "MEID";
+        // <string> VERSION
+        case MBTK_INFO_ID_DEV_VERSION_REQ:
+        case MBTK_INFO_ID_DEV_VERSION_RSP:
+            return "VERSION";
+        // <uint8> 0:Close 1:Open
+        case MBTK_INFO_ID_DEV_VOLTE_REQ:
+        case MBTK_INFO_ID_DEV_VOLTE_RSP:
+            return "VOLTE";
+        // <string> Temperature
+        case MBTK_INFO_ID_DEV_TEMP_REQ:  // Temperature
+        case MBTK_INFO_ID_DEV_TEMP_RSP:
+            return "TEMPERATURE";
+        case MBTK_INFO_ID_DEV_TIME_REQ:  // Time
+        case MBTK_INFO_ID_DEV_TIME_RSP:
+            return "Time";
+        // Sim Information
+        // <uint8> 0:NOT_EXIST 1:READY ...
+        case MBTK_INFO_ID_SIM_STATE_REQ:
+        case MBTK_INFO_ID_SIM_STATE_RSP:
+            return "SIM_STATE";
+        // <string> PIN
+        case MBTK_INFO_ID_SIM_PIN_REQ:
+        case MBTK_INFO_ID_SIM_PIN_RSP:
+            return "SIM_PIN";
+        // <string> PUK
+        case MBTK_INFO_ID_SIM_PUK_REQ:
+        case MBTK_INFO_ID_SIM_PUK_RSP:
+            return "SIM_PUK";
+        // <string> IMSI
+        case MBTK_INFO_ID_SIM_IMSI_REQ:
+        case MBTK_INFO_ID_SIM_IMSI_RSP:
+            return "IMSI";
+        // <string> ICCID
+        case MBTK_INFO_ID_SIM_ICCID_REQ:
+        case MBTK_INFO_ID_SIM_ICCID_RSP:
+            return "ICCID";
+        // <string> Phone Number
+        case MBTK_INFO_ID_SIM_PN_REQ:
+        case MBTK_INFO_ID_SIM_PN_RSP:
+            return "PHONE_NUMBER";
+        // Network Information
+        // <uint8> 0:OFF 1:ON
+        case MBTK_INFO_ID_NET_RADIO_REQ:
+        case MBTK_INFO_ID_NET_RADIO_RSP:
+            return "RADIO_STATE";
+        case MBTK_INFO_ID_NET_AVAILABLE_REQ:
+        case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+            return "NET_AVAILABLE";
+        case MBTK_INFO_ID_NET_SEL_MODE_REQ:
+        case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+            return "NET_SEL_MODE";
+        case MBTK_INFO_ID_NET_BAND_REQ:
+        case MBTK_INFO_ID_NET_BAND_RSP:
+            return "NET_BNAD";
+        // <uint16>[4]  rssi,rscp,rsrp,snr
+        case MBTK_INFO_ID_NET_SIGNAL_REQ:
+        case MBTK_INFO_ID_NET_SIGNAL_RSP:
+            return "SIGNAL";
+        case MBTK_INFO_ID_NET_REG_REQ:
+        case MBTK_INFO_ID_NET_REG_RSP:
+            return "NET_REG";
+        // <string> cmnet/ctnet/3gnet/...
+        case MBTK_INFO_ID_NET_APN_REQ:
+        case MBTK_INFO_ID_NET_APN_RSP:
+            return "APN";
+        // Lock net/cell/frequency
+        case MBTK_INFO_ID_NET_CELL_REQ:
+        case MBTK_INFO_ID_NET_CELL_RSP:
+            return "NET_CELL";
+        case MBTK_INFO_ID_NET_DATA_CALL_REQ:
+        case MBTK_INFO_ID_NET_DATA_CALL_RSP:
+            return "DATA_CALL";
+        // Call Information
+        case MBTK_INFO_ID_CALL_STATE_REQ:
+        case MBTK_INFO_ID_CALL_STATE_RSP:
+            return "CALL_STATE";
+        // SMS Information
+        case MBTK_INFO_ID_SMS_STATE_REQ:
+        case MBTK_INFO_ID_SMS_STATE_RSP:
+            return "SMS_STATE";
+        // PhoneBook Information
+        case MBTK_INFO_ID_PB_STATE_REQ:
+        case MBTK_INFO_ID_PB_STATE_RSP:
+            return "PB_STATE";
+        // IND Information
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+            return "IND_NET_STATE";
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+            return "IND_CALL_STATE";
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+            return "IND_SMS_STATE";
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+            return "IND_RADIO_STATE";
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+            return "IND_SIM_STATE";
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_PDP_STATE_CHANGE:
+            return "IND_PDP_STATE";
+        // <uint8>  State
+        case MBTK_INFO_ID_IND_SERVER_STATE_CHANGE:
+            return "IND_SERVER_STATE";
+        default:
+        {
+            return "UNKNOWN";
+        }
+    }
+}
+
+char* err2str(mbtk_info_err_enum err)
+{
+    switch(err)
+    {
+        case MBTK_INFO_ERR_SUCCESS:
+            return "SUCCESS";
+        case MBTK_INFO_ERR_FORMAT:
+            return "ERR_FORMAT";
+        case MBTK_INFO_ERR_REQ_UNKNOWN:
+            return "ERR_REQ_UNKNOWN";
+        case MBTK_INFO_ERR_REQ_PARAMETER:
+            return "ERR_REQ_PARAMETER";
+        case MBTK_INFO_ERR_UNSUPPORTED:
+            return "ERR_UNSUPPORTED";
+        case MBTK_INFO_ERR_MEMORY:
+            return "ERR_MEMORY";
+        case MBTK_INFO_ERR_IND_FULL:
+            return "ERR_IND_FULL";
+        case MBTK_INFO_ERR_IND_UNKNOWN:
+            return "ERR_IND_UNKNOWN";
+        case MBTK_INFO_ERR_CID_EXIST:
+            return "ERR_CID_EXIS";
+        case MBTK_INFO_ERR_CID_NO_EXIST:
+            return "ERR_CID_NO_EXIST";
+        case MBTK_INFO_ERR_NET_NO_INIT:
+            return "ERR_CID_NO_EXIST";
+        default:
+        {
+            if(err >= MBTK_INFO_ERR_CME) {
+                return "CME ERROR";
+            }
+
+            return "UNKNOWN";
+        }
+    }
+}
+
+/*
+0   GSM
+1   GSM_COMPACT
+2   UTRAN
+3   GSM_EGPRS
+4   UTRAN_HSDPA
+5   UTRAN_HSUPA
+6   UTRAN_HSDPA_HSUPA
+7   EUTRAN
+8   ECGSM
+*/
+mbtk_net_type_enum mbtk_net_type_get(mbtk_radio_technology_enum radio_tech)
+{
+    switch(radio_tech)
+    {
+        case MBTK_RADIO_TECH_GSM:
+        case MBTK_RADIO_TECH_GSM_COMPACT:
+        case MBTK_RADIO_TECH_GSM_EGPRS:
+        case MBTK_RADIO_TECH_UTRAN_HSPA:
+        {
+            return MBTK_NET_TYPE_GSM;
+        }
+        case MBTK_RADIO_TECH_UTRAN:
+        case MBTK_RADIO_TECH_UTRAN_HSDPA:
+        case MBTK_RADIO_TECH_UTRAN_HSUPA:
+        case MBTK_RADIO_TECH_UTRAN_HSDPA_HSUPA:
+        {
+            return MBTK_NET_TYPE_UMTS;
+        }
+        case MBTK_RADIO_TECH_E_UTRAN:
+        {
+            return MBTK_NET_TYPE_LTE;
+        }
+        default:
+        {
+            return MBTK_NET_TYPE_UNKNOWN;
+        }
+    }
+}
+
+
+#if 0
+void net_list_free(void *data)
+{
+    if (data)
+    {
+        mbtk_net_info_t *info = (mbtk_net_info_t*) data;
+        LOG("Free net [%s].", info->plmn);
+        free(info);
+    }
+}
+#endif
+
+mbtk_info_type_enum mbtk_info_type_get(int info_id)
+{
+    if(info_id > MBTK_INFO_ID_IND_BEGIN && info_id < MBTK_INFO_ID_IND_END)
+    {
+        return MBTK_INFO_TYPE_IND;
+    }
+    else if(info_id == MBTK_INFO_ID_DEV_BEGIN ||
+            info_id == MBTK_INFO_ID_DEV_END ||
+            info_id == MBTK_INFO_ID_SIM_BEGIN ||
+            info_id == MBTK_INFO_ID_SIM_END ||
+            info_id == MBTK_INFO_ID_NET_BEGIN ||
+            info_id == MBTK_INFO_ID_NET_END ||
+            info_id == MBTK_INFO_ID_CALL_BEGIN ||
+            info_id == MBTK_INFO_ID_CALL_END ||
+            info_id == MBTK_INFO_ID_SMS_BEGIN ||
+            info_id == MBTK_INFO_ID_SMS_END ||
+            info_id == MBTK_INFO_ID_PB_BEGIN ||
+            info_id == MBTK_INFO_ID_PB_END ||
+            info_id == MBTK_INFO_ID_REQ_UNKNOWN)
+    {
+        return MBTK_INFO_TYPE_UNKNOWN;
+    }
+    else if(info_id % 2 == 1)
+    {
+        return MBTK_INFO_TYPE_REQ;
+    }
+    else
+    {
+        return MBTK_INFO_TYPE_RSP;
+    }
+}
+
+mbtk_info_pack_t* mbtk_info_pack_creat(int info_id)
+{
+    mbtk_info_pack_t *pack = (mbtk_info_pack_t *)malloc(sizeof(mbtk_info_pack_t));
+    if(!pack)
+    {
+        LOG("malloc() error[%d]", errno);
+        return NULL;
+    }
+
+    pack->info_id = (uint16)info_id;
+    pack->info_err = (uint16)0;
+    pack->data_len = (uint16)0;
+    pack->data = NULL;
+
+    return pack;
+}
+
+#if 0
+int mbtk_info_pack_data_set(mbtk_info_pack_t *pack, const void *data, int data_len)
+{
+    if(!pack)
+    {
+        LOG("Packet is NULL.");
+        return -1;
+    }
+
+    mbtk_info_type_enum info_type = mbtk_info_type_get(pack->info_id);
+    // IND
+    if(info_type == MBTK_INFO_TYPE_IND)
+    {
+        switch(pack->info_id)
+        {
+            // <uint8>  State
+            case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+            {
+                pack->data_len = (uint16)data_len;
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+            default:
+            {
+                LOG("Unknown IND : %s", id2str(pack->info_id));
+                break;
+            }
+        }
+    }
+    //else if(pack->info_id % 2 == 1)     // REQ (Set Data)
+    else if(info_type == MBTK_INFO_TYPE_REQ || info_type == MBTK_INFO_TYPE_RSP) // REQ or RSP
+    {
+        switch(pack->info_id)
+        {
+            case MBTK_INFO_ID_DEV_VOLTE_REQ:    // <uint8> 0:Close 1:Open
+            case MBTK_INFO_ID_DEV_VOLTE_RSP:
+            case MBTK_INFO_ID_SIM_STATE_REQ:    // <uint8> 0:NOT_EXIST 1:READY ...
+            case MBTK_INFO_ID_SIM_STATE_RSP:
+            case MBTK_INFO_ID_NET_RADIO_REQ:    // <uint8> 0:OFF 1:ON
+            case MBTK_INFO_ID_NET_RADIO_RSP:
+            case MBTK_INFO_ID_NET_BAND_REQ:     // mbtk_band_info_t
+            case MBTK_INFO_ID_NET_BAND_RSP:
+            case MBTK_INFO_ID_NET_CELL_REQ:     // Lock net/cell/frequency
+            case MBTK_INFO_ID_NET_CELL_RSP:
+            case MBTK_INFO_ID_DEV_IMEI_REQ:     // <string> SN
+            case MBTK_INFO_ID_DEV_IMEI_RSP:
+            case MBTK_INFO_ID_DEV_SN_REQ:       // <string> SN
+            case MBTK_INFO_ID_DEV_SN_RSP:
+            case MBTK_INFO_ID_DEV_MEID_REQ:     // <string> MEID
+            case MBTK_INFO_ID_DEV_MEID_RSP:
+            case MBTK_INFO_ID_DEV_VERSION_REQ:  // <string> VERSION
+            case MBTK_INFO_ID_DEV_VERSION_RSP:
+            case MBTK_INFO_ID_DEV_TEMP_REQ:     // <string> Temperature
+            case MBTK_INFO_ID_DEV_TEMP_RSP:
+            case MBTK_INFO_ID_SIM_PIN_REQ:      // <string> PIN
+            case MBTK_INFO_ID_SIM_PIN_RSP:
+            case MBTK_INFO_ID_SIM_PUK_REQ:      // <string> PUK
+            case MBTK_INFO_ID_SIM_PUK_RSP:
+            case MBTK_INFO_ID_SIM_IMSI_REQ:     // <string> IMSI
+            case MBTK_INFO_ID_SIM_IMSI_RSP:
+            case MBTK_INFO_ID_SIM_ICCID_REQ:    // <string> ICCID
+            case MBTK_INFO_ID_SIM_ICCID_RSP:
+            case MBTK_INFO_ID_NET_APN_REQ:      // <string> cmnet/ctnet/3gnet/...
+            case MBTK_INFO_ID_NET_APN_RSP:
+            case MBTK_INFO_ID_NET_SEL_MODE_REQ: // mbtk_net_info_t
+            case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+            case MBTK_INFO_ID_NET_AVAILABLE_REQ: // mbtk_net_info_t[]
+            case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+            {
+                pack->data_len = (uint16)data_len;
+#if 1
+                pack->data = (uint8*)memdup(data, pack->data_len);
+#else
+                LOG("%d -> %d", data_len, pack->data_len);
+                log_hex("pack1", pack, sizeof(mbtk_info_pack_t));
+                #if 0
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                #else
+
+                LOG("1 pack->%p,data->%p", pack, pack->data);
+                pack->data = (uint8*)calloc(pack->data_len, sizeof(uint8));
+                LOG("2 pack->%p,data->%p", pack, pack->data);
+
+                memcpy(pack->data, data, data_len);
+                #endif
+
+                LOG("data_len - %d", pack->data_len);
+                log_hex("pack2", pack, sizeof(mbtk_info_pack_t));
+#endif
+                break;
+            }
+            case MBTK_INFO_ID_NET_SIGNAL_REQ:   // <sint16>[4]  rssi,rscp,rsrp,snr
+            case MBTK_INFO_ID_NET_SIGNAL_RSP:
+            {
+                // const mbtk_net_signal_t* signal = (const mbtk_net_signal_t*)data;
+                pack->data_len = (uint16)sizeof(mbtk_net_signal_t);
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+            case MBTK_INFO_ID_NET_IPV4_DNS_REQ: // <uint32>[2]  Preferred DNS,Alternate DNS
+            case MBTK_INFO_ID_NET_IPV4_DNS_RSP:
+            {
+                // const mbtk_net_dns_ipv4_t* dns_ipv4 = (const mbtk_net_dns_ipv4_t*)data;
+                pack->data_len = (uint16)sizeof(mbtk_net_dns_ipv4_t);
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+            case MBTK_INFO_ID_NET_IPV6_DNS_REQ: // <uint32>[8]  Preferred DNS,Alternate DNS
+            case MBTK_INFO_ID_NET_IPV6_DNS_RSP:
+            {
+                // const mbtk_net_dns_ipv6_t* dns_ipv6 = (const mbtk_net_dns_ipv6_t*)data;
+                pack->data_len = (uint16)sizeof(mbtk_net_dns_ipv6_t);
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+            case MBTK_INFO_ID_NET_IPV4_REQ:     // <uint32> IPv4
+            case MBTK_INFO_ID_NET_IPV4_RSP:
+            {
+                pack->data_len = (uint16)sizeof(uint32);
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+            case MBTK_INFO_ID_NET_IPV6_REQ:     // <uint32>[4] IPv6
+            case MBTK_INFO_ID_NET_IPV6_RSP:
+            {
+                pack->data_len = (uint16)(sizeof(uint32) * 4);
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+            case MBTK_INFO_ID_NET_LOCAL_REQ:    // <uint16>[2] tag,earfcn
+            case MBTK_INFO_ID_NET_LOCAL_RSP:
+            {
+                pack->data_len = (uint16)sizeof(mbtk_local_info_t);
+                pack->data = (uint8*)memdup(data, pack->data_len);
+                break;
+            }
+#if 0
+            case MBTK_INFO_ID_NET_SEL_MODE_REQ:
+            case MBTK_INFO_ID_NET_SEL_MODE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)
+            {
+                const mbtk_net_info_t* net = (const mbtk_net_info_t*)data;
+                pack->data_len = sizeof(uint8) + sizeof(uint8) + sizeof(uint32);
+                pack->data = (uint8*)malloc(pack->data_len);
+                if(pack->data == NULL) {
+                    LOG("malloc() fail.");
+                    return -1;
+                }
+
+                pack->data[0] = net->net_sel_mode;
+                pack->data[1] = net->net_type;
+                uint32_2_byte((uint32)atoi((char*)net->plmn), pack->data + 2,false);
+                break;
+            }
+#endif
+#if 0
+            case MBTK_INFO_ID_NET_AVAILABLE_REQ:
+            case MBTK_INFO_ID_NET_AVAILABLE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+            {
+                const mbtk_net_array_info_t* nets = (const mbtk_net_array_info_t*)data;
+                mbtk_net_info_t *net = NULL;
+                //LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP set");
+                //sleep(1);
+                list_first(nets->net_list);
+                pack->data_len = nets->count * sizeof(mbtk_net_info_t);
+                if(pack->data_len > 0) {
+                    int i = 0;
+                    pack->data = (uint8*)malloc(pack->data_len);
+                    if(pack->data == NULL) {
+                        LOG("malloc() fail.");
+                        return -1;
+                    }
+                    memset(pack->data, 0, pack->data_len);
+
+                    while ((net = (mbtk_net_info_t*) list_next(nets->net_list)))
+                    {
+                        #if 0
+                        memcpy(pack->data + i, net, sizeof(mbtk_net_info_t));
+                        i += sizeof(mbtk_net_info_t);
+                        #else
+                        pack->data[i++] = net->net_sel_mode;
+                        pack->data[i++] = net->net_type;
+                        //uint32_2_byte((uint32)atoi((char*)net->plmn), pack->data + i,false);
+                        uint32_2_byte(net->plmn, pack->data + i,false);
+                        i += sizeof(uint32);
+                        #endif
+                    }
+                }
+                break;
+            }
+#endif
+            default:
+            {
+                LOG("Unknown REQ/RSP : %s", id2str(pack->info_id));
+                break;
+            }
+        }
+    }
+    else
+    {
+        LOG("Unknown info : %s", id2str(pack->info_id));
+        return -1;
+    }
+    return 0;
+}
+
+void* mbtk_info_pack_data_get(mbtk_info_pack_t *pack, int *data_len)
+{
+    if(pack == NULL || pack->data_len == 0 || pack->data == NULL)
+    {
+        LOG("Packet is NULL.");
+        return NULL;
+    }
+
+    mbtk_info_type_enum info_type = mbtk_info_type_get(pack->info_id);
+    // IND
+    if(info_type == MBTK_INFO_TYPE_IND)
+    {
+        switch(pack->info_id)
+        {
+            // <uint8>  State
+            case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+            case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+            {
+                return pack->data;
+            }
+            default:
+            {
+                LOG("Unknown IND : %s", id2str(pack->info_id));
+                break;
+            }
+        }
+    }
+    //else if(pack->info_id % 2 == 1)     // REQ (Set Data)
+    else if(info_type == MBTK_INFO_TYPE_REQ || info_type == MBTK_INFO_TYPE_RSP) // REQ or RSP
+    {
+        switch(pack->info_id)
+        {
+            case MBTK_INFO_ID_DEV_VOLTE_REQ:    // <uint8> 0:Close 1:Open
+            case MBTK_INFO_ID_DEV_VOLTE_RSP:
+            case MBTK_INFO_ID_SIM_STATE_REQ:    // <uint8> 0:NOT_EXIST 1:READY ...
+            case MBTK_INFO_ID_SIM_STATE_RSP:
+            case MBTK_INFO_ID_NET_RADIO_REQ:    // <uint8> 0:OFF 1:ON
+            case MBTK_INFO_ID_NET_RADIO_RSP:
+            case MBTK_INFO_ID_DEV_IMEI_REQ:     // <string> SN
+            case MBTK_INFO_ID_DEV_IMEI_RSP:
+            case MBTK_INFO_ID_DEV_SN_REQ:       // <string> SN
+            case MBTK_INFO_ID_DEV_SN_RSP:
+            case MBTK_INFO_ID_DEV_MEID_REQ:     // <string> MEID
+            case MBTK_INFO_ID_DEV_MEID_RSP:
+            case MBTK_INFO_ID_DEV_VERSION_REQ:  // <string> VERSION
+            case MBTK_INFO_ID_DEV_VERSION_RSP:
+            case MBTK_INFO_ID_DEV_TEMP_REQ:     // <string> Temperature
+            case MBTK_INFO_ID_DEV_TEMP_RSP:
+            case MBTK_INFO_ID_SIM_PIN_REQ:      // <string> PIN
+            case MBTK_INFO_ID_SIM_PIN_RSP:
+            case MBTK_INFO_ID_SIM_PUK_REQ:      // <string> PUK
+            case MBTK_INFO_ID_SIM_PUK_RSP:
+            case MBTK_INFO_ID_SIM_IMSI_REQ:     // <string> IMSI
+            case MBTK_INFO_ID_SIM_IMSI_RSP:
+            case MBTK_INFO_ID_SIM_ICCID_REQ:    // <string> ICCID
+            case MBTK_INFO_ID_SIM_ICCID_RSP:
+            case MBTK_INFO_ID_NET_APN_REQ:      // <string> cmnet/ctnet/3gnet/...
+            case MBTK_INFO_ID_NET_APN_RSP:
+            case MBTK_INFO_ID_NET_BAND_REQ:     // mbtk_band_info_t
+            case MBTK_INFO_ID_NET_BAND_RSP:
+            case MBTK_INFO_ID_NET_CELL_REQ:     // Lock net/cell/frequency
+            case MBTK_INFO_ID_NET_CELL_RSP:
+            case MBTK_INFO_ID_NET_SEL_MODE_REQ:  // mbtk_net_info_t
+            case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+            case MBTK_INFO_ID_NET_AVAILABLE_REQ: // mbtk_net_info_t[]
+            case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+            {
+                return pack->data;
+            }
+            case MBTK_INFO_ID_NET_SIGNAL_REQ:   // <sint16>[4]  rssi,rscp,rsrp,snr
+            case MBTK_INFO_ID_NET_SIGNAL_RSP:
+            {
+                mbtk_net_signal_t* signal = (mbtk_net_signal_t*)malloc(sizeof(mbtk_net_signal_t));
+                if(!signal)
+                {
+                    LOG("malloc() error[%d]", errno);
+                    return NULL;
+                }
+
+                signal->rssi = (sint16)byte_2_uint16(pack->data, false);
+                signal->rscp = (sint16)byte_2_uint16(pack->data + sizeof(uint16), false);
+                signal->rsrp = (sint16)byte_2_uint16(pack->data + sizeof(uint16) * 2, false);
+                signal->snr = (sint16)byte_2_uint16(pack->data + sizeof(uint16) * 3, false);
+                return signal;
+            }
+            case MBTK_INFO_ID_NET_IPV4_DNS_REQ: // <uint32>[2]  Preferred DNS,Alternate DNS
+            case MBTK_INFO_ID_NET_IPV4_DNS_RSP:
+            {
+                mbtk_net_dns_ipv4_t* dns_ipv4 = (mbtk_net_dns_ipv4_t*)malloc(sizeof(mbtk_net_dns_ipv4_t));
+                if(!dns_ipv4)
+                {
+                    LOG("malloc() error[%d]", errno);
+                    return NULL;
+                }
+
+                dns_ipv4->preferred_dns = byte_2_uint32(pack->data, false);
+                dns_ipv4->alternate_dns = byte_2_uint32(pack->data + sizeof(uint32), false);
+                return dns_ipv4;
+            }
+            case MBTK_INFO_ID_NET_IPV6_DNS_REQ: // <uint32>[8]  Preferred DNS,Alternate DNS
+            case MBTK_INFO_ID_NET_IPV6_DNS_RSP:
+            {
+                return memdup(pack->data, sizeof(mbtk_net_dns_ipv6_t));
+            }
+            case MBTK_INFO_ID_NET_IPV4_REQ:     // <uint32> IPv4
+            case MBTK_INFO_ID_NET_IPV4_RSP:
+            {
+                return memdup(pack->data, sizeof(uint32));
+                break;
+            }
+            case MBTK_INFO_ID_NET_IPV6_REQ:     // <uint32>[4] IPv6
+            case MBTK_INFO_ID_NET_IPV6_RSP:
+            {
+                return memdup(pack->data, sizeof(uint32) * 4);
+                break;
+            }
+            case MBTK_INFO_ID_NET_LOCAL_REQ:    // <uint16>[2] tag,earfcn
+            case MBTK_INFO_ID_NET_LOCAL_RSP:
+            {
+                mbtk_local_info_t* local = (mbtk_local_info_t*)malloc(sizeof(mbtk_local_info_t));
+                if(!local)
+                {
+                    LOG("malloc() error[%d]", errno);
+                    return NULL;
+                }
+
+                local->tag = (sint16)byte_2_uint16(pack->data, false);
+                local->earfcn = (sint16)byte_2_uint16(pack->data + sizeof(uint16), false);
+                return local;
+            }
+#if 0
+            case MBTK_INFO_ID_NET_SEL_MODE_REQ:
+            case MBTK_INFO_ID_NET_SEL_MODE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)
+            {
+                mbtk_net_info_t* net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+                if(!net)
+                {
+                    LOG("malloc() error[%d]", errno);
+                    return NULL;
+                }
+                memset(net, 0, sizeof(mbtk_net_info_t));
+                net->net_sel_mode = pack->data[0];
+                net->net_type = pack->data[1];
+                //itoa(byte_2_uint32(pack->data + 2, false), net->plmn, 10);
+                sprintf(net->plmn, "%d", byte_2_uint32(pack->data + 2, false));
+
+                return net;
+            }
+#endif
+#if 0
+            case MBTK_INFO_ID_NET_AVAILABLE_REQ:
+            case MBTK_INFO_ID_NET_AVAILABLE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+            {
+                mbtk_net_array_info_t* nets = (mbtk_net_array_info_t*)malloc(sizeof(mbtk_net_array_info_t));
+                if(!nets)
+                {
+                    LOG("malloc() error[%d]", errno);
+                    return NULL;
+                }
+                nets->count = 0;
+                nets->net_list = list_create(NULL);
+                if(nets->net_list == NULL)
+                {
+                    LOG("list_create() fail.");
+                    free(nets);
+                    return NULL;
+                }
+
+                int i = 0;
+                while(i < pack->data_len) {
+                    LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 1");
+                    sleep(1);
+                    mbtk_net_info_t* net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+                    LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 2");
+                    sleep(1);
+                    if(!net)
+                    {
+                        LOG("malloc() error[%d]", errno);
+                        sleep(3);
+                        //list_free(nets->net_list);
+                        //free(nets);
+                        return NULL;
+                    }
+                    memset(net, 0, sizeof(mbtk_net_info_t));
+
+                    LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 3");
+                    sleep(1);
+#if 1
+                    #if 1
+                    #if 0
+                    memcpy(net, pack->data + i, sizeof(mbtk_net_info_t));
+                    i += sizeof(mbtk_net_info_t);
+                    #else
+                    net->net_sel_mode = pack->data[i++];
+                    net->net_type = pack->data[i++];
+                    //sprintf(net->plmn, "%d", byte_2_uint32(pack->data + i, false));
+                    net->plmn = byte_2_uint32(pack->data + i, false);
+                    i += sizeof(uint32);
+                    #endif
+                    #endif
+
+                    LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 5");
+                    log_hex("NET 2", net, sizeof(mbtk_net_info_t));
+                    sleep(1);
+
+                    list_add(nets->net_list, net);
+
+#endif
+                    LOG("list_add");
+                    sleep(1);
+                }
+
+                sleep(10);
+
+                // Data lenght changed.
+                *data_len = sizeof(mbtk_net_array_info_t);
+                return nets;
+            }
+#endif
+            default:
+            {
+                LOG("Unknown REQ/RSP : %s", id2str(pack->info_id));
+                break;
+            }
+        }
+    }
+    else
+    {
+        LOG("Unknown info : %s", id2str(pack->info_id));
+    }
+
+    return NULL;
+}
+#endif
+
+int mbtk_info_pack_send(int fd, mbtk_info_pack_t *pack)
+{
+    if(!pack)
+    {
+        LOG("Packet is NULL.");
+        return -1;
+    }
+    uint8 data[SOCK_MSG_LEN_MAX] = {0};
+    uint8* data_ptr = data + SOCK_PACK_EXTRA_LEN;
+
+    data_ptr += uint16_2_byte(pack->info_id, data_ptr, false);
+    data_ptr += uint16_2_byte(pack->info_err, data_ptr, false);
+    data_ptr += uint16_2_byte(pack->data_len, data_ptr, false);
+    //log_hex("DATA1", data, 40);
+    if(pack->data_len > 0)
+    {
+        memcpy(data_ptr, pack->data, pack->data_len);
+        data_ptr += pack->data_len;
+        //log_hex("DATA2", data, 40);
+    }
+
+    // Set flag and packet length.
+    uint32_2_byte(MBTK_INFO_PACKET_FLAG, data, true);
+    uint16_2_byte(data_ptr - data - SOCK_PACK_EXTRA_LEN, data + sizeof(uint32), false);
+
+    //log_hex("DATA3", data, 40);
+    return sock_write(fd, data, data_ptr - data);
+}
+
+mbtk_info_pack_t** mbtk_info_pack_recv(int fd, bool is_server, mbtk_info_err_enum *err)
+{
+    uint8 msg[SOCK_MSG_LEN_MAX + 1];
+    *err = MBTK_INFO_ERR_SUCCESS;
+    int len = sock_read(fd, msg, SOCK_MSG_LEN_MAX + 1);
+    if(len < SOCK_PACK_LEN_MIN)
+    {
+        if(len > 0)
+        {
+            *err = MBTK_INFO_ERR_FORMAT;
+            LOG("Insufficient packet data.");
+        }
+        return NULL;
+    }
+
+    int pack_count = pack_num_check(msg, len);
+    LOG("Packet number : %d", pack_count);
+    if(pack_count < 1)
+    {
+        *err = MBTK_INFO_ERR_FORMAT;
+        LOG("Packet not found.");
+        return NULL;
+    }
+    uint8 *ptr = msg;
+    mbtk_info_pack_t** packs = (mbtk_info_pack_t**)malloc(sizeof(mbtk_info_pack_t*) * (pack_count + 1));
+    int i = 0;
+    while(i < pack_count)
+    {
+        // TAG
+        if(MBTK_INFO_PACKET_FLAG != byte_2_uint32(ptr, true))
+        {
+            *err = MBTK_INFO_ERR_FORMAT;
+            LOG("Packet TAG error.");
+            goto error;
+        }
+        ptr += sizeof(uint32);
+
+        // Jump packet length.
+        ptr += sizeof(uint16);
+
+        mbtk_info_id_enum info_id = (mbtk_info_id_enum)byte_2_uint16(ptr, false);
+        mbtk_info_type_enum info_type = mbtk_info_type_get(info_id);
+        if(is_server)
+        {
+            // For server,"info_type" must by REQ or IND(Register IND).
+            if(info_type != MBTK_INFO_TYPE_REQ && info_type != MBTK_INFO_TYPE_IND)
+            {
+                *err = MBTK_INFO_ERR_FORMAT;
+                LOG("Packet Type error.");
+                goto error;
+            }
+        }
+        else
+        {
+            // For client,"info_type" must by RSP or IND.
+            if(info_type != MBTK_INFO_TYPE_RSP && info_type != MBTK_INFO_TYPE_IND)
+            {
+                *err = MBTK_INFO_ERR_FORMAT;
+                LOG("Packet Type error.");
+                goto error;
+            }
+        }
+        ptr += sizeof(uint16);
+
+        mbtk_info_pack_t* pack = mbtk_info_pack_creat(info_id);
+        if(pack == NULL)
+        {
+            *err = MBTK_INFO_ERR_MEMORY;
+            LOG("Packet malloc() fail.");
+            goto error;
+        }
+
+        // "info_err"
+        pack->info_err = byte_2_uint16(ptr, false);
+        ptr += sizeof(uint16);
+
+        // "data_len"
+        pack->data_len = byte_2_uint16(ptr, false);
+        ptr += sizeof(uint16);
+
+        if(pack->data_len > 0)
+        {
+            pack->data = (uint8*)memdup(ptr, pack->data_len);
+            ptr += pack->data_len;
+        }
+
+        packs[i++] = pack;
+    }
+    packs[i] = NULL;
+
+    return packs;
+
+error:
+    LOG("mbtk_info_pack_recv error, will free().");
+    if(packs)
+    {
+        mbtk_info_pack_t** pack_ptr = packs;
+        while(*pack_ptr)
+        {
+            mbtk_info_pack_free(pack_ptr);
+            pack_ptr++;
+        }
+
+        free(packs);
+    }
+    return NULL;
+}
+
+int mbtk_info_pack_free(mbtk_info_pack_t **pack)
+{
+    if(pack == NULL || *pack == NULL)
+    {
+        LOG("Packet is NULL.");
+        return -1;
+    }
+
+    // LOG("Free packet : %s", id2str((*pack)->info_id));
+#if 0
+    if((*pack)->data)
+    {
+        free((*pack)->data);
+    }
+#endif
+    free(*pack);
+    *pack = NULL;
+    return 0;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_info_api.c b/mbtk/mbtk_lib/src/mbtk_info_api.c
new file mode 100755
index 0000000..6472ea0
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_info_api.c
@@ -0,0 +1,2232 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_info.h"
+#include "mbtk_list.h"
+#include "mbtk_utils.h"
+
+#include "time.h"
+
+#define EPOLL_LISTEN_MAX 100
+#define EPOLL_LISTEN_MAX 100
+
+#if 0
+struct
+{
+    uint8 operator[128];
+    uint8 operator[128];
+    uint8 mcc_mnc[10];
+} 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"},
+    {NULL, NULL, NULL}
+};
+#endif
+
+static int pack_process(mbtk_info_handle_t* handle, mbtk_info_pack_t* pack)
+{
+    mbtk_info_type_enum info_type = mbtk_info_type_get(pack->info_id);
+    LOG("Type : %s, ID : %s, Result : %s ,Length : %d", type2str(info_type),
+                                                        id2str(pack->info_id),
+                                                        err2str(pack->info_err),
+                                                        pack->data_len);
+    if(0 && pack->data_len > 0)
+    {
+        log_hex("DATA", pack->data, pack->data_len);
+    }
+    // IND Message.
+    if(info_type == MBTK_INFO_TYPE_IND)
+    {
+        if(pack->data_len > 0 && pack->data != NULL) // IND message.
+        {
+            log_hex(id2str(pack->info_id), pack->data, pack->data_len);
+            switch(pack->info_id)
+            {
+                case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+                {
+                    if(handle->net_state_cb)
+                        handle->net_state_cb(pack->data, pack->data_len);
+                    break;
+                }
+                case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+                {
+                    if(handle->call_state_cb)
+                        handle->call_state_cb(pack->data, pack->data_len);
+                    break;
+                }
+                case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+                {
+                    if(handle->sms_state_cb)
+                        handle->sms_state_cb(pack->data, pack->data_len);
+                    break;
+                }
+                case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+                {
+                    if(handle->radio_state_cb)
+                        handle->radio_state_cb(pack->data, pack->data_len);
+                    break;
+                }
+                case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+                {
+                    if(handle->sim_state_cb)
+                        handle->sim_state_cb(pack->data, pack->data_len);
+                    break;
+                }
+                case MBTK_INFO_ID_IND_PDP_STATE_CHANGE:
+                {
+                    if(handle->pdp_state_cb)
+                        handle->pdp_state_cb(pack->data, pack->data_len);
+                    break;
+                }
+                //mbtk wyq for server_ready_status add start
+                case MBTK_INFO_ID_IND_SERVER_STATE_CHANGE:
+                {
+                    handle->server_ready_status = 1;
+                    LOG("handshake message recv ok.");
+                    break;
+                }
+                //mbtk wyq for server_ready_status add end
+                default:
+                {
+                    LOG("Unknown IND : %d", pack->info_id);
+                    break;
+                }
+            }
+        }
+        else // Register IND response.
+        {
+            handle->info_err = pack->info_err;
+            if(pack->info_err == MBTK_INFO_ERR_SUCCESS)
+            {
+                LOG("IND %s register success.", id2str(pack->info_id));
+            }
+            else
+            {
+                LOG("IND %s register fail : %s", id2str(pack->info_id), err2str(pack->info_err));
+            }
+
+            if(handle->is_waitting) {
+                pthread_mutex_lock(&handle->mutex);
+                pthread_cond_signal(&handle->cond);
+                pthread_mutex_unlock(&handle->mutex);
+            }
+        }
+    }
+    else     // Response Information.
+    {
+        handle->info_err = pack->info_err;
+
+        // Set data length.
+        // If data change,will change this lenght in mbtk_info_pack_data_get().
+        handle->data_len = pack->data_len;
+        // Copy data buffer,because it will be released.
+        if(handle->data && pack->data && pack->data_len > 0) {
+            memcpy(handle->data, pack->data, handle->data_len);
+        }
+
+        if(handle->is_waitting) {
+            pthread_mutex_lock(&handle->mutex);
+            pthread_cond_signal(&handle->cond);
+            pthread_mutex_unlock(&handle->mutex);
+        }
+
+
+#if 0
+        if(pack->info_err == MBTK_INFO_ERR_SUCCESS)
+        {
+            LOG("REQ %s success.", id2str(pack->info_id));
+#if 0
+            if(pack->data_len > 0)
+            {
+                log_hex("DATA", pack->data, pack->data_len);
+            }
+#endif
+            switch(pack->info_id)
+            {
+                case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+                {
+                    mbtk_net_array_info_t* nets = (mbtk_net_array_info_t*)mbtk_info_pack_data_get(pack);
+                    if(nets)
+                    {
+                        mbtk_net_info_t *net = NULL;
+                        list_first(nets->net_list);
+                        while ((net = (mbtk_net_info_t*) list_next(nets->net_list)))
+                        {
+                            LOG("NET : %d, %d, %s", net->net_sel_mode, net->net_type, net->plmn);
+                        }
+                        list_free(nets->net_list);
+                        free(nets);
+                    }
+                    else
+                    {
+                        LOG("mbtk_info_pack_data_get() fail.");
+                    }
+
+                    break;
+                }
+                case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+                {
+                    mbtk_net_info_t* net = (mbtk_net_info_t*)mbtk_info_pack_data_get(pack);
+                    if(net)
+                    {
+                        LOG("NET : %d, %d, %d", net->net_sel_mode, net->net_type, net->plmn);
+                        free(net);
+                    }
+                    else
+                    {
+                        LOG("mbtk_info_pack_data_get() fail.");
+                    }
+
+                    break;
+                }
+                case MBTK_INFO_ID_NET_BAND_RSP:
+                {
+                    mbtk_band_info_t* band = (mbtk_band_info_t*)mbtk_info_pack_data_get(pack);
+                    if(band) {
+                        LOG("BAND : %d, %d, %d, %d, %d", band->net_pref,
+                                                         band->gsm_band,
+                                                         band->umts_band,
+                                                         band->tdlte_band,
+                                                         band->fddlte_band);
+                    } else {
+                        LOG("mbtk_info_pack_data_get() fail.");
+                    }
+
+                    break;
+                }
+                default:
+                {
+                    break;
+                }
+            }
+        }
+        else
+        {
+            LOG("REQ %s fail : %s", id2str(pack->info_id), err2str(pack->info_err));
+        }
+#endif
+    }
+    return 0;
+}
+
+
+static void* info_read_run(void* arg)
+{
+    int epoll_fd = epoll_create(5);
+    if(epoll_fd < 0)
+    {
+        LOG("epoll_create() fail[%d].", errno);
+        return NULL;
+    }
+    mbtk_info_handle_t* handle = (mbtk_info_handle_t*)arg;
+
+    uint32 event = EPOLLIN | EPOLLET;
+    struct epoll_event ev_cli, ev_exit;
+    ev_cli.data.fd = handle->client_fd;
+    ev_cli.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+    epoll_ctl(epoll_fd,EPOLL_CTL_ADD,handle->client_fd,&ev_cli);
+
+    ev_exit.data.fd = handle->exit_fd[0];
+    ev_exit.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+    epoll_ctl(epoll_fd,EPOLL_CTL_ADD,handle->exit_fd[0],&ev_exit);
+
+    int nready = -1;
+    struct epoll_event epoll_events[EPOLL_LISTEN_MAX];
+    while(1)
+    {
+        nready = epoll_wait(epoll_fd, epoll_events, EPOLL_LISTEN_MAX, -1);
+        if(nready > 0)
+        {
+            int i;
+            for(i = 0; i < nready; i++)
+            {
+                LOG("fd[%d] event = %x",epoll_events[i].data.fd, epoll_events[i].events);
+                if(epoll_events[i].events & EPOLLHUP)   // Closed by server.
+                {
+
+                }
+                else if(epoll_events[i].events & EPOLLIN)
+                {
+                    if(handle->client_fd == epoll_events[i].data.fd)  // Server data arrive.
+                    {
+                        // Read and process every message.
+                        mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+                        mbtk_info_pack_t **pack = mbtk_info_pack_recv(handle->client_fd, false, &err);
+
+                        // Parse packet error,send error response to client.
+                        if(pack == NULL)
+                        {
+                            if(err != MBTK_INFO_ERR_SUCCESS)
+                            {
+                                LOG("RSP packet error[%s].", err2str(err));
+                            }
+                        }
+                        else
+                        {
+                            mbtk_info_pack_t** pack_ptr = pack;
+                            while(*pack_ptr)
+                            {
+                                pack_process(handle, *pack_ptr);
+                                mbtk_info_pack_free(pack_ptr);
+                                pack_ptr++;
+                            }
+                            free(pack);
+                        }
+                    }
+                    else if(handle->exit_fd[0] == epoll_events[i].data.fd) //
+                    {
+                        char buff[100] = {0};
+                        int len = read(handle->exit_fd[0], buff, 100);
+                        if(len > 0) {
+                            LOGI("CMD : %s", buff);
+                            if(strcmp(buff, "EXIT") == 0) {
+                                goto read_thread_exit;
+                            } else {
+                                LOGD("Unkonw cmd : %s", buff);
+                            }
+                        } else {
+                            LOGE("sock_read() fail.");
+                        }
+                    }
+                    else
+                    {
+                        LOG("Unknown socket : %d", epoll_events[i].data.fd);
+                    }
+                }
+                else
+                {
+                    LOG("Unknown event : %x", epoll_events[i].events);
+                }
+            }
+        }
+        else
+        {
+            LOG("epoll_wait() fail[%d].", errno);
+        }
+    }
+
+read_thread_exit:
+    LOGD("info_read thread exit.");
+    return NULL;
+}
+
+#if 0
+static int info_item_get(mbtk_info_handle_t* handle, mbtk_info_id_enum id, void* data)
+{
+    int data_len = 0;
+    if(data == NULL) {
+        LOG("data is null.");
+        return -1;
+    }
+    mbtk_info_pack_t* pack = mbtk_info_pack_creat(id);
+    if(pack == NULL) {
+        LOG("mbtk_info_item_get() fail.");
+        return -1;
+    }
+
+    mbtk_info_pack_send(handle->client_fd, pack);
+    mbtk_info_pack_free(&pack);
+    handle->data = data;
+
+    // Wait for server response.
+    pthread_mutex_lock(&handle->mutex);
+    handle->is_waitting = true;
+    pthread_cond_wait(&handle->cond, &handle->mutex);
+    handle->is_waitting = false;
+    pthread_mutex_unlock(&handle->mutex);
+
+    if(handle->info_err == MBTK_INFO_ERR_SUCCESS)
+    {
+        LOG("REQ %s success.", id2str(id));
+        if(data && handle->data_len > 0) {
+            data_len = handle->data_len;
+            handle->data_len = 0;
+            handle->data = NULL;
+        }
+        return data_len;
+    } else {
+        LOG("REQ %s fail : %s", id2str(id), err2str(handle->info_err));
+        return -1;
+    }
+}
+#endif
+
+/*
+* Return recv data length.
+* -1 : fail.
+*/
+static int info_item_process(mbtk_info_handle_t *handle,
+                             mbtk_info_id_enum  id,
+                             const void         *send_buff,
+                             int                send_buff_len,
+                             void               *recv_buff)
+{
+    if(handle == NULL/* || ((send_buff == NULL || send_buff_len == 0) && recv_buff == NULL)*/) {
+        LOG("ARG error.");
+        return -1;
+    }
+
+    mbtk_info_pack_t* pack = mbtk_info_pack_creat(id);
+    if(pack == NULL) {
+        return -1;
+    }
+    if(send_buff && send_buff_len > 0) { // Set the data to be sent.
+        // log_hex("data", send_buff, send_buff_len);
+        // mbtk_info_pack_data_set(pack, data, data_len);
+        pack->data_len = (uint16)send_buff_len;
+        pack->data = (const uint8*)send_buff;
+    }
+    mbtk_info_pack_send(handle->client_fd, pack);
+    mbtk_info_pack_free(&pack);
+
+    if(recv_buff != NULL)
+        handle->data = recv_buff;
+
+    // Wait for server response.
+    pthread_mutex_lock(&handle->mutex);
+    handle->is_waitting = true;
+    pthread_cond_wait(&handle->cond, &handle->mutex);
+    handle->is_waitting = false;
+    pthread_mutex_unlock(&handle->mutex);
+
+    if(handle->info_err == MBTK_INFO_ERR_SUCCESS)
+    {
+        LOG("REQ %s success.", id2str(id));
+        int recv_len = 0;
+        if(recv_buff && handle->data_len > 0) {
+            recv_len = handle->data_len;
+            handle->data_len = 0;
+            handle->data = NULL;
+        }
+        return recv_len;
+    } else {
+        LOG("REQ %s fail : %s", id2str(id), err2str(handle->info_err));
+        return -1;
+    }
+}
+
+
+
+mbtk_info_handle_t* mbtk_info_handle_get()
+{
+    mbtk_info_handle_t* handle = (mbtk_info_handle_t*)malloc(sizeof(mbtk_info_handle_t));
+    if(!handle)
+    {
+        LOG("malloc() error[%d].", errno);
+        return NULL;
+    }
+    memset(handle, 0, sizeof(mbtk_info_handle_t));
+    handle->client_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if(handle->client_fd < 0)
+    {
+        LOG("socket() fail[%d].", errno);
+        goto error;
+    }
+
+    // Set O_NONBLOCK
+    int flags = fcntl(handle->client_fd, F_GETFL, 0);
+    if (flags < 0)
+    {
+        LOG("Get flags error:%d", errno);
+        goto error;
+    }
+    flags |= O_NONBLOCK;
+    if (fcntl(handle->client_fd, F_SETFL, flags) < 0)
+    {
+        LOG("Set flags error:%d", errno);
+        goto error;
+    }
+
+    struct sockaddr_un cli_addr;
+    memset(&cli_addr, 0, sizeof(cli_addr));
+    cli_addr.sun_family = AF_LOCAL;
+    strcpy(cli_addr.sun_path, SOCK_INFO_PATH);
+    if(connect(handle->client_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
+    {
+        LOG("connect() fail[%d].", errno);
+        goto error;
+    }
+
+    if(pipe(handle->exit_fd)) {
+        LOG("pipe() fail[%d].", errno);
+        goto error;
+    }
+#if 0
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+    {
+        LOG("pthread_attr_setdetachstate() fail.");
+        goto error;
+    }
+
+    if(pthread_create(&(handle->read_thread_id), &thread_attr, info_read_run, handle))
+    {
+        LOG("pthread_create() fail.");
+        goto error;
+    }
+    pthread_attr_destroy(&thread_attr);
+#else
+    if(pthread_create(&(handle->read_thread_id), NULL, info_read_run, handle))
+    {
+        LOG("pthread_create() fail.");
+        goto error;
+    }
+#endif
+
+    pthread_mutex_init(&handle->mutex, NULL);
+    pthread_cond_init(&handle->cond, NULL);
+    handle->is_waitting = false;
+
+    //mbtk wyq for server_ready_status add start
+    int timeout = 5;//The wait server timeout by default
+    LOG("wait server handshake message--->.");
+    while(timeout)
+    {
+        if(handle->server_ready_status)
+        {
+            break;
+        }
+        else
+        {
+            sleep(1);
+            timeout--;
+        }
+    }
+
+    if(timeout <= 0)
+    {
+        if(handle->exit_fd[1] > 0)
+        {
+            write(handle->exit_fd[1], "EXIT", 4);
+        }
+        pthread_join(handle->read_thread_id,NULL);
+        LOG("mbtk_info_handle_get() server not ready.");
+        goto error;
+    }
+    else
+    {
+        LOG("mbtk_info_handle_get() server ready ok.");
+    }
+    //mbtk wyq for server_ready_status add end
+    return handle;
+error:
+    if(handle)
+    {
+        if(handle->client_fd > 0)
+        {
+            close(handle->client_fd);
+        }
+        if(handle->exit_fd[0] > 0) {
+            close(handle->exit_fd[0]);
+        }
+        if(handle->exit_fd[1] > 0) {
+            close(handle->exit_fd[1]);
+        }
+        free(handle);
+        handle = NULL;
+    }
+
+    return NULL;
+}
+
+int mbtk_info_handle_free(mbtk_info_handle_t** handle)
+{
+    if(handle == NULL || *handle == NULL)
+    {
+        LOG("Handle is NULL.");
+        return -1;
+    }
+
+    if((*handle)->exit_fd[1] > 0) {
+        write((*handle)->exit_fd[1], "EXIT", 4);
+    }
+
+    // Wait read_thread exit.
+    pthread_join((*handle)->read_thread_id,NULL);
+
+    if((*handle)->exit_fd[0] > 0) {
+        close((*handle)->exit_fd[0]);
+        (*handle)->exit_fd[0] = -1;
+    }
+
+    if((*handle)->exit_fd[1] > 0) {
+        close((*handle)->exit_fd[1]);
+        (*handle)->exit_fd[1] = -1;
+    }
+
+    if((*handle)->client_fd > 0)
+    {
+        close((*handle)->client_fd);
+        (*handle)->client_fd = -1;
+    }
+    free(*handle);
+    *handle = NULL;
+    return 0;
+}
+
+/*
+* Get platform version.
+*/
+int mbtk_version_get(mbtk_info_handle_t* handle, void *version)
+{
+    if(handle == NULL || version == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_VERSION_REQ, NULL, 0, version) > 0) {
+        LOG("Version : %s", version);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform version.
+*/
+int mbtk_model_get(mbtk_info_handle_t* handle, void *model)
+{
+    if(handle == NULL || model == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_MODEL_REQ, NULL, 0, model) > 0) {
+        LOG("Version : %s", model);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform IMEI.
+*/
+int mbtk_imei_get(mbtk_info_handle_t* handle, void *imei)
+{
+    if(handle == NULL || imei == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_IMEI_REQ, NULL, 0, imei) > 0) {
+        LOG("IMEI : %s", imei);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform SN.
+*/
+int mbtk_sn_get(mbtk_info_handle_t* handle, void *sn)
+{
+    if(handle == NULL || sn == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_SN_REQ, NULL, 0, sn) > 0) {
+        LOG("SN : %s", sn);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform MEID.
+*/
+int mbtk_meid_get(mbtk_info_handle_t* handle, void *meid)
+{
+    if(handle == NULL || meid == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_MEID_REQ, NULL, 0, meid) > 0) {
+        LOG("MEID : %s", meid);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Return VoLTE state.
+*/
+int mbtk_volte_state_get(mbtk_info_handle_t* handle, int *volte_state)
+{
+    uint8 state;
+    if(handle == NULL || volte_state == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_VOLTE_REQ, NULL, 0, &state) > 0) {
+        LOG("VoLTE State : %d", state);
+        *volte_state = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set VoLTE state.
+*
+* volte_state:
+* 0 : Close VoLTE.
+* 1 : Open VoLTE.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_volte_state_set(mbtk_info_handle_t* handle, int volte_state)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    return info_item_process(handle, MBTK_INFO_ID_DEV_VOLTE_REQ, (uint8*)&volte_state, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get platform IMSI.
+*/
+int mbtk_imsi_get(mbtk_info_handle_t* handle, void *imsi)
+{
+    if(handle == NULL || imsi == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_IMSI_REQ, NULL, 0, imsi) > 0) {
+        LOG("IMSI : %s", imsi);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform ICCID.
+*/
+int mbtk_iccid_get(mbtk_info_handle_t* handle, void *iccid)
+{
+    if(handle == NULL || iccid == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_ICCID_REQ, NULL, 0, iccid) > 0) {
+        LOG("ICCID : %s", iccid);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get current phone number.
+*/
+int mbtk_phone_number_get(mbtk_info_handle_t* handle, void *phone_number)
+{
+    if(handle == NULL || phone_number == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_PN_REQ, NULL, 0, phone_number) > 0) {
+        LOG("Phone Number : %s", phone_number);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get PIN’s number of remaining retry
+*/
+int mbtk_pin_last_num_get(mbtk_info_handle_t* handle, mbtk_pin_puk_last_times *last_times)
+{
+    if(handle == NULL || last_times == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_PINPUK_TIMES_REQ, NULL, 0, last_times) > 0) {
+        LOG("Sim sim_pin_puk_last_times : %d, %d, %d, %d", last_times->p1_retry,last_times->p2_retry,last_times->puk1_retry,last_times->puk2_retry);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* emable PIN
+*/
+int mbtk_enable_pin(mbtk_info_handle_t* handle, mbtk_enable_pin_info *pin)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_ENABLE_PIN_REQ, pin, sizeof(mbtk_enable_pin_info), NULL) >= 0) {
+        LOG("pin Number : %s", pin->pin_value);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+
+}
+
+/*
+* Verify PIN
+*/
+int mbtk_verify_pin(mbtk_info_handle_t* handle, char *pin)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_PIN_REQ, pin, strlen(pin), NULL) >= 0) {
+        LOG("pin Number : %s", pin);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+
+}
+
+/*
+* Verify PIN
+*/
+int mbtk_change_pin(mbtk_info_handle_t* handle, mbtk_change_pin_info *pin)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_CHANGE_PIN_REQ, pin, sizeof(mbtk_change_pin_info), NULL) >= 0) {
+        LOG("Change PIN : %s -> %s", pin->old_pin_value, pin->new_pin_value);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* unblock_pin
+*/
+int mbtk_unlock_pin(mbtk_info_handle_t* handle, mbtk_unlock_pin_info *pin)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_PUK_REQ, pin, sizeof(mbtk_unlock_pin_info), NULL) >= 0) {
+        LOG("Unlock : %s , %s", pin->pin_value , pin->puk_value);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get plmn list
+*/
+int mbtk_get_plmn_list(mbtk_info_handle_t* handle, mbtk_plmn_info *pin)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_PLMN_REQ, NULL, 0, pin) >= 0) {
+        //LOG("pin Number : %s", pin);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+
+/*
+* Get available network.
+*/
+int mbtk_available_net_get(mbtk_info_handle_t* handle, list_node_t **net_list)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    *net_list = list_create(NULL);
+    if(*net_list == NULL)
+    {
+        LOG("list_create() fail.");
+        return MBTK_INFO_ERR_MEMORY;
+    }
+
+    uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+    int buff_len;
+    if((buff_len = info_item_process(handle, MBTK_INFO_ID_NET_AVAILABLE_REQ, NULL, 0, buff)) > 0) {
+        int i = 0;
+        while (i < buff_len / sizeof(mbtk_net_info_t))
+        {
+            mbtk_net_info_t* net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+            if(net == NULL)
+            {
+                LOG("malloc() fail.");
+                list_free(*net_list);
+                return MBTK_INFO_ERR_MEMORY;
+            }
+            memcpy(net, buff + i * sizeof(mbtk_net_info_t), sizeof(mbtk_net_info_t));
+            list_add(*net_list, net);
+
+            LOG("NET-%d: %d, %d, %d, %d", i + 1, net->net_sel_mode, net->net_type, net->net_state, net->plmn);
+            i++;
+        }
+
+        return 0;
+    } else {
+        list_free(*net_list);
+        return handle->info_err;
+    }
+}
+
+/*
+* Set network select mode. (+COPS=...)
+*/
+int mbtk_net_sel_mode_set(mbtk_info_handle_t* handle, const mbtk_net_info_t *net)
+{
+    if(handle == NULL || net == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    return info_item_process(handle, MBTK_INFO_ID_NET_SEL_MODE_REQ, net, sizeof(mbtk_net_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get network select mode. (+COPS?)
+*/
+int mbtk_net_sel_mode_get(mbtk_info_handle_t* handle, mbtk_net_info_t *net)
+{
+    if(handle == NULL || net == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_NET_SEL_MODE_REQ, NULL, 0, net) > 0) {
+        LOG("NET : %d, %d, %d, %d", net->net_sel_mode, net->net_type, net->net_state, net->plmn);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform support bands.
+*/
+int mbtk_support_band_get(mbtk_info_handle_t* handle, mbtk_band_info_t *band)
+{
+    uint8 type = 0; // Get support bands.
+    if(handle == NULL || band == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_NET_BAND_REQ, &type, sizeof(uint8), band) > 0) {
+        LOG("BAND : %d, %d, %d, %d, %d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get platform current bands.
+*/
+int mbtk_current_band_get(mbtk_info_handle_t* handle, mbtk_band_info_t *band)
+{
+    uint8 type = 1; // Get current bands.
+    if(handle == NULL || band == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_NET_BAND_REQ, &type, sizeof(uint8), band) > 0) {
+        LOG("BAND : %d, %d, %d, %d, %d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set platform current bands.
+*/
+int mbtk_current_band_set(mbtk_info_handle_t* handle, const mbtk_band_info_t *band)
+{
+    if(handle == NULL || band == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    return info_item_process(handle, MBTK_INFO_ID_NET_BAND_REQ, band, sizeof(mbtk_band_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get current cell infomation.
+*/
+int mbtk_cell_get(mbtk_info_handle_t* handle, mbtk_cell_type_enum *type, list_node_t **cell_list)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    *cell_list = list_create(NULL);
+    if(*cell_list == NULL)
+    {
+        LOG("list_create() fail.");
+        return MBTK_INFO_ERR_MEMORY;
+    }
+
+    uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+    int buff_len;
+    if((buff_len = info_item_process(handle, MBTK_INFO_ID_NET_CELL_REQ, NULL, 0, buff)) > 0) {
+        int i = 0;
+        *type = buff[0]; // Set network type.
+        while (i < (buff_len - sizeof(uint8)) / sizeof(mbtk_cell_info_t))
+        {
+            mbtk_cell_info_t* cell = (mbtk_cell_info_t*)malloc(sizeof(mbtk_cell_info_t));
+            if(cell == NULL)
+            {
+                LOG("malloc() fail.");
+                list_free(*cell_list);
+                return MBTK_INFO_ERR_MEMORY;
+            }
+            memcpy(cell, buff + sizeof(uint8) + i * sizeof(mbtk_cell_info_t), sizeof(mbtk_cell_info_t));
+            list_add(*cell_list, cell);
+
+            // LOG("Cell-%d: %d, %d, %d, %d, %d", i + 1, cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+            i++;
+        }
+
+        return 0;
+    } else {
+        list_free(*cell_list);
+        return handle->info_err;
+    }
+}
+/*
+* Set cell info.
+*
+* at*CELL=<mode>,<act>,< band>,<freq>,<cellId>
+* at*cell=2,3,,40936,429   //
+* at*cell=0  //
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_cell_set(mbtk_info_handle_t* handle, char * info, char* response)
+{
+    printf("mbtk_cell_set() info:%s, len:%d",info, strlen(info));
+    char req[128] = {0};
+    if( info_item_process(handle, MBTK_INFO_ID_NET_CELL_REQ, info, strlen(info), req) > 0){
+        memcpy(response, req, strlen(req));
+        return 0;
+    }
+    else{
+        return 0;
+    //    return handle->info_err;
+    }
+}
+
+/*
+* Get all APN informations.
+*/
+int mbtk_apn_get(mbtk_info_handle_t* handle, int *apn_num, mbtk_apn_info_t apns[])
+{
+    int len;
+    if(handle == NULL || apn_num == NULL || apns == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    uint8 data[SOCK_MSG_LEN_MAX];
+    if((len = info_item_process(handle, MBTK_INFO_ID_NET_APN_REQ, NULL, 0, data)) > 0) {
+        /*
+        <apn_num[1]><cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>...
+                    <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
+        */
+        uint8* ptr = data;
+        if(apn_num == NULL || apns == NULL || *apn_num < *ptr) {
+            *apn_num = 0;
+            LOGE("APN array size to not enough.");
+            return -1;
+        }
+        *apn_num = *ptr++;
+        LOG("APN Number : %d", *apn_num);
+        int i = 0;
+        while(i < *apn_num) {
+            memset(&(apns[i]), 0 ,sizeof(mbtk_apn_info_t));
+            apns[i].cid = *ptr++;
+            apns[i].ip_type = (mbtk_ip_type_enum)(*ptr++);
+
+            // apn
+            len = byte_2_uint16(ptr, false);
+            ptr += sizeof(uint16);
+            if(len > 0) { // Has APN
+                memcpy(apns[i].apn, ptr, len);
+                ptr += len;
+            }
+            // user
+            len = byte_2_uint16(ptr, false);
+            ptr += sizeof(uint16);
+            if(len > 0) { // Has APN
+                memcpy(apns[i].user, ptr, len);
+                ptr += len;
+            }
+
+            // pass
+            len = byte_2_uint16(ptr, false);
+            ptr += sizeof(uint16);
+            if(len > 0) { // Has APN
+                memcpy(apns[i].pass, ptr, len);
+                ptr += len;
+            }
+            // auth
+            len = byte_2_uint16(ptr, false);
+            ptr += sizeof(uint16);
+            if(len > 0) { // Has APN
+                memcpy(apns[i].auth, ptr, len);
+                ptr += len;
+            }
+
+            i++;
+        }
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set current APN informations.
+*/
+int mbtk_apn_set(mbtk_info_handle_t* handle, int cid, mbtk_ip_type_enum ip_type, const void* apn_name,
+                    const void *user_name, const void *user_pass, const void *auth)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    uint8 data[SOCK_MSG_LEN_MAX];
+    memset(data, 0, SOCK_MSG_LEN_MAX);
+    // cid : 2 - 7
+    if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+        LOGE("CID error.");
+        return -1;
+    }
+    uint8* ptr = data;
+    // <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
+    *ptr++ = (uint8)cid;
+    *ptr++ = (uint8)ip_type;
+    if(str_empty(apn_name)) {
+        uint16_2_byte((uint16)0, ptr, false);
+        ptr += sizeof(uint16);
+    } else {
+        uint16_2_byte((uint16)strlen(apn_name), ptr, false);
+        ptr += sizeof(uint16);
+        memcpy(ptr, apn_name, strlen(apn_name));
+        ptr += strlen(apn_name);
+    }
+    if(str_empty(user_name)) {
+        uint16_2_byte((uint16)0, ptr, false);
+        ptr += sizeof(uint16);
+    } else {
+        uint16_2_byte((uint16)strlen(user_name), ptr, false);
+        ptr += sizeof(uint16);
+        memcpy(ptr, user_name, strlen(user_name));
+        ptr += strlen(user_name);
+    }
+
+    if(str_empty(user_pass)) {
+        uint16_2_byte((uint16)0, ptr, false);
+        ptr += sizeof(uint16);
+    } else {
+        uint16_2_byte((uint16)strlen(user_pass), ptr, false);
+        ptr += sizeof(uint16);
+        memcpy(ptr, user_pass, strlen(user_pass));
+        ptr += strlen(user_pass);
+    }
+
+    if(str_empty(auth)) {
+        uint16_2_byte((uint16)0, ptr, false);
+        ptr += sizeof(uint16);
+    } else {
+        uint16_2_byte((uint16)strlen(auth), ptr, false);
+        ptr += sizeof(uint16);
+        memcpy(ptr, auth, strlen(auth));
+        ptr += strlen(auth);
+    }
+
+    return info_item_process(handle, MBTK_INFO_ID_NET_APN_REQ, data, ptr - data, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Start data call.
+*/
+int mbtk_data_call_start(mbtk_info_handle_t* handle, int cid, int auto_conn_interval, bool boot_conn, int timeout)
+{
+    uint8 data[10];
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    memset(data, 0, 10);
+    if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+        LOGE("CID error.");
+        return -1;
+    }
+    uint8* ptr = data;
+    /* <call_type[1]><cid[1]><auto_conn_interval[1]><boot_conn[1]><timeout[1]>
+     call_type : mbtk_data_call_type_enum
+     cid : 2 - 7
+     timeout : second
+    */
+    *ptr++ = (uint8)MBTK_DATA_CALL_START;
+    *ptr++ = (uint8)cid;
+    *ptr++ = (uint8)(auto_conn_interval > 0 ? auto_conn_interval : 0); // 拨号失败后重拨间隔(s)
+    *ptr++ = (uint8)(boot_conn ? 1 : 0); // 开机自动拨号
+    if(timeout <= 0) {
+        *ptr++ = (uint8)MBTK_DATA_CALL_TIMEOUT_DEFAULT;
+    } else {
+        *ptr++ = (uint8)timeout;
+    }
+
+    return info_item_process(handle, MBTK_INFO_ID_NET_DATA_CALL_REQ, data, 5, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Stop data call.
+*/
+int mbtk_data_call_stop(mbtk_info_handle_t* handle, int cid, int timeout)
+{
+    uint8 data[10];
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    memset(data, 0, 10);
+    if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+        LOGE("CID error.");
+        return -1;
+    }
+    uint8* ptr = data;
+    /* <call_type[1]><cid[1]><timeout[1]>
+     call_type : mbtk_data_call_type_enum
+     cid : 2 - 7
+     timeout : second
+    */
+    *ptr++ = (uint8)MBTK_DATA_CALL_STOP;
+    *ptr++ = (uint8)cid;
+    *ptr++ = (uint8)timeout;
+
+    return info_item_process(handle, MBTK_INFO_ID_NET_DATA_CALL_REQ, data, 3, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get data call state.
+*/
+int mbtk_data_call_state_get(mbtk_info_handle_t* handle, int cid, mbtk_ipv4_info_t *ipv4, mbtk_ipv6_info_t *ipv6)
+{
+    uint8 data[10];
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    uint8 recv_buff[SOCK_MSG_LEN_MAX]={0};
+    memset(data, 0, 10);
+    if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+        LOGE("CID error.");
+        return -1;
+    }
+    uint8* ptr = data;
+    /* <call_type[1]><cid[1]><timeout[1]>
+     call_type : mbtk_data_call_type_enum
+     cid : 2 - 7
+     timeout : second
+    */
+    *ptr++ = (uint8)MBTK_DATA_CALL_STATE;
+    *ptr++ = (uint8)cid;
+    *ptr++ = (uint8)0;
+
+    if(ipv4) {
+        memset(ipv4, 0, sizeof(mbtk_ipv4_info_t));
+    }
+
+    if(ipv6) {
+        memset(ipv6, 0, sizeof(mbtk_ipv6_info_t));
+    }
+
+    if(info_item_process(handle, MBTK_INFO_ID_NET_DATA_CALL_REQ, data, 3, recv_buff) > 0) {
+        if(recv_buff[0] == 0) { // IPv4 Only.
+            if(ipv4) {
+                memcpy(ipv4, recv_buff + sizeof(uint8), sizeof(mbtk_ipv4_info_t));
+            }
+        } else if(recv_buff[0] == 1) { // IPv6 Only.
+            if(ipv6) {
+                memcpy(ipv6, recv_buff + sizeof(uint8), sizeof(mbtk_ipv6_info_t));
+            }
+        } else if(recv_buff[0] == 2) { // IPv4 and IPv6.
+            if(ipv4) {
+                memcpy(ipv4, recv_buff + sizeof(uint8), sizeof(mbtk_ipv4_info_t));
+            }
+
+            if(ipv6) {
+                memcpy(ipv6, recv_buff + sizeof(uint8) + sizeof(mbtk_ipv4_info_t), sizeof(mbtk_ipv6_info_t));
+            }
+        } else {
+            LOGE("Unknown IP type : %d", recv_buff[0]);
+            return -1;
+        }
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+
+
+/*
+* Get current network signal.
+*/
+int mbtk_net_signal_get(mbtk_info_handle_t* handle, mbtk_signal_info_t *signal)
+{
+    if(handle == NULL || signal == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_NET_SIGNAL_REQ, NULL, 0, signal) > 0) {
+        LOG("Signal : %d, %d, %d, %d, %d, %d, %d", signal->rssi, signal->rxlev, signal->ber, signal->rscp, signal->ecno,
+            signal->rsrq, signal->rsrp);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get current network register information.
+*/
+int mbtk_net_reg_get(mbtk_info_handle_t* handle, mbtk_net_reg_info_t *reg)
+{
+    if(handle == NULL || reg == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_NET_REG_REQ, NULL, 0, reg) > 0) {
+        if(reg->call_state || reg->data_state || reg->ims_state) {
+            LOGD("REG : call_state=%d, data_state=%d, ims_state=%d, net_type=%d, %04x, %08x", reg->call_state, reg->data_state, reg->ims_state, reg->type, reg->lac, reg->ci);
+        } else {
+            LOGE("Net not reg.");
+        }
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+
+/*
+* Get radio state.
+*/
+int mbtk_radio_state_get(mbtk_info_handle_t* handle, int *radio_state)
+{
+    uint8 state;
+    if(handle == NULL || radio_state == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_NET_RADIO_REQ, NULL, 0, &state) > 0) {
+        LOG("Radio state : %d", state);
+        *radio_state = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set radio state.
+*/
+int mbtk_radio_state_set(mbtk_info_handle_t* handle, int radio_state)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    return info_item_process(handle, MBTK_INFO_ID_NET_RADIO_REQ, (uint8*)&radio_state, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get time type.
+*/
+int mbtk_time_get(mbtk_info_handle_t* handle, int *time_type)
+{
+    uint8 state;
+    if(handle == NULL || time_type == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_TIME_REQ, NULL, 0, &state) > 0) {
+        LOG("Time type : %d", state);
+        *time_type = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+*Get Absolute time
+*"23/05/24 06:09:32 +32 00"
+*/
+int mbtk_get_abs_time(char *time_str, time_t *time_out)
+{
+    struct tm tm_;
+
+    char *ptr = strstr(time_str + 10, " ");
+    *ptr = '\0';
+
+    LOGD("time : \"%s\"", time_str);
+#if 1
+    if(strptime(time_str, "%y/%m/%d %T", &tm_) == NULL) {
+        LOGE("strptime() fail.");
+        return -1;
+    }
+#else
+    int year, month, day, hour, minute,second,time_zone;
+    if(strstr(time_str, "+")) {
+        sscanf(time_str, "%d/%d/%d %d:%d:%d +%d",&year,&month,&day,&hour,&minute,&second,&time_zone);
+    } else if(strstr(time_str, "-")) {
+        sscanf(time_str, "%d/%d/%d %d:%d:%d -%d",&year,&month,&day,&hour,&minute,&second,&time_zone);
+    } else {
+        LOGE("Time format error:%s", time_str);
+        return -1;
+    }
+
+    // 1970+
+    if(year < 70) { // 20xx
+        tm_.tm_year  = 2000 + year;
+    } else { // 19xx
+        tm_.tm_year  = 1900 + year;
+    }
+    tm_.tm_mon   = month - 1;
+    tm_.tm_mday  = day;
+    tm_.tm_hour  = hour;
+    tm_.tm_min   = minute;
+    tm_.tm_sec   = second;
+    tm_.tm_isdst = 0;
+#endif
+
+    time_t timeStamp = mktime(&tm_);
+    LOGD("tm_.tm_year = %d,tm_.tm_mon = %d,tm_.tm_mday = %d,tm_.tm_hour = %d,tm_.tm_min = %d,tm_.tm_sec = %d,tm_.tm_isdst = %d",tm_.tm_year,tm_.tm_mon,tm_.tm_mday,tm_.tm_hour,tm_.tm_min,tm_.tm_sec,tm_.tm_isdst);
+    LOGD("time = %ld,%x", timeStamp,timeStamp);
+    *time_out = timeStamp;
+
+    return 0;
+}
+
+/*
+* Get time type.
+* "23/05/24,06:09:32+32" -> "23/05/24 06:09:32 +32 00"
+*/
+int mbtk_net_time_get(mbtk_info_handle_t* handle, char* time_str)
+{
+    uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+    if(handle == NULL || time_str == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    //printf("mbtk_net_time_get begin info_item_process\n");
+    if(info_item_process(handle, MBTK_INFO_ID_NET_TIME_REQ, NULL, 0, buff) > 0) {
+        memcpy(time_str,buff,strlen(buff));
+
+        uint8 *temp = strstr(time_str, ",");
+        if(temp) {
+            *temp = ' '; // ',' -> ' '
+
+            temp = strstr(time_str, "+");
+            if(temp == NULL) {
+                temp = strstr(time_str, "-");
+            }
+
+            if(temp) {
+                // Copy +XX or -XX
+                uint8 *last_ptr = temp + strlen(temp) + 1;
+                while(last_ptr > temp) {
+                    *last_ptr = *(last_ptr - 1);
+                    last_ptr--;
+                }
+
+                *last_ptr = ' ';
+
+                memcpy(temp + strlen(temp), "00", 2);
+
+                LOGD("%s -> %s", buff, time_str);
+                return 0;
+            } else {
+                LOGE("Time error:%s",buff);
+                return MBTK_INFO_ERR_TIME_FORMAT;
+            }
+        } else {
+            LOGE("Time error:%s",buff);
+            return MBTK_INFO_ERR_TIME_FORMAT;
+        }
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set time.
+*
+* time_type:
+* 0: Cell time
+* 1: NTP time
+* 2: User time
+* time_str: "YYYY-MM-DD HH:MM:SS"
+*/
+int mbtk_time_set(mbtk_info_handle_t* handle, mbtk_time_type_enum time_type, char* time_str)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    uint8 buffer[100] = {0};
+    buffer[0] = (uint8)time_type;
+    if(time_type == MBTK_TIME_TYPE_USER) {
+        if(!str_empty(time_str)) {
+            memcpy(buffer + sizeof(uint8), time_str, strlen(time_str));
+            return info_item_process(handle, MBTK_INFO_ID_DEV_TIME_REQ,
+                    buffer, sizeof(uint8) + strlen(time_str), NULL) ? handle->info_err : 0;
+        } else {
+            return -1;
+        }
+    } else {
+        return info_item_process(handle, MBTK_INFO_ID_DEV_TIME_REQ,
+                buffer, sizeof(uint8), NULL) ? handle->info_err : 0;
+    }
+}
+
+/*
+* Return sms cmgf.
+*/
+int mbtk_sms_cmgf_get(mbtk_info_handle_t* handle, int *volte_state)
+{
+    uint8 state;
+    if(info_item_process(handle, MBTK_INFO_ID_SMS_CMGF_REQ, NULL, 0, &state) > 0) {
+        LOG("mbtk_sms_cmgf_get()-----------sms cmgf : %d", state);
+        *volte_state = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set sms cmgf.
+*
+* volte_state:
+* 0 : PDU mode.
+* 1 :  text mode.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgf_set(mbtk_info_handle_t* handle, int mode)
+{
+    printf("mbtk_sms_cmgf_set()--------mode=:%d, len:%d", mode, sizeof(uint8));
+    return info_item_process(handle, MBTK_INFO_ID_SMS_CMGF_REQ, (uint8*)&mode, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cmgs.
+*
+if PDU mode (+CMGF=0):
++CMGS=<length><CR>
+PDU is given<ctrl-Z/ESC>
+
+if text mode (+CMGF=1):
++CMGS=<da>[,<toda>]<CR>
+text is entered<ctrl-Z/ESC>
+
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgs_set(mbtk_info_handle_t* handle, char * cmgs, char *resp)
+{
+    printf("mbtk_sms_cmgs_set(1)--------cmgs=:%s, len:%d", cmgs, strlen(cmgs));
+//    char req[20] = {0}
+    if(info_item_process(handle, MBTK_INFO_ID_SMS_CMGS_REQ, cmgs, strlen(cmgs), resp)  > 0){
+        printf("resp:%s\n", resp);
+        return 0;
+    }else{
+        return handle->info_err;
+    }
+}
+
+/*
+* Set sms cmgw.
+*
+if text mode (+CMGF=1):
++CMGW=<oa/da>[,<tooa/toda>[,<stat>]]
+<CR>
+text is entered<ctrl-Z/ESC>
+if PDU mode (+CMGF=0):
++CMGW=<length>[,<stat>]<CR>PDU is
+given<ctrl-Z/ESC>
+
+*/
+
+int mbtk_sms_cmgw_set(mbtk_info_handle_t* handle, char * cmgw, char *resp)
+{
+    printf("mbtk_sms_cmgw_set() ----------cmgw:%s, len:%d", cmgw, strlen(cmgw));
+    if(info_item_process(handle, MBTK_INFO_ID_SMS_CMGW_REQ, cmgw, strlen(cmgw), resp)  > 0){
+        printf("resp:%s\n", resp);
+        return 0;
+    }else{
+        return handle->info_err;
+    }
+}
+
+/*
+* Set sms cmgd.
+*
+* +CMGD=<index>[,<delflag>]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgd_set(mbtk_info_handle_t* handle, char * cmdg)
+{
+    printf("mbtk_sms_cmgd_set() cmdg:%s, len:%d",cmdg, strlen(cmdg));
+    return info_item_process(handle, MBTK_INFO_ID_SMS_CMGD_REQ, cmdg, strlen(cmdg), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cmgl.
+*
+* AT+CMGL[=<stat>]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgl_set(mbtk_info_handle_t* handle, char * cmgl, char *resp)
+{
+    printf("0mbtk_sms_cmgl_set() cmgl:%s, len:%d\n",cmgl, strlen(cmgl));
+    char reg[5*1024] ={0};
+    if( info_item_process(handle, MBTK_INFO_ID_SMS_CMGL_REQ, cmgl, strlen(cmgl), reg) > 0){
+        printf("len:%d , reg:%s\n", strlen(reg), reg);
+    //    memcpy(resp, reg, strlen(reg));
+        return 0;
+    }else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Return sms csca.
+*/
+int mbtk_sms_csca_get(mbtk_info_handle_t* handle, char *buf)
+{
+  //  char  state;
+    if(info_item_process(handle, MBTK_INFO_ID_SMS_CSCA_REQ, NULL, 0, buf) > 0) {
+        LOG("mbtk_sms_csca_get()-----------sms csca : %s", buf);
+    //    *volte_state = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set sms csca.
+*
+* AT+CSCA=<number> [,<type>]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_csca_set(mbtk_info_handle_t* handle, char * csca)
+{
+    printf("mbtk_sms_csca_set() csca:%s, len:%d",csca, strlen(csca));
+    return info_item_process(handle, MBTK_INFO_ID_SMS_CSCA_REQ, csca, strlen(csca), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms csmp.
+*
+* AT+CSMP=[<fo>[,<vp>[,<pid>[,<dcs>]]]]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_csmp_set(mbtk_info_handle_t* handle, char * csmp)
+{
+    printf("mbtk_sms_csmp_set() csmp:%s, len:%d",csmp, strlen(csmp));
+    return info_item_process(handle, MBTK_INFO_ID_SMS_CSMP_REQ, csmp, strlen(csmp), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cscb.
+*
+* AT+CSCB=<[<mode>[,<mids>[,<dcss>]]]>
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cscb_set(mbtk_info_handle_t* handle, char * cscb)
+{
+    printf("mbtk_sms_cscb_set() cscb:%s, len:%d",cscb, strlen(cscb));
+    return info_item_process(handle, MBTK_INFO_ID_SMS_CSCB_REQ, cscb, strlen(cscb), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cnmi.
+*
+at+cnmi=1,2
+
+OK
+if sending fails:
++CMS ERROR: <err>
+*/
+int mbtk_sms_cnmi_set(mbtk_info_handle_t* handle)
+{
+    printf("mbtk_sms_cnmi_set()------------start\n");
+
+    return info_item_process(handle, MBTK_INFO_ID_SMS_CNMI_REQ, NULL, 0, NULL)? handle->info_err : 0;
+}
+
+/*
+* Set sms cmss.
+*
++CMSS=<index>[,<da>[,<toda>]]
+
+if sending successful:
++CMSS: <mr>
+OK
+if sending fails:
++CMS ERROR: <err>
+*/
+int mbtk_sms_cmss_set(mbtk_info_handle_t* handle, char * cmss, char *resp)
+{
+    printf("mbtk_sms_cmss_set()------------cmss:%s, len:%d", cmss, strlen(cmss));
+    if( info_item_process(handle, MBTK_INFO_ID_SMS_CMSS_REQ, cmss, strlen(cmss), resp) > 0){
+        printf("resp:%s\n", resp);
+        return 0;
+    }else{
+        return handle->info_err;
+    }
+}
+
+/*
+* Return sms cmgf.
+*/
+int mbtk_sms_cpms_get(mbtk_info_handle_t* handle, char * mem)
+{
+    char req[128] = {0};
+    if(info_item_process(handle, MBTK_INFO_ID_SMS_CPMS_REQ, NULL, 0, &req) > 0) {
+        LOG("mbtk_sms_cpms_get()  req : %s, strlen(mem_ptr):%d\n", req, strlen(req));
+        memcpy(mem, req, strlen(req));
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+
+/*
+* Set sms cpms.
+*
+* AT+CPMS=<mem1>[,<mem2>[,<mem3>]]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cpms_set(mbtk_info_handle_t* handle, char * mem, char* response)
+{
+    printf("mbtk_sms_cpms_set() mem:%s, len:%d",mem, strlen(mem));
+    char req[128] = {0};
+    if( info_item_process(handle, MBTK_INFO_ID_SMS_CPMS_REQ, mem, strlen(mem), req) > 0){
+        memcpy(response, req, strlen(req));
+        return 0;
+    }
+    else{
+        return handle->info_err;
+    }
+}
+
+/*
+* Set sms cm.
+*
+* +CMGR=<index>
+
+if PDU mode (+CMGF=0) ��command successful:
++CMGR: <stat>,[<alpha>],<length><CR><LF><pdu>
+OK
+if text mode (+CMGF=1), command successful and SMS-DELIVER:
++CMGR:<stat>,<oa>,[<alpha>],<scts>[,<tooa>,<fo>,<pid>,<dcs
+>, <sca>,<tosca>,<length>]<CR><LF><data>
+OK
+if text mode (+CMGF=1), command successful and SMS-SUBMIT:
++CMGR:
+<stat>,<da>,[<alpha>][,<toda>,<fo>,<pid>,<dcs>,[<vp>],
+<sca>,<tosca>,<length>]<CR><LF><data>
+OK
+otherwise:
++CMS ERROR: <err>
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgr_set(mbtk_info_handle_t* handle, int index, char *resp)
+{
+    printf("mbtk_sms_cmgr_set() --------------index:%d",index);
+    if( info_item_process(handle, MBTK_INFO_ID_SMS_CMGR_REQ, (uint8*)&index, sizeof(uint8), resp) > 0){
+        printf("resp:%s\n", resp);
+        return 0;
+    }else{
+        return handle->info_err;
+    }
+}
+
+
+/*
+* Get sim state.
+*/
+int mbtk_sim_state_get(mbtk_info_handle_t* handle, mbtk_sim_state_enum *sim_state)
+{
+    uint8 state;
+    if(handle == NULL || sim_state == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_STATE_REQ, NULL, 0, &state) > 0) {
+        *sim_state = (mbtk_sim_state_enum)state;
+        LOG("Sim state : %d", *sim_state);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get sim card type.
+*/
+int mbtk_sim_card_type_get(mbtk_info_handle_t* handle, mbtk_sim_card_type_enum *sim_card_type)
+{
+    uint8 state;
+    if(handle == NULL || sim_card_type == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_SIM_STYPE_REQ, NULL, 0, &state) > 0) {
+        *sim_card_type = (mbtk_sim_card_type_enum)state;
+        LOG("Sim sim_card_type : %d", *sim_card_type);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Get system temperature.
+*
+* type[IN]:
+*   0: Soc temperature.
+*   1: RF temperature.
+* temp[OUT]:
+*   temperature in celsius.
+*/
+int mbtk_temp_get(mbtk_info_handle_t* handle, int type, int* temp)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(type != 0 && type != 1 || temp == NULL)
+    {
+        return -1;
+    }
+
+    uint8 temp_type = (uint8)type;
+    uint8 temp_ptr;
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_TEMP_REQ, &temp_type, sizeof(uint8), &temp_ptr) > 0) {
+        *temp = temp_ptr;
+        LOG("Temperature : %d", *temp);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+
+    return 0;
+}
+
+
+/*
+* Set sim power state.
+* power:
+* 0: Sim power off.
+* 1: Sim power on.
+*/
+int mbtk_sim_power_set(int power)
+{
+    if(power != 0 && power != 1)
+    {
+        return -1;
+    }
+
+    //  /sys/devices/virtual/usim_event/usim0/send_event
+    char cmd[100] = {0};
+    sprintf(cmd, "echo %d > /sys/devices/virtual/usim_event/usim0/send_event", power ? 0 : 1);
+    system(cmd);
+
+    return 0;
+}
+
+/*
+* System power.
+* type:
+* 0: Reboot system.
+* 1: Poweroff system.
+* 2: Halt system.
+*/
+int mbtk_system_reboot(int type)
+{
+    if(type != 0 && type != 1 && type != 2)
+    {
+        return -1;
+    }
+
+    switch(type) {
+        case 0: {
+            system("reboot");
+            break;
+        }
+        case 1: {
+            system("poweroff");
+            break;
+        }
+        case 2: {
+            system("halt");
+            break;
+        }
+        default: {
+            break;
+        }
+    }
+
+    return 0;
+}
+
+/*
+*   set modem fun
+*
+*/
+int mbtk_set_modem_fun(mbtk_info_handle_t* handle, mbtk_modem_info_t *info)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    return info_item_process(handle, MBTK_INFO_ID_DEV_MODEM_REQ, info, sizeof(mbtk_modem_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+*   get modem fun
+*
+*/
+int mbtk_get_modem_fun(mbtk_info_handle_t* handle, int* fun)
+{
+    uint8 state;
+    if(handle == NULL || fun == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_DEV_MODEM_REQ, NULL, 0, &state) > 0) {
+        LOG("modem type : %d", state);
+        *fun = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* call_start
+*
+*/
+int mbtk_call_start(mbtk_info_handle_t* handle, char* phone_number)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(str_empty(phone_number))
+        return -1;
+
+    return info_item_process(handle, MBTK_INFO_ID_CALL_START_REQ,
+            phone_number, strlen(phone_number), NULL) ? handle->info_err : 0;
+}
+/*
+* Answer the phone call.
+*
+*/
+int mbtk_call_answer(mbtk_info_handle_t* handle)
+{
+    return info_item_process(handle, MBTK_INFO_ID_CALL_ANSWER_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up all call.
+*
+*/
+int mbtk_call_hang(mbtk_info_handle_t* handle)
+{
+    return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up a call.
+*
+*/
+int mbtk_a_call_hang(mbtk_info_handle_t* handle, int phone_id)
+{
+    return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_A_REQ, (uint8*)&phone_id, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up waiting or background call.
+*
+*/
+int mbtk_waiting_or_background_call_hang(mbtk_info_handle_t* handle)
+{
+    return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_B_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up foreground resume background call.
+*
+*/
+int mbtk_foreground_resume_background_call_hang(mbtk_info_handle_t* handle)
+{
+    return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_C_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get current call phone number.
+*/
+int mbtk_call_reg_get(mbtk_info_handle_t* handle, mbtk_call_info_t *reg)
+{
+    if(info_item_process(handle, MBTK_INFO_ID_CALL_WAITIN_REQ, NULL, 0, reg) > 0) {
+        LOG("CLCC : %d, %d, %d, %d, %d, %s, %d", reg->dir1, reg->dir, reg->state, reg->mode, reg->mpty, reg->phone_number, reg->type);
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Return mute state.
+*/
+int mbtk_mute_state_get(mbtk_info_handle_t* handle, int *mute_state)
+{
+    uint8 state;
+    if(info_item_process(handle, MBTK_INFO_ID_CALL_MUTE_REQ, NULL, 0, &state) > 0) {
+        LOG("Mute State : %d", state);
+        *mute_state = state;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set mute state.
+*
+* mute_state:
+* 0 : of mute.
+* 1 : on mute.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_mute_state_set(mbtk_info_handle_t* handle, int mute_state)
+{
+    return info_item_process(handle, MBTK_INFO_ID_CALL_MUTE_REQ, (uint8*)&mute_state, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set DTMF character.
+*
+*/
+int mbtk_dtmf_send(mbtk_info_handle_t* handle, mbtk_call_dtmf_info_t *dtmf_character)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    return info_item_process(handle, MBTK_INFO_ID_CALL_DTMF_REQ,
+            dtmf_character, sizeof(mbtk_call_dtmf_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set pdp state change callback function.
+*/
+int mbtk_pdp_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_IND_PDP_STATE_CHANGE, NULL, 0, NULL) < 0) {
+        return handle->info_err;
+    } else {
+        handle->pdp_state_cb = cb;
+        return 0;
+    }
+}
+
+/*
+* Set network state change callback function.
+*/
+int mbtk_net_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_IND_NET_STATE_CHANGE, NULL, 0, NULL) > 0) {
+        handle->net_state_cb = cb;
+        return 0;
+    } else {
+        return handle->info_err;
+    }
+}
+
+/*
+* Set call state change callback function.
+*/
+int mbtk_call_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_IND_CALL_STATE_CHANGE, NULL, 0, NULL) < 0) {
+        return handle->info_err;
+    } else {
+        handle->call_state_cb = cb;
+        return 0;
+    }
+}
+
+/*
+* Set sms state change callback function.
+*/
+int mbtk_sms_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_IND_SMS_STATE_CHANGE, NULL, 0, NULL) < 0) {
+        return handle->info_err;
+    } else {
+        handle->sms_state_cb = cb;
+        return 0;
+    }
+}
+
+/*
+* Set radio state change callback function.
+*/
+int mbtk_radio_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_IND_RADIO_STATE_CHANGE, NULL, 0, NULL) < 0) {
+        return handle->info_err;
+    } else {
+        handle->radio_state_cb = cb;
+        return 0;
+    }
+}
+
+/*
+* Set sim state change callback function.
+*/
+int mbtk_sim_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+    if(handle == NULL)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+    if(info_item_process(handle, MBTK_INFO_ID_IND_SIM_STATE_CHANGE, NULL, 0, NULL) < 0) {
+        return handle->info_err;
+    } else {
+        handle->sim_state_cb = cb;
+        return 0;
+    }
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_list.c b/mbtk/mbtk_lib/src/mbtk_list.c
new file mode 100755
index 0000000..d31cedf
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_list.c
@@ -0,0 +1,332 @@
+/*
+ * mbtk_list.c
+ *
+ *  Created on: Aug 18, 2020
+ *      Author: lb
+ */
+#include <string.h>
+#include <stdlib.h>
+#include "mbtk_list.h"
+
+list_node_t* list_create(list_free_func free_func)
+{
+    list_node_t *list = (list_node_t*) malloc(sizeof(list_node_t));
+    if (list) {
+        memset(list, 0x0, sizeof(list_node_t));
+        list->size = 0;
+        list->cur_index = 0;
+        list->cur_array_data = NULL;
+        list->sort_func = NULL;
+        list->free_func = free_func;
+        return list;
+    }
+
+    return NULL;
+}
+
+uint32 list_size(list_node_t *list)
+{
+    if (list) {
+        return list->size;
+    } else {
+        return 0;
+    }
+}
+
+static list_treenode_t* list_treeadd(list_node_t *list, list_treenode_t *node,
+        list_arraynode_t *data)
+{
+    if (node && node->data) {
+        int result = list->sort_func(data->data, node->data->data);
+        if (result == 0) { // Same node
+            node->count++;
+            // printf("Same[%d]:%s\n", node->count, data->data);
+
+            // Add the same node to last.
+            list_arraynode_t *array_node = node->data;
+            while (array_node->next) {
+                array_node = array_node->next;
+            }
+            array_node->next = data;
+            array_node->next->next = NULL;
+
+        } else if (result < 0) {
+            node->left = list_treeadd(list, node->left, data);
+        } else {
+            node->right = list_treeadd(list, node->right, data);
+        }
+    } else {
+        if (!node) {
+            node = (list_treenode_t*) malloc(sizeof(list_treenode_t));
+        }
+        node->left = NULL;
+        node->right = NULL;
+        node->data = data;
+        node->count = 1;
+    }
+
+    return node;
+}
+
+void list_add(list_node_t *list, void *data)
+{
+    if (list && data) {
+        list_arraynode_t *node = &(list->array_data);
+        while (node->next) {
+            node = node->next;
+        }
+
+        node->next = (list_arraynode_t*) malloc(sizeof(list_arraynode_t));
+        if(node->next) {
+            node->next->data = data;
+            node->next->next = NULL;
+            list->size++;
+        }
+    }
+}
+
+void list_add_unique(list_node_t *list, void *data, uint32 len)
+{
+    if (list && data && len > 0) {
+        list_arraynode_t *node = &(list->array_data);
+        while (node->next) {
+            if (!memcmp(node->next->data, data, len)) {
+                return;
+            }
+            node = node->next;
+        }
+
+        node->next = (list_arraynode_t*) malloc(sizeof(list_arraynode_t));
+        node->next->data = data;
+        node->next->next = NULL;
+
+        list->size++;
+    }
+}
+
+void* list_remove(list_node_t *list, void *data)
+{
+    if (list) {
+        list_arraynode_t *node = list->array_data.next;
+        if (node) {
+            if (data == node->data) { // Find node
+                list_arraynode_t *result = node;
+                void *reault_data = result->data;
+                list->array_data.next = node->next;
+                free(result);
+                list->size--;
+                return reault_data;
+            }
+        } else {
+            return NULL;
+        }
+
+        while (node->next) {
+            if (data == node->next->data) { // Find node
+                list_arraynode_t *result = node->next;
+                void *reault_data = result->data;
+                node->next = node->next->next;
+                free(result);
+                list->size--;
+                return reault_data;
+            }
+            node = node->next;
+        }
+    }
+
+    return NULL;
+}
+
+void* list_remove_by_content(list_node_t *list, void *data, uint32 data_len)
+{
+    if (list) {
+        list_arraynode_t *node = list->array_data.next;
+        if (node) {
+            if (!memcmp(data, node->data, data_len)) { // Find node
+                list_arraynode_t *result = node;
+                void *reault_data = result->data;
+                list->array_data.next = node->next;
+                free(result);
+                list->size--;
+                return reault_data;
+            }
+        } else {
+            return NULL;
+        }
+
+        while (node->next) {
+            if (!memcmp(data, node->next->data, data_len)) { // Find node
+                list_arraynode_t *result = node->next;
+                void *reault_data = result->data;
+                node->next = node->next->next;
+                free(result);
+                list->size--;
+                return reault_data;
+            }
+            node = node->next;
+        }
+    }
+
+    return NULL;
+}
+
+void list_first(list_node_t *list)
+{
+    if (list) {
+        list->cur_index = 0;
+        list->cur_array_data = list->array_data.next;
+    }
+}
+
+void* list_next(list_node_t *list)
+{
+    if (list) {
+        list_arraynode_t *node = list->cur_array_data;
+        if (node) {
+            list->cur_array_data = list->cur_array_data->next;
+            list->cur_index++;
+
+            return node->data;
+        } else {
+            return NULL;
+        }
+    } else {
+        return NULL;
+    }
+}
+
+void* list_get(list_node_t *list, uint32 index)
+{
+    if (list) {
+        if (index >= list->size) {
+            return NULL;
+        }
+
+        list_arraynode_t *node = list->array_data.next;
+        if (node) {
+            uint32 i = 0;
+            while (node) {
+                if (i == index) {
+                    return node->data;
+                }
+                node = node->next;
+                i++;
+            }
+        }
+
+        return NULL;
+    } else {
+        return NULL;
+    }
+}
+
+static void list_treenext(list_node_t *list, list_treenode_t *tree_node)
+{
+    if (list && tree_node) {
+        list_treenode_t *left = tree_node->left;
+        list_treenode_t *right = tree_node->right;
+        list_treenext(list, left);
+
+        list_arraynode_t *array_node = tree_node->data;
+        while (array_node) {
+            list->cur_array_data->next = array_node;
+            list->cur_array_data = array_node;
+            array_node = array_node->next;
+        }
+        list_treenext(list, right);
+    }
+}
+
+static void list_treefree(list_node_t *list, list_treenode_t *tree_node)
+{
+    if (list && tree_node) {
+        list_treefree(list, tree_node->left);
+        list_treefree(list, tree_node->right);
+
+        if (&(list->tree_data) != tree_node) {
+            free(tree_node);
+            tree_node = NULL;
+        }
+    }
+}
+
+void list_sort(list_node_t *list, list_sort_func sort_func)
+{
+    if (list && sort_func) {
+        list->sort_func = sort_func;
+        list_arraynode_t *node = list->array_data.next; // First node
+        if (node) {
+            uint32 i = 0;
+            list_arraynode_t **temp = (list_arraynode_t **) malloc(
+                    sizeof(list_arraynode_t*) * list->size);
+            list_arraynode_t *temp_node = node;
+            while (node) {
+                temp[i] = node;
+                temp_node = node;
+                node = node->next;
+                temp_node->next = NULL;
+                i++;
+            }
+
+            for (i = 0; i < list->size; i++) {
+                list_treeadd(list, &(list->tree_data), temp[i]);
+            }
+
+            /*while (node) {
+             list_treeadd(list, &(list->tree_data), node);
+             node = node->next;
+             }*/
+
+            // Sort complete.
+            list->cur_array_data = &(list->array_data);
+            list_treenext(list, &(list->tree_data));
+
+            list_treefree(list, &(list->tree_data));
+            free(temp);
+        }
+    }
+}
+
+void list_free(list_node_t *list)
+{
+    if (list) {
+        list_arraynode_t *node = &(list->array_data); // Head node
+        list_arraynode_t *node_temp = NULL;
+        while (node->next) {
+            node_temp = node->next;
+            node->next = node->next->next;
+
+            if (list->free_func) {
+                list->free_func(node_temp->data);
+            } else {
+                free(node_temp->data);
+            }
+            free(node_temp);
+        }
+        free(list);
+    }
+}
+
+void list_clear(list_node_t *list)
+{
+    if (list) {
+        list_arraynode_t *node = &(list->array_data); // Head node
+        list_arraynode_t *node_temp = NULL;
+        while (node->next) {
+            node_temp = node->next;
+            node->next = node->next->next;
+
+            if (list->free_func) {
+                list->free_func(node_temp->data);
+            }
+            free(node_temp);
+        }
+        list_free_func free_func = list->free_func;
+        memset(list, 0x0, sizeof(list_node_t));
+        list->size = 0;
+        list->cur_index = 0;
+        list->cur_array_data = NULL;
+        list->sort_func = NULL;
+        list->free_func = free_func;
+    }
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_log.c b/mbtk/mbtk_lib/src/mbtk_log.c
new file mode 100755
index 0000000..54c107b
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_log.c
@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include <include/log.h>
+#include <sys/un.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+
+#define LOG_VERBOSE 8
+
+static int tlog_fd = -1;
+static int syslog_radio_enable = 0;
+static FILE* logfile = NULL;
+static int signal_fd = -1;
+
+/**
+ * @brief      mbtk_log_init
+ *
+ * @details    设置Log输出方式
+ * @param
+ *             path:
+ *                   不填参数(NULL) stdout : 命令行输
+ *                   "syslog":输出到syslog
+ *                   "radio":CatStudio
+ *                   文件路径:输出到自定义文件路径
+ *             tag : 自定义tag
+ *
+ *   example:
+ *       mbtk_log_init(NULL, "MBTK_RIL");
+ *       mbtk_log_init("syslog", "MBTK_RIL");
+ *       mbtk_log_init("radio", "MBTK_RIL");
+ *       mbtk_log_init("/tmp/log/test.log", "MBTK_RIL");
+ */
+void mbtk_log_init(char* path, char* tag)
+{
+    if (str_empty(path)) {
+        tlog_fd = STDOUT_FILENO;
+    } else if (0 == memcmp(path, "syslog", 6)) {
+        openlog(tag, LOG_PID, LOG_USER);
+        syslog_radio_enable = 1;
+    } else if (0 == memcmp(path, "radio", 5)) {
+        if (tag && strlen(tag) > 0) {
+            set_service_log_tag(tag);
+        } else {
+            set_service_log_tag("MBTK");
+        }
+        syslog_radio_enable = 2;
+    } else if (path) {
+        tlog_fd = open(path, O_CREAT | O_WRONLY | O_APPEND, 0600);
+        if (tlog_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
+            exit(-1);
+        }
+    }
+}
+
+/* Control the log output */
+void mbtk_log(int level, const char* format, ...)
+{
+    char buf[1024] = {0};
+    va_list ap;
+    struct timeval log_time;
+    int length = 0;
+
+    va_start(ap, format);
+    length = vsnprintf(buf, sizeof(buf), format, ap);
+    if (length < 0 || 0 == length) {
+        return -1;
+    }
+
+    if (1 == syslog_radio_enable) {
+        syslog(level, "%s", buf);
+    } else if (2 == syslog_radio_enable) {
+        __android_log_printf(LOG_ID_RADIO, level, "%s", buf);
+    } else if (-1 != tlog_fd) {
+        char tmp[50] = {0};
+        gettimeofday(&log_time, NULL);
+        struct tm* tm_t = localtime(&(log_time.tv_sec));
+        strftime(tmp, 50, "%F %T", tm_t);
+        snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), " %d<%d>:", (int)(log_time.tv_usec / 1000), level);
+        write(tlog_fd, tmp, strlen(tmp));
+        write(tlog_fd, buf, length);
+        if (buf[length - 1] != '\n') {
+            write(tlog_fd, "\n", 1);
+        }
+        if (tlog_fd > 2) {
+            fsync(tlog_fd);
+        }
+    }
+
+    va_end(ap);
+}
+
+void log_hex(const char* tag, const void* data, int data_len)
+{
+    char buffer[60];
+    char str[17];
+    int size = 0;
+    uint8* ptr = (uint8*)data;
+    int i, j;
+    memset(buffer, 0x0, 60);
+    memset(str, 0x0, 17);
+    LOGI("%s,Length-%d:", tag, data_len);
+    LOGI("       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
+    size += snprintf(buffer, 60, "%04x| ", 0);
+    for (i = 0; i < data_len; i++) {
+        size += snprintf(buffer + size, 60 - size, "%02x ", ptr[i]);
+        if (isprint(ptr[i])) {
+            str[i % 16] = ptr[i];
+        } else {
+            str[i % 16] = '.';
+        }
+        if ((i + 1) % 16 == 0 || i == data_len - 1) {
+            for (j = size; j < 54; j++) {
+                buffer[j] = ' ';
+            }
+            LOGI("%s| %s", buffer, str);
+
+            memset(buffer, 0x0, 60);
+            memset(str, 0x0, 17);
+            size = 0;
+            size += snprintf(buffer, 60, "%04x| ", (i + 1) / 16);
+        }
+    }
+}
+
+#define _MOPEN_RILD_SOCKET "/tmp/logd_socket"
+
+int mbtk_signal_log(char *data)
+{
+    char buff[256];
+    int size = 0;
+    int ret = 0;
+    int i = 0;
+    static struct sockaddr_un srv_addr;
+
+    if(signal_fd < 0) {
+        if (access(_MOPEN_RILD_SOCKET, F_OK) == -1) {
+            LOGW("Service not running...");
+            return -1;
+        }
+
+        signal_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+        if (signal_fd < 0) {
+            LOGE("cannot creat socket");
+            return -1;
+        }
+
+        srv_addr.sun_family = AF_UNIX;
+        strcpy(srv_addr.sun_path, _MOPEN_RILD_SOCKET);
+        ret = connect(signal_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
+        if (ret < 0) {
+            LOGE("cannot connect server, ret=%d, errno=%d", ret, errno);
+            close(signal_fd);
+            signal_fd = -1;
+            return -1;
+        }
+    }
+
+    memset(buff, 0, sizeof(buff));
+    snprintf(buff, sizeof(buff), "%s\n", data);
+    size = write(signal_fd, buff, sizeof(buff));
+    if (size < 0 || size == 0) {
+        LOGE("cannot write , ret=%d, errno=%d\n", ret, errno);
+        return 1;
+    }
+
+    // close(signal_fd);
+
+    return 0;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_map.c b/mbtk/mbtk_lib/src/mbtk_map.c
new file mode 100755
index 0000000..061a538
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_map.c
@@ -0,0 +1,242 @@
+/*
+ * mbtk_map.c
+ *
+ *  Created on: Aug 18, 2020
+ *      Author: lb
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "mbtk_map.h"
+
+map_node_t* map_create(uint32 capacity, map_free_func free_func)
+{
+    if (capacity > 0) {
+        map_node_t *map = (map_node_t*) malloc(sizeof(map_node_t));
+        if (map) {
+            memset(map, 0x0, sizeof(map_node_t));
+            map->size = 0;
+            map->cur_index = 0;
+            map->cur_data = NULL;
+            map->capacity = (uint32) (capacity * 0.75f); // Default 0.75
+            if(map->capacity < 1) {
+                free(map);
+                return NULL;
+            }
+            map->free_func = free_func;
+            map->map_array = (map_data_t**) malloc(
+                    sizeof(map_data_t*) * map->capacity);
+            uint32 i = 0;
+            while (i < map->capacity) {
+                map->map_array[i] = NULL;
+                i++;
+            }
+            return map;
+        }
+    }
+
+    return NULL;
+}
+
+uint32 map_size(map_node_t* map)
+{
+    if (map) {
+        return map->size;
+    }
+
+    return 0;
+}
+
+uint32 map_hash(const char* key, uint32 capacity)
+{
+    uint32 hash = 0;
+    const uint8 *ptr = (const uint8*) key;
+    while (*ptr) {
+        hash = 31 * hash + *ptr;
+        ptr++;
+    }
+
+    return hash % capacity;
+}
+
+void map_put(map_node_t* map, const char* key, void* value)
+{
+    if (map && key && strlen(key) > 0 && value) {
+        uint32 index = map_hash(key, map->capacity);
+
+        map_data_t *ptr = map->map_array[index];
+        if (!ptr) { // Add to first position.
+            ptr = (map_data_t*) malloc(sizeof(map_data_t));
+            ptr->key = strdup(key);
+            ptr->value = value;
+            ptr->next = NULL;
+
+            map->size++;
+            map->map_array[index] = ptr;
+        } else { // This position has one item at least.
+            if (!memcmp(ptr->key, key, strlen(key))) { // Has this item,will change.
+                if (map->free_func) {
+                    map->free_func(ptr->value);
+                }
+
+                ptr->value = value;
+            } else {
+                while (ptr->next) {
+                    if (!memcmp(ptr->next->key, key, strlen(key))) // Has this item,will change.
+                        break;
+                    ptr = ptr->next;
+                }
+
+                if (!ptr->next) { // Add new item.
+                    ptr->next = (map_data_t*) malloc(sizeof(map_data_t));
+
+                    ptr->next->key = strdup(key);
+                    ptr->next->value = value;
+                    ptr->next->next = NULL;
+                    map->size++;
+                } else { // Change item.
+                    if (map->free_func) {
+                        map->free_func(ptr->next->value);
+                    }
+
+                    ptr->next->value = value;
+                }
+            }
+        }
+    }
+}
+
+void* map_get(map_node_t* map, char* key)
+{
+    if (map && key && strlen(key) > 0) {
+        uint32 index = map_hash(key, map->capacity);
+        map_data_t *ptr = map->map_array[index];
+        while (ptr) {
+            if (ptr->key && !memcmp(ptr->key, key, strlen(key))) {
+                return ptr->value;
+            }
+            ptr = ptr->next;
+        }
+    }
+    return NULL;
+}
+
+void* map_remove(map_node_t* map, char* key)
+{
+    if (map && key && strlen(key) > 0) {
+        uint32 index = map_hash(key, map->capacity);
+        map_data_t *ptr = map->map_array[index];
+        if (!ptr) { // No items.
+            return NULL;
+        }
+
+        if (!memcmp(ptr->key, key, strlen(key))) { // Is first item
+            map_data_t *temp = ptr;
+            void *result = temp->value;
+            map->map_array[index] = ptr->next;
+            free(temp);
+            map->size--;
+
+            return result;
+        } else {
+            while (ptr->next) {
+                if (!memcmp(ptr->next->key, key, strlen(key))) {
+                    map_data_t *temp = ptr->next;
+                    void *result = temp->value;
+                    ptr->next = temp->next;
+                    free(temp);
+                    map->size--;
+
+                    return result;
+                }
+                ptr = ptr->next;
+            }
+        }
+    }
+    return NULL;
+}
+
+void map_first(map_node_t *map)
+{
+    if (map) {
+        map->cur_index = 0;
+        map->cur_data = map->map_array[0];
+    }
+}
+
+void* map_next(map_node_t *map)
+{
+    if (map) {
+        while (1) {
+            if (map->cur_data) {
+                void *result = map->cur_data;
+                map->cur_data = map->cur_data->next;
+                return result;
+            } else {
+                map->cur_index++;
+                if (map->cur_index < map->capacity) {
+                    map->cur_data = map->map_array[map->cur_index];
+                } else { // Finish
+                    return NULL;
+                }
+            }
+        }
+    } else {
+        return NULL;
+    }
+}
+
+void map_clear(map_node_t* map)
+{
+    if (map) {
+        uint32 i = 0;
+        map_data_t *ptr = NULL;
+        while (i < map->capacity) {
+            ptr = map->map_array[i];
+            while (ptr) {
+                map->map_array[i] = ptr->next;
+
+                free(ptr->key);
+                if (map->free_func) {
+                    map->free_func(ptr->value);
+                }
+                free(ptr);
+
+                ptr = map->map_array[i];
+            }
+            i++;
+        }
+
+        map->size = 0;
+        map->cur_index = 0;
+        map->cur_data = NULL;
+        memset(map->map_array, 0x0,
+                sizeof(sizeof(map_data_t*) * map->capacity));
+    }
+}
+
+void map_free(map_node_t* map)
+{
+    if (map) {
+        uint32 i = 0;
+        map_data_t *ptr = NULL;
+        while (i < map->capacity) {
+            ptr = map->map_array[i];
+            while (ptr) {
+                map->map_array[i] = ptr->next;
+
+                free(ptr->key);
+                if (map->free_func) {
+                    map->free_func(ptr->value);
+                }
+                free(ptr);
+
+                ptr = map->map_array[i];
+            }
+            i++;
+        }
+
+        free(map->map_array);
+        free(map);
+    }
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_mp3_to_wav.c b/mbtk/mbtk_lib/src/mbtk_mp3_to_wav.c
new file mode 100755
index 0000000..fe13e38
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_mp3_to_wav.c
@@ -0,0 +1,372 @@
+#include "audio_if_types.h"
+#include "audio_if_ubus.h"
+#include "audio_if_parameter.h"
+#include "audio_if.h"
+#include "audio_if_api.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include <string.h>
+//#include "audio_if_audio_hw_mrvl.h"
+#include "utlEventHandler.h"
+#include "udev_monitor.h"
+#include "audio_hw_mrvl.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <cutils/str_parms.h>
+#include "vcm.h"
+#include <libavutil/avutil.h>
+#include <libavutil/attributes.h>
+#include <libavutil/opt.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/timestamp.h>
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+#include <libavutil/mathematics.h>
+#include <libswresample/swresample.h>
+//#include <libavutil/channel_layout.h>
+#include <libavutil/common.h>
+#include <libavformat/avio.h>
+#include <libavutil/file.h>
+#include <libswresample/swresample.h>
+#include <libavfilter/avfilter.h>
+
+
+extern int mbtk_audio_play_stream_old(void *dev_hdl, const void *pData, int len);
+
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
+
+/* the size may be modified because of different decoded sample number. */
+#define MGR_BUFFER_SIZE 1024
+
+//#define DEBUG_FFMPEG_PCM_STREAM
+
+/* needed by PCM stream */
+extern void* audio_hal_install(void);
+extern void audio_hal_uninstall(void);
+extern void configure_vcm(unsigned int data[]);
+extern void set_pcm_config(int role, int rate);
+extern int mrvl_hw_dev_config_pcm(struct audio_hw_device *dev, unsigned int pcm);
+
+
+typedef struct {
+    int videoindex;
+    int sndindex;
+    AVFormatContext* pFormatCtx;
+    AVCodecContext* sndCodecCtx;
+    AVCodec* sndCodec;
+    SwrContext *swr_ctx;
+    DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 2];
+    //DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE];
+}AudioState;
+
+/******************************************************************************
+ *  Globals
+ ******************************************************************************/
+/* needed by FFMPEG */
+extern int64_t av_get_default_channel_layout(int nb_channels);
+extern AVFrame *avcodec_alloc_frame(void);
+
+
+static int my_init_ffmpeg1(AudioState* is, char* filepath)
+{
+    is->sndindex = -1;
+
+    if(NULL == filepath)
+    {
+        printf("input file is NULL");
+        return -1;
+    }
+
+    avcodec_register_all();
+    avfilter_register_all();
+    av_register_all();
+
+    is->pFormatCtx = avformat_alloc_context();
+
+    if(avformat_open_input(&is->pFormatCtx, filepath, NULL, NULL)!=0)
+        return -1;
+
+    if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
+        return -1;
+
+    av_dump_format(is->pFormatCtx,0, 0, 0);
+
+    is->videoindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_VIDEO, is->videoindex, -1, NULL, 0); 
+    is->sndindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_AUDIO,is->sndindex, is->videoindex, NULL, 0);
+
+    printf("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);
+
+    if(is->sndindex != -1)
+    {
+        is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
+        is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
+
+        if(is->sndCodec == NULL)
+        {
+            printf("Codec not found");
+            return -1;
+        }
+
+        if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
+            return -1;
+    }
+
+    return 0;
+} 
+
+
+int mbtk_audio_mp3_to_wav(const char *wavpath, char *mp3path)
+{
+    int in_channel_nb = 0;
+    int ret, rc;
+    int fd;
+    int size;
+    int len;
+    int file_data_size = 0;
+    int converted_nb_samples = 0;
+    int got_frame;
+    int index =0;
+    int i =0;
+    AVPacket *packet = av_mallocz(sizeof(AVPacket));
+    //AVFrame *frame = av_frame_alloc();
+    AVFrame *frame = avcodec_alloc_frame();
+    AudioState* is = (AudioState*) av_mallocz(sizeof(AudioState));
+    uint8_t *out[] = { is->audio_buf };
+    //char buf[MGR_BUFFER_SIZE];
+
+    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; //输出采样格式16bit PCM
+
+    int out_channel_nb = 0;
+    struct wav_header header;
+
+
+#if 1
+    int sample_rate = 8000;
+    //int sample_rate = 16000;
+    //int sample_rate = 44100;
+
+    int out_sample_rate = sample_rate; //输出采样率
+    uint64_t out_ch_layout = AV_CH_LAYOUT_MONO; //输出的声道布局
+    //uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO; //输出的声道布局
+
+#endif
+
+    fd = open(wavpath, O_WRONLY | O_CREAT);  //wavpath
+
+    //leave enough room for header
+    lseek(fd, sizeof(struct wav_header), SEEK_SET);
+
+
+    //第1步初始化ffmpeg,并用ffmpeg解码,最后转为pcm格式
+    if( (ret = my_init_ffmpeg1(is, mp3path)) != 0)            //1.1 初始化ffmpeg
+    {
+        printf("my_init_ffmpeg error");
+        return -1;
+    }
+
+    while(av_read_frame(is->pFormatCtx, packet) >= 0)    //1.2 循环读取mp3文件中的数据帧
+    {
+        if(packet->stream_index != is->sndindex)
+            continue;
+
+        if((ret = avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, packet)) < 0) //1.3 解码数据帧
+        {
+            printf("file eof");
+            break;
+        }
+
+        if(got_frame <= 0) /* No data yet, get more frames */
+            continue;
+
+        //1.4下面将ffmpeg解码后的数据帧转为我们需要的数据(关于"需要的数据"下面有解释)
+        if(NULL==is->swr_ctx)
+        {
+            if(is->swr_ctx != NULL)
+                swr_free(&is->swr_ctx);
+
+            //输入的声道个数
+            in_channel_nb = av_get_channel_layout_nb_channels(frame->channel_layout);
+
+            //输出的声道个数
+            out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
+
+            printf("frame: input channel: channnels=%d, format=%d, sample_rate=%d, nb_samples=%d.\n",
+                    in_channel_nb, frame->format, frame->sample_rate, frame->nb_samples);
+            printf("frame: out channel: channels=%d, format=%d, sample_rate=%d.\n", out_channel_nb, out_sample_fmt, out_sample_rate);
+
+            is->swr_ctx = swr_alloc_set_opts(NULL, out_ch_layout, out_sample_fmt, out_sample_rate, av_get_default_channel_layout(in_channel_nb), frame->format, frame->sample_rate, 0, NULL);
+
+
+            if(is->swr_ctx == NULL)
+            {
+                printf("swr_ctx == NULL");
+            }
+
+            swr_init(is->swr_ctx);
+        }
+
+        converted_nb_samples = swr_convert(is->swr_ctx, out, AVCODEC_MAX_AUDIO_FRAME_SIZE * 2, (const uint8_t **)frame->data, frame->nb_samples);
+
+        file_data_size += converted_nb_samples;
+
+        //1.5 数据格式转换完成后就写到文件中
+        //sample bit is 16bits = 2Bytes
+        size = converted_nb_samples*out_channel_nb*2;
+        write(fd, (char *)(is->audio_buf), size);
+
+    }
+
+    //sample bit is 16bits = 2Bytes
+    file_data_size *= (out_channel_nb*2);//(numSamples * wavFMT->numChannels * wavFMT->uiBitsPerSample) / 8
+
+    printf("file_data_size=%d, nb_samples=%d, converted_nb_samples=%d.\n", file_data_size, frame->nb_samples, converted_nb_samples);
+
+    //第2步添加上wav的头
+    //write header now all information is known
+    header.riff_id = ID_RIFF;
+    header.riff_sz = 0;
+    header.riff_fmt = ID_WAVE;
+    header.fmt_id = ID_FMT;
+    header.fmt_sz = 16;
+    header.audio_format = 1;        //FORMAT_PCM;
+    header.num_channels = out_channel_nb;        //Modem ONLY support mono recording
+    header.sample_rate = sample_rate;     //44100, 8000, 16000
+    header.bits_per_sample = 16;    //PCM_SAMPLEBITS_S16_LE;
+    header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
+    header.block_align = header.num_channels * (header.bits_per_sample / 8);
+    header.data_id = ID_DATA;
+
+    header.data_sz = file_data_size;
+    header.riff_sz = header.data_sz + sizeof(header) - 8;
+
+    lseek(fd, 0, SEEK_SET);
+    write(fd, &header, sizeof(struct wav_header));
+    printf("%s: sample_rate = %d, num_channels = %d!\n", __FUNCTION__,  header.sample_rate, header.num_channels);
+
+    av_free_packet(packet);
+    av_free(frame);
+    avcodec_close(is->sndCodecCtx);
+    avformat_close_input(&is->pFormatCtx);
+
+    close(fd);
+
+    return 0;
+}
+
+
+int mbtk_audio_mp3_to_play(char *mp3path, int hdl, int sample_rate)
+{
+    int in_channel_nb = 0;
+    int ret, rc;
+    int size;
+    int len;
+    int file_data_size = 0;
+    int converted_nb_samples = 0;
+    int got_frame;
+    int index =0;
+    int i =0;
+    AVPacket *packet = av_mallocz(sizeof(AVPacket));
+    //AVFrame *frame = av_frame_alloc();
+    AVFrame *frame = avcodec_alloc_frame();
+    AudioState* is = (AudioState*) av_mallocz(sizeof(AudioState));
+    uint8_t *out[] = { is->audio_buf };
+    //char buf[MGR_BUFFER_SIZE];
+
+    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; //输出采样格式16bit PCM
+
+    int out_channel_nb = 0;
+
+
+    if(sample_rate)
+    {
+        sample_rate = 16000;
+    }
+    else
+    {
+        sample_rate = 8000;
+    }
+//    int sample_rate = 8000;
+    //int sample_rate = 16000;
+    //int sample_rate = 44100;
+
+    int out_sample_rate = sample_rate; //输出采样率
+    uint64_t out_ch_layout = AV_CH_LAYOUT_MONO; //输出的声道布局
+    //uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO; //输出的声道布局
+
+    //第1步初始化ffmpeg,并用ffmpeg解码,最后转为pcm格式
+    if( (ret = my_init_ffmpeg1(is, mp3path)) != 0)            //1.1 初始化ffmpeg
+    {
+        printf("my_init_ffmpeg error");
+        return -1;
+    }
+
+    while(av_read_frame(is->pFormatCtx, packet) >= 0)    //1.2 循环读取mp3文件中的数据帧
+    {
+        if(packet->stream_index != is->sndindex)
+            continue;
+
+        if((ret = avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, packet)) < 0) //1.3 解码数据帧
+        {
+            printf("file eof");
+            break;
+        }
+
+        if(got_frame <= 0) /* No data yet, get more frames */
+            continue;
+
+        //1.4下面将ffmpeg解码后的数据帧转为我们需要的数据(关于"需要的数据"下面有解释)
+        if(NULL==is->swr_ctx)
+        {
+            if(is->swr_ctx != NULL)
+                swr_free(&is->swr_ctx);
+
+            //输入的声道个数
+            in_channel_nb = av_get_channel_layout_nb_channels(frame->channel_layout);
+
+            //输出的声道个数
+            out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
+
+            printf("frame: input channel: channnels=%d, format=%d, sample_rate=%d, nb_samples=%d.\n",
+                    in_channel_nb, frame->format, frame->sample_rate, frame->nb_samples);
+            printf("frame: out channel: channels=%d, format=%d, sample_rate=%d.\n", out_channel_nb, out_sample_fmt, out_sample_rate);
+
+            is->swr_ctx = swr_alloc_set_opts(NULL, out_ch_layout, out_sample_fmt, out_sample_rate, av_get_default_channel_layout(in_channel_nb), frame->format, frame->sample_rate, 0, NULL);
+
+
+            if(is->swr_ctx == NULL)
+            {
+                printf("swr_ctx == NULL");
+            }
+
+            swr_init(is->swr_ctx);
+        }
+
+        converted_nb_samples = swr_convert(is->swr_ctx, out, AVCODEC_MAX_AUDIO_FRAME_SIZE * 2, (const uint8_t **)frame->data, frame->nb_samples);
+
+        file_data_size += converted_nb_samples;
+
+        //1.5 数据格式转换完成后就写到文件中
+        //sample bit is 16bits = 2Bytes
+        size = converted_nb_samples*out_channel_nb*2;
+
+        mbtk_audio_play_stream_old((void *)hdl, (char *)(is->audio_buf), size);
+
+    }
+
+
+    av_free_packet(packet);
+    av_free(frame);
+    avcodec_close(is->sndCodecCtx);
+    avformat_close_input(&is->pFormatCtx);
+
+    return 0;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_net_control.c b/mbtk/mbtk_lib/src/mbtk_net_control.c
new file mode 100755
index 0000000..ff3af08
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_net_control.c
@@ -0,0 +1,535 @@
+/*************************************************************
+Description:
+    C file for network control.
+Author:
+    LiuBin
+Date:
+    2019/7/24 17:13:06
+*************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/route.h>
+#include <cutils/properties.h>
+#include <telephony/ril.h>
+
+#include "mbtk_type.h"
+#include "mbtk_net_control.h"
+#include "mbtk_task.h"
+#include "mbtk_utils.h"
+#include "mbtk_str.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "mbtk_net_control"
+#include "mbtk_log.h"
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+#define NET_CONTROL_BUF_SIZE 1024
+#ifndef INFTIM
+#define INFTIM          (-1)    /* infinite poll timeout */
+#endif
+#define MBTK_NET_PING_HOST "223.5.5.5"
+#define MBTK_NET_PING_IP "180.97.33.107" // IP for www.baidu.com
+
+// #define MBTK_NET_MONITOR_SUPPORT
+
+/*************************************************************
+    Variables:local
+*************************************************************/
+static char net_interface[20];
+static char net_ip[20];
+static mbtk_net_state_t net_state = MBTK_NET_STATE_OFF;
+static bool net_control_thread_running = FALSE;
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+static pthread_t net_control_thread_id = -1;
+static int net_control_fd = -1;
+#endif
+
+/*************************************************************
+    Variables:public
+*************************************************************/
+
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+
+/*************************************************************
+    Local Function Definitions
+*************************************************************/
+// Test network connected?
+// ping www.baidu.com
+static bool net_connected(const char *inf)
+{
+    char cmd[100];
+    char cmd_rsp[100];
+
+    // IP get now, ping www.baidu.com
+    memset(cmd,0,100);
+    snprintf(cmd,100,
+             "ping -I %s -c1 -s0 -w1000 %s | grep \"8 bytes from \"",
+             inf,
+             MBTK_NET_PING_HOST);
+    if(!mbtk_cmd_line(cmd,cmd_rsp,100))
+    {
+        LOGE("ping www.baidu.com cmd error.");
+        return FALSE;
+    }
+
+    LOGI("cmd_rsp:%s",cmd_rsp);
+    // ping www.baidu.com success.
+    if(str_startwith(cmd_rsp, "8 bytes from "))
+    {
+        return TRUE;
+    }
+#if 0
+    else if(str_contains(cmd_rsp, "unknown host"))
+    {
+        // DNS error,ping IP angin.
+        memset(cmd,0,100);
+        snprintf(cmd,100,
+                 "ping -I %s -c1 -s0 -w1000 %s | grep \"8 bytes from \"",
+                 inf,
+                 MBTK_NET_PING_IP);
+        if(!mbtk_cmd_line(cmd,cmd_rsp,100))
+        {
+            LOGW("ping www.baidu.com IP cmd error.");
+            return FALSE;
+        }
+
+        if(str_startwith(cmd_rsp, "8 bytes from "))
+        {
+            return TRUE;
+        }
+        else
+        {
+            LOGW("Network unconnected.(ping baidu IP fail)");
+            return FALSE;
+        }
+    }
+#endif
+    else
+    {
+        LOGW("Network unconnected.(ping baidu host fail)");
+        return FALSE;
+    }
+
+    LOGW("ifconfig cmd fail.");
+    return FALSE;
+}
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+static int net_control_netlink_init()
+{
+    struct sockaddr_nl sa;
+    int len = 2048;
+
+    net_control_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    if(net_control_fd < 0)
+    {
+        LOGE("socket() fail.[%d]",errno);
+        return -1;
+    }
+
+    if(setsockopt(net_control_fd,
+                  SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) < 0)
+    {
+        LOGE("setsockopt() fail.[%d]",errno);
+        return -1;
+    }
+
+    bzero(&sa, sizeof(sa));
+    sa.nl_family = AF_NETLINK;
+    sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE /*| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE*/;
+    if(bind(net_control_fd,
+            (struct sockaddr *) &sa, sizeof(sa)) < 0)
+    {
+        LOGE("bind() fail.[%d]",errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void net_control_if_change(struct nlmsghdr *nh)
+{
+    struct rtattr *tb[IFLA_MAX + 1];
+    struct ifinfomsg *ifinfo;
+    bzero(tb, sizeof(tb));
+    if(nh == NULL)
+    {
+        LOGE("mbtk_net_if_change() nh == NULL");
+        return;
+    }
+
+    ifinfo = NLMSG_DATA(nh);
+    if(ifinfo == NULL)
+    {
+        LOGE("mbtk_net_if_change() ifinfo == NULL");
+        return;
+    }
+
+    LOGD("nlmsghdr:%d,%d,%d,%d,%d\n",nh->nlmsg_len,
+         nh->nlmsg_type,
+         nh->nlmsg_flags,
+         nh->nlmsg_seq,
+         nh->nlmsg_pid);
+
+    LOGD("ifinfomsg:%d,%d,%d,%d,%d,%d\n",ifinfo->ifi_family,
+         ifinfo->__ifi_pad,
+         ifinfo->ifi_type,
+         ifinfo->ifi_index,
+         ifinfo->ifi_flags,
+         ifinfo->ifi_change);
+
+    if((ifinfo->ifi_flags & IFF_RUNNING)
+       && (ifinfo->ifi_flags & IFF_LOWER_UP))
+    {
+        LOGD("Wired inserted.");
+    }
+    else
+    {
+        LOGD("Wired not insert.");
+    }
+}
+
+static void net_control_addr_change(struct nlmsghdr *nh)
+{
+    if(nh == NULL)
+    {
+        LOGE("mbtk_net_if_change() nh == NULL");
+        return;
+    }
+
+    if(nh->nlmsg_type==RTM_NEWADDR)
+    {
+        LOGD("New addr...");
+    }
+    else
+    {
+        LOGD("Del addr...");
+    }
+}
+
+static void* net_control_monitor_run(void *arg)
+{
+    LOGI("net_control_monitor_run start.");
+    if(net_control_netlink_init() < 0)
+    {
+        LOGE("mbtk_net_monitor_run() fail.");
+        return ((void*)0);
+    }
+
+    fd_set rd_set;
+    struct timeval timeout;
+    int select_r;
+    int read_r;
+    struct sockaddr_nl sa;
+    struct nlmsghdr *nh;
+    char buff[NET_CONTROL_BUF_SIZE];
+
+    while (net_control_thread_running)
+    {
+        FD_ZERO(&rd_set);
+        FD_SET(net_control_fd, &rd_set);
+        timeout.tv_sec = 5;
+        timeout.tv_usec = 0;
+        select_r = select(net_control_fd + 1, &rd_set, NULL, NULL, &timeout);
+        if (select_r < 0)
+        {
+            perror("select");
+        }
+        else if (select_r > 0)
+        {
+            if (FD_ISSET(net_control_fd, &rd_set))
+            {
+                read_r = read(net_control_fd, buff, NET_CONTROL_BUF_SIZE);
+                LOGI("Net change:read len:%d",read_r);
+
+                int i;
+                for(i = 0; i < 32 && i < read_r; i++)
+                    LOGI("data:%x",buff[i]);
+
+                for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_r); nh = NLMSG_NEXT(nh, read_r))
+                {
+                    LOGI("msg_type:%d",nh->nlmsg_type);
+                    switch (nh->nlmsg_type)
+                    {
+                        default:
+                            LOGI("nh->nlmsg_type = %d\n", nh->nlmsg_type);
+                            break;
+                        case NLMSG_DONE:
+                        case NLMSG_ERROR:
+                            break;
+                        case RTM_NEWLINK:
+                        case RTM_DELLINK:
+                            net_control_if_change(nh);
+                            break;
+                        case RTM_NEWADDR:
+                        case RTM_DELADDR:
+                            net_control_addr_change(nh);
+                            break;
+                        case RTM_NEWROUTE:
+                        case RTM_DELROUTE:
+                            //print_rtmsg(nh);
+                            break;
+                    }
+
+                }
+            }
+        }
+    }
+
+    LOGD("mbtk_net_monitor_run exist ...");
+
+    return ((void*)0);
+}
+
+static mbtk_task_info net_control_thread =
+{
+    .task_id = &net_control_thread_id,
+    .thread_run = net_control_monitor_run,
+    .args = NULL
+};
+#endif
+
+static int net_control_interface_init()
+{
+    // seth_ltex
+    int i = 0;
+    int size = 0;
+    char result[NET_CONTROL_BUF_SIZE];
+    char cmd[100];
+    int index = 0;
+    while(i <= 7)
+    {
+        size = snprintf(cmd, 100,"ifconfig ccinet%d", i);
+        cmd[size] = '\0';
+        memset(result,0x0,NET_CONTROL_BUF_SIZE);
+        if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+        {
+            index = str_indexof(result,"inet addr:");
+            if(index > 0)
+            {
+                size = snprintf(net_interface, 20,"ccinet%d", i);
+                net_interface[size] = '\0';
+
+                memcpy(net_ip,result + index + 10,20);
+
+                char *ptr = net_ip;
+                while(*ptr && *ptr != ' ')
+                {
+                    ptr++;
+                }
+                *ptr = '\0';
+                break;
+            }
+        }
+        i++;
+    }
+
+    LOGI("Interface : %s, IP : %s",net_interface,net_ip);
+    if(index )
+    {
+        return 0;
+    }
+    else{
+        return -1;
+    }
+}
+
+static int net_control_init()
+{
+//    if(net_control_thread_running)
+//    {
+//        LOGD("Network control has inited.");
+//        return 0;
+//    }
+
+    memset(net_ip,0x0,20);
+    memset(net_interface,0x0,20);
+    if( net_control_interface_init())
+        return -1;
+    net_control_thread_running = TRUE;
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+    if(mbtk_task_start(&net_control_thread))
+    {
+        LOGE("Create thread fail.");
+        net_control_thread_id = -1;
+        net_control_thread_running = FALSE;
+        return -1;
+    }
+#endif
+    LOGI("net_control_init() success.");
+    return 0;
+}
+
+static int net_control_state_change(bool enable)
+{
+    int size;
+    char result[NET_CONTROL_BUF_SIZE];
+    char cmd[100];
+    if(enable)
+    {
+        // ifconfig seth_lte1 up
+        // ip route add default via 10.94.251.205 dev seth_lte1
+        size = snprintf(cmd,100,"ifconfig %s up",net_interface);
+        cmd[size] = '\0';
+
+        if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+        {
+            size = snprintf(cmd,100,"ip route add default via %s dev %s",net_ip,net_interface);
+            cmd[size] = '\0';
+
+            if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+            {
+                net_state = MBTK_NET_STATE_CONN;
+                return 0;
+            }
+        }
+    }
+    else
+    {
+        // ifconfig seth_lte1 down
+        size = snprintf(cmd,100,"ifconfig %s down",net_interface);
+        cmd[size] = '\0';
+
+        if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+        {
+            net_state = MBTK_NET_STATE_OFF;
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+/*************************************************************
+    Public Function Definitions
+*************************************************************/
+/*=============================================
+FUNCTION
+    mbtk_net_state_get()
+
+DESCRIPTION
+    Get network state.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    None
+
+RETURN VALUE
+    Current network state.
+
+SIDE EFFECTS
+    None
+=============================================*/
+mbtk_net_state_t mbtk_net_state_get()
+{
+    net_control_init();
+
+    net_state = MBTK_NET_STATE_OFF;
+    if(strlen(net_ip) > 0)
+    {
+        if(net_connected(net_interface))
+            net_state = MBTK_NET_STATE_CONN;
+    }
+
+    LOGI("[GET]Net state:%d",net_state);
+
+    if(net_state == MBTK_NET_STATE_CONN)
+    {
+        char value[PROPERTY_VALUE_MAX] = {0};
+        if (property_get("persist.mbtk.netstate", value, "0,0") > 0 && strcmp(value,"0,0")) {
+            int regStatus = 0, gprsState = 0;
+            char *ptr = value;
+            regStatus = atoi(ptr);
+            if((ptr = strstr(ptr, ",")))
+            {
+                gprsState = atoi(ptr + 1);
+            }
+
+            LOGI("regStatus : %d, gprsState : %d", regStatus, gprsState);
+            if(regStatus != 1 && regStatus != 5)   // Not Home/Roaming Network.
+            {
+                net_state = MBTK_NET_STATE_CONN_UNKNOWN;
+            }
+            else
+            {
+                if (gprsState == RADIO_TECH_LTE || gprsState == RADIO_TECH_LTEP)
+                {
+                    net_state = MBTK_NET_STATE_CONN_4G;
+                }
+                else if ((gprsState == RADIO_TECH_GPRS) || (gprsState == RADIO_TECH_EDGE) || (gprsState == RADIO_TECH_GSM))
+                {
+                    net_state = MBTK_NET_STATE_CONN_2G;
+                } else if((gprsState == RADIO_TECH_UMTS) || (gprsState == RADIO_TECH_HSDPA)
+                         || (gprsState == RADIO_TECH_HSUPA) || (gprsState == RADIO_TECH_HSPA)) {
+                    net_state = MBTK_NET_STATE_CONN_3G;
+                } else {
+                    net_state = MBTK_NET_STATE_CONN_UNKNOWN;
+                }
+            }
+        }
+        else
+        {
+            LOGE("property_get persist.mbtk.netstate fail.");
+            net_state = MBTK_NET_STATE_CONN_UNKNOWN;
+            goto end;
+        }
+    }
+
+end:
+    return net_state;
+}
+
+/*=============================================
+FUNCTION
+    mbtk_net_enable()
+
+DESCRIPTION
+    Set network state.
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    enable
+        TRUE : Enable network.
+        FALSE: Diable network.
+
+RETURN VALUE
+    0 : Success
+    -1: Fail
+
+SIDE EFFECTS
+    None
+=============================================*/
+int mbtk_net_enable(bool enable)
+{
+    if( net_control_init())
+        return -1;
+
+    int result = net_control_state_change(enable);
+
+    LOGI("[SET]Net state:%d",net_state);
+
+    return result;
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_ntp.c b/mbtk/mbtk_lib/src/mbtk_ntp.c
new file mode 100755
index 0000000..de92991
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_ntp.c
@@ -0,0 +1,289 @@
+/*
+* FILE: ntp.c
+* NOTE: socket网络编程学习,NTP时间获取程序
+*
+* TIME: 2021年11月13日00:05:39
+*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <netinet/in.h>
+
+#include "mbtk_log.h"
+
+#define   NTP_PORT   123
+#define   TIME_PORT  37
+#define   NTP_SERVER_IP  "cn.pool.ntp.org"
+
+#define   NTP_PORT_STR   "123"
+#define   NTPV1       "NTP/V1"
+#define NTPV2 "NTP/V2"
+
+#define NTPV3 "NTP/V3"
+#define NTPV4 "NTP/V4"
+#define TIME "TIME/UDP"
+
+#define   NTP_PCK_LEN   48
+
+#define LI 0
+#define VN 3
+#define MODE 3
+#define STRATUM 0
+#define POLL 4
+#define PREC -6
+
+#define JAN_1970 0x83aa7e80 /* 1900 年~1970 年之间的时间秒数 */
+#define NTPFRAC(x) (4294 * (x) + ((1981 * (x)) >> 11))
+#define USEC(x) (((x) >> 12) - 759 * ((((x) >> 10) + 32768) >> 16))
+
+
+time_t sys_time;
+typedef struct _ntp_time
+{
+    unsigned int coarse;
+    unsigned int fine;
+} ntp_time;
+
+/* NTP时钟同步报文 */
+struct ntp_packet
+{
+    unsigned char leap_ver_mode;
+    unsigned char startum;
+    char poll;
+    char precision;
+    int root_delay;
+    int root_dispersion;
+    int reference_identifier;
+    ntp_time reference_timestamp;
+    ntp_time originage_timestamp;
+    ntp_time receive_timestamp;
+    ntp_time transmit_timestamp;
+};
+
+char protocol[32];
+
+int construct_packet(char *packet)
+{
+    char version = 1;
+    long tmp_wrd;
+    int port;
+    time_t timer;
+    strcpy(protocol, NTPV4);
+    /*判断协议版本*/
+    if(!strcmp(protocol, NTPV1)||!strcmp(protocol, NTPV2)||!strcmp(protocol, NTPV3)||!strcmp(protocol, NTPV4))
+    {
+        memset(packet, 0, NTP_PCK_LEN);
+        port = NTP_PORT;
+        /*设置 16 字节的包头*/
+        version = protocol[5] - 0x30;
+        tmp_wrd = htonl((LI << 30)|(version << 27) \
+            |(MODE << 24)|(STRATUM << 16)|(POLL << 8)|(PREC & 0xff));
+        memcpy(packet, &tmp_wrd, sizeof(tmp_wrd));
+
+        /*设置 Root Delay、 Root Dispersion 和 Reference Indentifier */
+        tmp_wrd = htonl(1<<16);
+        memcpy(&packet[4], &tmp_wrd, sizeof(tmp_wrd));
+        memcpy(&packet[8], &tmp_wrd, sizeof(tmp_wrd));
+        /*设置 Timestamp 部分*/
+        time(&timer);
+        /*设置 Transmit Timestamp coarse*/
+        tmp_wrd = htonl(JAN_1970 + (long)timer);
+        memcpy(&packet[40], &tmp_wrd, sizeof(tmp_wrd));
+        /*设置 Transmit Timestamp fine*/
+        tmp_wrd = htonl((long)NTPFRAC(timer));
+        memcpy(&packet[44], &tmp_wrd, sizeof(tmp_wrd));
+        return NTP_PCK_LEN;
+    }
+    else if (!strcmp(protocol, TIME))/* "TIME/UDP" */
+    {
+        port = TIME_PORT;
+        memset(packet, 0, 4);
+        return 4;
+    }
+
+    return 0;
+}
+
+/*获取 NTP 时间*/
+int get_ntp_time(int sk, struct addrinfo *addr, struct ntp_packet *ret_time)
+{
+    fd_set pending_data;
+    struct timeval block_time;
+    char data[NTP_PCK_LEN * 8];
+    int packet_len, data_len = addr->ai_addrlen, count = 0, result, i,re;
+
+    /* 组织请求报文 */
+    if (!(packet_len = construct_packet(data)))
+    {
+        return 0;
+    }
+    /*客户端给服务器端发送 NTP 协议数据包*/
+    if ((result = sendto(sk, data, packet_len, 0, addr->ai_addr, data_len)) < 0)
+    {
+        LOGE("sendto");
+        return 0;
+    }
+    /*调用select()函数,并设定超时时间为10s*/
+    FD_ZERO(&pending_data);
+    FD_SET(sk, &pending_data);
+    block_time.tv_sec=10;
+    block_time.tv_usec=0;
+    if (select(sk + 1, &pending_data, NULL, NULL, &block_time) > 0)
+    {
+        /*接收服务器端的信息*/
+        if ((count = recvfrom(sk, data, NTP_PCK_LEN * 8, 0, addr->ai_addr, &data_len)) < 0)
+        {
+            LOGE("recvfrom");
+            return 0;
+        }
+
+       // if (protocol == TIME)
+        if(!strcmp(protocol,TIME))
+        {
+            memcpy(&ret_time->transmit_timestamp, data, 4);
+            return 1;
+        }
+        else if (count < NTP_PCK_LEN)
+        {
+            return 0;
+        }
+
+        /* 设置接收 NTP 包的数据结构 */
+        ret_time->leap_ver_mode = ntohl(data[0]);
+        ret_time->startum = ntohl(data[1]);
+        ret_time->poll = ntohl(data[2]);
+        ret_time->precision = ntohl(data[3]);
+        ret_time->root_delay = ntohl(*(int*)&(data[4]));
+        ret_time->root_dispersion = ntohl(*(int*)&(data[8]));
+        ret_time->reference_identifier = ntohl(*(int*)&(data[12]));
+        ret_time->reference_timestamp.coarse = ntohl(*(int*)&(data[16]));
+        ret_time->reference_timestamp.fine = ntohl(*(int*)&(data[20]));
+        ret_time->originage_timestamp.coarse = ntohl(*(int*)&(data[24]));
+        ret_time->originage_timestamp.fine = ntohl(*(int*)&(data[28]));
+        ret_time->receive_timestamp.coarse = ntohl(*(int*)&(data[32]));
+        ret_time->receive_timestamp.fine = ntohl(*(int*)&(data[36]));
+        ret_time->transmit_timestamp.coarse = ntohl(*(int*)&(data[40]));
+        ret_time->transmit_timestamp.fine = ntohl(*(int*)&(data[44]));
+
+        /* 将NTP时间戳转换为日期 */
+        time_t currentTime = ret_time->transmit_timestamp.coarse - JAN_1970;
+        sys_time = ret_time->transmit_timestamp.coarse - JAN_1970;
+        struct tm CurlocalTime;
+        localtime_r(&currentTime, &CurlocalTime);
+        char dateTime[30];
+        strftime(dateTime, 30, "%Y-%m-%d %H:%M:%S %A", &CurlocalTime);
+
+        LOGI("%s\n", dateTime);
+
+        return 1;
+    } /* end of if select */
+
+
+    return 0;
+}
+
+/* 修改本地时间 */
+int set_local_time(struct ntp_packet * pnew_time_packet)
+{
+    struct timeval tv;
+    tv.tv_sec = pnew_time_packet->transmit_timestamp.coarse - JAN_1970;
+    tv.tv_usec = USEC(pnew_time_packet->transmit_timestamp.fine);
+    return settimeofday(&tv, NULL);
+}
+
+int ntp_main()
+{
+    int sockfd, rc;
+    struct addrinfo hints, *res = NULL;
+    struct ntp_packet new_time_packet;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_DGRAM;
+    hints.ai_protocol = IPPROTO_UDP;
+
+    /*调用 getaddrinfo()函数, 获取地址信息*/
+    rc = getaddrinfo(NTP_SERVER_IP, NTP_PORT_STR, &hints, &res);
+    if (rc != 0)
+    {
+        LOGE("getaddrinfo");
+        return 0;
+    }
+
+    /* 创建套接字 */
+    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //IPv4, 数据报套接字, UDP
+    if (sockfd <0 )
+    {
+        LOGE("socket");
+        return 0;
+    }
+
+    /*调用取得 NTP 时间的函数*/
+    if (get_ntp_time(sockfd, res, &new_time_packet))
+    {
+        LOGI("NTP client success!\n");
+    }
+
+    close(sockfd);
+
+    return sys_time;
+}
+
+time_t ntp_server_set(const char* server_ip, const char * port)
+{
+    int sockfd, rc;
+    struct addrinfo hints, *res = NULL;
+    struct ntp_packet new_time_packet;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_DGRAM;
+    hints.ai_protocol = IPPROTO_UDP;
+
+    printf("server_ip:%s,port:%s\n", server_ip, port);
+
+    /*调用 getaddrinfo()函数, 获取地址信息*/
+    rc = getaddrinfo(NTP_SERVER_IP, NTP_PORT_STR, &hints, &res);
+    if (rc != 0)
+    {
+        printf("getaddrinfo");
+        return 0;
+    }
+
+    /* 创建套接字 */
+    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //IPv4, 数据报套接字, UDP
+    if (sockfd <0 )
+    {
+        printf("socket");
+        return 0;
+    }
+
+    /*调用取得 NTP 时间的函数*/
+    if (get_ntp_time(sockfd, res, &new_time_packet))
+    {
+        printf("NTP client success!\n");
+    }
+
+    close(sockfd);
+
+    return sys_time;
+}
+
+
+time_t mbtk_ntp_server_set(const char* server_ip, const char * port)
+{
+    return ntp_server_set(server_ip, port);
+}
+
+
+int mbtk_at_systime(void)
+{
+    return ntp_main();
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_pdu_sms.c b/mbtk/mbtk_lib/src/mbtk_pdu_sms.c
new file mode 100755
index 0000000..5825cb6
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_pdu_sms.c
@@ -0,0 +1,1086 @@
+//

+// Created by hitmoon on 15-12-9.

+//

+

+#include <stddef.h>

+#include <stdlib.h>

+#include <stdio.h>

+#include "mbtk_pdu_sms.h"

+#include "mbtk_alphabet.h"

+

+#define SUB_STR_SIZE 512

+char temp[SUB_STR_SIZE];

+

+// some constant

+

+//长短信信息元素参考号

+enum EnumCSMIEI mCSMIEI;

+// 服务中心地址

+char *mSCA;

+// 请求状态报告

+bool mSRR;

+// 拒绝副本

+bool mRD;

+// 短信有效期

+char *mVP;

+// 长短信信息元素消息参考号

+int mCSMMR;

+

+// initialize PDU constants

+void sms_init()

+{

+    mCSMMR = 0;

+    mRD = false;

+    mSRR = false;

+    mSCA = "";

+    mVP = "";

+    mCSMIEI = BIT8MIEI;

+}

+

+

+char *sub_str(const char *str, int start, int size) {

+    memset(temp, '\0', SUB_STR_SIZE);

+    if (size > 0)

+        strncpy(temp, str + start, size);

+    else if (size < 0)

+        strcpy(temp, str + start);

+

+    return temp;

+}

+

+struct SMS_Struct PDUDecoding(const char *data) {

+

+    struct SMS_Struct sms;

+    int end_index;

+    int PDUType;

+    // 短信中心

+    sms.SCA = SCADecoding(data, &end_index);

+

+    // 协议数据单元类型

+    PDUType = strtol(sub_str(data, end_index, 2), NULL, 16);

+    end_index += 2;

+

+    sms.RP = PDUType & (1 << 7) ? true : false;   // 应答路径

+    sms.UDHI = PDUType & (1 << 6) ? true : false;  // 用户数据头标识

+    sms.SRI = PDUType & (1 << 5) ? true : false;  // 状态报告指示

+    sms.MMS = PDUType & (1 << 2) ? false : true;  // 更多信息发送

+    sms.MTI = PDUType & 3;                        // 信息类型指示

+

+    // 发送方SME的地址

+    sms.OA = OADecoding(data, end_index, &end_index);

+

+    // 协议标识

+    sms.PID = strtol(sub_str(data, end_index, 2), NULL, 16);

+    end_index += 2;

+

+    // 数据编码方案

+    int DCSType = strtol(sub_str(data, end_index, 2), NULL, 16);

+    end_index += 2;

+

+    // 文本压缩指示

+    sms.TC = DCSType & (1 << 5);

+    // 编码字符集

+    sms.DCS = (enum EnumDCS) ((DCSType >> 2) & 3);

+

+    if (DCSType & (1 << 4)) {

+        // 信息类型信息 0:立即显示 1:移动设备特定类型 2:SIM特定类型 3:终端设备特定类型

+        sms.MC = DCSType & 3;

+    }

+    else {

+        // 不含信息类型信息

+        sms.MC = -1;

+    }

+    // 服务中心时间戳(BCD编码)

+    sms.SCTS = SCTSDecoding(data, end_index);

+    end_index += 14;

+

+    // 用户数据头

+    if (sms.UDHI) {

+        sms.UDH = UDHDecoding(data, end_index + 2);

+    }

+    else {

+        sms.UDH = NULL;

+    }

+

+    // 用户数据

+    sms.UD = UserDataDecoding(data, end_index, sms.UDHI, sms.DCS);

+

+    return sms;

+}

+

+

+char *SCADecoding(const char *data, int *EndIndex) {

+    int len;

+

+    char *result;

+    char *buf;

+	int i = 0;

+

+    len = strtol(sub_str(data, 0, 2), NULL, 16);

+    if (len == 0) {

+        *EndIndex = 2;

+        return NULL;

+    }

+

+    *EndIndex = (len + 1) * 2;

+

+    result = (char *) malloc(sizeof(char) * len * 2);

+    //wmemset(result, '0', sizeof(char) * (len * 2 + 1));

+

+    buf = result;

+    len *= 2;

+

+    // 服务中心地址类型

+    if (strncmp(data + 2, "91", 2) == 0) {

+        sprintf(buf++, "+");

+    }

+

+    // 服务中心地

+

+	for (i = 4; i < *EndIndex; i += 2) {

+        sprintf(buf++, "%c", data[i + 1]);

+        sprintf(buf++, "%c", data[i]);

+    }

+

+    //  去掉填充的 'F'

+    if (result[strlen(result) - 1] == L'F') {

+        result[strlen(result) - 1] = L'\0';

+    }

+

+    return result;

+}

+

+char *OADecoding(const char *data, int index, int *EndIndex) {

+    int len;

+    char *result, *buf;

+

+    len = strtol(sub_str(data, index, 2), NULL, 16);

+

+    if (len == 0) {

+        *EndIndex = index + 2;

+        return NULL;

+    }

+

+    *EndIndex = index + 4 + len;

+

+    result = (char *) malloc(sizeof(char) * (len + 2));

+    //wmemset(result, 0, sizeof(char) * (len + 1));

+    buf = result;

+    

+    if (strncmp(data + index + 2, "91", 2) == 0) {

+        sprintf(buf++, "+");

+    }

+

+    // 电话号码

+	int i = 0;

+    for (i = 0; i < len; i += 2) {

+        sprintf(buf++, "%c", data[index + i + 5]);

+        sprintf(buf++, "%c", data[index + i + 4]);

+

+    }

+

+    if (len % 2 != 0) {

+        result[strlen(result) - 1] = '\0';

+        (*EndIndex)++;

+    }

+    return result;

+}

+

+char *SCTSDecoding(const char *data, int index) {

+

+    char *result;

+

+    result = (char *) malloc(sizeof(char) * 32);

+    sprintf(result, "20%02d-%02d-%02d %02d:%02d:%02d",

+             BCDDecoding(data, index, 0),                // 年

+             BCDDecoding(data, index + 2, 0),            // 月

+             BCDDecoding(data, index + 4, 0),            // 日

+             BCDDecoding(data, index + 6, 0),            // 时

+             BCDDecoding(data, index + 8, 0),            // 分

+             BCDDecoding(data, index + 10, 0)            // 秒

+

+    );

+    return result;

+}

+

+int BCDDecoding(const char *data, int index, bool isMSB) {

+

+    int n1, n10;

+

+    n1 = strtol(sub_str(data, index, 1), NULL, 10);

+    n10 = strtol(sub_str(data, index + 1, 1), NULL, 10);

+

+    if (isMSB) {

+        if (n10 >= 8)

+            return -((n10 - 8) * 10 + n1); // 负值

+        else

+            return n10 * 10 + n1;

+    }

+    else {

+        return n10 * 10 + n1;

+    }

+}

+

+struct UDHS *UDHDecoding(const char *data, int index) {

+

+    int len;

+    struct UDHS *result;

+

+    len = strtol(sub_str(data, index, 2), NULL, 16);

+    index += 2;

+    int i = 0;

+

+    result = (struct UDHS *) malloc(sizeof(struct UDHS));

+    result->UDH = (struct PDUUDH *) malloc(sizeof(struct PDUUDH) * len);

+    result->count = 0;

+    memset(result->UDH, 0, sizeof(struct PDUUDH) * len);

+

+    while (i < len) {

+        // 信息元素标识(Information Element Identifier

+        char IEI = strtol(sub_str(data, index, 2), NULL, 16);

+        index += 2;

+        // 信息元素数据长度(Length of Information Element)

+        int IEDL = strtol(sub_str(data, index, 2), NULL, 16);

+        index += 2;

+        // 信息元素数据(Information Element Data)

+        char *IED = (char *) malloc(sizeof(char) * (IEDL + 1));

+        int j = 0;

+		for (j = 0; j < IEDL; j++) {

+            IED[j] = strtol(sub_str(data, index, 2), NULL, 16);

+            index += 2;

+        }

+        result->UDH[result->count].IEI = IEI;

+        result->UDH[result->count].IED = IED;

+        result->count++;

+        i += IEDL + 2;

+    }

+

+    return result;

+}

+

+char *UserDataDecoding(const char *data, int index, bool UDHI, enum EnumDCS dcs) {

+    char *result = NULL;

+    char *buf;

+

+    // 用户数据区长度

+    int UDL = strtol(sub_str(data, index, 2), NULL, 16);

+    index += 2;

+

+    // 跳过用户数据头

+    int UDHL = 0;

+    if (UDHI) {

+        // 用户数据头长度

+        UDHL = strtol(sub_str(data, index, 2), NULL, 16);

+        UDHL++;

+        index += UDHL << 1;

+

+    }

+

+    // 获取用户数据

+    if (dcs == UCS2) {

+        int len = (UDL - UDHL) >> 1;

+        int utf8_len;

+

+        result = (char *) malloc(sizeof(char) * (len * 3));

+        buf = result;

+        u_int32_t code[2];

+

+		int i = 0;

+        for (i = 0; i < len; i++) {

+            code[0] = strtol(sub_str(data, (i << 2) + index, 4), NULL, 16);

+            code[1] = 0;

+            utf32toutf8((wchar_t*)code, (unsigned char*)buf, len * 3, &utf8_len);

+            buf += utf8_len;

+        }

+

+        buf[0] = '\0';

+        return result;

+    }

+    else if (dcs == BIT7) {

+        int Septets = UDL - (UDHL * 8 + 6) / 7;           // 7-Bit编码字符数

+

+        int FillBits = (UDHL * 8 + 6) / 7 * 7 - UDHL * 8; //  填充位数

+        return BIT7Decoding(BIT7Unpack(data, index, Septets, FillBits), Septets);

+    }

+    else {// 8Bit编码

+        // 获取数据长度

+        UDL -= UDHL;

+        result = (char *) malloc(sizeof(char) * (UDL + 1));

+        int i = 0;

+		for (i = 0; i < UDL; i++) {

+            result[i] = strtol(sub_str(data, (i << 1) + index, 2), NULL, 16);

+        }

+        return result;

+    }

+

+    return "Error!";

+}

+

+char *BIT7Unpack(const char *data, int index, int Septets, int FillBits) {

+    char *result;

+

+    result = (char *) malloc(sizeof(char) * (Septets + 1));

+    // 每8个7-Bit编码字符存放到7个字节

+    int PackLen = (Septets * 7 + FillBits + 7) / 8;

+    int n = 0;

+    int left = 0;

+

+//    printf("Unapck data = %s\n", data + index);

+//    printf("Septets = %d\n", Septets);

+//    printf("pack len = %d\n", PackLen);

+//    printf("fillbits = %d\n", FillBits);

+

+	int i = 0;

+    for (i = 0; i < PackLen; i++) {

+

+        int Order = (i + (7 - FillBits)) % 7;

+        int Value = strtol(sub_str(data, (i << 1) + index, 2), NULL, 16);

+        if (i != 0 || FillBits == 0) {

+            result[n++] = ((Value << Order) + left) & 0x7F;

+        }

+//        printf("left = %d, i = %d, order = %d, value = %d\n", left, i, Order, Value);

+//        printf("result[%d] = %d\n", n - 1, result[n - 1]);

+        left = Value >> (7 - Order);

+        if (Order == 6) {

+            if (n == Septets)

+                break;

+            result[n++] = left;

+            //printf("result[%d] = %d\n", n - 1, result[n - 1]);

+            left = 0;

+        }

+    }

+

+    return result;

+}

+

+char *BIT7Decoding(char *BIT7Data, unsigned int size)

+{

+    char *result, *buf;

+

+    result = (char *) malloc(sizeof(char) * (size + 1));

+    buf = result;

+

+	int i = 0;

+    for (i = 0; i < size; i++) {

+        u_int16_t key = BIT7Data[i];

+        if (isBIT7Same(key)) {

+            sprintf(buf++, "%c", key);

+        }

+        else if (map_get_value(BIT7ToUCS2, map_size(BIT7ToUCS2), key) >= 0) {

+            u_int16_t value;

+            if (key == 0x1B) { // 转义字符

+                value = map_get_value(BIT7EToUCS2, map_size(BIT7EToUCS2), BIT7Data[i + 1]);

+                if (i < size - 1 && value > 0) {

+                    sprintf(buf++, "%c", value);

+                    i++;

+                }

+                else {

+                    value = map_get_value(BIT7ToUCS2, map_size(BIT7ToUCS2), key);

+                    sprintf(buf++, "%c", value);

+                }

+            }

+            else {

+                //printf("go b\n");

+                value = map_get_value(BIT7ToUCS2, map_size(BIT7ToUCS2), key);

+                //printf("value = %u\n", value);

+                sprintf(buf++, "%c", value);

+

+            }

+        }

+        else {// 异常数据

+            sprintf(buf++, "?");

+        }

+

+    }

+    return result;

+

+}

+

+int isBIT7Same(u_int16_t UCS2) {

+	if ((UCS2 >= 0x61 && UCS2 <= 0x7A) ||

+	    (UCS2 >= 0x41 && UCS2 <= 0x5A) ||

+	    (UCS2 >= 0x25 && UCS2 <= 0x3F) ||

+	    (UCS2 >= 0x20 && UCS2 <= 0x23) ||

+	    UCS2 == 0x0A || UCS2 == 0x0D) {

+        return 1;

+    }

+    return 0;

+}

+

+struct PDUS *PDUEncoding(char *SCA, char *DA, char *UDC, struct UDHS *udhs) {

+    enum EnumDCS DCS;

+

+    sms_init();

+

+//    if (isGSMString(UDC))

+//        DCS = BIT7;

+//    else

+        DCS = UCS2;

+

+    return PDUDoEncoding(SCA, DA, UDC, udhs, DCS);

+}

+

+struct PDUS *PDUDoEncoding(char *SCA, char *DA, char *UDC, struct UDHS *udhs, enum EnumDCS DCS) {

+    // 短信拆分

+    struct UDS *uds = UDCSplit(UDC, udhs, DCS);

+    struct PDUS *pdus;

+

+    if (uds == NULL)

+        return NULL;

+    pdus = (struct PDUS *) malloc(sizeof(struct PDUS));

+    pdus->count = 0;

+    pdus->PDU = (char **) malloc(sizeof(char *) * uds->total);

+

+    if (uds->total > 1) {

+        // 长短信

+        int CSMMR = mCSMMR;

+        if (++mCSMMR > 0xFFFF)

+            mCSMMR = 0;

+        // 生成短信编码序列

+		int i = 0;

+        for (i = 0; i < uds->total; i++) {

+            // 更新用户数据头

+            struct UDHS *CSMUDH = UpdateUDH(udhs, CSMMR, uds->total, i);

+            pdus->PDU[i] = SoloPDUEncoding(SCA, DA, uds->Data[i], CSMUDH, DCS);

+            pdus->count++;

+        }

+

+    }

+    else {  // 单条短信

+        pdus->PDU[0] = SoloPDUEncoding(SCA, DA, uds->Data[0], udhs, DCS);

+        pdus->count = 1;

+    }

+

+    return pdus;

+}

+

+int isGSMString(char *Data) {

+

+    if (Data == NULL || strcmp(Data, "") == 0)

+        return 1;

+

+    if (is_acsii((unsigned char*)Data) == 0) {

+        int len;

+        len = utf8len((unsigned char *) Data); 

+

+        u_int16_t *code = (u_int16_t *) malloc(sizeof(u_int16_t) * len);

+        utf8toutf16((unsigned char *) Data, code, len, &len);

+

+        while (*code) {

+            if (!(isBIT7Same(*code) || map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), *code) >= 0))

+                return 0;

+            code++;

+        }

+

+        return 1;

+    }

+    else

+        return 1;

+

+}

+

+struct UDS *UDCSplit(char *UDC, struct UDHS *udhs, enum EnumDCS DCS) {

+    int UDHL = getUDHL(udhs);

+    struct UDS *result;

+

+    if (DCS == BIT7) {

+        // 7-Bit编码

+        // 计算剩余房间数

+        int room = BIT7UDL - (UDHL * 8 + 6) / 7;

+        if (room < 1) {

+            if (UDC == NULL || strcmp(UDC, "") == 0) {

+                result = (struct UDS *) malloc(sizeof(struct UDS));

+                result->Data = (char **)malloc(sizeof(char *));

+                result->total = 1;

+                result->Data[0] = UDC;

+                return result;

+            }

+            else

+                return NULL;

+        }

+

+        // 不需要拆分

+        if (SeptetsLength(UDC) <= room) {

+            result = (struct UDS *) malloc(sizeof(struct UDS));

+            result->Data = (char **)malloc(sizeof(char *));

+            result->total = 1;

+            result->Data[0] = UDC;

+            return result;

+        }

+        else // 拆分短信

+        {

+            if (UDHL == 0)

+                UDHL++;

+            if (mCSMIEI == BIT8MIEI)

+                UDHL += 5;  // 1字节消息参考号

+            else

+                UDHL += 6;  // 2字节消息参考号

+            // 更新剩余房间数

+            room = BIT7UDL - (UDHL * 8 + 6) / 7;

+            if (room < 1)

+                return NULL;

+

+            int i = 0;

+            int len = strlen(UDC);

+

+            result = (struct UDS *) malloc(sizeof(struct UDS));

+            result->total = 0;

+            result->Data = (char **) malloc(MAX_SMS_NR * sizeof(char *));

+

+            while (i < len) {

+                int step = SeptetsToChars(UDC, i, room);

+                if (i + step < len) {

+                    result->Data[result->total] = (char *) malloc(sizeof(char) * (step + 1));

+                    strcpy(result->Data[result->total++], sub_str(UDC, i, step));

+                }

+                else {

+                    result->Data[result->total] = (char *) malloc(sizeof(char) * (len - i + 1));

+                    strcpy(result->Data[result->total++], sub_str(UDC, i, -1));

+                }

+

+                i += step;

+

+            }

+            return result;

+

+        }

+    }

+    else { // UCS2编码

+        // 计算剩余房间数

+        int room = (BIT8UDL - UDHL) >> 1;

+        if (room < 1) {

+            if (UDC == NULL || strcmp(UDC, "") == 0) {

+                result = (struct UDS *) malloc(sizeof(struct UDS));

+                result->Data = (char **)malloc(sizeof(char *));

+                result->total = 1;

+                result->Data[0] = UDC;

+                return result;

+            }

+            else

+                return NULL;

+        }

+        if (UDC == NULL || utf8len(UDC) <= room) {

+            result = (struct UDS *) malloc(sizeof(struct UDS));

+            result->Data = (char **)malloc(sizeof(char *));

+            result->total = 1;

+            result->Data[0] = UDC;

+            return result;

+        }

+        else // 需要拆分成多条短信

+        {

+            if (UDHL == 0)

+                UDHL++;

+            if (mCSMIEI == BIT8MIEI)

+                UDHL += 5;  // 1字节消息参考号

+            else

+                UDHL += 6;  // 2字节消息参考号

+

+            // 更新剩余房间数

+            room = (BIT8UDL - UDHL) >> 1;

+            if (room < 1)

+                return NULL;

+

+            int len = utf8len(UDC);

+

+            result = (struct UDS *) malloc(sizeof(struct UDS));

+            result->total = 0;

+            result->Data = (char **) malloc(MAX_SMS_NR * sizeof(char *));

+	    int index = 0;

+		int i = 0;

+            for (i = 0; i < len; i += room) {

+		    int real_size;

+                if (i + room < len) {

+		    real_size = utf8_get_size(UDC + index, room);

+                    result->Data[result->total] = (char*)malloc(sizeof(char) * (real_size + 1));

+                    strcpy(result->Data[result->total++],sub_str(UDC, index, real_size));

+                }

+                else {

+		    real_size = utf8_get_size(UDC + index, len - i);

+                    result->Data[result->total] = (char*)malloc(sizeof(char) * (real_size + 1));

+                    strcpy(result->Data[result->total++], sub_str(UDC, index, -1));

+                }

+		index += real_size;

+            }

+            return result;

+        }

+

+    }

+}

+

+int getUDHL(struct UDHS *udhs) {

+    if (udhs == NULL)

+        return 0;

+

+    // 加上1字节的用户数据头长度

+    int UDHL = 1;

+	int i = 0;

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

+        UDHL += strlen(udhs->UDH[i].IED) + 2;

+    }

+    return UDHL;

+}

+

+int SeptetsLength(char *source) {

+    if (source == NULL || strcmp(source, "") == 0) {

+        return 0;

+    }

+    int len = strlen(source);

+    while (*source) {

+        u_int16_t code = (u_int16_t) *source;

+        if (map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), code) > 0xFF) {

+            len++;

+        }

+        source++;

+    }

+    return len;

+}

+

+int SeptetsToChars(char *source, int index, int septets) {

+    if (source == NULL || strcmp(source, "") == 0)

+        return 0;

+    int count = 0;

+    int i;

+

+    for (i = index; i < strlen(source); i++) {

+        u_int16_t code = (u_int16_t) source[i];

+        if (map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), code) > 0xFF)

+            count++;

+

+        if (++count >= septets) {

+            if (count == septets)

+                i++;

+            break;

+        }

+    }

+    return i - index;

+}

+

+struct UDHS *UpdateUDH(struct UDHS *udhs, int CSMMR, int total, int index) {

+    struct UDHS *result;

+

+    result = (struct UDHS *) malloc(sizeof(struct UDHS));

+

+    if (udhs == NULL || udhs->count == 0) {

+        result->UDH = (struct PDUUDH *) malloc(sizeof(struct PDUUDH));

+        result->count = 1;

+

+    }

+    else {

+        result->UDH = (struct PDUUDH *) malloc(sizeof(struct PDUUDH) * (udhs->count + 1));

+        result->count = udhs->count + 1;

+        // 复制 UDH

+        memcpy(&result->UDH[1], udhs->UDH, sizeof(struct PDUUDH) * udhs->count);

+    }

+    // 插入第一个位置

+    if (mCSMIEI == BIT8MIEI) {

+        result->UDH[0].IED = (char *) malloc(sizeof(char) * 3);

+        result->UDH[0].count = 3;

+        result->UDH[0].IED[0] = CSMMR & 0xFF;

+        result->UDH[0].IED[1] = total;

+        result->UDH[0].IED[2] = index + 1;

+        result->UDH[0].IEI = 0;

+    }

+    else {

+        result->UDH[0].IED = (char *) malloc(sizeof(char) * 4);

+        result->UDH[0].count = 4;

+        result->UDH[0].IED[0] = (CSMMR >> 8) & 0xFF;

+        result->UDH[0].IED[1] = CSMMR & 0xFF;

+        result->UDH[0].IED[2] = total;

+        result->UDH[0].IED[3] = index + 1;

+        result->UDH[0].IEI = 8;

+    }

+

+    return result;

+}

+

+char *SoloPDUEncoding(char *SCA, char *DA, char *UC, struct UDHS *udhs, enum EnumDCS DCS) {

+    char *result;

+    char *buf, *ret;

+    int index;

+

+    result = (char *) malloc(sizeof(char) * 400);

+    buf = result;

+

+/*    //  短信中心

+	ret = SCAEncoding(SCA);

+    index = strlen(ret);

+    sprintf(buf, "%s", ret);

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

+    buf += index;

+

+*/

+    // 协议数据单元类型

+    if (udhs == NULL || udhs->count == 0) {

+        ret = PDUTypeEncoding(false);

+        sprintf(buf, "%s", ret);

+        buf += strlen(ret);

+    }

+    else {

+        ret = PDUTypeEncoding(true);

+        sprintf(buf, "%s", ret);

+        buf += strlen(ret);

+    }

+    // 消息参考值

+    ret = MREncoding();

+    sprintf(buf, "%s", ret);

+    buf += strlen(ret);

+    // 接收方SME地址

+    ret = DAEncoding(DA);

+    sprintf(buf, "%s", ret);

+    buf += strlen(ret);

+    // 协议标识

+    ret = PIDEncoding();

+    sprintf(buf, "%s", ret);

+    buf += strlen(ret);

+    // 编码方案

+    ret = DCSEncoding(UC, DCS);

+    sprintf(buf, "%s", ret);

+    buf += strlen(ret);

+    // 有效期

+    sprintf(buf, "%s", mVP);

+    buf += strlen(mVP);

+

+    // 用户数据长度及内容

+    ret = UDEncoding(UC, udhs, DCS);

+    sprintf(buf, "%s", ret);

+

+    return result;

+}

+

+char *SCAEncoding(char *SCA) {

+

+    if (SCA == NULL || strcmp(SCA, "") == 0) {

+        // 表示使用SIM卡内部的设置值,该值通过AT+CSCA指令设置

+        return "00";

+    }

+

+    char *result;

+    char *buf;

+    int len;

+    len = strlen(SCA);

+    result = (char *) malloc((len + 5) * sizeof(char));

+    buf = result;

+

+    int index = 0;

+    if (SCA[0] == '+') {

+        // 国际号码

+        sprintf(buf, "%02X", len / 2 + 1);

+        buf += 2;

+        sprintf(buf, "91");

+        buf += 2;

+        index = 1;

+    }

+    else {

+        // 国内号码

+        sprintf(buf, "%02X", len / 2 + 1);

+        buf += 2;

+        sprintf(buf, "81");

+        buf += 2;

+    }

+    // SCA地址编码

+    for (; index < len; index += 2) {

+        if (index == len - 1) {

+            // 补“F”凑成偶数个

+            sprintf(buf++, "F");

+            sprintf(buf++, "%c", SCA[index]);

+

+        }

+        else {

+            sprintf(buf++, "%c", SCA[index + 1]);

+            sprintf(buf++, "%c", SCA[index]);

+        }

+    }

+

+    return result;

+}

+

+char *PDUTypeEncoding(bool UDH) {

+    // 信息类型指示(Message Type Indicator)

+    // 01 SMS-SUBMIT(MS -> SMSC)

+    int PDUType = 0x11;    // 508TLC change

+//	int PDUType = 0x01;

+    char *result;

+    result = (char *) malloc(3 * sizeof(char));

+

+    // 用户数据头标识(User Data Header Indicator)

+    if (UDH) {

+        PDUType |= 0x40;

+    }

+    // 有效期格式(Validity Period Format)

+    if (strlen(mVP) == 2) {

+        // VP段以整型形式提供(相对的)

+        PDUType |= 0x10;

+    }

+    else if (strlen(mVP) == 14) {

+        // VP段以8位组的一半(semi-octet)形式提供(绝对的)

+        PDUType |= 0x18;

+    }

+

+    // 请求状态报告(Status Report Request)

+    if (mSRR) {

+        // 请求状态报告

+        PDUType |= 0x20;

+    }

+

+    // 拒绝复本(Reject Duplicate)

+    if (mRD) {

+        PDUType |= 0x04;

+    }

+    sprintf(result, "%02X", PDUType);

+    return result;

+}

+

+char *MREncoding() {

+    // 由手机设置

+    return "00";

+}

+

+char *DAEncoding(char *DA) {

+    if (DA == NULL || strcmp(DA, "") == 0) {

+        // 地址长度0,地址类型未知

+        return "0080";

+    }

+    char *result, *buf;

+    int len = strlen(DA);

+    int index;

+

+    result = (char *) malloc(sizeof(char) * (len + 5));

+    buf = result;

+

+    if (DA[0] == '+') {

+        // 国际号码

+        // 地址长度编码

+        sprintf(buf, "%02X", len - 1);

+        buf += 2;

+        // 地址类型

+        sprintf(buf, "91");

+        buf += 2;

+        index = 1;

+    }

+    else {

+        // 国内号码

+        // 地址长度编码

+        sprintf(buf, "%02X", len);

+        buf += 2;

+        // 地址类型

+        sprintf(buf, "81");

+        buf += 2;

+    }

+

+    for (; index < len; index += 2) {

+        // 号码部分奇偶位对调

+        if (index == len - 1) {

+            sprintf(buf++, "F");

+            sprintf(buf++, "%c", DA[index]);

+        }

+        else {

+            sprintf(buf++, "%c", DA[index + 1]);

+            sprintf(buf++, "%c", DA[index]);

+        }

+    }

+    return result;

+

+}

+

+char *PIDEncoding() {

+    return "00";

+}

+

+char *DCSEncoding(char *UD, enum EnumDCS DCS) {

+    if (DCS == BIT7) {

+        // 7-Bit编码

+        return "00";

+    }

+    else {

+        // UCS2编码

+        return "0800";

+    }

+}

+

+char *UDEncoding(char *UD, struct UDHS *udhs, enum EnumDCS DCS) {

+    int UDHL;

+

+    char *result;

+

+    // 用户数据头编码

+    char *header = UDHEncoding(udhs, &UDHL);

+

+    // 用户数据内容编码

+    int UDCL;

+    char *body;

+

+    body = UDCEncoding(UD, &UDCL, UDHL, DCS);

+

+    // 用户数据区长度

+    int UDL;

+    if (DCS == BIT7) {

+        // 7-Bit编码

+        UDL = (UDHL * 8 + 6) / 7 + UDCL;

+    }

+    else {

+        // UCS2编码或者8-Bit编码

+        UDL = UDHL + UDCL;

+    }

+

+    int len = strlen(header) + strlen(body) + 2;

+    result = (char *) malloc(sizeof(char) * (len + 1));

+    sprintf(result, "%02X%s%s", UDL, header, body);

+

+    return result;

+

+}

+

+char *UDHEncoding(struct UDHS *udhs, int *UDHL) {

+

+    *UDHL = 0;

+

+    if (udhs == NULL || udhs->count == 0)

+        return "";

+	int i = 0;

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

+        *UDHL += udhs->UDH[i].count + 2;

+    }

+

+    char *result;

+    char *buf;

+    result = (char *) malloc(sizeof(char) * ((*UDHL + 1) * 2 + 1));

+    buf = result;

+

+    sprintf(buf, "%02X", *UDHL);

+    buf += 2;

+	

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

+        // 信息元素标识1字节

+        sprintf(buf, "%02X", udhs->UDH[i].IEI);

+        buf += 2;

+        // 信息元素长度1字节

+        sprintf(buf, "%02X", udhs->UDH[i].count);

+        buf += 2;

+        // 信息元素数据

+		int j = 0;

+        for (j = 0; j < udhs->UDH[i].count; j++) {

+            sprintf(buf, "%02X", udhs->UDH[i].IED[j]);

+            buf += 2;

+        }

+

+    }

+    // 加上1字节的用户数据头长度

+    (*UDHL)++;

+    return result;

+

+}

+

+char *UDCEncoding(char *UDC, int *UDCL, int UDHL, enum EnumDCS DCS) {

+    if (UDC == NULL || strcmp(UDC, "") == 0) {

+        *UDCL = 0;

+        return "";

+    }

+

+    if (DCS == BIT7) {

+        // 7-Bit编码,需要参考用户数据头长度,已保证7-Bit边界对齐

+        return BIT7Pack(BIT7Encoding(UDC, UDCL), UDHL);

+    }

+    else {

+        // UCS2编码

+

+        int len = utf8len((unsigned char*)UDC);

+        int len2;

+        unsigned short *code;

+

+        code = (unsigned short*)malloc(sizeof(unsigned short) * len);

+        utf8toutf16((unsigned char*)UDC, code, len, &len2);

+        *UDCL = len * 2;

+        char *result = (char *) malloc(sizeof(char) * (*UDCL * 2 + 1));

+        char *buf = result;

+

+		int i = 0;

+        for (i = 0; i < len; i++) {

+            sprintf(buf, "%04X", code[i]);

+            buf += 4;

+        }

+        free(code);

+        return result;

+    }

+}

+

+struct ByteArray *BIT7Encoding(char *UDC, int *Septets) {

+    struct ByteArray *result;

+

+    int len = strlen(UDC);

+

+    result = (struct ByteArray *) malloc(sizeof(struct ByteArray));

+    result->len = 0;

+    result->array = (char *) malloc(sizeof(char) * (len * 2 + 1));

+    *Septets = 0;

+

+	int i = 0;

+    for (i = 0; i < len; i++) {

+        u_int16_t code = (u_int16_t) UDC[i];

+        if (isBIT7Same(code)) {

+            //  编码不变

+	    result->array[(*Septets)++] = code;

+        }

+        else {

+            u_int16_t value = map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), code);

+            if (value >= 0) {

+                if (value > 0xFF) {

+                    // 转义序列

+			result->array[(*Septets)++] = value >> 8;

+			result->array[(*Septets)++] = value & 0xFF;

+                }

+                else {

+			result->array[(*Septets)++] = value;

+                }

+            }

+            else {

+                // 未知字符

+		    result->array[(*Septets)++] = (u_int16_t) '?';

+            }

+        }

+    }

+    // 重新调整大小

+    result->len = *Septets;

+

+    return result;

+}

+

+char *BIT7Pack(struct ByteArray *Bit7Array, int UDHL) {

+    // 7Bit对齐需要的填充位

+    int fillBits = (UDHL * 8 + 6) / 7 * 7 - (UDHL * 8);

+

+    // 压缩字节数

+    int len = Bit7Array->len;

+    int packLen = (len * 7 + fillBits + 7) / 8;

+    char *result;

+    char *buf;

+

+    result = (char *) malloc(sizeof(char) * (packLen * 2 + 1));

+    buf = result;

+

+    int left = 0;

+	int i = 0;

+    for (i = 0; i < len; i++) {

+        // 每8个字节压缩成7个字节

+        int32_t Value = Bit7Array->array[i];

+        int32_t index = (i + 8 - fillBits) % 8;

+        if (index == 0) {

+            left = Value;

+        }

+        else {

+            int32_t n = ((Value << (8 - index)) | left) & 0xFF;

+            sprintf(buf, "%02X", n);

+            buf += 2;

+            left = Value >> index;

+        }

+    }

+

+

+    if ((len * 7 + fillBits) % 8 != 0) {

+        // 写入剩余数据

+        sprintf(buf, "%02X", left);

+        buf += 2;

+    }

+    buf[0] = '\0';

+    return result;

+}

+

diff --git a/mbtk/mbtk_lib/src/mbtk_queue.c b/mbtk/mbtk_lib/src/mbtk_queue.c
new file mode 100755
index 0000000..8abc4d1
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_queue.c
@@ -0,0 +1,218 @@
+/*************************************************************
+Description:
+    mbtk_queue.c
+    Used to implement mobiletek standard queue interfaces
+Author:
+    YangDagang
+Date:
+    2019-7-13
+*************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mbtk_type.h"
+#include "mbtk_queue.h"
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+
+/*************************************************************
+    Definitions:enum,struct,union
+*************************************************************/
+
+
+/*************************************************************
+    Variables:local,extern
+*************************************************************/
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Extern Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Function Definitions
+*************************************************************/
+/*=============================================
+FUNCTION
+    mbtk_tcpip_ptr
+
+DESCRIPTION
+    get tcpip information pointer
+
+DEPENDENCIES
+    None
+
+PARAMETERS
+    None
+
+RETURN VALUE
+    tcpip information pointer
+
+SIDE EFFECTS
+    None
+=============================================*/
+void mbtk_queue_init(mbtk_queue_node_t *queue)
+{
+    if(queue == NULL)
+    {
+        return;
+    }
+    queue->count = 0;
+    queue->payload = NULL;
+    queue->front = NULL;
+    queue->rear = NULL;
+    mbtk_mutex_init(&queue->mutex);
+}
+
+int mbtk_queue_put(mbtk_queue_node_t *queue,void *payload)
+{
+    mbtk_queue_node_t *curr = NULL;
+    mbtk_queue_node_t *p = NULL;
+
+    if(payload == NULL || queue == NULL)
+    {
+        return -1;
+    }
+    mbtk_mutex_lock(&queue->mutex);
+    curr = (mbtk_queue_node_t*)malloc(sizeof(mbtk_queue_node_t));
+    if(curr == NULL)
+    {
+        mbtk_mutex_unlock(&queue->mutex);
+        return -1;
+    }
+    curr->count = 0;
+    curr->rear = NULL;
+    curr->payload = payload;
+    if(queue->front != NULL)
+    {
+        p = queue->front;
+        p->rear = curr;
+        curr->front = p;
+        queue->front = curr;
+    }
+    else
+    {
+        //fisrt add node
+        queue->front = curr;
+        queue->rear = curr;
+        curr->front = queue;
+    }
+    queue->count++;
+    mbtk_mutex_unlock(&queue->mutex);
+    return 0;
+}
+
+int mbtk_queue_insert(mbtk_queue_node_t *queue,void *payload)
+{
+    mbtk_queue_node_t *curr = NULL;
+    mbtk_queue_node_t *p = NULL;
+
+    if(payload == NULL || queue == NULL)
+    {
+        return -1;
+    }
+    mbtk_mutex_lock(&queue->mutex);
+    curr = (mbtk_queue_node_t*)malloc(sizeof(mbtk_queue_node_t));
+    if(curr == NULL)
+    {
+        mbtk_mutex_unlock(&queue->mutex);
+        return -1;
+    }
+    curr->rear = NULL;
+    curr->count = 0;
+    curr->payload = payload;
+    if(queue->front != NULL)
+    {
+        p = queue->rear;
+        queue->rear = curr;
+        curr->front = queue;
+        curr->rear = p;
+        p->front = curr;
+    }
+    else
+    {
+        //fisrt add node
+        queue->front = curr;
+        queue->rear = curr;
+        curr->front = queue;
+    }
+    queue->count++;
+    mbtk_mutex_unlock(&queue->mutex);
+    return 0;
+}
+
+void* mbtk_queue_get(mbtk_queue_node_t *queue)
+{
+    mbtk_queue_node_t *curr = NULL;
+    void *payload = NULL;
+
+    if((queue == NULL) || mbtk_queue_empty(queue))
+    {
+        return NULL;
+    }
+    mbtk_mutex_lock(&queue->mutex);
+    curr = queue->rear;
+    payload = curr->payload;
+    if(curr->rear != NULL)
+    {
+        queue->rear = curr->rear;
+        curr->rear->front = queue;
+    }
+    else
+    {
+        queue->front = NULL;
+        queue->rear = NULL;
+    }
+    free(curr);
+    curr = NULL;
+    queue->count--;
+    mbtk_mutex_unlock(&queue->mutex);
+    return payload;
+}
+
+bool mbtk_queue_empty(mbtk_queue_node_t *queue)
+{
+    bool is_empty = FALSE;
+
+    mbtk_mutex_lock(&queue->mutex);
+    if(queue != NULL)
+    {
+        if((queue->front == NULL) && (queue->rear == NULL))
+        {
+            is_empty = TRUE;
+        }
+    }
+    mbtk_mutex_unlock(&queue->mutex);
+    return is_empty;
+}
+
+bool mbtk_queue_is_full(mbtk_queue_node_t *queue)
+{
+    bool is_full = FALSE;
+
+    mbtk_mutex_lock(&queue->mutex);
+    if((queue != NULL) && (queue->count == MBTK_QUEUE_MAX_NUM))
+    {
+        is_full = TRUE;
+    }
+    mbtk_mutex_unlock(&queue->mutex);
+    return is_full;
+}
+
+void mbtk_queue_deinit(mbtk_queue_node_t *queue)
+{
+    if(queue == NULL)
+    {
+        return;
+    }
+    queue->count = 0;
+    queue->payload = NULL;
+    queue->front = NULL;
+    queue->rear = NULL;
+    mbtk_mutex_deinit(&queue->mutex);
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_sock.c b/mbtk/mbtk_lib/src/mbtk_sock.c
new file mode 100755
index 0000000..d52abdb
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_sock.c
@@ -0,0 +1,659 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include "mbtk_sock.h"
+#include "mbtk_log.h"
+
+int sock_net_open(mbtk_net_info_s *net_info, mbtk_addr_family_e addr_family)
+{
+    return 0;
+}
+
+int sock_open(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err)
+{
+    if(net_info == NULL || sock_info == NULL) {
+        LOGE("ARG error.");
+        return -1;
+    }
+    int family = AF_INET;
+    if(sock_info->addr_family == MBTK_ADDR_IPV6) { // Only IPv6
+        family = AF_INET6;
+    }
+    if(sock_info->sock_type == MBTK_SOCK_UDP) { // UDP
+        // socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+        if((sock_info->fd = socket(family, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+            LOGE("socket() fail.[%d]",errno);
+            goto result_fail;
+        }
+    } else if(sock_info->sock_type == MBTK_SOCK_TCP){ // TCP
+        if((sock_info->fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0){
+            LOGE("socket() fail.[%d]",errno);
+            goto result_fail;
+        }
+    } else {
+        LOGE("Unknown socket type:%d", sock_info->sock_type);
+        return -1;
+    }
+#if 1
+    // Set O_NONBLOCK
+    int flags = fcntl(sock_info->fd, F_GETFL, 0);
+    if (flags < 0) {
+        LOGE("Get flags error:%d", errno);
+        goto result_fail_with_close;
+    }
+    flags |= O_NONBLOCK;
+    if (fcntl(sock_info->fd, F_SETFL, flags) < 0) {
+        LOGE("Set flags error:%d", errno);
+        goto result_fail_with_close;
+    }
+#endif
+    // Connect
+    LOGD("Start conn:%s:%d",sock_info->host,sock_info->port);
+    if (strlen(sock_info->host) > 0 && sock_info->port > 0)
+    {
+        if(family == AF_INET6)
+        {
+            struct addrinfo hints;
+            struct addrinfo *answer, *curr;
+            memset(&hints, 0, sizeof(struct addrinfo));
+            hints.ai_family = AF_INET6;    /* Allow IPv4 or IPv6 */
+            hints.ai_socktype = sock_info->sock_type; /* Datagram socket */
+            hints.ai_flags = 0;
+            hints.ai_protocol = 0;          /* Any protocol */
+
+            int ret = getaddrinfo(sock_info->host, NULL, &hints, &answer);
+            if(ret < 0)
+            {
+                printf("\ngetaddrinfo error\n");
+                goto result_fail_with_close;
+            }
+
+            struct sockaddr_in6 *addr_in6=NULL;
+            struct sockaddr_in6 serverSockAddr;
+            bzero(&serverSockAddr, sizeof(struct sockaddr_in6));
+            serverSockAddr.sin6_family = AF_INET6;
+            serverSockAddr.sin6_port = htons(sock_info->port);
+            //memcpy(&serverSockAddr.sin6_addr, he->h_addr_list[0], sizeof(struct in6_addr));
+            //memcpy(&sock_info->addr.addr.dst_sock_addr6.sin6_addr, he->h_addr_list[0], sizeof(struct in_addr));
+            sock_info->addr.addr_len = sizeof(struct sockaddr_in6);
+
+            for (curr = answer; curr != NULL; curr = curr->ai_next)
+            {
+                addr_in6 = (struct sockaddr_in6 *)curr->ai_addr;
+				memcpy(&(serverSockAddr.sin6_addr), &(addr_in6->sin6_addr), sizeof(struct in6_addr));
+            }
+            if (connect(sock_info->fd, &serverSockAddr, sizeof(struct sockaddr_in6)) < 0)
+            {
+                if (EINPROGRESS != errno)
+                {
+                    LOGE("connect() fail.[%d]", errno);
+                    goto result_fail_with_close;
+                }
+            }
+        }
+        else
+        {
+            struct hostent *he = gethostbyname(sock_info->host);
+            if (he == NULL)
+            {
+                LOGE("gethostbyname() fail.[%d]", errno);
+                goto result_fail_with_close;
+            }
+            struct sockaddr_in serverSockAddr;
+            bzero(&serverSockAddr, sizeof(struct sockaddr_in));
+            serverSockAddr.sin_family = AF_INET;
+            serverSockAddr.sin_port = htons(sock_info->port);
+            memcpy(&serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+
+            log_hex("IPv4", he->h_addr_list[0], sizeof(struct in_addr));
+
+            memcpy(&sock_info->addr.addr.serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+            sock_info->addr.addr_len = sizeof(struct sockaddr_in);
+            if (connect(sock_info->fd, (struct sockaddr *) &serverSockAddr, sizeof(serverSockAddr)) < 0)
+            {
+                if (EINPROGRESS != errno)
+                {
+                    LOGE("connect() fail.[%d]", errno);
+                    goto result_fail_with_close;
+                }
+            }
+        }
+
+        fd_set rset, wset;
+        FD_ZERO(&rset);
+        FD_ZERO(&wset);
+        FD_SET(sock_info->fd, &rset);
+        FD_SET(sock_info->fd, &wset);
+        struct timeval time_out;
+        /*
+        time_out.tv_sec = timeout / 1000;
+        time_out.tv_usec = timeout % 1000 * 1000;
+        */
+        time_out.tv_sec = 100;
+        time_out.tv_usec = 0;
+        int nready = select(sock_info->fd + 1, &rset, &wset, NULL, &time_out);
+        LOGD("nready = %d", nready);
+        if (nready == 0)   // Timeout
+        {
+            LOGE("Timeout.");
+            goto result_fail_with_close;
+        }
+        else
+        {
+            if (FD_ISSET(sock_info->fd, &rset) && FD_ISSET(sock_info->fd, &wset))
+            {
+                int error = -1;
+                socklen_t len = sizeof(int);
+                LOGE("Can read and write.");
+                if (getsockopt(sock_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+                {
+                    LOGE("getsockopt fail.[%d]", errno);
+                    goto result_fail_with_close;
+                }
+                else
+                {
+                    LOGE("error = %d", error);
+                    if (error != 0)   // Fail
+                    {
+                        goto result_fail_with_close;
+                    }
+                }
+            }
+            else if (FD_ISSET(sock_info->fd, &wset))
+            {
+                LOGI("Can write.");
+            }
+            else
+            {
+                LOGE("Can read(Impossible).");
+                goto result_fail_with_close;
+            }
+        }
+    }
+    else
+    {
+        LOGE("Can not conn.");
+        goto result_fail_with_close;
+    }
+
+    if (sock_info->is_ssl)
+    {
+
+    }
+
+    sock_info->read_buff.buffer = (char*)malloc(MBTK_BUFF_SIZE);
+    if(sock_info->read_buff.buffer) {
+        memset(sock_info->read_buff.buffer, 0x0, MBTK_BUFF_SIZE);
+        sock_info->read_buff.size = 0;
+        sock_info->read_buff.size_max = MBTK_BUFF_SIZE;
+    } else {
+        LOGE("malloc() fail.");
+        goto result_fail_with_close;
+    }
+
+    return sock_info->fd;
+result_fail_with_close:
+    close(sock_info->fd);
+    sock_info->fd = -1;
+result_fail:
+    LOGE("mbtk_sock_open() end:fail");
+    return -1;
+}
+
+int sock_addr_set(mbtk_net_info_s *net_info,mbtk_sock_info_s *sock_info,void *host, uint32 port)
+{
+    if(sock_info->fd <= 0) {
+        LOGE("Socket not open.");
+        return -1;
+    }
+
+    sock_info->addr.addr.serverSockAddr.sin_family = AF_INET;
+    sock_info->addr.addr.serverSockAddr.sin_port = htons(port);
+    struct hostent *he = gethostbyname(host);
+    if (he == NULL)
+    {
+        LOGE("gethostbyname() fail.[%d]", errno);
+        return -1;
+    }
+    else
+    {
+        LOGD("Ip(len-%d)", he->h_length);
+        int i = 0;
+        for(;i < he->h_length;i++){
+            LOGD("Ip Addr[%d]:%.2x", i, 0x0FF & he->h_addr_list[0][i]);
+        }
+    }
+    memcpy(&sock_info->addr.addr.serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+    sock_info->addr.addr_len = sizeof(struct sockaddr_in);
+
+    return 0;
+}
+
+int sock_bind(int sockfd, bool is_ipv6, uint16 port)
+{
+    int ret_val;
+    struct sockaddr *ds_sockaddr = NULL;
+    struct sockaddr_in localaddr;
+    uint16 addr_legth = 0;
+
+    memset((char *) &localaddr, 0, sizeof(struct sockaddr_in));
+    localaddr.sin_family = AF_INET;
+    localaddr.sin_addr.s_addr = INADDR_ANY;
+    localaddr.sin_port = htons(port);
+    addr_legth = sizeof(struct sockaddr_in);
+    ds_sockaddr = (struct sockaddr *)&localaddr;
+    ret_val = bind(sockfd,ds_sockaddr,addr_legth);
+    if (ret_val < 0){
+         LOGE("bind() sockfd= %d fail", sockfd);
+         return -1;
+    }
+
+    return 0;
+}
+
+int sock_read(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+    unsigned int count = 0;
+    int len = 0;
+    int try_count = 0;
+    int times = timeout / 50;
+    memset(buffer, 0x0, buf_len);
+    while (count < buf_len)
+    {
+        try_count++;
+        if (sock_info->is_ssl)
+        {
+
+        }
+        else
+        {
+            len = read(sock_info->fd, (char*) buffer + count, buf_len - count);
+        }
+        if (len <= 0)
+        {
+            if (errno == EWOULDBLOCK || errno == EAGAIN)
+            {
+                if (count > 0) // Read data
+                    break; // Read data end.
+
+                if (try_count >= times)   // Timeout
+                {
+                    count = -1;
+                    if (times != 0)
+                    {
+                        *err = 10; // FTP_ERR_NET_TIMEOUT
+                    }
+                    LOGE("Not read enough data,return.[%d/%d]", count, buf_len);
+                    break;
+                }
+                else
+                {
+                    usleep(50000);
+                    continue;
+                }
+            }
+            else
+            {
+                LOGD("read error.[%d]", errno);
+                if (errno == EINPROGRESS)
+                {
+                    if (close(sock_info->fd) == 0)   // Success
+                    {
+                        LOGD("Socket disconnected.Close it.");
+                        sock_info->fd = -1;
+                    }
+                    if (count <= 0)
+                        count = -1;
+                }
+                else
+                {
+                    if (count <= 0)
+                        count = 0;
+                }
+                break;
+            }
+        }
+        else
+        {
+            count += len;
+        }
+    }
+
+    LOGV("Read data[%d/%d].", count, buf_len);
+
+    return count;
+}
+
+int sock_read_async(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+    int len = -1;
+    int try_count = 0;
+    int times = timeout / 50;
+
+TCP_READ_AGAIN:
+    memset(buffer, 0x0, buf_len);
+    try_count++;
+    if (sock_info->is_ssl)
+    {
+
+    }
+    else
+    {
+        len = read(sock_info->fd, (char*) buffer, buf_len);
+    }
+    if (len < 0)
+    {
+        if (errno == EWOULDBLOCK)
+        {
+            if(try_count == times)
+            {
+                LOGD("read timeout");
+                return -1;
+            }
+            usleep(50000);
+            goto TCP_READ_AGAIN;
+        }
+        else
+        {
+            LOGE("read error.[%d]", errno);
+            return -1;
+        }
+    }
+
+    LOGV("Read data[%d/%d].", len, buf_len);
+
+    return len;
+}
+
+#if 0
+int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+    if (sock_info->fd > 0)
+    {
+        char *buf_ptr = (char*)buffer;
+        char read_buf[1];
+        int read_len = 0;
+        while (TRUE)
+        {
+            if (sock_read_async(net_info, sock_info, read_buf, 1, timeout, err) == 1)
+            {
+                *buf_ptr++ = read_buf[0];
+                read_len++;
+
+                if (read_buf[0] == '\n' || read_len >= buf_len)
+                {
+                    return read_len;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+        }
+    }
+    return -1;
+}
+#else
+int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+    if (sock_info->fd > 0)
+    {
+        memset(buffer,0,buf_len);
+        int read_len = 0;
+        char *buf_ptr = (char*)buffer;
+        char *temp_ptr = sock_info->read_buff.buffer;
+
+        LOGV("TEMP buffer[fd - %d, len-%d]:%s", sock_info->fd, sock_info->read_buff.size, sock_info->read_buff.buffer);
+copy_angin:
+        while(sock_info->read_buff.size > 0 && *temp_ptr != '\n') {
+            *buf_ptr++ = *temp_ptr++;
+            sock_info->read_buff.size--;
+            read_len++;
+        }
+
+        LOGV("SIZE : %d,TEMP is \\n : %d", sock_info->read_buff.size, *temp_ptr == '\n');
+
+        if(sock_info->read_buff.size == 0) {
+            sock_info->read_buff.size = sock_read(net_info, sock_info, sock_info->read_buff.buffer,
+                                            sock_info->read_buff.size_max, timeout, err);
+            if(sock_info->read_buff.size <= 0) {
+                if(read_len == 0) { // No data.
+                    LOGE("sock_read() fail.");
+                    return -1;
+                } else {
+                    return read_len;
+                }
+            }
+
+            temp_ptr = sock_info->read_buff.buffer;
+            goto copy_angin;
+        } else if(*temp_ptr == '\n') { // Read line.
+            *buf_ptr++ = '\n';
+            sock_info->read_buff.size--;
+            read_len++;
+
+            if(sock_info->read_buff.size > 0)
+                memcpy(sock_info->read_buff.buffer, temp_ptr + 1, sock_info->read_buff.size);
+
+            return read_len;
+        }
+
+    }
+    return -1;
+}
+#endif
+
+int sock_write(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+    int len = 0;
+    uint32 try_count = 0;
+    uint32 times = timeout * 100;
+    unsigned int count = 0;
+    while (count < buf_len)
+    {
+        try_count++;
+        if (sock_info->is_ssl)
+        {
+            //printf("  try_count = %d   timeout = %d        sock_info->is_ssl = 1\n",try_count,timeout);
+            if(try_count >= times)
+            {
+                printf("over time \n");
+                break;
+            }
+        }
+        else
+        {
+            len = write(sock_info->fd, (const char*)buffer + count, buf_len - count);
+        }
+        if (len < 0)
+        {
+            if (errno == EWOULDBLOCK)
+            {
+                usleep(50000);
+                continue;
+            }
+            else
+            {
+                LOGE("write error.[%d]", errno);
+                if (count <= 0)
+                    count = -1;
+                break;
+            }
+        }
+        else if (len == 0)
+        {
+            LOGE("write error(len == 0).[%d]", errno);
+        }
+        else
+        {
+            count += len;
+        }
+    }
+
+    if (count > 0)
+    {
+        LOGV("Write data[%d/%d] success.", count, buf_len);
+    }
+    else     // Open session fail
+    {
+        LOGV("Write data[%d/%d] fail.", count, buf_len);
+    }
+
+    return count;
+}
+
+int sock_recv(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout)
+{
+    unsigned int count = 0;
+    int len = 0;
+    int try_count = 0;
+    int times = timeout / 50; // ms
+    memset(buffer, 0x0, buf_len);
+    while (count < buf_len)
+    {
+        try_count++;
+        len = recvfrom(sock_info->fd, (char*) buffer + count, buf_len - count, 0,
+                    (struct sockaddr *)&sock_info->addr.addr.serverSockAddr, (socklen_t *)&sock_info->addr.addr_len);
+        if (len <= 0)
+        {
+            if (errno == EWOULDBLOCK || errno == EAGAIN)
+            {
+                if (count > 0) // Read data
+                    break; // Read data end.
+
+                if (try_count >= times)   // Timeout
+                {
+                    count = -1;
+                    break;
+                }
+                else
+                {
+                    usleep(50000);
+                    continue;
+                }
+            }
+            else if (errno == EINPROGRESS)
+            {
+                if (close(sock_info->fd) == 0)   // Success
+                {
+                    LOGD("Socket disconnected.Close it.");
+                }
+                if (count <= 0)
+                    count = -1;
+                break;
+            }
+            else
+            {
+                LOGE("recv error.[%d]", errno);
+                if (count <= 0)
+                    count = -1;
+                break;
+            }
+        }
+        else
+        {
+            count += len;
+        }
+    }
+
+    LOGV("Read data[%d/%d].", count, buf_len);
+
+    return count;
+}
+
+int sock_sendto(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout)
+{
+    int len = 0;
+    unsigned int count = 0;
+    int try_count = 0;
+    int times = timeout / 50; // ms
+    while (count < buf_len)
+    {
+        try_count++;
+        len = sendto(sock_info->fd,(char*) buffer + count, buf_len - count, 0,
+                (struct sockaddr *)&sock_info->addr.addr.serverSockAddr, sock_info->addr.addr_len);
+        if (len < 0)
+        {
+            if (errno == EWOULDBLOCK)
+            {
+                if (count > 0) // Send part data
+                    break;
+
+                if (try_count >= times)   // Timeout
+                {
+                    count = -1;
+                    break;
+                }
+                else
+                {
+                    usleep(50000);
+                    continue;
+                }
+            }
+            else
+            {
+                LOGE("sendto error.[%d]", errno);
+                if (count <= 0)
+                    count = -1;
+                break;
+            }
+        }
+        else if (len == 0)
+        {
+            LOGE("write error(len == 0).[%d]", errno);
+        }
+        else
+        {
+            count += len;
+        }
+    }
+
+    if (count == buf_len)
+    {
+        LOGV("Sendto data[%d/%d] success.", count, buf_len);
+    }
+    else
+    {
+        LOGV("Sendto data[%d/%d] fail.", count, buf_len);
+    }
+
+    return count;
+}
+
+int sock_close(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err)
+{
+    if(sock_info->fd > 0) {
+        if(close(sock_info->fd) < 0)
+        {
+            LOGE("Close socket fail[%d].", errno);
+            return -1;
+        }
+        sock_info->fd = -1;
+    }
+
+    if(sock_info->read_buff.buffer) {
+        free(sock_info->read_buff.buffer);
+        sock_info->read_buff.buffer = NULL;
+    }
+    return 0;
+}
+
+int sock_net_close(mbtk_net_info_s *net_info, uint32 timeout, int *err)
+{
+    return 0;
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_sock2.c b/mbtk/mbtk_lib/src/mbtk_sock2.c
new file mode 100755
index 0000000..461c68c
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_sock2.c
@@ -0,0 +1,1344 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <polarssl/net.h>
+#include <polarssl/ssl.h>
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#include <polarssl/certs.h>
+#include <polarssl/x509.h>
+#include <polarssl/error.h>
+#include <polarssl/debug.h>
+#include <polarssl/config.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "mbtk_sock"
+#include <mbtk_log.h>
+
+#include "mbtk_sock2.h"
+#include "mbtk_sock_internal.h"
+//#include "mbtk_openssl.h"
+
+#define SA struct sockaddr
+
+// Must define LOG_TAG in the first.
+//#include "mbtk_log.h"
+static int epoll_fd = -1;
+static int pipe_fds[2];
+static struct epoll_event epoll_events[20];
+static pthread_t sock_thread_id = -1;
+static bool sock_thread_running = FALSE;
+static mbtk_sock_s *mbtk_sock[MBTK_HANDLE_MAX_NUM] = {NULL};
+
+static int sock_find_first_free(const mbtk_sock_inter_info_s *inter_info)
+{
+    if(inter_info == NULL) {
+        LOGE("inter_info is NULL.");
+        return -1;
+    }
+
+    int index = 0;
+    //while((inter_info + index)->fd > 0) {
+    while(inter_info[index].fd > 0) {
+        index++;
+    }
+
+    if(index == MBTK_SOCK_MAX_NUM) {
+        LOGE("sock_infos too more.");
+        return -1;
+    }
+
+    return index;
+}
+
+static bool sock_info_check(int handle,mbtk_sock_inter_info_s *inter_info)
+{
+    if(inter_info == NULL || mbtk_sock[handle] == NULL) {
+        LOGE("internal_info is NULL.");
+        return FALSE;
+    }
+
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(inter_info->fd ==
+            mbtk_sock[handle]->inter_infos[index].fd) {
+            return TRUE;
+        }
+        index++;
+    }
+
+    return FALSE;
+}
+
+static bool sock_is_close(int sockfd)
+{
+    char buff[32];
+    int recvBytes = recv(sockfd, buff, sizeof(buff), MSG_PEEK);
+
+    int err = errno;
+    //cout << "In close function, recv " << recvBytes << " bytes, err " << sockErr << endl;
+
+    if(recvBytes > 0) //Get data
+        return FALSE;
+
+    if((recvBytes == -1) && (err == EWOULDBLOCK)) //No receive data
+        return FALSE;
+
+    return TRUE;
+}
+
+static int sock_info_find_by_fd(int handle,int fd)
+{
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(fd == mbtk_sock[handle]->inter_infos[index].fd) {
+            return index;
+        }
+        index++;
+    }
+
+    return -1;
+}
+
+static void* sock_thread_run(void *data)
+{
+    LOGD("socket thread is running...");
+    if(data != NULL)
+        LOGD("sock_thread_run has arg.");
+
+    int nready;
+    if (socketpair( AF_UNIX, SOCK_STREAM, 0, pipe_fds) < 0) {
+        LOGE("socketpair() error.");
+        return NULL;
+    } else {
+        struct epoll_event ev;
+        ev.data.fd = pipe_fds[1];
+        ev.events = EPOLLIN | EPOLLET;
+        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,pipe_fds[1],&ev);
+    }
+
+    while(sock_thread_running) {
+        nready = epoll_wait(epoll_fd,epoll_events,20,-1);
+        int i;
+        for(i=0;i<nready;++i) {
+            LOGD("fd[%d] event = %x",epoll_events[i].data.fd,epoll_events[i].events);
+            if(pipe_fds[1] == epoll_events[i].data.fd) {
+                LOGD("Get exist sig.");
+                sock_thread_running = FALSE;
+                break;
+            }
+
+            int handle = 0;
+            while(handle < MBTK_HANDLE_MAX_NUM) {
+                if(mbtk_sock[handle] != NULL) {
+                    int index = sock_info_find_by_fd(handle,epoll_events[i].data.fd);
+                    if(index >= 0 && mbtk_sock[handle]->init_info.sock_cb != NULL) {
+                        mbtk_sock_inter_info_s *inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+
+                        //if(sock_is_close(epoll_events[i].data.fd)) {
+                        //    LOGE("Socket %d is closed.",epoll_events[i].data.fd);
+                        //    break;
+                        //}
+
+                        mbtk_sock[handle]->init_info.sock_cb(handle,inter_info->fd,epoll_events[i].events);
+
+                        if(epoll_events[i].events & EPOLLERR){ // error[ UDP server can't use.]
+                            LOGD("%d EPOLLERR.",epoll_events[i].data.fd);
+                        }
+
+                        if ((epoll_events[i].events & EPOLLIN)
+                            && (epoll_events[i].events & EPOLLOUT)) {
+                            LOGD("%d can read and write.",epoll_events[i].data.fd);
+                            int error = -1;
+                            int len = sizeof(int);
+                            if(getsockopt(epoll_events[i].data.fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0){
+                                LOGE("getsockopt fail.[%d]",errno);
+                            }else{
+                                LOGD("error = %d",error);
+                            }
+                        }
+
+                        if (epoll_events[i].events & EPOLLOUT) { // Can write.
+                            LOGD("%d can write.",epoll_events[i].data.fd);
+                        }
+
+                        if (epoll_events[i].events & EPOLLIN) { // Can read.
+                            LOGD("%d can read.",epoll_events[i].data.fd);
+                        }
+                    }
+                }
+
+                handle++;
+            }
+        }
+    }
+
+    LOGD("socket thread exit.");
+    return ((void*)0);
+}
+
+static int sock_thread_start()
+{
+    sock_thread_running = TRUE;
+    if (0 != pthread_create(&sock_thread_id, NULL, sock_thread_run, NULL))
+    {
+        LOGE("error when create pthread,%d\n", errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+extern mbtk_sock_handle mbtk_sock_init(mbtk_init_info *info)
+{
+    mbtk_sock_handle handle = 0;
+    while(handle < MBTK_HANDLE_MAX_NUM) {
+        if(mbtk_sock[handle] == NULL)
+            break;
+
+        handle++;
+    }
+
+    if(handle == MBTK_HANDLE_MAX_NUM) {
+        LOGE("Socket handle is full.");
+        return -1;
+    }
+
+    mbtk_sock[handle] = (mbtk_sock_s*)malloc(sizeof(mbtk_sock_s));
+    memset(mbtk_sock[handle],0x0,sizeof(mbtk_sock_s));
+    if(info != NULL) {
+        mbtk_sock[handle]->init_info.net_type = info->net_type;
+        mbtk_sock[handle]->init_info.net_cb = info->net_cb;
+        mbtk_sock[handle]->init_info.sock_cb = info->sock_cb;
+    } else {
+        mbtk_sock[handle]->init_info.net_type = MBTK_NET_LINUX;
+        mbtk_sock[handle]->init_info.net_cb = NULL;
+        mbtk_sock[handle]->init_info.sock_cb = NULL;
+    }
+
+    if(!sock_thread_running) {
+        epoll_fd = epoll_create(256);
+        if(sock_thread_start()) {
+            LOGE("Start thread fail.");
+            return -1;
+        }
+    }
+
+    return handle;
+}
+
+static int mbtk_ssl_init(int fd ,bool ingnore_cert,mbtk_sock_inter_info_s* inter_info)
+{
+    LOGE("8\n");
+    int ret = 0, len, tail_len, i, written, frags;
+    unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
+    const char *pers = "ssl_client";
+    opt.server_name         = DFL_SERVER_NAME;
+    opt.server_addr         = DFL_SERVER_ADDR;
+    opt.server_port         = DFL_SERVER_PORT;
+    opt.debug_level         = DFL_DEBUG_LEVEL;
+    opt.nbio                = DFL_NBIO;
+    opt.request_page        = DFL_REQUEST_PAGE;
+    opt.request_size        = DFL_REQUEST_SIZE;
+    opt.ca_file             = DFL_CA_FILE;
+    opt.ca_path             = DFL_CA_PATH;
+    opt.crt_file            = DFL_CRT_FILE;
+    opt.key_file            = DFL_KEY_FILE;
+    opt.psk                 = DFL_PSK;
+    opt.psk_identity        = DFL_PSK_IDENTITY;
+    opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
+    opt.renegotiation       = DFL_RENEGOTIATION;
+    opt.allow_legacy        = DFL_ALLOW_LEGACY;
+    opt.renegotiate         = DFL_RENEGOTIATE;
+    opt.exchanges           = DFL_EXCHANGES;
+    opt.min_version         = DFL_MIN_VERSION;
+    opt.max_version         = DFL_MAX_VERSION;
+    opt.auth_mode           = DFL_AUTH_MODE;
+    opt.mfl_code            = DFL_MFL_CODE;
+    opt.trunc_hmac          = DFL_TRUNC_HMAC;
+    opt.reconnect           = DFL_RECONNECT;
+    opt.reco_delay          = DFL_RECO_DELAY;
+    opt.tickets             = DFL_TICKETS;
+    opt.alpn_string         = DFL_ALPN_STRING;
+
+    entropy_context entropy;
+    ctr_drbg_context ctr_drbg;
+    ssl_context ssl;
+    ssl_session saved_session;
+    x509_crt cacert;
+    x509_crt clicert;
+    pk_context pkey;
+
+    memset( &ssl, 0, sizeof( ssl_context ) );
+    memset( &saved_session, 0, sizeof( ssl_session ) );
+    x509_crt_init( &cacert );
+    x509_crt_init( &clicert );
+    pk_init( &pkey );
+    LOGE("9\n");
+     /*
+     * 0. Initialize the RNG and the session data
+     */
+
+    entropy_init( &entropy );
+    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        LOGE( " failed\n  ! ctr_drbg_init returned -0x%x\n", -ret );
+        return -1;
+    }
+    if(!ingnore_cert)
+    {
+        LOGE("10\n");
+     /*
+     * 1.1. Load the trusted CA
+     */
+    //ret = x509_crt_parse(&cacert,ca1_cert,strlen(ca1_cert));
+        ret = x509_crt_parse_file( &cacert, opt.ca_path );
+        if( ret < 0 )
+        {
+            LOGE( " failed\n  !  ca x509_crt_parse returned -0x%x\n\n", -ret );
+            return -1;
+        }
+
+         /*
+         * 1.2. Load own certificate and private key
+         *
+         * (can be skipped if client authentication is not required)
+         */
+
+        ret = x509_crt_parse_file( &clicert, opt.crt_file );
+        if( ret != 0 )
+        {
+            LOGE( " failed\n  !  crt x509_crt_parse returned -0x%x\n\n", -ret );
+            return -1;
+        }
+
+        ret = pk_parse_keyfile( &pkey, opt.key_file, NULL);
+        if( ret != 0 )
+        {
+            LOGE( " failed\n  !  key x509_crt_parse returned -0x%x\n\n", -ret );
+            return -1;
+        }
+    }
+     /*
+     * 2. Setup stuff
+     */
+    LOGE( "  . Setting up the SSL/TLS structure..." );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        LOGE( " failed\n  ! ssl_init returned -0x%x\n\n", -ret );
+        return -1;
+    }
+
+    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+    if(ingnore_cert)
+    {
+        opt.auth_mode = SSL_VERIFY_OPTIONAL;
+    }
+    else
+    {
+        opt.auth_mode = SSL_VERIFY_REQUIRED;
+    }
+
+    ssl_set_authmode( &ssl, opt.auth_mode );
+
+    ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
+
+    ssl_set_bio( &ssl, net_recv, &fd, net_send, &fd );
+
+    ssl_set_renegotiation( &ssl, opt.renegotiation );
+    ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
+
+    ssl_set_ca_chain( &ssl, &cacert, NULL, NULL );
+    if(!ingnore_cert)
+    {
+        if( ( ret = ssl_set_own_cert( &ssl, &clicert, &pkey ) ) != 0 )
+            {
+                LOGE( " failed\n  ! ssl_set_own_cert returned %d\n\n", ret );
+                    return -1;
+            }
+    }
+    if( opt.min_version != -1 )
+        ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+    if( opt.max_version != -1 )
+        ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+    /*
+     * 3. Handshake
+     */
+    LOGE( "  . Performing the SSL/TLS handshake..." );
+
+    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
+    {
+        if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
+        {
+            LOGE( " failed\n  ! ssl_handshake returned -0x%x\n", -ret );
+            if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
+                LOGE(
+                    "    Unable to verify the server's certificate. "
+                        "Either it is invalid,\n"
+                    "    or you didn't set ca_file or ca_path "
+                        "to an appropriate value.\n"
+                    "    Alternatively, you may want to use "
+                        "auth_mode=optional for testing purposes.\n" );
+            LOGE( "\n" );
+            return -1;;
+        }
+    }
+
+    LOGE( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
+    printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
+
+    /*
+     * 4. Verify the server certificate
+     */
+    LOGE( "  . Verifying peer X.509 certificate..." );
+
+    if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
+    {
+        LOGE( " failed\n" );
+
+        if( ( ret & BADCERT_EXPIRED ) != 0 )
+            LOGE( "  ! server certificate has expired\n" );
+
+        if( ( ret & BADCERT_REVOKED ) != 0 )
+            LOGE( "  ! server certificate has been revoked\n" );
+
+        if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
+            LOGE( "  ! CN mismatch (expected CN=%s)\n", opt.server_name );
+
+        if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
+            LOGE( "  ! self-signed or not signed by a trusted CA\n" );
+
+    }
+
+    if( ssl_get_peer_cert( &ssl ) != NULL )
+    {
+        LOGE( "  . Peer certificate information    ...\n" );
+        x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
+                       ssl_get_peer_cert( &ssl ) );
+        LOGE( "%s\n", buf );
+    }
+
+    inter_info->cacert = &cacert;
+    inter_info->clicert = &clicert;
+    inter_info->ctr_drbg = &ctr_drbg;
+    inter_info->entropy = &entropy;
+    inter_info->pkey = &pkey;
+    inter_info->saved_session = &saved_session;
+    inter_info->ssl  = &ssl;
+
+    return 0;
+}
+
+int mbtk_ssl_close(mbtk_sock_inter_info_s *inter_info)
+{
+    if (inter_info == NULL)
+    {
+        return -1;
+    }
+
+    int ret = -1;
+    while( ( ret = ssl_close_notify( inter_info->ssl ) ) < 0 )
+    {
+        if( ret == POLARSSL_ERR_NET_CONN_RESET )
+        {
+            LOGE( " ok (already closed by peer)\n" );
+            ret = 0;
+            return -1;
+        }
+
+        if( ret != POLARSSL_ERR_NET_WANT_READ &&
+            ret != POLARSSL_ERR_NET_WANT_WRITE )
+        {
+            LOGE( " failed\n  ! ssl_close_notify returned %d\n\n", ret );
+            return -1;
+        }
+    }
+
+    x509_crt_free( inter_info->clicert );
+    x509_crt_free( inter_info->cacert );
+    pk_free( inter_info->pkey );
+    ssl_session_free( inter_info->saved_session );
+    ssl_free( inter_info->ssl );
+    ctr_drbg_free( inter_info->ctr_drbg );
+    entropy_free( inter_info->entropy );
+    return 0;
+}
+
+extern mbtk_sock_session mbtk_sock_open(mbtk_sock_handle handle,mbtk_sock_info *info,
+                unsigned int timeout,
+                int *mbtk_errno)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    *mbtk_errno = MBTK_SOCK_ERROR;
+    if(info == NULL) {
+        LOGE("mbtk_sock_info not be NULL.");
+        return -1;
+    }
+
+    int index_free = sock_find_first_free(mbtk_sock[handle]->inter_infos);
+    if(index_free < 0) {
+        LOGE("sock_find_first_free() fail.");
+        return -1;
+    }
+
+    memcpy(&(mbtk_sock[handle]->infos[index_free]),info,sizeof(mbtk_sock_info));
+    if(info->type == MBTK_SOCK_UDP) { // UDP
+        if((mbtk_sock[handle]->inter_infos[index_free].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
+            LOGE("socket() fail.[%d]",errno);
+            goto result_fail;
+        }
+    } else { // TCP
+        if((mbtk_sock[handle]->inter_infos[index_free].fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
+            LOGE("socket() fail.[%d]",errno);
+            goto result_fail;
+        }
+    }
+    // Set O_NONBLOCK
+    int flags = fcntl(mbtk_sock[handle]->inter_infos[index_free].fd, F_GETFL, 0);
+    if (flags < 0) {
+        LOGE("Get flags error:%s\n", strerror(errno));
+        goto result_fail_with_close;
+    }
+    flags |= O_NONBLOCK;
+    if (fcntl(mbtk_sock[handle]->inter_infos[index_free].fd, F_SETFL, flags) < 0) {
+        LOGE("Set flags error:%s\n", strerror(errno));
+        goto result_fail_with_close;
+    }
+
+    // Connect
+    LOGD("Start conn:%s:%d",info->address,info->port);
+    if(strlen(info->address) > 0 && info->port > 0) {
+        struct sockaddr_in servaddr;
+        bzero(&servaddr, sizeof(servaddr));
+        servaddr.sin_family = AF_INET;
+        servaddr.sin_port = htons(info->port);
+
+        struct hostent *he = gethostbyname(info->address);
+        if (he == NULL){
+            LOGE("gethostbyname() fail.[%d]",errno);
+            goto result_fail_with_close;
+        } else {
+            LOGD("Ip : %s",he->h_addr_list[0]);
+        }
+        memcpy(&servaddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+
+        if(connect(mbtk_sock[handle]->inter_infos[index_free].fd, (SA *) &servaddr, sizeof(servaddr)) < 0){
+            if(EINPROGRESS != errno){
+                LOGE("connect() fail.[%d]",errno);
+                goto result_fail_with_close;
+            }
+        }
+
+        fd_set rset, wset;
+        FD_ZERO(&rset);
+        FD_ZERO(&wset);
+        FD_SET(mbtk_sock[handle]->inter_infos[index_free].fd, &rset);
+        FD_SET(mbtk_sock[handle]->inter_infos[index_free].fd, &wset);
+        struct timeval time_out;
+        time_out.tv_sec = timeout/1000;
+        time_out.tv_usec = timeout%1000*1000;
+        int nready = select(mbtk_sock[handle]->inter_infos[index_free].fd + 1,
+                        &rset, &wset, NULL, &time_out);
+        LOGD("nready = %d",nready);
+        if(nready == 0){// Timeout
+            LOGE("Timeout.");
+            printf("Timeout.\n");
+            goto result_fail_with_close;
+        }else{
+            if (FD_ISSET(mbtk_sock[handle]->inter_infos[index_free].fd, &rset)
+                && FD_ISSET(mbtk_sock[handle]->inter_infos[index_free].fd, &wset)) {
+                int error = -1;
+                int len = sizeof(int);
+                LOGE("Can read and write.");
+                if(getsockopt(mbtk_sock[handle]->inter_infos[index_free].fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0){
+                    LOGE("getsockopt fail.[%d]",errno);
+                    goto result_fail_with_close;
+                }else{
+                    LOGE("error = %d",error);
+                    if(error != 0){ // Fail
+                        goto result_fail_with_close;
+                    }
+                }
+            }else if(FD_ISSET(mbtk_sock[handle]->inter_infos[index_free].fd, &wset)){
+                LOGI("Can write.");
+                printf("Can write.\n");
+            }else{
+                LOGE("Can read(Impossible).");
+                goto result_fail_with_close;
+            }
+        }
+    } else {
+        LOGE("Can not conn.");
+        goto result_fail_with_close;
+    }
+
+    if(mbtk_sock[handle]->init_info.sock_cb) {
+        struct epoll_event ev;
+        ev.data.fd = mbtk_sock[handle]->inter_infos[index_free].fd;
+        ev.events = EPOLLIN | EPOLLET;
+        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,mbtk_sock[handle]->inter_infos[index_free].fd,&ev);
+    }
+#if 1
+    if(info->ftp_ssl_support)
+    {
+        if(info->is_support_ssl){
+            mbtk_sock[handle]->infos[index_free].is_support_ssl = 0;
+            unsigned char mbtk_ftp_ssl_read_buf_s[256];
+            int err_rw;
+                memset(mbtk_ftp_ssl_read_buf_s,0,sizeof(mbtk_ftp_ssl_read_buf_s));
+                mbtk_sock_read(handle,mbtk_sock[handle]->inter_infos[index_free].fd,
+                        mbtk_ftp_ssl_read_buf_s,
+                        sizeof(mbtk_ftp_ssl_read_buf_s),
+                        60000,
+                        &err_rw);
+                printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf_s);
+
+            char cmd_buff[50];
+            int len=0,code;
+            memset(cmd_buff,0,sizeof(cmd_buff));
+
+            len = snprintf(cmd_buff, 50, "AUTH TLS\r\n");
+            cmd_buff[len] = '\0';
+            //printf("\n cmd_buff = %s\n", cmd_buff);
+
+            mbtk_sock_write(handle,mbtk_sock[handle]->inter_infos[index_free].fd,
+                                                cmd_buff,
+                                                strlen(cmd_buff),
+                                                60000,
+                                                &err_rw);
+
+            memset(mbtk_ftp_ssl_read_buf_s,0,sizeof(mbtk_ftp_ssl_read_buf_s));
+                mbtk_sock_read(handle,mbtk_sock[handle]->inter_infos[index_free].fd,
+                        mbtk_ftp_ssl_read_buf_s,
+                        sizeof(mbtk_ftp_ssl_read_buf_s),
+                        60000,
+                        &err_rw);
+                printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf_s);
+                
+            mbtk_sock[handle]->infos[index_free].is_support_ssl=1;
+        }else{
+            mbtk_sock[handle]->infos[index_free].is_support_ssl=1;
+        }
+    }
+#endif
+    if(info->is_support_ssl){
+        if(mbtk_ssl_init(mbtk_sock[handle]->inter_infos[index_free].fd,info->ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]) == -1){
+            LOGE("mbtk_openssl_init fail");
+            goto result_fail_with_close;
+        }
+
+    }
+
+    *mbtk_errno = MBTK_SOCK_SUCCESS;
+
+    mbtk_sock[handle]->sock_num++;
+    return mbtk_sock[handle]->inter_infos[index_free].fd;
+result_fail_with_close:
+    close(mbtk_sock[handle]->inter_infos[index_free].fd);
+    mbtk_sock[handle]->inter_infos[index_free].fd = -1;
+result_fail:
+    memset(&(mbtk_sock[handle]->inter_infos[index_free]),0x0,sizeof(mbtk_sock_inter_info_s));
+    memset(&(mbtk_sock[handle]->infos[index_free]),0x0,sizeof(mbtk_sock_info));
+    LOGE("mbtk_sock_open() end:fail");
+    return -1;
+}
+extern int mbtk_ssl_init_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd)
+{   
+    int i=0;
+    int index_free=0;
+
+    for (i=0;i<10;i++)
+    {
+        if(mbtk_sock[handle]->inter_infos[i].fd == fd)
+        {
+            index_free = i;
+            break;
+        }
+    }
+    return mbtk_ssl_init(mbtk_sock[handle]->inter_infos[index_free].fd,ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]);
+}
+extern int mbtk_ssl_close_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd)
+{   
+    int i=0;
+    int index_free=0;
+
+    for (i=0;i<10;i++)
+    {
+        if(mbtk_sock[handle]->inter_infos[i].fd == fd)
+        {
+            index_free = i;
+            break;
+        }
+    }
+    if(mbtk_sock[handle]->inter_infos[index_free].ssl!=NULL);
+        printf("\nmbtk_sock[handle]->inter_infos[index_free].ssl not empty\n");
+    return mbtk_ssl_close(&mbtk_sock[handle]->inter_infos[index_free]);
+}
+
+extern int mbtk_sock_write(mbtk_sock_handle handle,mbtk_sock_session session,
+                void *buffer,
+                unsigned int buf_len,
+                unsigned int timeout,
+                int *mbtk_errno)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || session < 0 || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    *mbtk_errno = MBTK_SOCK_ERROR;
+    if(buffer == NULL) {
+        LOGE("mbtk_sock_write() args error.");
+        return -1;
+    }
+
+    mbtk_sock_inter_info_s *inter_info = NULL;
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(session ==
+            mbtk_sock[handle]->inter_infos[index].fd) {
+            inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+            break;
+        }
+        index++;
+    }
+
+    if(!sock_info_check(handle,inter_info)) {
+        LOGE("sock_info_check() fail.");
+        return -1;
+    }
+
+    index = sock_info_find_by_fd(handle,inter_info->fd);
+    if(index < 0) {
+        LOGE("No such socket in session list.");
+        return -1;
+    }
+
+    int len = 0;
+    unsigned int count = 0;
+    if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+        while(count < buf_len){
+            if(mbtk_sock[handle]->infos[index].is_support_ssl)
+                len = ssl_write(inter_info->ssl,(char*)buffer + count,buf_len - count);
+            else
+                len = write(inter_info->fd,(char*)buffer + count,buf_len - count);
+            if(len < 0){
+                if(errno == EWOULDBLOCK){
+                    usleep(50000);
+                    continue;
+                } else {
+                    LOGE("write error.[%d]",errno);
+                    if(count <= 0)
+                        count = -1;
+                    break;
+                }
+            } else if(len == 0) {
+                LOGE("write error(len == 0).[%d]",errno);
+            } else {
+                count += len;
+            }
+        }
+    } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP){
+        // Start send data
+        while(count < buf_len){
+            len = sendto(inter_info->fd,(char*)buffer + count,buf_len - count,0,NULL,0);
+            if(len < 0){
+                if(errno == EWOULDBLOCK){
+                    usleep(50000);
+                    continue;
+                } else {
+                    LOGE("sendto error.[%d]",errno);
+                    if(ECONNREFUSED == errno) { // Disconnected.
+                        LOGD("Socket Disconnected.");
+                    }
+                    break;
+                }
+            } else if(len == 0) {
+                LOGD("write error(len == 0).[%d]",errno);
+            } else {
+                count += len;
+            }
+        }
+    } else {
+        LOGE("Socket type error.");
+        return -1;
+    }
+
+    if(count == buf_len){
+        LOGD("Write data[%d/%d] success.",count,buf_len);
+    } else { // Open session fail
+        LOGD("Write data[%d/%d] fail.",count,buf_len);
+    }
+
+    *mbtk_errno = MBTK_SOCK_SUCCESS;
+    return count;
+}
+
+extern int mbtk_sock_read(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len,
+            unsigned int timeout,
+            int *mbtk_errno)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || session < 0 || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    *mbtk_errno = MBTK_SOCK_ERROR;
+    if(buffer == NULL) {
+        LOGE("mbtk_sock_write() args error.");
+        return -1;
+    }
+
+    mbtk_sock_inter_info_s *inter_info = NULL;
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(session ==
+            mbtk_sock[handle]->inter_infos[index].fd) {
+            inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+            break;
+        }
+        index++;
+    }
+
+    if(!sock_info_check(handle,inter_info)) {
+        LOGE("sock_info_check() fail.");
+        return -1;
+    }
+
+    index = sock_info_find_by_fd(handle,inter_info->fd);
+    if(index < 0) {
+        LOGE("No such socket in session list.");
+        return -1;
+    }
+
+    unsigned int count = 0;
+    if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+        int len = 0;
+        int try_count = 0;
+        int times = timeout / 50;
+        memset(buffer,0x0,buf_len);
+        while(count < buf_len){
+            try_count++;
+            if(mbtk_sock[handle]->infos[index].is_support_ssl)
+                len = ssl_read(inter_info->ssl,(char*)buffer + count,buf_len - count);
+            else
+                len = read(inter_info->fd,(char*)buffer + count,buf_len - count);
+            if(len < 0){
+                if(errno == EWOULDBLOCK){
+                    if(count > 0) // Read data
+                        break; // Read data end.
+
+                    if(try_count >= times){ // Timeout
+                        count = -1;
+                        if(times != 0) {
+                            *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+                        }
+                        LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+                        break;
+                    } else {
+                        usleep(50000);
+                        continue;
+                    }
+                } else {
+                    LOGE("read error.[%d]",errno);
+                    if(count <= 0)
+                        count = -1;
+                    break;
+                }
+            } else if(len == 0) {
+                LOGE("read error(len == 0).[%d]",errno);
+                if(errno == EINPROGRESS) {
+                    if(close(inter_info->fd) == 0) {// Success
+                        LOGD("Socket disconnected.Close it.");
+                    }
+                    if(count <= 0)
+                        count = -1;
+                } else {
+                    if(count <= 0)
+                        count = 0;
+                }
+                break;
+            } else {
+                count += len;
+            }
+        }
+    } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+        // Start recv data
+        struct sockaddr_in seraddr;
+        socklen_t seraddr_len;
+        int try_count = 0;
+        int times = timeout / 50;
+        int len = 0;
+        memset(buffer,0x0,buf_len);
+        while(TRUE){
+            try_count++;
+            seraddr_len = sizeof(struct sockaddr_in);
+            len = recvfrom(inter_info->fd,buffer,buf_len,0,&seraddr,&seraddr_len);
+            if(len < 0){
+                if(errno == EWOULDBLOCK){// No data can read.
+                    if(count > 0) // Read data
+                        break; // Read data end.
+
+                    if(try_count >= times){ // Timeout
+                        if(times == 0) {
+                            LOGE("Can not read.");
+                        } else {
+                            LOGE("Timeout");
+                            *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+                        }
+                        count = -1;
+                        LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+                        break;
+                    } else {
+                        usleep(50000);
+                        continue;
+                    }
+                } else {
+                    LOGE("recvfrom error.[%d]",errno);
+                    if(count <= 0)
+                        count = -1;
+                    break;
+                }
+            } else if(len == 0) {
+                LOGE("write error(len == 0).[%d]",errno);
+                if(count <= 0)
+                    count = 0;
+                break;
+            } else {
+                count += len;
+            }
+        }
+    } else {
+        LOGE("Socket type error.");
+        return -1;
+    }
+
+//    if(count == buf_len){
+//        LOGD("Read data[%d/%d] success.",count,buf_len);
+//    } else { // Open session fail
+//        LOGD("Read data[%d/%d] fail.",count,buf_len);
+//    }
+
+    LOGV("Read data[%d/%d].",count,buf_len);
+
+    *mbtk_errno = MBTK_SOCK_SUCCESS;
+    return count;
+}
+extern int mbtk_sock_readline(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len,
+            unsigned int timeout,
+            int *mbtk_errno,
+            int *read_line_count,
+            char *buf_ptr)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || session < 0 || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    *mbtk_errno = MBTK_SOCK_ERROR;
+    if(buffer == NULL) {
+        LOGE("mbtk_sock_write() args error.");
+        return -1;
+    }
+
+    mbtk_sock_inter_info_s *inter_info = NULL;
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(session ==
+            mbtk_sock[handle]->inter_infos[index].fd) {
+            inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+            break;
+        }
+        index++;
+    }
+
+    if(!sock_info_check(handle,inter_info)) {
+        LOGE("sock_info_check() fail.");
+        return -1;
+    }
+
+    index = sock_info_find_by_fd(handle,inter_info->fd);
+    if(index < 0) {
+        LOGE("No such socket in session list.");
+        return -1;
+    }
+
+    unsigned int count = 0;
+    unsigned int read_count = 0;
+    memset(buf_ptr, 0, buf_len);
+    char *temp_ptr = (char *)buffer;
+copy_angin_ssl:
+    while(*read_line_count > 0 && *temp_ptr != '\n') {
+        if(*temp_ptr == NULL)
+        {
+            printf("\n*temp_ptr is null\n");
+            goto read_end;
+        }
+        *buf_ptr++ = *temp_ptr++;
+        (*read_line_count)--;
+        count++;
+    }
+    if(*read_line_count == 0)
+    {
+        if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+            int len = 0;
+            int try_count = 0;
+            int times = timeout / 50;
+            memset(buffer,0x0,buf_len);
+            while(count < buf_len){
+                try_count++;
+                if( inter_info->ssl == NULL)
+                    printf("\ninter_info->ssl == NULL\n");
+                if(mbtk_sock[handle]->infos[index].is_support_ssl)
+                    len = ssl_read(inter_info->ssl,(char*)buffer + count,buf_len - count);
+                else
+                    len = read(inter_info->fd,(char*)buffer + count,buf_len - count);
+                *read_line_count = len;
+                if(len < 0){
+                    if(errno == EWOULDBLOCK){
+                        if(count > 0) // Read data
+                        {
+                            *read_line_count = count;
+                            count = 0;
+                            goto copy_angin_ssl;
+                            break; // Read data end.
+                        }
+                        else
+                        {
+                            //printf("\nread_end\n");
+                            goto read_end;
+                        }
+                        if(try_count >= times){ // Timeout
+                            count = -1;
+                            if(times != 0) {
+                                *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+                            }
+                            LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+                            goto read_end;
+                            break;
+                        } else {
+                            usleep(50000);
+                            continue;
+                        }
+                    } else {
+                        LOGE("read error.[%d]",errno);
+                        if(count <= 0)
+                            count = -1;
+                        else { 
+                            *read_line_count = count;
+                        }
+                        break;
+                    }
+                } else if(len == 0) {
+                    LOGE("read error(len == 0).[%d]",errno);
+                    if(errno == EINPROGRESS) {
+                        if(close(inter_info->fd) == 0) {// Success
+                            LOGD("Socket disconnected.Close it.");
+                        }
+                        if(count <= 0)
+                            count = -1;
+                    } else {
+                        if(count <= 0)
+                            count = 0;
+                        else
+                            count = -1;
+                    }
+                    goto read_end;
+                    break;
+                } else {
+                    count += len;
+                }
+            }
+        } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+            // Start recv data
+            struct sockaddr_in seraddr;
+            socklen_t seraddr_len;
+            int try_count = 0;
+            int times = timeout / 50;
+            int len = 0;
+            memset(buffer,0x0,buf_len);
+            while(TRUE){
+                try_count++;
+                seraddr_len = sizeof(struct sockaddr_in);
+                len = recvfrom(inter_info->fd,buffer,buf_len,0,&seraddr,&seraddr_len);
+                if(len < 0){
+                    if(errno == EWOULDBLOCK){// No data can read.
+                        if(count > 0) // Read data
+                            break; // Read data end.
+
+                        if(try_count >= times){ // Timeout
+                            if(times == 0) {
+                                LOGE("Can not read.");
+                                //printf("Can not read.\n");
+                            } else {
+                                LOGE("Timeout");
+                                //printf("Timeout\n");
+                                *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+                            }
+                            count = -1;
+                            LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+                            //printf("Not read enough data,return.[%d/%d]\n",count,buf_len);
+                            break;
+                        } else {
+                            usleep(50000);
+                            continue;
+                        }
+                    } else {
+                        LOGE("recvfrom error.[%d]",errno);
+                        if(count <= 0)
+                            count = -1;
+                        break;
+                    }
+                } else if(len == 0) {
+                    LOGE("write error(len == 0).[%d]",errno);
+                    if(count <= 0)
+                        count = 0;
+                    break;
+                } else {
+                    count += len;
+                }
+            }
+        } else {
+            LOGE("Socket type error.");
+            //printf("Socket type error.\n");
+            return -1;
+        }
+        count = 0;
+        goto copy_angin_ssl;
+    } else if(*temp_ptr == '\n') { // Read line.
+        *buf_ptr++ = '\n';
+        (*read_line_count)--;
+        count++;
+
+        if(*read_line_count > 0)
+            memcpy(buffer, temp_ptr + 1, *read_line_count);
+        return count;
+    }
+    LOGV("Read data[%d/%d].",count,buf_len);
+read_end:
+    *mbtk_errno = MBTK_SOCK_SUCCESS;
+    return count;
+}
+
+extern int mbtk_sock_read_async(mbtk_sock_handle handle,mbtk_sock_session session,
+            void *buffer,
+            unsigned int buf_len)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || session < 0 || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    if(buffer == NULL) {
+        LOGE("mbtk_sock_write() args error.");
+        return -1;
+    }
+
+    mbtk_sock_inter_info_s *inter_info = NULL;
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(session ==
+            mbtk_sock[handle]->inter_infos[index].fd) {
+            inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+            break;
+        }
+        index++;
+    }
+    if(!sock_info_check(handle,inter_info)) {
+        LOGE("sock_info_check() fail.");
+        return -1;
+    }
+
+    index = sock_info_find_by_fd(handle,inter_info->fd);
+    if(index < 0) {
+        LOGE("No such socket in session list.");
+        return -1;
+    }
+
+    int len;
+    if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+TCP_READ_AGAIN:
+        memset(buffer,0x0,buf_len);
+        if(mbtk_sock[handle]->infos[index].is_support_ssl)
+            len = ssl_read(inter_info->ssl,(char*)buffer,buf_len);
+        else
+            len = read(inter_info->fd,(char*)buffer,buf_len);
+        if(len < 0){
+            if(errno == EWOULDBLOCK){
+                usleep(100000);
+                goto TCP_READ_AGAIN;
+            } else {
+                LOGE("read error.[%d]",errno);
+                return -1;
+            }
+        }
+    } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+        // Start recv data
+        struct sockaddr_in seraddr;
+        socklen_t seraddr_len;
+UDP_READ_AGAIN:
+        memset(buffer,0x0,buf_len);
+        seraddr_len = sizeof(struct sockaddr_in);
+        len = recvfrom(inter_info->fd,buffer,buf_len,0,&seraddr,&seraddr_len);
+        if(len < 0){
+            if(errno == EWOULDBLOCK){
+                usleep(100000);
+                goto UDP_READ_AGAIN;
+            } else {
+                LOGE("read error.[%d]",errno);
+                return -1;
+            }
+        }
+    } else {
+        LOGE("Socket type error.");
+        return -1;
+    }
+
+    LOGV("Read data[%d/%d].",len,buf_len);
+
+    return len;
+}
+
+extern int mbtk_sock_close(mbtk_sock_handle handle,mbtk_sock_session session,
+            unsigned int timeout,
+            int *mbtk_errno)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || session < 0 || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    *mbtk_errno = MBTK_SOCK_ERROR;
+    mbtk_sock_inter_info_s *inter_info = NULL;
+    int index = 0;
+    while(index < MBTK_SOCK_MAX_NUM) {
+        if(session == mbtk_sock[handle]->inter_infos[index].fd) {
+            inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+            break;
+        }
+        index++;
+    }
+    if(!sock_info_check(handle,inter_info)) {
+        LOGE("sock_info_check() fail.");
+        return -1;
+    }
+
+    index = sock_info_find_by_fd(handle,inter_info->fd);
+    if(index < 0) {
+        LOGE("No such socket in session list.");
+        return -1;
+    }
+
+    int i;
+    for(i = 0;i < MBTK_SOCK_MAX_NUM;i++) {
+        if(mbtk_sock[handle]->inter_infos[i].fd == inter_info->fd){
+            if(mbtk_sock[handle]->init_info.sock_cb) {
+                struct epoll_event ev;
+                ev.data.fd = inter_info->fd;
+                ev.events = EPOLLIN | EPOLLET;
+                epoll_ctl(epoll_fd,EPOLL_CTL_DEL,inter_info->fd,&ev);
+            }
+
+            if(close(inter_info->fd) < 0) {// Success
+                LOGE("Close socket fail[%d].",errno);
+                //break;
+            }
+            mbtk_sock[handle]->inter_infos[i].fd = -1;
+            memset(&(mbtk_sock[handle]->infos[i]),0x0,sizeof(mbtk_sock_info));
+            mbtk_sock[handle]->sock_num--;
+            break;
+        }
+    }
+
+    if(mbtk_sock[handle]->infos[index].is_support_ssl){
+        if(mbtk_ssl_close(inter_info)== -1)
+        {
+            LOGE("close ssl fail");
+            return -1;
+        }
+    }
+
+    *mbtk_errno = MBTK_SOCK_SUCCESS;
+    return 0;
+}
+
+extern int mbtk_sock_deinit(mbtk_sock_handle handle)
+{
+    if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+        || mbtk_sock[handle] == NULL) {
+        LOGE("Socket not inited.");
+        return -1;
+    }
+
+    if(mbtk_sock[handle]->sock_num > 0) {
+        LOGE("There are socket not close.");
+        return MBTK_SOCK_ERROR;
+    }
+
+    LOGD("mbtk_sock_deinit() start.");
+#if 0
+    sock_thread_running = FALSE;
+    write(pipe_fds[0],"0",1);
+
+    // Wait for thread exist.
+    while(sock_inited) {
+        usleep(100);
+    }
+#endif
+
+    int i;
+    for(i = 0;i < MBTK_SOCK_MAX_NUM;i++) {
+        if(mbtk_sock[handle]->inter_infos[i].fd > 0){
+            if(mbtk_sock[handle]->init_info.sock_cb) {
+                struct epoll_event ev;
+                ev.data.fd = mbtk_sock[handle]->inter_infos[i].fd;
+                ev.events = EPOLLIN | EPOLLET;
+                epoll_ctl(epoll_fd,EPOLL_CTL_DEL,mbtk_sock[handle]->inter_infos[i].fd,&ev);
+            }
+
+            if(close(mbtk_sock[handle]->inter_infos[i].fd) < 0) {// Success
+                LOGE("Close socket fail[%d].",errno);
+                //break;
+            }
+            mbtk_sock[handle]->inter_infos[i].fd = -1;
+            memset(&(mbtk_sock[handle]->infos[i]),0x0,sizeof(mbtk_sock_info));
+            break;
+        }
+    }
+
+    //memset(&mbtk_sock,0x0,sizeof(mbtk_sock_s));
+    free(mbtk_sock[handle]);
+    mbtk_sock[handle] = NULL;
+    LOGD("mbtk_sock_deinit() end.");
+    return MBTK_SOCK_SUCCESS;
+}
+
+
diff --git a/mbtk/mbtk_lib/src/mbtk_str.c b/mbtk/mbtk_lib/src/mbtk_str.c
new file mode 100755
index 0000000..ff2db9e
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_str.c
@@ -0,0 +1,250 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <mbtk_str.h>
+
+/*
+* Converts all of the characters in this String to lower.
+*
+* Parameters:
+*   src - The string should be converted.
+*   dest  - The lowercase string.
+*   len - The length of result string.Must be "strlen(src) + 1"
+* Returns:
+*   The string, converted to lowercase,or NULL for fail.
+*/
+void*
+str_tolower
+(
+    const void *src,
+    void *dest,
+    size_t len
+)
+{
+    const char *s = (char*)src;
+    char *d = (char*)dest;
+    if(!s
+        || !d
+        || (strlen(d) + 1 > len)){
+        return NULL;
+    }
+
+    char* temp = d;
+    while(*s){
+        *temp++ = tolower(*s++);
+    }
+    *temp = '\0';
+
+    return dest;
+}
+
+/*
+* Converts all of the characters in this String to upper case.
+*
+* Parameters:
+*   src - The string should be converted.
+*   dest  - The uppercase string.
+*   len - The length of result string.Must be "strlen(str_ptr) + 1"
+* Returns:
+*   The string, converted to uppercase.or NULL for fail.
+*/
+void*
+str_toupper
+(
+    const void *src,
+    void *dest,
+    size_t len
+)
+{
+    const char *s = (char*)src;
+    char *d = (char*)dest;
+    if(!s
+        || !d
+        || (strlen(d) + 1 > len)){
+        return NULL;
+    }
+    char* temp = d;
+    while(*s){
+        *temp++ = toupper(*s++);
+    }
+    *temp = '\0';
+    return dest;
+}
+
+/*
+* Remove the head and tail spaces.
+*/
+void*
+str_trim
+(
+    const void* str,
+    void *result,
+    size_t len
+)
+{
+    if(str == NULL || result == NULL
+        || len <= strlen((char*)str))
+    {
+        return NULL;
+    }
+
+    char* str_ptr = (char*)str;
+    while(*str_ptr && (*str_ptr == ' ' || *str_ptr == '\t' || *str_ptr == '\n' || *str_ptr == '\r')){
+        str_ptr++;
+    }
+
+    memset(result,0x0,len);
+    if(*str_ptr && strlen(str_ptr) > 0)
+    {
+        memset(result,0x0,len);
+        memcpy(result,str_ptr,strlen(str_ptr));
+        str_ptr = (char*)result + strlen((char*)result) - 1;
+        while(*str_ptr && (*str_ptr == ' ' || *str_ptr == '\t' || *str_ptr == '\n' || *str_ptr == '\r')){
+            *str_ptr = '\0';
+            str_ptr--;
+        }
+    }
+
+    return result;
+}
+
+/*
+* Returns true if and only if this string contains the specified sequence of char values.
+*
+* Parameters:
+*   str   -   The substring to search from.
+*   sub_str - The substring to search for.
+* Returns:
+*   True if str contains sub_str, false otherwise.
+*/
+bool
+str_contains
+(
+    const void* str,
+    const void* sub_str
+)
+{
+    const char *s = (char*)str;
+    const char *s_sub = (char*)sub_str;
+
+    if(!s || !s_sub){
+        return FALSE;
+    }
+
+    return str_indexof(s,s_sub)==-1?FALSE:TRUE;
+}
+
+/*
+* Returns the index within this string of the first occurrence of the specified substring.
+* If no such substring, then -1 is returned.
+*
+* Parameters:
+*   str   -   The substring to search from.
+*   sub_str - The substring to search for.
+* Returns:
+*   The index of the first occurrence of the specified substring,
+*   or -1 if there is no such occurrence.
+*/
+ssize_t
+str_indexof
+(
+    const void* str,
+    const void* sub_str
+)
+{
+    const char *s = (char*)str;
+    const char *s_sub = (char*)sub_str;
+
+    if(!s || !s_sub){
+            return -1;
+    }
+    char* position = strstr(s,s_sub);
+    if(!position){
+        return -1;
+    }else{
+        return position - s;
+    }
+}
+
+/*
+* Returns a new string that is a substring of this string. The substring begins
+* at the specified beginIndex and extends to the character at index endIndex - 1.
+* Thus the length of the substring is endIndex-beginIndex.
+*
+* Examples:
+*   "hamburger".substring(4, 8) returns "urge"
+*   "smiles".substring(1, 5) returns "mile"
+*
+* Parameters:
+*   begin_index     The beginning index, inclusive.
+*   end_index       The ending index, exclusive.
+* Returns:
+*   The specified substring or NULL.
+*/
+void*
+str_substring
+(
+    const void* str,
+    size_t begin_index,
+    size_t end_index,
+    void *sub_str,
+    size_t len
+)
+{
+    const char* s = (char*)str;
+    char *result = (char*)sub_str;
+    if(!s
+        || !result
+        || begin_index >= end_index
+        || begin_index >= strlen(s)
+        || end_index - begin_index + 1 > len){
+        return NULL;
+    }
+
+    if(end_index > strlen(s)){
+        end_index = strlen(s);
+    }
+
+    memcpy(result,s + begin_index,end_index - begin_index);
+    result[end_index - begin_index] = '\0';
+
+    return result;
+}
+
+bool str_startwith(const char* str, const void* prefix)
+{
+    if (!str || !(char*) prefix) {
+        return FALSE;
+    }
+    if (strlen((char*) str) < strlen((char*) prefix)) {
+        return FALSE;
+    }
+    return str_indexof(str, (char*) prefix) ? FALSE : TRUE;
+}
+
+void* strstr_hex(char *haystack,int haystack_len,
+                const char *needle,int needle_len)
+{
+    int index = 0;
+    if(haystack_len < needle_len)
+        return NULL;
+
+    while(index <= haystack_len - needle_len) {
+        if(!memcmp(haystack + index,needle,needle_len)){
+            return haystack + index;
+        }
+        index++;
+    }
+
+    return NULL;
+}
+
+bool str_empty(const void *str)
+{
+    if (str && strlen((char*)str) > 0)
+        return false;
+
+    return true;
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_task.c b/mbtk/mbtk_lib/src/mbtk_task.c
new file mode 100755
index 0000000..935369a
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_task.c
@@ -0,0 +1,139 @@
+/*************************************************************
+Description:
+    mbtk_task.c
+    Used to implement mobiletek standard task or thread interfaces
+Author:
+    YangDagang
+Date:
+    2019-7-13
+*************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "mbtk_type.h"
+#include "mbtk_queue.h"
+#include "mbtk_task.h"
+#include "mbtk_log.h"
+
+/*************************************************************
+    Constants and Macros
+*************************************************************/
+
+/*************************************************************
+    Definitions:enum,struct,union
+*************************************************************/
+
+
+/*************************************************************
+    Variables:local,extern
+*************************************************************/
+
+/*************************************************************
+    Local Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Extern Function Declaration
+*************************************************************/
+
+/*************************************************************
+    Function Definitions
+*************************************************************/
+void mbtk_mutex_init(mbtk_mutex *mutex)
+{
+    pthread_mutex_init(&mutex->crit_sect, NULL);
+}
+
+void mbtk_mutex_deinit(mbtk_mutex *mutex)
+{
+    pthread_mutex_destroy(&mutex->crit_sect);
+}
+
+void mbtk_mutex_lock(mbtk_mutex *mutex)
+{
+    pthread_mutex_lock(&mutex->crit_sect);
+}
+
+void mbtk_mutex_unlock(mbtk_mutex *mutex)
+{
+    pthread_mutex_unlock(&mutex->crit_sect);
+}
+
+int mbtk_task_start(mbtk_task_info *task)
+{
+    static pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+    {
+        LOGE("pthread_attr_setdetachstate() fail.");
+        return -1;
+    }
+
+    if (pthread_create((pthread_t*)task->task_id,
+        &thread_attr, task->thread_run, task->args) != 0)
+    {
+        LOGE("%s errno: %d (%s)",__func__, errno, strerror(errno));
+        return -1;
+    }
+    pthread_attr_destroy(&thread_attr);
+
+    return 0;
+}
+
+int mbtk_task_queue_start(void *param,mbtk_task_cb_handle cb)
+{
+    int res = 0;
+    mbtk_task_queue_info *ts = (mbtk_task_queue_info *)param;
+
+    if(cb == NULL)
+    {
+        return MBTK_FAILE;
+    }
+    mbtk_queue_init(&ts->queue);
+    mbtk_mutex_init(&ts->mutex);
+    pthread_cond_init(&ts->cond, NULL);
+    res = pthread_create(&ts->thread_id,NULL,cb,NULL);
+    usleep(500000);
+    return res;
+}
+
+void mbtk_task_queue_stop(void *param)
+{
+    mbtk_task_queue_info *ts = (mbtk_task_queue_info *)param;
+    pthread_cancel(ts->thread_id);
+}
+
+int mbtk_signal_send(void *param,mbtk_signal_info* info)
+{
+    int res = 0;
+    mbtk_task_queue_info *ts = (mbtk_task_queue_info *)param;
+
+    mbtk_mutex_lock(&ts->mutex);
+    res = mbtk_queue_put(&ts->queue,(void*)info);
+    pthread_cond_signal(&ts->cond);
+    mbtk_mutex_unlock(&ts->mutex);
+    return res;
+}
+
+mbtk_signal_info *mbtk_signal_get(void *param)
+{
+    void *res = NULL;
+    mbtk_task_queue_info *ts = (mbtk_task_queue_info *)param;
+
+    mbtk_mutex_lock(&ts->mutex);
+    res = mbtk_queue_get(&ts->queue);
+    if(res == NULL){
+        // extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
+        //      pthread_mutex_t *__restrict __mutex)
+        pthread_cond_wait(&ts->cond, (pthread_mutex_t*)(&ts->mutex));
+        res = mbtk_queue_get(&ts->queue);
+    }
+    mbtk_mutex_unlock(&ts->mutex);
+    return res;
+}
+
diff --git a/mbtk/mbtk_lib/src/mbtk_utf.c b/mbtk/mbtk_lib/src/mbtk_utf.c
new file mode 100755
index 0000000..295ff1d
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_utf.c
@@ -0,0 +1,703 @@
+//
+// Created by hitmoon on 15-12-17.
+//
+#include "mbtk_utf.h"
+#include <stdio.h>
+#include <wchar.h>
+#include <string.h>
+
+static const int halfShift = 10;
+/* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START  (UTF32)0xD800
+#define UNI_SUR_HIGH_END    (UTF32)0xDBFF
+#define UNI_SUR_LOW_START   (UTF32)0xDC00
+#define UNI_SUR_LOW_END     (UTF32)0xDFFF
+#define false       0
+#define true        1
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16(
+        const UTF32 **sourceStart, const UTF32 *sourceEnd,
+        UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF32 *source = *sourceStart;
+    UTF16 *target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch;
+        if (target >= targetEnd) {
+            result = targetExhausted;
+            break;
+        }
+        ch = *source++;
+        if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+            /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = (UTF16) ch; /* normal case */
+            }
+        } else if (ch > UNI_MAX_LEGAL_UTF32) {
+            if (flags == strictConversion) {
+                result = sourceIllegal;
+            } else {
+                *target++ = UNI_REPLACEMENT_CHAR;
+            }
+        } else {
+            /* target is a character in range 0xFFFF - 0x10FFFF. */
+            if (target + 1 >= targetEnd) {
+                --source; /* Back up source pointer! */
+                result = targetExhausted;
+                break;
+            }
+            ch -= halfBase;
+            *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START);
+            *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START);
+        }
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32(
+        const UTF16 **sourceStart, const UTF16 *sourceEnd,
+        UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF16 *source = *sourceStart;
+    UTF32 *target = *targetStart;
+    UTF32 ch, ch2;
+    while (source < sourceEnd) {
+        const UTF16 *oldSource = source; /*  In case we have to back up because of target overflow. */
+        ch = *source++;
+        /* If we have a surrogate pair, convert to UTF32 first. */
+        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+            /* If the 16 bits following the high surrogate are in the source buffer... */
+            if (source < sourceEnd) {
+                ch2 = *source;
+                /* If it's a low surrogate, convert to UTF32. */
+                if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+                    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+                         + (ch2 - UNI_SUR_LOW_START) + halfBase;
+                    ++source;
+                } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                }
+            } else { /* We don't have the 16 bits following the high surrogate. */
+                --source; /* return to the high surrogate */
+                result = sourceExhausted;
+                break;
+            }
+        } else if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        if (target >= targetEnd) {
+            source = oldSource; /* Back up source pointer! */
+            result = targetExhausted;
+            break;
+        }
+        *target++ = ch;
+    }
+    *sourceStart = source;
+    *targetStart = target;
+#ifdef CVTUTF_DEBUG
+    if (result == sourceIllegal) {
+    fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x/n", ch, ch2);
+    fflush(stderr);
+}
+#endif
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = {0x00000000UL, 0x00003080UL, 0x000E2080UL,
+                                         0x03C82080UL, 0xFA082080UL, 0x82082080UL};
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow.  There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF8(
+        const UTF16 **sourceStart, const UTF16 *sourceEnd,
+        UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF16 *source = *sourceStart;
+    UTF8 *target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch;
+        unsigned short bytesToWrite = 0;
+        const UTF32 byteMask = 0xBF;
+        const UTF32 byteMark = 0x80;
+        const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
+        ch = *source++;
+        /* If we have a surrogate pair, convert to UTF32 first. */
+        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+            /* If the 16 bits following the high surrogate are in the source buffer... */
+            if (source < sourceEnd) {
+                UTF32 ch2 = *source;
+                /* If it's a low surrogate, convert to UTF32. */
+                if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+                    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+                         + (ch2 - UNI_SUR_LOW_START) + halfBase;
+                    ++source;
+                } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                }
+            } else { /* We don't have the 16 bits following the high surrogate. */
+                --source; /* return to the high surrogate */
+                result = sourceExhausted;
+                break;
+            }
+        } else if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        /* Figure out how many bytes the result will require */
+        if (ch < (UTF32) 0x80) {
+            bytesToWrite = 1;
+        } else if (ch < (UTF32) 0x800) {
+            bytesToWrite = 2;
+        } else if (ch < (UTF32) 0x10000) {
+            bytesToWrite = 3;
+        } else if (ch < (UTF32) 0x110000) {
+            bytesToWrite = 4;
+        } else {
+            bytesToWrite = 3;
+            ch = UNI_REPLACEMENT_CHAR;
+        }
+
+        target += bytesToWrite;
+        if (target > targetEnd) {
+            source = oldSource; /* Back up source pointer! */
+            target -= bytesToWrite;
+            result = targetExhausted;
+            break;
+        }
+        switch (bytesToWrite) { /* note: everything falls through. */
+            case 4:
+                *--target = (UTF8) ((ch | byteMark) & byteMask);
+                ch >>= 6;
+            case 3:
+                *--target = (UTF8) ((ch | byteMark) & byteMask);
+                ch >>= 6;
+            case 2:
+                *--target = (UTF8) ((ch | byteMark) & byteMask);
+                ch >>= 6;
+            case 1:
+                *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+        }
+        target += bytesToWrite;
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ *  length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false.  The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length) {
+    UTF8 a;
+    const UTF8 *srcptr = source + length;
+    switch (length) {
+        default:
+            return false;
+            /* Everything else falls through when "true"... */
+        case 4:
+            if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+        case 3:
+            if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+        case 2:
+            if ((a = (*--srcptr)) > 0xBF) return false;
+
+            switch (*source) {
+                /* no fall-through in this inner switch */
+                case 0xE0:
+                    if (a < 0xA0) return false;
+                    break;
+                case 0xED:
+                    if (a > 0x9F) return false;
+                    break;
+                case 0xF0:
+                    if (a < 0x90) return false;
+                    break;
+                case 0xF4:
+                    if (a > 0x8F) return false;
+                    break;
+                default:
+                    if (a < 0x80) return false;
+            }
+
+        case 1:
+            if (*source >= 0x80 && *source < 0xC2) return false;
+    }
+    if (*source > 0xF4) return false;
+    return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+    int length = trailingBytesForUTF8[*source] + 1;
+    if (source + length > sourceEnd) {
+        return false;
+    }
+    return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16(
+        const UTF8 **sourceStart, const UTF8 *sourceEnd,
+        UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF8 *source = *sourceStart;
+    UTF16 *target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch = 0;
+        unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+        if (source + extraBytesToRead >= sourceEnd) {
+            result = sourceExhausted;
+            break;
+        }
+        /* Do this check whether lenient or strict */
+        if (!isLegalUTF8(source, extraBytesToRead + 1)) {
+            result = sourceIllegal;
+            break;
+        }
+        /*
+         * The cases all fall through. See "Note A" below.
+         */
+        switch (extraBytesToRead) {
+            case 5:
+                ch += *source++;
+                ch <<= 6; /* remember, illegal UTF-8 */
+            case 4:
+                ch += *source++;
+                ch <<= 6; /* remember, illegal UTF-8 */
+            case 3:
+                ch += *source++;
+                ch <<= 6;
+            case 2:
+                ch += *source++;
+                ch <<= 6;
+            case 1:
+                ch += *source++;
+                ch <<= 6;
+            case 0:
+                ch += *source++;
+        }
+        ch -= offsetsFromUTF8[extraBytesToRead];
+
+        if (target >= targetEnd) {
+            source -= (extraBytesToRead + 1); /* Back up source pointer! */
+            result = targetExhausted;
+            break;
+        }
+        if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    source -= (extraBytesToRead + 1); /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = (UTF16) ch; /* normal case */
+            }
+        } else if (ch > UNI_MAX_UTF16) {
+            if (flags == strictConversion) {
+                result = sourceIllegal;
+                source -= (extraBytesToRead + 1); /* return to the start */
+                break; /* Bail out; shouldn't continue */
+            } else {
+                *target++ = UNI_REPLACEMENT_CHAR;
+            }
+        } else {
+            /* target is a character in range 0xFFFF - 0x10FFFF. */
+            if (target + 1 >= targetEnd) {
+                source -= (extraBytesToRead + 1); /* Back up source pointer! */
+                result = targetExhausted;
+                break;
+            }
+            ch -= halfBase;
+            *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START);
+            *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START);
+        }
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8(
+        const UTF32 **sourceStart, const UTF32 *sourceEnd,
+        UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF32 *source = *sourceStart;
+    UTF8 *target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch;
+        unsigned short bytesToWrite = 0;
+        const UTF32 byteMask = 0xBF;
+        const UTF32 byteMark = 0x80;
+        ch = *source++;
+        if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        /*
+         * Figure out how many bytes the result will require. Turn any
+         * illegally large UTF32 things (> Plane 17) into replacement chars.
+         */
+        if (ch < (UTF32) 0x80) {
+            bytesToWrite = 1;
+        } else if (ch < (UTF32) 0x800) {
+            bytesToWrite = 2;
+        } else if (ch < (UTF32) 0x10000) {
+            bytesToWrite = 3;
+        } else if (ch <= UNI_MAX_LEGAL_UTF32) {
+            bytesToWrite = 4;
+        } else {
+            bytesToWrite = 3;
+            ch = UNI_REPLACEMENT_CHAR;
+            result = sourceIllegal;
+        }
+
+        target += bytesToWrite;
+        if (target > targetEnd) {
+            --source; /* Back up source pointer! */
+            target -= bytesToWrite;
+            result = targetExhausted;
+            break;
+        }
+        switch (bytesToWrite) { /* note: everything falls through. */
+            case 4:
+                *--target = (UTF8) ((ch | byteMark) & byteMask);
+                ch >>= 6;
+            case 3:
+                *--target = (UTF8) ((ch | byteMark) & byteMask);
+                ch >>= 6;
+            case 2:
+                *--target = (UTF8) ((ch | byteMark) & byteMask);
+                ch >>= 6;
+            case 1:
+                *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+        }
+        target += bytesToWrite;
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32(
+        const UTF8 **sourceStart, const UTF8 *sourceEnd,
+        UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) {
+    ConversionResult result = conversionOK;
+    const UTF8 *source = *sourceStart;
+    UTF32 *target = *targetStart;
+    while (source < sourceEnd) {
+        UTF32 ch = 0;
+        unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+        if (source + extraBytesToRead >= sourceEnd) {
+            result = sourceExhausted;
+            break;
+        }
+        /* Do this check whether lenient or strict */
+        if (!isLegalUTF8(source, extraBytesToRead + 1)) {
+            result = sourceIllegal;
+            break;
+        }
+        /*
+         * The cases all fall through. See "Note A" below.
+         */
+        switch (extraBytesToRead) {
+            case 5:
+                ch += *source++;
+                ch <<= 6;
+            case 4:
+                ch += *source++;
+                ch <<= 6;
+            case 3:
+                ch += *source++;
+                ch <<= 6;
+            case 2:
+                ch += *source++;
+                ch <<= 6;
+            case 1:
+                ch += *source++;
+                ch <<= 6;
+            case 0:
+                ch += *source++;
+        }
+        ch -= offsetsFromUTF8[extraBytesToRead];
+
+        if (target >= targetEnd) {
+            source -= (extraBytesToRead + 1); /* Back up the source pointer! */
+            result = targetExhausted;
+            break;
+        }
+        if (ch <= UNI_MAX_LEGAL_UTF32) {
+            /*
+             * UTF-16 surrogate values are illegal in UTF-32, and anything
+             * over Plane 17 (> 0x10FFFF) is illegal.
+             */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    source -= (extraBytesToRead + 1); /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = ch;
+            }
+        } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+            result = sourceIllegal;
+            *target++ = UNI_REPLACEMENT_CHAR;
+        }
+    }
+    *sourceStart = source;
+    *targetStart = target;
+    return result;
+}
+
+/* ---------------------------------------------------------------------
+
+    Note A.
+    The fall-through switches in UTF-8 reading code save a
+    temp variable, some decrements & conditionals.  The switches
+    are equivalent to the following loop:
+	{
+	    int tmpBytesToRead = extraBytesToRead+1;
+	    do {
+		ch += *source++;
+		--tmpBytesToRead;
+		if (tmpBytesToRead) ch <<= 6;
+	    } while (tmpBytesToRead > 0);
+	}
+    In UTF-8 writing code, the switches on "bytesToWrite" are
+    similarly unrolled loops.
+
+   --------------------------------------------------------------------- */
+
+const unsigned char *utf32toutf8(wchar_t *source, unsigned char *target, size_t size,  int *len){
+
+    wchar_t *s_start;
+    unsigned char *t_start;
+
+    s_start = source;
+    t_start = target;
+
+    if (ConvertUTF32toUTF8((const UTF32**) &s_start, (UTF32*)s_start + wcslen(source), (UTF8**)&t_start, (UTF8*)t_start + size, strictConversion) == conversionOK) {
+        *len = t_start - target;
+    }
+    else {
+        *len = 0;
+    }
+    target[*len] = '\0';
+    return (const unsigned char*)target;
+}
+
+
+unsigned char *utf16toutf8(unsigned short *source, unsigned char *target, size_t size,  int *len){
+
+    unsigned short *s_start;
+    unsigned char *t_start;
+
+    s_start = source;
+    t_start = target;
+
+    if (ConvertUTF16toUTF8((const UTF16**) &s_start, (UTF16*)s_start + strlen((const char*)source) / 2, (UTF8**)&t_start, (UTF8*)t_start + size, strictConversion) == conversionOK) {
+        *len = t_start - target;
+    }
+    else {
+        *len = 0;
+    }
+    target[*len] = '\0';
+    return target;
+}
+
+unsigned short *utf8toutf16(unsigned char *source, unsigned short *target, size_t size,  int *len)
+{
+    unsigned char *s_start;
+    unsigned short *t_start;
+
+    s_start = source;
+    t_start = target;
+
+    if (ConvertUTF8toUTF16((const UTF8 **)&s_start, s_start + strlen((const char*)source), &t_start, t_start + size, strictConversion) == conversionOK) {
+        *len = t_start - target;
+    }
+    else {
+        *len = 0;
+    }
+
+    return target;
+}
+
+u_int32_t next_char(unsigned char **string) {
+
+    int len = strlen((const char*)*string);
+    unsigned char ch[4];
+	int i = 0;
+
+    if (len < 4){
+        for (i = 0; i < len; i++)
+            ch[i] = (*string)[i];
+    }
+    else {
+        ch[0] = (*string)[0];
+        ch[1] = (*string)[1];
+        ch[2] = (*string)[2];
+        ch[3] = (*string)[3];
+    }
+
+    if(ch[0] < 0x80) {
+        *string =  (*string + 1);
+        return ch[0];
+    }
+    else if (ch[0] >= 0xc0 && ch[0] <= 0xdf) {
+        *string = (*string + 2);
+        return ch[1] << 8 | ch[0];
+    }
+    else if (ch[0] >= 0xe0 && ch[0] <= 0xef) {
+        *string = (*string + 3);
+        return ch[2] << 16 | ch[1] << 8 | ch[0];
+    }
+    else if (ch[0] >= 0xf0 && ch[0] <= 0xf7) {
+        *string = (*string + 4);
+        return ch[3] << 24 | ch[2] << 16 | ch[1] << 8 | ch[0];
+    }
+
+    return *(u_int32_t*)ch;
+}
+
+
+int utf8len(unsigned char *string)
+{
+    unsigned char *end;
+    int ret = 0;
+
+    end = string + strlen((const char*)string);
+    while(string < end) {
+        next_char(&string);
+        ret++;
+    }
+    return ret;
+}
+
+int is_acsii(unsigned char *string)
+{
+    while(*string) {
+        if (*string >= 0x80)
+            return 0;
+        string++;
+    }
+    return 1;
+}
+
+size_t utf8_get_size(unsigned char *source, size_t num)
+{
+	size_t ret = 0;
+
+	unsigned char *cur = source;
+	while (num-- && *cur) {
+		next_char(&cur);
+	}
+	ret = cur - source;
+
+	return ret;
+}
diff --git a/mbtk/mbtk_lib/src/mbtk_utils.c b/mbtk/mbtk_lib/src/mbtk_utils.c
new file mode 100755
index 0000000..3d61daf
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_utils.c
@@ -0,0 +1,539 @@
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_type.h"
+#include "mbtk_utils.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "mbtk_utils"
+#include "mbtk_log.h"
+
+#define MBTK_AT_BUF_SIZE 2048
+#define MBTK_AT_CLIENT_SOCKET "/data/sock_mbtk_at"
+#define PROC_CMDLINE "/proc/cmdline"
+#define TIME_FORMAT "%F %T"
+
+static int at_fd = -1;
+static bool at_timeout = FALSE;
+
+static void
+at_timer_alrm(int signo)
+{
+    LOGW("AT Timeout.[%d]\n",signo);
+    at_timeout = TRUE;
+}
+
+
+/*
+* Exec shell command.
+*/
+bool mbtk_cmd_line
+(
+    const char *cmd,
+    char *buf,
+    int buf_size
+)
+{
+    FILE *fcmd;
+    bool result = FALSE;
+    fcmd = popen(cmd, "r");
+    memset(buf, 0, buf_size);
+    if(fcmd)
+    {
+        int pos = 0;
+        int len = 0;
+
+        while(!ferror(fcmd) && !feof(fcmd))
+        {
+            if(buf_size - pos == 0)
+            {
+                break;
+            }
+            len = fread(buf + pos,1,buf_size - pos,fcmd);
+            if(len > 0)
+                pos += len;
+        }
+
+        if(buf_size == pos)
+            buf[buf_size - 1] = '\0';
+
+        pclose(fcmd);
+        result = TRUE;
+    }
+
+    LOGV("%s [result:%d]: %s",cmd,result,buf);
+
+    return result;
+}
+
+bool mbtk_cmd_line_ex
+(
+    const char *cmd,
+    mbtk_cmd_cb_func cb
+)
+{
+#define BUFF_SIZE 1024
+    FILE *fcmd;
+    bool result = FALSE;
+    // Get stdout and stderr data.
+    // xxx 2>&1
+    char buff[BUFF_SIZE + 1] = {0};
+    snprintf(buff, BUFF_SIZE + 1, "%s 2>&1", cmd);
+    fcmd = popen(buff, "r");
+    if(!cb)
+    {
+        return FALSE;
+    }
+    if(fcmd)
+    {
+        int len = 0;
+        if(setvbuf(fcmd, NULL, _IOLBF, BUFF_SIZE)) {
+            LOGE("setvbuf() fail:%d", errno);
+        }
+        errno = 0;
+        LOGI("ferror - %d,feof - %d",ferror(fcmd),feof(fcmd));
+        while(!ferror(fcmd) && !feof(fcmd))
+        {
+            memset(buff, 0, BUFF_SIZE + 1);
+            len = fread(buff,1,BUFF_SIZE,fcmd);
+            if(len > 0)
+            {
+                cb(buff,len);
+            }
+            else
+            {
+                LOGE("len - %d,errno - %d",len,errno);
+            }
+        }
+
+        pclose(fcmd);
+        result = TRUE;
+
+        cb(NULL,0);
+    }
+    else
+    {
+        LOGE("popen() fail.[errno=%d]",errno);
+        cb(NULL,0);
+    }
+
+    return result;
+}
+
+
+
+#if 1
+// Send msg to stanet_daemon
+int mbtk_send_at(const void *at_req,void* at_rsp,int rsp_size,int timeout)
+{
+    if(at_fd < 0)
+    {
+        struct sockaddr_un servaddr;
+        at_fd = socket(AF_LOCAL,SOCK_STREAM,0);
+        if(at_fd < 0)
+        {
+            LOGE("socket fail.(%d)\n",errno);
+            at_fd = -1;
+            return -1;
+        }
+
+        // Set O_NONBLOCK
+//        int flags = fcntl(at_fd, F_GETFL, 0);
+//        if (flags < 0) {
+//            LOGE("Get flags error:%s\n", strerror(errno));
+//            return -1;
+//        }
+//        flags |= O_NONBLOCK;
+//        if (fcntl(at_fd, F_SETFL, flags) < 0) {
+//            LOGE("Set flags error:%s\n", strerror(errno));
+//            return -1;
+//        }
+
+        memset(&servaddr,0x0,sizeof(servaddr));
+        servaddr.sun_family = AF_LOCAL;
+        strcpy(servaddr.sun_path,MBTK_AT_CLIENT_SOCKET);
+
+        if(connect(at_fd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
+        {
+            LOGE("connect fail.(%d)\n",errno);
+            close(at_fd);
+            at_fd = -1;
+            return -1;
+        }
+    }
+
+    at_timeout = FALSE;
+    int n = write(at_fd,at_req,strlen((char*)at_req));
+    if(n == -1)
+    {
+        LOGE("write fail[%d].\n",errno);
+        close(at_fd);
+        at_fd = -1;
+        return -1;
+    }
+
+    // Set timer
+    signal(SIGALRM, at_timer_alrm);
+    struct itimerval    val;
+    // Only time
+    val.it_interval.tv_sec  = 0;
+    val.it_interval.tv_usec = 0;
+    // Time
+    if(timeout >= 1000)
+    {
+        val.it_value.tv_sec  = timeout/1000;
+        val.it_value.tv_usec = timeout%1000;
+    }
+    else
+    {
+        val.it_value.tv_sec  = 0;
+        val.it_value.tv_usec = timeout;
+    }
+    if (setitimer(ITIMER_REAL, &val, NULL) == -1)
+    {
+        LOGE("setitimer fail.[%d]",errno);
+        return -1;
+    }
+
+    memset(at_rsp,0x0,rsp_size);
+    while(!at_timeout)
+    {
+        n = read(at_fd,at_rsp,rsp_size);
+        if(n < 0)
+        {
+            if(errno == EWOULDBLOCK)
+            {
+                usleep(50000);
+                continue;
+            }
+            else
+            {
+                LOGW("read error.[%d]",errno);
+                break;
+            }
+        }
+        else if (n > 0)
+        {
+            LOGI("RSP:%s",(char*)at_rsp);
+            break;
+        }
+        else
+        {
+            LOGW("read error.[%d]",errno);
+            break;
+        }
+    }
+
+    val.it_value.tv_sec = 0;
+    val.it_value.tv_usec = 0;
+    val.it_interval = val.it_value;
+    setitimer(ITIMER_REAL, &val, NULL);
+
+    if(n > 0)
+        return 0;
+
+    return -1;
+}
+#else
+int mbtk_send_at(const void *at_req,void* at_rsp,int rsp_size,int timeout)
+{
+    if(!at_req || !at_rsp || rsp_size <= 0)
+    {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    // Return "ERROR" if AT fail.
+    const char* result = sendCmd(0,(const char*)at_req);
+    memset(at_rsp,0x0,rsp_size);
+    snprintf(at_rsp,rsp_size,"%s",result);
+
+    return 0;
+}
+#endif
+
+/*
+* Set timer as microseconds.
+*/
+int mbtk_timer_set(mbtk_timer_alrm_func func,uint32 timeout_ms)
+{
+    signal(SIGALRM, func);
+    struct itimerval    val;
+    // Only time
+    val.it_interval.tv_sec  = 0;
+    val.it_interval.tv_usec = 0;
+    // Time
+    if(timeout_ms >= 1000)
+    {
+        val.it_value.tv_sec  = timeout_ms/1000;
+        val.it_value.tv_usec = timeout_ms%1000;
+    }
+    else
+    {
+        val.it_value.tv_sec  = 0;
+        val.it_value.tv_usec = timeout_ms;
+    }
+    if (setitimer(ITIMER_REAL, &val, NULL) == -1)
+    {
+        LOGE("setitimer fail.[errno - %d]",errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+* Clear current timer.
+*/
+int mbtk_timer_clear()
+{
+    struct itimerval value;
+    value.it_value.tv_sec = 0;
+    value.it_value.tv_usec = 0;
+    value.it_interval = value.it_value;
+    if (setitimer(ITIMER_REAL, &value, NULL) == -1)
+    {
+        LOGE("setitimer fail.[errno - %d]",errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* MRD still need to read /proc/cmdline after we drop root permission,
+ * so cache it in this function */
+int mbtk_get_kernel_cmdline(char *buf, int len)
+{
+    static char cmdline[MBTK_CMDLINE_LEN];
+    static int is_init = 0;
+    int ret = -1;
+    int fd;
+
+    if(!buf || len <= 0) return -1;
+
+    if(is_init)
+        goto INITED;
+
+    fd = open(PROC_CMDLINE, O_RDONLY);
+    if (fd < 0)
+        goto ERR_RET;
+
+    ret = read(fd, cmdline, MBTK_CMDLINE_LEN);
+    close(fd);
+
+    if(ret <= 0 || ret > MBTK_CMDLINE_LEN)
+        goto ERR_RET;
+    cmdline[ret - 1] = '\0';
+
+INITED:
+    ret = strlen(cmdline) + 1;
+    if(ret > len)
+        ret = len;
+
+    strncpy(buf, cmdline, ret);
+    buf[ret - 1] = '\0';
+
+    is_init = 1;
+
+    return ret;
+
+ERR_RET:
+    return -1;
+}
+
+/** returns 1 if line starts with prefix, 0 if it does not */
+int strStartsWith(const char *line, const char *prefix)
+{
+    if(prefix == NULL || strlen(prefix) == 0) {
+        return 1;
+    }
+
+    for ( ; *line != '\0' && *prefix != '\0' ; line++, prefix++) {
+        if (*line != *prefix) {
+            return 0;
+        }
+    }
+
+    return *prefix == '\0';
+}
+
+char* mbtk_time_text_get(char *buff, size_t buff_size)
+{
+    long now_nsec = 0;
+    if(buff == NULL || buff_size <= 0) {
+        return NULL;
+    }
+    memset(buff, 0x0, buff_size);
+#if 0
+    time_t now;
+    now = time(&now);
+    if(now == -1) {
+        LOGE("time() fail.");
+        return NULL;
+    }
+    struct tm *now_tm = gmtime(&now);
+#else
+    struct timespec now;
+    if(-1 == clock_gettime(CLOCK_REALTIME, &now)) {
+        LOGE("clock_gettime() fail.");
+        return NULL;
+    }
+
+    struct tm *now_tm = gmtime((time_t*)(&(now.tv_sec)));
+    now_nsec = now.tv_nsec;
+#endif
+
+    if(now_tm == NULL) {
+        LOGE("gmtime() fail.");
+        return NULL;
+    }
+
+    if(0 == strftime(buff, buff_size, TIME_FORMAT, now_tm)) {
+        LOGE("strftime() fail.");
+        return NULL;
+    }
+
+    snprintf(buff + strlen(buff), buff_size - strlen(buff),
+        "-%03ld", now_nsec / 1000000);
+
+    return buff;
+}
+
+mbtk_byteorder_enum mbtk_byteorder_get()
+{
+    union {
+        short a;
+        char c[sizeof(short)];
+    } un;
+    un.a = 0x0102;
+    if(sizeof(short) == 2) {
+        if(un.c[0] == 1 && un.c[1] == 2) {
+            return MBTK_BYTEORDER_BIG;
+        } else if(un.c[0] == 2 && un.c[1] == 1) {
+            return MBTK_BYTEORDER_LITTLE;
+        } else {
+            return MBTK_BYTEORDER_UNKNOWN;
+        }
+    } else {
+        LOGE("Unknown byte order.");
+        return MBTK_BYTEORDER_UNKNOWN;
+    }
+}
+
+uint16 byte_2_uint16(const void *buff, bool big_endian)
+{
+    const uint8* ptr = (const uint8*)buff;
+    if(big_endian) {
+        return (uint16)((ptr[0] << 8) | ptr[1]);
+    } else {
+        return (uint16)((ptr[1] << 8) | ptr[0]);
+    }
+}
+
+int uint16_2_byte(uint16 a, void *buff, bool big_endian)
+{
+    uint8* ptr = (uint8*)buff;
+    if(big_endian) {
+        ptr[0] = (uint8)(a >> 8);
+        ptr[1] = (uint8)a;
+    } else {
+        ptr[1] = (uint8)(a >> 8);
+        ptr[0] = (uint8)a;
+    }
+    return sizeof(uint16);
+}
+
+uint32 byte_2_uint32(const void *buff, bool big_endian)
+{
+    const uint8* ptr = (const uint8*)buff;
+    if(big_endian) {
+        return (uint32)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]);
+    } else {
+        return (uint32)((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
+    }
+}
+
+int uint32_2_byte(uint32 a, void *buff, bool big_endian)
+{
+    uint8* ptr = (uint8*)buff;
+    if(big_endian) {
+        ptr[0] = (uint8)(a >> 24);
+        ptr[1] = (uint8)(a >> 16);
+        ptr[2] = (uint8)(a >> 8);
+        ptr[3] = (uint8)a;
+    } else {
+        ptr[3] = (uint8)(a >> 24);
+        ptr[2] = (uint8)(a >> 16);
+        ptr[1] = (uint8)(a >> 8);
+        ptr[0] = (uint8)a;
+    }
+    return sizeof(uint32);
+}
+
+uint64 byte_2_uint64(const void *buff, bool big_endian)
+{
+    const uint8* ptr = (const uint8*)buff;
+    if(big_endian) {
+        return (uint64)(((uint64)ptr[0] << 56) | ((uint64)ptr[1] << 48) | ((uint64)ptr[2] << 40) | ((uint64)ptr[3] << 32) | (ptr[4] << 24) | (ptr[5] << 16) | (ptr[6] << 8) | ptr[7]);
+    } else {
+        return (uint64)(uint64)(((uint64)ptr[7] << 56) | ((uint64)ptr[6] << 48) | ((uint64)ptr[5] << 40) | ((uint64)ptr[4] << 32) | (ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
+    }
+}
+
+int uint64_2_byte(uint64 a, void *buff, bool big_endian)
+{
+    uint8* ptr = (uint8*)buff;
+    if(big_endian) {
+        ptr[0] = (uint8)(a >> 56);
+        ptr[1] = (uint8)(a >> 48);
+        ptr[2] = (uint8)(a >> 40);
+        ptr[3] = (uint8)(a >> 32);
+        ptr[4] = (uint8)(a >> 24);
+        ptr[5] = (uint8)(a >> 16);
+        ptr[6] = (uint8)(a >> 8);
+        ptr[7] = (uint8)a;
+    } else {
+        ptr[7] = (uint8)(a >> 56);
+        ptr[6] = (uint8)(a >> 48);
+        ptr[5] = (uint8)(a >> 40);
+        ptr[4] = (uint8)(a >> 32);
+        ptr[3] = (uint8)(a >> 24);
+        ptr[2] = (uint8)(a >> 16);
+        ptr[1] = (uint8)(a >> 8);
+        ptr[0] = (uint8)a;
+    }
+    return sizeof(uint64);
+}
+
+void* memdup(const void* data, int data_len)
+{
+    if(data && data_len > 0)
+    {
+        uint8* result = (uint8*)malloc(data_len);
+        if(result == NULL)
+        {
+            return NULL;
+        }
+        memcpy(result, data, data_len);
+        return result;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+
diff --git a/mbtk/mbtk_lib/src/ringbuffer.c b/mbtk/mbtk_lib/src/ringbuffer.c
new file mode 100755
index 0000000..d5225cc
--- /dev/null
+++ b/mbtk/mbtk_lib/src/ringbuffer.c
@@ -0,0 +1,90 @@
+#include "ringbuffer.h"
+
+/**
+ * @file
+ * Implementation of ring buffer functions.
+ */
+
+void ring_buffer_init(ring_buffer_t *buffer, char *buf, size_t buf_size) {
+  RING_BUFFER_ASSERT(RING_BUFFER_IS_POWER_OF_TWO(buf_size) == 1);
+  buffer->buffer = buf;
+  buffer->buffer_mask = buf_size - 1;
+  buffer->tail_index = 0;
+  buffer->head_index = 0;
+}
+
+void ring_buffer_queue(ring_buffer_t *buffer, char data) {
+  /* Is buffer full? */
+  if(ring_buffer_is_full(buffer)) {
+    /* Is going to overwrite the oldest byte */
+    /* Increase tail index */
+    buffer->tail_index = ((buffer->tail_index + 1) & RING_BUFFER_MASK(buffer));
+  }
+
+  /* Place data in buffer */
+  buffer->buffer[buffer->head_index] = data;
+  buffer->head_index = ((buffer->head_index + 1) & RING_BUFFER_MASK(buffer));
+}
+
+void ring_buffer_queue_arr(ring_buffer_t *buffer, const char *data, ring_buffer_size_t size) {
+  /* Add bytes; one by one */
+  ring_buffer_size_t i;
+  for(i = 0; i < size; i++) {
+    ring_buffer_queue(buffer, data[i]);
+  }
+}
+
+uint8_t ring_buffer_dequeue(ring_buffer_t *buffer, char *data) {
+  if(ring_buffer_is_empty(buffer)) {
+    /* No items */
+    return 0;
+  }
+
+  *data = buffer->buffer[buffer->tail_index];
+  buffer->tail_index = ((buffer->tail_index + 1) & RING_BUFFER_MASK(buffer));
+  return 1;
+}
+
+ring_buffer_size_t ring_buffer_dequeue_arr(ring_buffer_t *buffer, char *data, ring_buffer_size_t len) {
+  if(ring_buffer_is_empty(buffer)) {
+    /* No items */
+    return 0;
+  }
+
+  char *data_ptr = data;
+  ring_buffer_size_t cnt = 0;
+  while((cnt < len) && ring_buffer_dequeue(buffer, data_ptr)) {
+    cnt++;
+    data_ptr++;
+  }
+  return cnt;
+}
+
+uint8_t ring_buffer_peek(ring_buffer_t *buffer, char *data, ring_buffer_size_t index) {
+  if(index >= ring_buffer_num_items(buffer)) {
+    /* No items at index */
+    return 0;
+  }
+
+  /* Add index to pointer */
+  ring_buffer_size_t data_index = ((buffer->tail_index + index) & RING_BUFFER_MASK(buffer));
+  *data = buffer->buffer[data_index];
+  return 1;
+}
+
+uint8_t ring_buffer_is_empty(ring_buffer_t *buffer) {
+  return (buffer->head_index == buffer->tail_index);
+}
+
+uint8_t ring_buffer_is_full(ring_buffer_t *buffer) {
+  return ((buffer->head_index - buffer->tail_index) & RING_BUFFER_MASK(buffer)) == RING_BUFFER_MASK(buffer);
+}
+
+ring_buffer_size_t ring_buffer_num_items(ring_buffer_t *buffer) {
+  return ((buffer->head_index - buffer->tail_index) & RING_BUFFER_MASK(buffer));
+}
+
+void ring_buffer_clean(ring_buffer_t *buffer) {
+  buffer->tail_index = 0;
+  buffer->head_index = 0;
+}
diff --git a/mbtk/mbtk_logd/Makefile b/mbtk/mbtk_logd/Makefile
new file mode 100755
index 0000000..562a644
--- /dev/null
+++ b/mbtk/mbtk_logd/Makefile
@@ -0,0 +1,40 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_logd
+
+INC_DIR += -I$(BUILD_ROOT)
+	
+LIB_DIR +=
+
+LIBS += -lubus -lubox -ljson-c -lblobmsg_json
+
+CFLAGS +=
+
+DEFINE +=
+
+MY_FILES_PATH:=$(LOCAL_PATH)
+#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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/bin/mbtk_logd
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
diff --git a/mbtk/mbtk_logd/alog_read.c b/mbtk/mbtk_logd/alog_read.c
new file mode 100755
index 0000000..33f227f
--- /dev/null
+++ b/mbtk/mbtk_logd/alog_read.c
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include "log_config.h"
+
+#define  ALOG_DEV "/dev/log_radio"
+
+typedef enum android_LogPriority {
+    ANDROID_LOG_UNKNOWN = 0,
+    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
+    ANDROID_LOG_VERBOSE,
+    ANDROID_LOG_DEBUG,
+    ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,
+    ANDROID_LOG_ERROR,
+    ANDROID_LOG_FATAL,
+    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+typedef struct AndroidLogEntry_t {
+    time_t tv_sec;
+    long tv_nsec;
+    android_LogPriority priority;
+    int32_t pid;
+    int32_t tid;
+    const char * tag;
+    size_t messageLen;
+    const char * message;
+} AndroidLogEntry;
+
+static const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_size = 1 * 1024 * 1024;
+
+static log_config_entry *config = NULL;
+static char tmp_log[48] = {0};
+
+void hex_print(char* buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        printf("%x ", buf[i]);
+    }
+}
+
+static char filterPriToChar(android_LogPriority pri)
+{
+    switch (pri) {
+        case ANDROID_LOG_VERBOSE:
+            return 'V';
+        case ANDROID_LOG_DEBUG:
+            return 'D';
+        case ANDROID_LOG_INFO:
+            return 'I';
+        case ANDROID_LOG_WARN:
+            return 'W';
+        case ANDROID_LOG_ERROR:
+            return 'E';
+        case ANDROID_LOG_FATAL:
+            return 'F';
+        case ANDROID_LOG_SILENT:
+            return 'S';
+
+        case ANDROID_LOG_DEFAULT:
+        case ANDROID_LOG_UNKNOWN:
+        default:
+            return '?';
+    }
+}
+
+static android_LogPriority filterCharToPri(char c)
+{
+    switch (c) {
+        case 'v':
+            return ANDROID_LOG_VERBOSE;
+        case 'd':
+            return ANDROID_LOG_DEBUG;
+        case 'i':
+            return ANDROID_LOG_INFO;
+        case 'w':
+            return ANDROID_LOG_WARN;
+        case 'e':
+            return ANDROID_LOG_ERROR;
+        case 'f':
+            return ANDROID_LOG_FATAL;
+        case 's':
+            return ANDROID_LOG_SILENT;
+        case '*':
+        default:
+            return ANDROID_LOG_VERBOSE;
+    }
+}
+
+int fileter_log(int pri, char *tag, struct filter_list_t *filter)
+{
+    struct filter_list_t *_filter = filter;
+
+    while(_filter)
+    {
+        int p = filterCharToPri(_filter->priority);
+        if(_filter->tag)
+        {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if(0 == memcmp(_filter->tag, tag, len) && ((pri > p) || (pri == p)))
+                return 0;
+        }else{ // have no tag
+            if(pri < p)
+                return -1;
+            else
+                return 0;
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+
+int alog_process(char* data, int len, AndroidLogEntry *entry)
+{
+    int i, n = 0;
+    int tmp_len;
+
+    for (i = 0; i < len;) {
+        if (data[i] == '\0') {
+            i += 1;
+        } else {
+            switch (n) {
+                case 0: {
+                    // printf("%d - %d: %x\n", i, tmp_len, data[i]);
+                    i++;
+                    break;
+                }
+                case 1: {
+                    int* pid = (int*)&data[i];
+                    entry->pid = *pid;
+                    // printf("%d pid: %d\n", i, entry->pid);
+                    i += 4;
+                    break;
+                }
+                case 2: {
+                    int* tid = (int*)&data[i];
+                    entry->tid = *tid;
+                    // printf("%d tid: %d\n", i, entry->tid);
+                    i += 4;
+                    break;
+                }
+                case 3: {
+                    // printf("%d - %d: %x %x %x %x\n", i, tmp_len, data[i], data[i + 1], data[i + 2], data[i + 3]);
+                    time_t* _t = (time_t*)&data[i];
+                    entry->tv_sec = *_t;
+                    i += 8;
+                    break;
+                }
+                case 4: {
+                    entry->priority = data[i];
+                    entry->tag = &data[i + 1];
+                    i += strlen(&data[i]);
+                    break;
+                }
+                //* format: <priority:1><tag:N>\0<message:N>\0
+                case 5: {
+                    entry->message = &data[i];
+                    entry->messageLen = strlen(&data[i]);
+                    i += entry->messageLen;
+                    break;
+                }
+                default:
+                    printf("process error \n");
+                    break;
+            }
+            n++;
+        }
+    }
+    return 0;
+}
+
+int android_log_printLogLine(
+    int fd,
+    struct file_list_t *_file_list,
+    const AndroidLogEntry *entry)
+{
+    char priChar;
+    char timeBuf[32];
+    char defaultBuffer[512];
+    size_t totalLen;
+    int fd_new = fd;
+	struct stat s;
+    char * ret = NULL;
+
+	if (log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        fd_new = get_rotate_file(fd_new, log_file, _file_list);
+		if (fd_new < 0) {
+			fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
+			exit(-1);
+        }
+	}
+
+    if(fileter_log(entry->priority, entry->tag, config->filter_list))
+    {
+        // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, entry->priority, entry->tag);
+        return -1;
+    }
+
+    priChar = filterPriToChar(entry->priority);
+    struct tm* ptm = localtime(&entry->tv_sec);
+    strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+
+    totalLen = snprintf(defaultBuffer, sizeof(defaultBuffer),
+    "%s %c/%s (%d): %s\n", timeBuf, priChar, entry->tag, entry->pid, entry->message);
+
+    ret = write(fd_new, defaultBuffer, totalLen);
+
+    return ret;
+}
+
+void* alog_thread(void* argv)
+{
+    int dev_fd, ret;
+    int log_fd;
+    AndroidLogEntry entry;
+    char buf[512] = {0};
+    static struct file_list_t file_list;
+    config = (log_config_entry *)argv;
+
+    pthread_detach(pthread_self());
+    if (NULL == argv)
+        return NULL;
+
+    dev_fd = open(ALOG_DEV, O_RDONLY, 0600);
+    if (dev_fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", ALOG_DEV, strerror(errno));
+        exit(-1);
+    }
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    log_file = config->out_path;
+
+    if (config->ip && config->port) {
+        int port = atoi(config->port);
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_fd = tcp_connect(config->ip, port);
+    } else if (log_file) {
+        sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+        // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+        log_fd = open(tmp_log, O_CREAT | O_WRONLY| O_APPEND, 0600);
+        if (log_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+            exit(-1);
+        }
+    } else {
+        log_fd = STDOUT_FILENO;
+    }
+    if(config->rotate_file_size)
+        log_size = config->rotate_file_size;
+
+    printf("android log start...\n");
+    while (1) {
+        ret = read(dev_fd, buf, sizeof(buf));
+        if (ret < 0) {
+            printf("read error\n");
+            break;
+        }
+        alog_process(buf, ret, &entry);
+        android_log_printLogLine(log_fd, &file_list, &entry);
+        memset(buf, 0, sizeof(buf));
+    }
+    close(dev_fd);
+    close(log_fd);
+
+    printf("%s exit \n", __FUNCTION__);
+    pthread_exit(NULL);
+	return NULL;
+}
diff --git a/mbtk/mbtk_logd/common.c b/mbtk/mbtk_logd/common.c
new file mode 100755
index 0000000..1e293b6
--- /dev/null
+++ b/mbtk/mbtk_logd/common.c
@@ -0,0 +1,282 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include "log_config.h"
+
+/* 文件大小和修改时间 */
+static int get_file_size_time(const char *filename)
+{
+	struct stat statbuf;
+	/* 判断未打开文件 */
+	if(stat(filename,&statbuf)==-1)
+	{
+		printf("Get stat on %s Error: %s\n", filename, strerror(errno));
+		return(-1);
+	}
+	if(S_ISDIR(statbuf.st_mode)) // 目录
+		return(1);
+	if(S_ISREG(statbuf.st_mode)) // 文件
+		printf("%s size: %ld bytes\tmodified at %s", filename, statbuf.st_size, ctime(&statbuf.st_mtime));
+	return(0);
+}
+
+int __main(int argc,char **argv)
+{
+	DIR *dirp;
+	struct dirent *direntp;
+	int stats;
+
+	if(argc!=2)
+	{
+		printf("Usage: %s filename\n\a", argv[0]);
+		exit(1);
+	}
+
+	if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1)) // 文件或出现错误
+		exit(1);
+
+	/* 打开目录 */
+	if((dirp=opendir(argv[1]))==NULL)
+	{
+		printf("Open Directory %s Error: %s\n", argv[1], strerror(errno));
+		exit(1);
+	}
+
+	/* 返回目录中文件大小和修改时间 */
+	while((direntp=readdir(dirp))!=NULL)
+	{
+		/* 给文件或目录名添加路径:argv[1]+"/"+direntp->d_name */
+		char dirbuf[512];
+		memset(dirbuf,0,sizeof(dirbuf));
+		strcpy(dirbuf,argv[1]);
+		strcat(dirbuf,"/");
+		strcat(dirbuf,direntp->d_name);
+		if(get_file_size_time(dirbuf)==-1) break;
+	}
+
+	closedir(dirp);
+	exit(1);
+}
+// 从后往前找
+char *strstr_tail(const char *dst, const char *src)
+{
+    if(NULL == dst || NULL == src)
+        return NULL;
+    const char *pdst = dst;
+    const char *psrc = src;
+    char *tmp = NULL ;
+    while (*pdst)                          //因为要从后向前找,则首先让pdst指向'\0'
+    {
+       pdst++;
+    }
+
+    while (pdst >= dst )                     //当pdst大于dst则表明dst这个字符串还没有找完
+    {
+        if (tmp=(char *)strstr(pdst, psrc = src))  //使用strstr帮助寻找,找到保存到tmp
+        return tmp;
+
+        pdst--;
+     }
+
+     return NULL ;
+}
+
+char* strcpy_malloc(char* src)
+{
+    if (NULL == src || 0 == strlen(src)) {
+        return NULL;
+    }
+    int len = strlen(src);
+    char* temp = malloc(len + 1);
+    if (NULL == temp) {
+        return NULL;
+    }
+    memset(temp, 0, len + 1);
+    strcpy(temp, src);
+
+    return temp;
+}
+
+int get_time (char *out_time)
+{
+    time_t rawtime;
+    struct tm *info;
+    char buffer[16] = {0};
+
+    time( &rawtime );
+    info = localtime(&rawtime);
+    strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S \n", info);
+    if(out_time)
+        memcpy(out_time, &buffer[2], 12);
+
+    return(0);
+}
+
+int tcp_connect(char* ip, int port)
+{
+    int sockfd;
+    struct hostent* he;
+    struct sockaddr_in server;
+
+    he = gethostbyname(ip);
+
+    if (he == NULL) {
+        printf("gethostbyname error\n");
+        exit(1);
+    }
+
+    sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+    if (sockfd == -1) {
+        printf("socket error\n");
+        exit(1);
+    }
+
+    bzero(&server, sizeof(server));
+    server.sin_family = AF_INET;
+    server.sin_port = htons(port);
+    server.sin_addr = *((struct in_addr*)he->h_addr);
+
+    if (connect(sockfd, (struct sockaddr*)&server, sizeof(server)) == -1) {
+        printf("connect error\n");
+        exit(1);
+    }
+
+    return sockfd;
+}
+int movefile(char *src, char *dst)
+{
+    if (strcmp(src, dst) == 0)
+    {
+        printf("Destination file name and source file name can't be the same!");
+        return -1;
+    }
+    FILE *fsrc = fopen(src, "rb"); //一定要“rb”否则复制的文件有时会不能使用
+    FILE *fdst = fopen(dst, "wb"); //一定要“wb”否则复制的文件有时会不能使用
+    int buflen = 1024;
+    char buf[1024];
+    int nread = 0;
+    while ((nread = fread(buf, 1, buflen, fsrc)) > 0) //最好把读文件的代码放这里
+    {
+        fwrite(buf, 1, nread, fdst);
+    }
+
+    fclose(fsrc);
+    fsrc = NULL;
+    fclose(fdst);
+    fdst = NULL;
+    remove(src);//删除源文件
+
+    return 0;
+}
+/**
+ * @brief      get_rotate_file
+ *
+ * @details    转移log文件
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int get_rotate_file(int fd, char *base_file, struct file_list_t *_file_list)
+{
+    char _time[16] = {0};
+    int num = 0;
+    char tmp_buf[48] = {0};
+    char *current_file = _file_list->file[_file_list->current];
+    int len = strlen(base_file);
+    char *old = malloc(len + 20);
+    int rotate_file_count_max;
+
+    if(_file_list->total == -1 || _file_list->total == 0 || _file_list->total > ROTATE_FILE_COUNT_MAX)
+        rotate_file_count_max = ROTATE_FILE_COUNT_MAX;
+    else
+        rotate_file_count_max = _file_list->total;
+
+
+    if(0 == _file_list->current && NULL == current_file)
+        _file_list->current = rotate_file_count_max - 1;
+    if(NULL == old)
+    {
+        fprintf(stderr, "failed to malloc %s\n", strerror(errno));
+        exit(-1);
+    }
+    close(fd);
+    sprintf(tmp_buf, "/tmp/log%s", strstr_tail(base_file, "/"));
+    get_time(_time);
+    sprintf(old, "%s.%s", base_file, _time);
+    if (current_file && strstr(current_file, old)) {
+        int tmp_len = strlen(current_file);
+        //  以时间命名的文件是否已经存在
+        if(current_file[tmp_len - 3] == '.'){
+            num = atoi(&current_file[tmp_len - 2]);
+            num++;
+            sprintf(old, "%s.%02d", old, num);
+        }else{
+            sprintf(old, "%s.%02d", old, num);
+        }
+    }
+    if (movefile(tmp_buf, old) != 0){
+        printf("%s %d: Renamed error ,%s to %s.\n", __FUNCTION__, __LINE__, tmp_buf, old);
+    }
+    _file_list->current++;
+    // ringbuf
+    if(_file_list->current > (rotate_file_count_max - 1))
+    {
+        _file_list->current = 0;
+    }
+    // 如果之前已经存在,先释放之前存放的资源
+    if(_file_list->file[_file_list->current])
+    {
+        // printf("%s %d: remove %s\n", __FUNCTION__, __LINE__, _file_list->file[_file_list->current]);
+        // 如果 不限制文件数目,则不删除文件
+        if(_file_list->total != -1)
+            unlink(_file_list->file[_file_list->current]);
+        free(_file_list->file[_file_list->current]);
+    }
+    // 将文件名保存下来
+    _file_list->file[_file_list->current] = strdup(old);
+    free(old);
+    int fd_new = open(tmp_buf, O_CREAT | O_WRONLY | O_APPEND, 0600);
+    if (fd_new < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", tmp_buf, strerror(errno));
+        exit(-1);
+    }
+
+    return fd_new;
+}
+
+#if 0
+void get_rotate_file_test()
+{
+    struct file_list_t file_list;
+    int i;
+    char *test_path = "/tmp/log/m_log.txt";
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = 3;
+
+    int fd = open(test_path, O_CREAT | O_WRONLY | O_APPEND, 0600);
+    if (fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", test_path, strerror(errno));
+        exit(-1);
+    }
+    write(fd, "test1111", 8);
+    for (i = 0; i < 6; ++i) {
+        // sleep(1);
+        fd = get_rotate_file(fd, test_path, &file_list);
+        write(fd, "test2222", 8);
+    }
+    close(fd);
+}
+#endif
diff --git a/mbtk/mbtk_logd/common_read.c b/mbtk/mbtk_logd/common_read.c
new file mode 100755
index 0000000..90f2f7f
--- /dev/null
+++ b/mbtk/mbtk_logd/common_read.c
@@ -0,0 +1,146 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include "log_config.h"
+
+#define  ALOG_DEV "/dev/log_radio"
+
+static const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_size = 1 * 1024 * 1024;
+
+static log_config_entry *config = NULL;
+static char tmp_log[48] = {0};
+
+
+static int fileter_log(int pri, char *tag, struct filter_list_t *filter)
+{
+    struct filter_list_t *_filter = filter;
+
+    while(_filter)
+    {
+        // _filter->priority
+        // 获取 筛选的等级 p
+        int p = 0;
+        if(_filter->tag)
+        {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if(0 == memcmp(_filter->tag, tag, len) && ((pri > p) || (pri == p)))
+                return 0;
+        }else{ // have no tag
+            if(pri < p)
+                return -1;
+            else
+                return 0;
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+
+int common_log_print(
+    int fd,
+    struct file_list_t *_file_list,
+    char *entry)
+{
+    char priChar;
+    char timeBuf[32];
+    char defaultBuffer[512];
+    size_t totalLen;
+    int fd_new = fd;
+	struct stat s;
+	time_t timetemp; // 定义一个时间结构体变量
+    char * ret = NULL;
+
+	if (log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        fd_new = get_rotate_file(fd_new, log_file, _file_list);
+		if (fd_new < 0) {
+			fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
+			exit(-1);
+        }
+	}
+
+    // if(fileter_log(entry->priority, entry->tag, config->filter_list))
+    // {
+        // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, entry->priority, entry->tag);
+    //     return -1;
+    // }
+	time(&timetemp); // 获得时间参数
+    struct tm* ptm = localtime(&timetemp);
+    strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+
+    totalLen = snprintf(defaultBuffer, sizeof(defaultBuffer),
+    "%s : %s\n", timeBuf, entry);
+
+    ret = write(fd_new, defaultBuffer, totalLen);
+
+    return ret;
+}
+
+void* common_log_thread(void* argv)
+{
+    int dev_fd, ret;
+    int log_fd;
+    char buf[512] = {0};
+    static struct file_list_t file_list;
+    config = (log_config_entry *)argv;
+
+    pthread_detach(pthread_self());
+    if (NULL == argv || NULL == config->name)
+        return NULL;
+
+    dev_fd = open(config->name, O_RDONLY, 0600);
+    if (dev_fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", config->name, strerror(errno));
+        exit(-1);
+    }
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    log_file = config->out_path;
+
+    if (config->ip && config->port) {
+        int port = atoi(config->port);
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_fd = tcp_connect(config->ip, port);
+    } else if (log_file) {
+        sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+        // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+        log_fd = open(tmp_log, O_CREAT | O_WRONLY| O_APPEND, 0600);
+        if (log_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+            exit(-1);
+        }
+    } else {
+        log_fd = STDOUT_FILENO;
+    }
+    if(config->rotate_file_size)
+        log_size = config->rotate_file_size;
+
+    printf("uart log start...\n");
+    while (1) {
+        ret = read(dev_fd, buf, sizeof(buf));
+        if (ret < 0) {
+            printf("read error\n");
+            break;
+        }
+        // common_log_process(buf, ret, &entry);
+        common_log_print(log_fd, &file_list, buf);
+        memset(buf, 0, sizeof(buf));
+    }
+    close(dev_fd);
+    close(log_fd);
+
+    printf("%s exit \n", __FUNCTION__);
+    pthread_exit(NULL);
+	return NULL;
+}
diff --git a/mbtk/mbtk_logd/log_config.h b/mbtk/mbtk_logd/log_config.h
new file mode 100755
index 0000000..c37ce24
--- /dev/null
+++ b/mbtk/mbtk_logd/log_config.h
@@ -0,0 +1,41 @@
+#ifndef _LOG_CONFIG_H
+#define _LOG_CONFIG_H
+
+
+#define LOG_CONFIG_PATH     "/etc/mbtk/mbtk_log.json"
+
+#define ROTATE_FILE_COUNT_MAX    10
+
+struct filter_list_t {
+    char priority;
+    char *tag;
+    struct filter_list_t *next;
+};
+
+struct file_list_t {
+    int total;
+    int current;
+    char *base_file;
+    char *file[ROTATE_FILE_COUNT_MAX];
+};
+
+typedef struct log_config_entry_t {
+    int enable;
+    char *name;
+    int send_fd;
+    char *out_path;
+    char *ip;
+    char *port;
+    int rotate_file_size;
+    int rotate_file_count;
+    int32_t log_format;
+    struct filter_list_t *filter_list;
+} log_config_entry;
+
+int get_rotate_file(int fd, char *base_file, struct file_list_t *_file_list);
+extern void* alog_thread(void* argv);
+extern void* syslog_main(void* argv);
+extern void* socket_log_thread(void* argv);
+extern void* common_log_thread(void* argv);
+
+#endif // _LOG_CONFIG_H
diff --git a/mbtk/mbtk_logd/main.c b/mbtk/mbtk_logd/main.c
new file mode 100755
index 0000000..25dbdb1
--- /dev/null
+++ b/mbtk/mbtk_logd/main.c
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "json/json.h"
+#include "json/printbuf.h"
+#include "log_config.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+#define mbtk_log(...)                    printf(__VA_ARGS__)
+#else
+#define mbtk_log(...)
+#endif
+
+static void handler_free(log_config_entry* listdata)
+{
+    int i, n;
+    struct filter_list_t* _filter_list = NULL;
+    log_config_entry* entry;
+
+    for (i = 0; i < 5; i++) {
+        entry = listdata + i;
+        if (entry->name) {
+            free(entry->name);
+            if (entry->out_path) {
+                free(entry->out_path);
+            }
+            if (entry->ip) {
+                free(entry->ip);
+            }
+            _filter_list = entry->filter_list;
+            for (n = 0; n < 10; n++) {
+                printf("%s %d: malloc %x!\n", __FUNCTION__, __LINE__, _filter_list);
+                if (_filter_list) {
+                    printf("%s %d: malloc %x!\n", __FUNCTION__, __LINE__, _filter_list->next);
+                    if (_filter_list->tag) {
+                        free(_filter_list->tag);
+                    }
+                    free(_filter_list);
+                    _filter_list = _filter_list->next;
+                } else {
+                    break;
+                }
+            }
+        } else {
+            break;
+        }
+    }
+}
+
+int parse_config(log_config_entry* listdata)
+{
+    json_object* jsonobj = NULL;
+    json_object* tmpjson = NULL;
+    json_object* datajson = NULL;
+    json_object* listjson = NULL;
+    json_object* fileterjson = NULL;
+    json_object* fileter_listjson = NULL;
+    log_config_entry* entry;
+    int i, n, ret;
+    char* cmdval = NULL;
+
+    jsonobj = json_object_from_file(LOG_CONFIG_PATH);
+    if (NULL == jsonobj) {
+        printf("Can't open config file: %s\n", LOG_CONFIG_PATH);
+        return -1;
+    }
+    ret = json_object_object_get_ex(jsonobj, "logd", &tmpjson);
+    if (!ret) {
+        printf("get jsondata error ...\n");
+    }
+
+    if (NULL == tmpjson) {
+        printf("the tmpjson : [%s]\n", json_object_to_json_string(tmpjson));
+    }
+    /**获取total***/
+    cmdval = json_object_get_string(tmpjson);
+    printf("logd enable : %s\n", cmdval);
+    json_object_put(tmpjson);
+    /***获取data***/
+    json_object_object_get_ex(jsonobj, "buffer_list", &tmpjson);
+    for (i = 0 ; i < 5; i++) {
+        struct filter_list_t* _filter_list = NULL;
+        struct filter_list_t* tmp_filter_list = NULL;
+        datajson = json_object_array_get_idx(tmpjson, i);
+        if (NULL == datajson) {
+            mbtk_log("the datajson exit\n");
+            break;
+        }
+        entry = listdata + i;
+        json_object_object_get_ex(datajson, "enable", &listjson);
+        entry->enable = json_object_get_int(listjson);
+        mbtk_log("enable: %d\n", entry->enable);
+
+        json_object_object_get_ex(datajson, "name", &listjson);
+        entry->name = strdup(json_object_get_string(listjson));
+        mbtk_log("cmdval: %x, %s\n", entry->name, entry->name);
+
+        json_object_object_get_ex(datajson, "log_file", &listjson);
+        entry->out_path = strdup(json_object_get_string(listjson));
+        mbtk_log("cmdval: %s\n", entry->out_path);
+
+        json_object_object_get_ex(datajson, "log_stream", &listjson);
+        if (listjson) {
+            entry->ip = strdup(json_object_get_string(listjson));
+            cmdval = strstr(entry->ip, ":");
+            if (cmdval) {
+                entry->port = &cmdval[1];
+                cmdval[0] = 0;
+                mbtk_log("cmdval: %s [%s]\n", entry->ip, entry->port);
+            } else {
+                printf("Can't find port!!\n");
+                free(entry->ip);
+                entry->ip = NULL;
+            }
+        }
+        json_object_object_get_ex(datajson, "rotate_file_size", &listjson);
+        entry->rotate_file_size = json_object_get_int(listjson) * 1024;
+        mbtk_log("rotate_file_size: %d\n", entry->rotate_file_size);
+
+        json_object_object_get_ex(datajson, "rotate_file_count", &listjson);
+        entry->rotate_file_count = json_object_get_int(listjson);
+        mbtk_log("rotate_file_count: %d\n", entry->rotate_file_count);
+
+        json_object_object_get_ex(datajson, "filter_list", &listjson);
+        if (NULL == listjson) {
+            printf("%s %d: object failure!\n", __FUNCTION__, __LINE__);
+            json_object_put(listjson);
+            continue;
+        }
+        entry->filter_list = (struct filter_list_t*)malloc(sizeof(struct filter_list_t));
+        _filter_list = entry->filter_list;
+
+        for (n = 0 ; n < 5; n++) {
+            fileterjson = json_object_array_get_idx(listjson, n);
+            if (NULL == fileterjson) {
+                mbtk_log("the fileterjson exit\n");
+                free(tmp_filter_list->next);
+                tmp_filter_list->next = NULL;
+                break;
+            }
+            memset(_filter_list, 0, sizeof(struct filter_list_t));
+            json_object_object_get_ex(fileterjson, "priority", &fileter_listjson);
+            char* str = json_object_get_string(fileter_listjson);
+            if (str) {
+                _filter_list->priority = str[0];
+                mbtk_log("fileter_listjson: %c\n", _filter_list->priority);
+            }
+            json_object_object_get_ex(fileterjson, "tag", &fileter_listjson);
+            // if (NULL == fileter_listjson) {
+            //     printf("%s %d: object failure!\n", __FUNCTION__, __LINE__);
+            // }
+            str = json_object_get_string(fileter_listjson);
+            if (str) {
+                _filter_list->tag = strdup(str);
+                mbtk_log("fileter_listjson: %s\n", _filter_list->tag);
+            }
+            json_object_put(fileter_listjson);
+            _filter_list->next = (struct filter_list_t*)malloc(sizeof(struct filter_list_t));
+            if (NULL == _filter_list->next) {
+                printf("%s %d: malloc failure!\n", __FUNCTION__, __LINE__);
+                break;
+            }
+            tmp_filter_list = _filter_list;
+            _filter_list = _filter_list->next;
+        }
+        json_object_put(listjson);
+    }
+    json_object_put(tmpjson);
+
+    /***释放json对象***/
+    json_object_put(jsonobj);
+
+    return 0;
+}
+
+#define  LOGD_PID  "/var/run/mbtk_logd.pid"
+
+static int save_pid(void)
+{
+    pid_t process_id;
+    int fd, ret;
+    char buf[12] = {0};
+
+    process_id  = getpid();
+    if(access(LOGD_PID, F_OK) == 0)
+    {
+        printf("mbtk_logd 进程已经存在\n");
+        return -1;
+    }
+    fd = open(LOGD_PID, O_CREAT | O_WRONLY, 0600);
+    if (fd < 0) {
+        fprintf(stderr, "failed to open %s: %s\n", LOGD_PID, strerror(errno));
+        return -2;
+    }
+    snprintf(buf, sizeof(buf), "%d\n", process_id);
+    ret = write(fd, buf, strlen(buf));
+    close(fd);
+
+    if(ret > 0)
+        return 0;
+    else
+        return -2;
+}
+
+int main(int argc, char* argv[])
+{
+    log_config_entry listdata[5];
+    pthread_t pid[5] = {0};
+    int i, ret;
+    void* tret;
+
+    memset(listdata, 0, sizeof(log_config_entry) * 5);
+
+    ret = parse_config(listdata);
+    if (ret) {
+        return -1;
+    }
+    if(0 != save_pid())
+    {
+        printf("%s %d: logd exit!\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    printf("logd %s start !\n", __FUNCTION__);
+
+    for (i = 0; i < 5; ++i) {
+        if (NULL == listdata[i].name) {
+            break;
+        }
+
+        if (0 == listdata[i].enable) {
+            printf("%s log disabled !\n", listdata[i].name);
+            continue;
+        }
+
+        if (0 == memcmp(listdata[i].name, "radio", 5)) {
+            ret = pthread_create(&pid[i], NULL, alog_thread, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s: Failed to create pthread\n", __FUNCTION__);
+            }
+        } else if (0 == memcmp(listdata[i].name, "syslog", 6)) {
+            ret = pthread_create(&pid[i], NULL, syslog_main, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s %d: Failed to create pthread\n", __FUNCTION__, __LINE__);
+            }
+        } else if (0 == memcmp(listdata[i].name, "local_socket", 12)) {
+            ret = pthread_create(&pid[i], NULL, socket_log_thread, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s %d: Failed to create pthread\n", __FUNCTION__, __LINE__);
+            }
+        } else if (0 == memcmp(listdata[i].name, "/dev/tty", 8)) {
+            ret = pthread_create(&pid[i], NULL, common_log_thread, &listdata[i]);
+            if (ret != 0) {
+                fprintf(stderr, "\n%s %d: Failed to create pthread\n", __FUNCTION__, __LINE__);
+            }
+        }
+    }
+
+    for (i = 0; i < 5; ++i) {
+        if (NULL == listdata[i].name) {
+            break;
+        }
+        if (pid[i]) {
+            if (pthread_join(pid[i], &tret) != 0) {
+                printf("Join thread %d : %d error!\n", i, pid[i]);
+                exit(1);
+            }
+        }
+    }
+    handler_free(listdata);
+
+    return 0;
+}
diff --git a/mbtk/mbtk_logd/socket_read.c b/mbtk/mbtk_logd/socket_read.c
new file mode 100755
index 0000000..df8fe27
--- /dev/null
+++ b/mbtk/mbtk_logd/socket_read.c
@@ -0,0 +1,228 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include "log_config.h"
+
+#define _MOPEN_RILD_CONNET_NUM  5
+#define _MOPEN_RILD_SOCKET "/tmp/logd_socket"
+
+static int client_sockfd[_MOPEN_RILD_CONNET_NUM];
+
+static const char* log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_size = 1 * 1024 * 1024;
+
+static log_config_entry* config = NULL;
+static char tmp_log[48] = {0};
+
+static int fileter_log(int pri, char* tag, struct filter_list_t* filter)
+{
+    struct filter_list_t* _filter = filter;
+
+    while (_filter) {
+        // _filter->priority
+        // 获取 筛选的等级 p
+        int p = 0;
+        if (_filter->tag) {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if (0 == memcmp(_filter->tag, tag, len) && ((pri > p) || (pri == p))) {
+                return 0;
+            }
+        } else { // have no tag
+            if (pri < p) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+
+int socket_log_print(
+    int fd,
+    struct file_list_t* _file_list,
+    char* entry)
+{
+    char priChar;
+    // char timeBuf[32];
+    // time_t timetemp; // 定义一个时间结构体变量
+    char defaultBuffer[512];
+    size_t totalLen;
+    int fd_new = fd;
+    struct stat s;
+    char* ret = NULL;
+
+    if (log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        fd_new = get_rotate_file(fd_new, log_file, _file_list);
+        if (fd_new < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno));
+            exit(-1);
+        }
+    }
+
+    // if(fileter_log(entry->priority, entry->tag, config->filter_list))
+    // {
+    // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, entry->priority, entry->tag);
+    //     return -1;
+    // }
+    // time(&timetemp); // 获得时间参数
+    // struct tm* ptm = localtime(&timetemp);
+    // strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+    totalLen = snprintf(defaultBuffer, sizeof(defaultBuffer), "%s", entry);
+
+    ret = write(fd_new, defaultBuffer, totalLen);
+
+    return ret;
+}
+
+static int open_local_socket(char *path)
+{
+    int listen_fd;
+    int ret;
+    struct sockaddr_un srv_addr;
+
+    listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (listen_fd < 0) {
+        printf("connect creat communication socket");
+        return -1;
+    }
+
+    unlink(path);
+    srv_addr.sun_family = AF_UNIX;
+    strcpy(srv_addr.sun_path, path);
+
+    ret = bind(listen_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
+    if (ret < 0) {
+        printf("cannot bind server socket");
+        close(listen_fd);
+        unlink(path);
+        return -1;
+    }
+
+    return listen_fd;
+}
+
+void* socket_log_thread(void* argv)
+{
+    int listen_fd;
+    int com_fd, fd_max, fd_num;
+    int ret, log_fd;
+    int i, n, str_len;
+    fd_set reads, cpy_reads;
+    struct timeval timeout;
+    char buf[512] = {0};
+    static struct file_list_t file_list;
+    config = (log_config_entry*)argv;
+
+    pthread_detach(pthread_self());
+    if (NULL == argv || NULL == config->name) {
+        return NULL;
+    }
+
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    log_file = config->out_path;
+
+    if (config->ip && config->port) {
+        int port = atoi(config->port);
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_fd = tcp_connect(config->ip, port);
+    } else if (log_file) {
+        sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+        // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+        log_fd = open(tmp_log, O_CREAT | O_WRONLY | O_APPEND, 0600);
+        if (log_fd < 0) {
+            fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+            exit(-1);
+        }
+    } else {
+        log_fd = STDOUT_FILENO;
+    }
+    if (config->rotate_file_size) {
+        log_size = config->rotate_file_size;
+    }
+
+    listen_fd = open_local_socket(_MOPEN_RILD_SOCKET);
+    if (listen_fd < 0 || listen_fd == 0) {
+        return NULL;
+    }
+    ret = listen(listen_fd, 1);
+    if (ret < 0) {
+        printf("cannot listen sockfd");
+        close(listen_fd);
+        unlink(_MOPEN_RILD_SOCKET);
+        return NULL;
+    }
+    FD_ZERO(&reads);
+    FD_SET(listen_fd, &reads);
+    fd_max = listen_fd;
+    printf("socket log start...\n");
+    memset(client_sockfd, 0, sizeof(client_sockfd));
+    for (;;) {
+        cpy_reads = reads;
+        timeout.tv_sec = 5;
+        timeout.tv_usec = 5000;
+
+        if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1) {
+            perror("select error");
+            break;
+        }
+        if (fd_num == 0) {
+            continue;
+        }
+
+        for (n = 0; n < fd_max + 1; n++) {
+            if (FD_ISSET(n, &cpy_reads)) {
+                if (n == listen_fd) {
+                    com_fd = accept(listen_fd, NULL, NULL);
+                    FD_SET(com_fd, &reads);
+                    if (fd_max < com_fd) {
+                        fd_max = com_fd;
+                    }
+                    printf("accept accept fd [%d]", com_fd);
+                    for (i = 0; i < _MOPEN_RILD_CONNET_NUM; i++) {
+                        if (client_sockfd[i] <= 0) {
+                            client_sockfd[i] = com_fd;
+                            break;
+                        }
+                    }
+                } else {
+                    str_len = read(n, buf, sizeof(buf));
+                    if (str_len == 0) {
+                        for (i = 0; i < _MOPEN_RILD_CONNET_NUM; i++) {
+                            if (client_sockfd[i] == n) {
+                                client_sockfd[i] = 0;
+                                break;
+                            }
+                        }
+                        FD_CLR(n, &reads);
+                        close(n);
+                        printf("closed client: %d \n", n);
+                    } else {
+                        socket_log_print(log_fd, &file_list, buf);
+                        memset(buf, 0, sizeof(buf));
+                    }
+                }
+            }
+        }
+    }
+    close(listen_fd);
+    close(log_fd);
+    unlink(_MOPEN_RILD_SOCKET);
+    printf("%s exit \n", __FUNCTION__);
+    pthread_exit(NULL);
+
+    return NULL;
+}
diff --git a/mbtk/mbtk_logd/syslog.h b/mbtk/mbtk_logd/syslog.h
new file mode 100755
index 0000000..b682ced
--- /dev/null
+++ b/mbtk/mbtk_logd/syslog.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SYSLOG_H
+#define __SYSLOG_H
+
+enum {
+	SOURCE_KLOG = 0,
+	SOURCE_SYSLOG = 1,
+	SOURCE_INTERNAL = 2,
+	SOURCE_ANY = 0xff,
+};
+
+struct log_head {
+	unsigned int size;
+	unsigned int id;
+	int priority;
+	int source;
+        struct timespec ts;
+	char data[];
+};
+
+void log_init(int log_size);
+void log_shutdown(void);
+
+typedef void (*log_list_cb)(struct log_head *h);
+struct log_head* log_list(int count, struct log_head *h);
+int log_buffer_init(int size);
+void log_add(char *buf, int size, int source);
+void ubus_notify_log(struct log_head *l);
+
+#endif
diff --git a/mbtk/mbtk_logd/syslog_read.c b/mbtk/mbtk_logd/syslog_read.c
new file mode 100755
index 0000000..3cae9e9
--- /dev/null
+++ b/mbtk/mbtk_logd/syslog_read.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#define SYSLOG_NAMES
+#include <syslog.h>
+
+#include <libubox/ustream.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/usock.h>
+#include <libubox/uloop.h>
+#include "libubus.h"
+#include "syslog.h"
+#include "log_config.h"
+
+enum {
+	LOG_STDOUT,
+	LOG_FILE,
+	LOG_NET,
+};
+
+enum {
+	LOG_MSG,
+	LOG_ID,
+	LOG_PRIO,
+	LOG_SOURCE,
+	LOG_TIME,
+	__LOG_MAX
+};
+
+static const struct blobmsg_policy log_policy[] = {
+	[LOG_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_STRING },
+	[LOG_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
+	[LOG_PRIO] = { .name = "priority", .type = BLOBMSG_TYPE_INT32 },
+	[LOG_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_INT32 },
+	[LOG_TIME] = { .name = "time", .type = BLOBMSG_TYPE_INT64 },
+};
+
+static struct uloop_timeout retry;
+static struct uloop_fd sender;
+static const char *log_file, *log_ip, *log_port, *log_prefix, *pid_file, *hostname;
+static int log_type = LOG_STDOUT;
+static int log_size = 1 * 1024 * 1024, log_udp, log_follow = 0;
+static struct file_list_t file_list;
+static struct filter_list_t *filter_log = NULL;
+static char tmp_log[48] = {0};
+
+static const char* getcodetext(int value, CODE *codetable) {
+	CODE *i;
+
+	if (value >= 0)
+		for (i = codetable; i->c_val != -1; i++)
+			if (i->c_val == value)
+				return (i->c_name);
+	return "<unknown>";
+};
+
+static void log_handle_reconnect(struct uloop_timeout *timeout)
+{
+	sender.fd = usock((log_udp) ? (USOCK_UDP) : (USOCK_TCP), log_ip, log_port);
+	if (sender.fd < 0) {
+		fprintf(stderr, "failed to connect: %s\n", strerror(errno));
+		uloop_timeout_set(&retry, 1000);
+	} else {
+		uloop_fd_add(&sender, ULOOP_READ);
+		syslog(0, "Logread connected to %s:%s\n", log_ip, log_port);
+	}
+}
+
+static void log_handle_fd(struct uloop_fd *u, unsigned int events)
+{
+	if (u->eof) {
+		uloop_fd_delete(u);
+		close(sender.fd);
+		sender.fd = -1;
+		uloop_timeout_set(&retry, 1000);
+	}
+}
+
+static int filter_char_to_pri(char c)
+{
+    switch (c) {
+        case 'v':
+            return 8;
+        case 'd':
+            return LOG_DEBUG;
+        case 'i':
+            return LOG_INFO;
+        case 'w':
+            return LOG_WARNING;
+        case 'e':
+            return LOG_ERR;
+        case 'f':
+            return LOG_ALERT;
+        case '*':
+        default:
+            return 8;
+    }
+}
+
+static int syslog_fileter_log(int pri, char *tag, struct filter_list_t *filter)
+{
+    struct filter_list_t *_filter = filter;
+
+    while(_filter)
+    {
+        int p = filter_char_to_pri(_filter->priority);
+        if(_filter->tag)
+        {
+            int len = strlen(_filter->tag);
+            // tag and priority
+            if(0 == memcmp(_filter->tag, tag, len) && ((pri < p) || (pri == p)))
+                return 0;
+        }else{ // have no tag
+            if(pri > p)
+                return -1;
+            else
+                return 0;
+        }
+        _filter = _filter->next;
+    }
+
+    return -1;
+}
+static int log_notify(struct blob_attr *msg)
+{
+	struct blob_attr *tb[__LOG_MAX];
+	struct stat s;
+	char buf[512];
+	uint32_t p;
+	char *str;
+	time_t t;
+	char *c, *m;
+
+	if (sender.fd < 0)
+		return 0;
+
+	blobmsg_parse(log_policy, ARRAY_SIZE(log_policy), tb, blob_data(msg), blob_len(msg));
+	if (!tb[LOG_ID] || !tb[LOG_PRIO] || !tb[LOG_SOURCE] || !tb[LOG_TIME] || !tb[LOG_MSG])
+		return 1;
+
+	if ((log_type == LOG_FILE) && log_size && (!stat(tmp_log, &s)) && (s.st_size > log_size)) {
+        sender.fd = get_rotate_file(sender.fd, log_file, &file_list);
+		if (sender.fd < 0) {
+			fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+			exit(-1);
+        }
+	}
+
+	m = blobmsg_get_string(tb[LOG_MSG]);
+	t = blobmsg_get_u64(tb[LOG_TIME]) / 1000;
+	c = ctime(&t);
+	p = blobmsg_get_u32(tb[LOG_PRIO]);
+	c[strlen(c) - 1] = '\0';
+	str = blobmsg_format_json(msg, true);
+
+    if(filter_log && syslog_fileter_log(LOG_PRI(p), m, filter_log))
+    {
+        // printf("%s %d: fileter pri:%d tag:%s!\n", __FUNCTION__, __LINE__, p, m);
+        exit(-1);
+    }
+	if (log_type == LOG_NET) {
+		int err;
+
+		snprintf(buf, sizeof(buf), "<%u>", p);
+		strncat(buf, c + 4, 16);
+		if (hostname) {
+			strncat(buf, hostname, sizeof(buf));
+			strncat(buf, " ", sizeof(buf));
+		}
+		if (log_prefix) {
+			strncat(buf, log_prefix, sizeof(buf));
+			strncat(buf, ": ", sizeof(buf));
+		}
+		if (blobmsg_get_u32(tb[LOG_SOURCE]) == SOURCE_KLOG)
+			strncat(buf, "kernel: ", sizeof(buf));
+		strncat(buf, m, sizeof(buf));
+		if (log_udp)
+			err = write(sender.fd, buf, strlen(buf));
+		else
+			err = send(sender.fd, buf, strlen(buf), 0);
+
+		if (err < 0) {
+			syslog(0, "failed to send log data to %s:%s via %s\n",
+				log_ip, log_port, (log_udp) ? ("udp") : ("tcp"));
+			uloop_fd_delete(&sender);
+			close(sender.fd);
+			sender.fd = -1;
+			uloop_timeout_set(&retry, 1000);
+		}
+	} else {
+		snprintf(buf, sizeof(buf), "%s %s.%s%s %s\n",
+			c, getcodetext(LOG_FAC(p) << 3, facilitynames), getcodetext(LOG_PRI(p), prioritynames),
+			(blobmsg_get_u32(tb[LOG_SOURCE])) ? ("") : (" kernel:"), m);
+		write(sender.fd, buf, strlen(buf));
+	}
+
+	free(str);
+	if (log_type == LOG_FILE)
+		fsync(sender.fd);
+
+	return 0;
+}
+
+static void logread_fd_data_cb(struct ustream *s, int bytes)
+{
+	while (true) {
+		int len;
+		struct blob_attr *a;
+
+		a = (void*) ustream_get_read_buf(s, &len);
+		if (len < sizeof(*a) || len < blob_len(a) + sizeof(*a))
+			break;
+		log_notify(a);
+		ustream_consume(s, blob_len(a) + sizeof(*a));
+	}
+	if (!log_follow)
+		uloop_end();
+}
+
+static void logread_fd_cb(struct ubus_request *req, int fd)
+{
+	static struct ustream_fd test_fd;
+
+	test_fd.stream.notify_read = logread_fd_data_cb;
+	ustream_fd_init(&test_fd, fd);
+}
+
+static void logread_complete_cb(struct ubus_request *req, int ret)
+{
+}
+
+void* syslog_main(void* argv)
+{
+	static struct ubus_request req;
+	struct ubus_context *ctx;
+	uint32_t id;
+	const char *ubus_socket = NULL;
+	int ch, ret, lines = 0;
+	static struct blob_buf b;
+	int tries = 5;
+    log_config_entry *config = (log_config_entry *)argv;
+
+    pthread_detach(pthread_self());
+
+    if (NULL == argv)
+        return NULL;
+
+	signal(SIGPIPE, SIG_IGN);
+	uloop_init();
+
+    log_file = config->out_path;
+    memset(&file_list, 0, sizeof(struct file_list_t));
+    file_list.total = config->rotate_file_count;
+    if(config->rotate_file_size)
+        log_size = config->rotate_file_size;
+    if(config->ip)
+    {
+        printf("%s %d : %s:%s\n", __FUNCTION__, __LINE__, config->ip, config->port);
+        log_ip = config->ip;
+        log_port = config->port;
+    }
+    filter_log = config->filter_list;
+    // Follow log messages
+    log_follow = 1;
+	ctx = ubus_connect(ubus_socket);
+	if (!ctx) {
+		fprintf(stderr, "Failed to connect to ubus\n");
+		return -1;
+	}
+	ubus_add_uloop(ctx);
+
+    printf("syslog log start...\n");
+	/* ugly ugly ugly ... we need a real reconnect logic */
+	do {
+		ret = ubus_lookup_id(ctx, "log", &id);
+		if (ret) {
+			fprintf(stderr, "Failed to find log object: %s\n", ubus_strerror(ret));
+			sleep(1);
+			continue;
+		}
+
+		blob_buf_init(&b, 0);
+		if (lines)
+			blobmsg_add_u32(&b, "lines", lines);
+		else if (log_follow)
+			blobmsg_add_u32(&b, "lines", 0);
+		if (log_follow) {
+			if (pid_file) {
+				FILE *fp = fopen(pid_file, "w+");
+				if (fp) {
+					fprintf(fp, "%d", getpid());
+					fclose(fp);
+				}
+			}
+		}
+
+		if (log_ip && log_port) {
+			openlog("logread", LOG_PID, LOG_DAEMON);
+			log_type = LOG_NET;
+			sender.cb = log_handle_fd;
+			retry.cb = log_handle_reconnect;
+			uloop_timeout_set(&retry, 1000);
+		} else if (log_file) {
+			log_type = LOG_FILE;
+            // 先将文件保存到 /tmp/log/ 目录下,后面到达 rotate_file_size 后,转移到out_path
+            sprintf(tmp_log, "/tmp/log%s", strstr_tail(log_file, "/"));
+			sender.fd = open(tmp_log, O_CREAT | O_WRONLY| O_APPEND, 0600);
+			if (sender.fd < 0) {
+				fprintf(stderr, "failed to open %s: %s\n", tmp_log, strerror(errno));
+				exit(-1);
+			}
+		} else {
+			sender.fd = STDOUT_FILENO;
+		}
+
+		ubus_invoke_async(ctx, id, "read", b.head, &req);
+		req.fd_cb = logread_fd_cb;
+		req.complete_cb = logread_complete_cb;
+		ubus_complete_request_async(ctx, &req);
+
+		uloop_run();
+		ubus_free(ctx);
+		uloop_done();
+
+	} while (ret && tries--);
+
+    pthread_exit(NULL);
+	return NULL;
+}
diff --git a/mbtk/mbtk_mqtt/MQTTClient.c b/mbtk/mbtk_mqtt/MQTTClient.c
new file mode 100755
index 0000000..4a349a7
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTClient.c
@@ -0,0 +1,684 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ *    http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ *   http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTClient.h"
+
+regnwl_info_t regnwl_info = {0};
+
+
+int core_json_value(const char *input, uint32_t input_len, const char *key, uint32_t key_len, char **value,
+                        uint32_t *value_len)
+{
+    int idx = 0;
+
+    for (idx = 0; idx < input_len; idx++) {
+        if (idx + key_len >= input_len) {
+            return -1;
+        }
+        if ((memcmp(&input[idx], key, key_len) == 0) &&
+            ((idx > 0) && (input[idx - 1] == '"')) &&
+            ((idx + key_len < input_len) && (input[idx + key_len] == '"'))) {
+            idx += key_len;
+            /* shortest ":x, or ":x} or ":x] */
+            if ((idx + 2 >= input_len) ||
+                (input[idx + 1] != ':')) {
+                return -1;
+            }
+            idx += 2;
+            if (input[idx] == '"') {
+                *value = (char *)&input[++idx];
+                for (; idx < input_len; idx++) {
+                    if ((input[idx] == '"')) {
+                        *value_len = (uint32_t)(idx - (*value - input));
+                        return SUCCESS;
+                    }
+                }
+            } else if (input[idx] == '{' || input[idx] == '[') {
+                char start = input[idx];
+                char end = (start == '{') ? ('}') : (']');
+                uint8_t count = 0;
+                *value = (char *)&input[idx];
+                for (; idx < input_len; idx++) {
+                    if ((input[idx] == start)) {
+                        count++;
+                    } else if ((input[idx] == end)) {
+                        if (--count == 0) {
+                            *value_len = (uint32_t)(idx - (*value - input) + 1);
+                            return SUCCESS;
+                        }
+                    }
+                }
+            } else {
+                *value = (char *)&input[idx];
+                for (; idx < input_len; idx++) {
+                    if ((input[idx] == ',' || input[idx] == ']' || input[idx] == '}')) {
+                        *value_len = (uint32_t)(idx - (*value - input));
+                        return SUCCESS;
+                    }
+                }
+            }
+        }
+    }
+
+    return -1;
+}
+
+
+void mbtk_ali_auth_regnwl_sava(MQTTMessage msg)
+{
+    printf("pub, payload: %d,%s\n", msg.payloadlen, msg.payload);
+    int32_t res = SUCCESS;
+
+    char *client_key = "clientId",*deviceToken_key="deviceToken";
+    uint32_t clientId_value_len = 0,deviceToken_value_len = 0;
+
+    char *client_value=NULL,*deviceToken_value=NULL;
+    if ((res = core_json_value((char *)msg.payload, msg.payloadlen,
+          client_key, strlen(client_key), &client_value, &clientId_value_len)) == SUCCESS)
+    {
+        memset(regnwl_info.clientId,0,clientId_value_len+1);
+        memcpy(regnwl_info.clientId,client_value,clientId_value_len);
+        printf("client_value:%s,\n regnwl_info->clientId:%s\n", client_value, regnwl_info.clientId);
+    }
+
+    if ((res = core_json_value((char *)msg.payload, msg.payloadlen,
+           deviceToken_key, strlen(deviceToken_key), &deviceToken_value, &deviceToken_value_len)) == SUCCESS)
+    {
+        memset(regnwl_info.deviceToken,0,deviceToken_value_len+1);
+        memcpy(regnwl_info.deviceToken,deviceToken_value,deviceToken_value_len);
+        printf("deviceToken_value:%s,\n regnwl_info->deviceToken:%s\n", deviceToken_value, regnwl_info.deviceToken);
+    }
+
+}
+
+
+void NewMessageData(MessageData* md, MQTTString* aTopicName, MQTTMessage* aMessgage) {
+    md->topicName = aTopicName;
+    md->message = aMessgage;
+}
+
+
+int getNextPacketId(Client *c) {
+    return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
+}
+
+
+int sendPacket(Client* c, int length, Timer* timer)
+{
+    int rc = FAILURE, 
+        sent = 0;
+    
+    while (sent < length && !expired(timer))
+    {
+        rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, left_ms(timer));
+        if (rc < 0)  // there was an error writing the data
+            break;
+        sent += rc;
+    }
+    printf("rc ----%d,sent----%d,length----%d\n",rc,sent,length);
+    if (sent == length)
+    {
+        countdown(&c->ping_timer, c->keepAliveInterval); // record the fact that we have successfully sent the packet    
+        rc = SUCCESS;
+    }
+    else
+        rc = FAILURE;
+    return rc;
+}
+
+
+void MQTTClient(Client* c, Network* network, unsigned int command_timeout_ms, unsigned char* buf, size_t buf_size, unsigned char* readbuf, size_t readbuf_size)
+{
+    int i;
+    c->ipstack = network;
+    
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+        c->messageHandlers[i].topicFilter = 0;
+    c->command_timeout_ms = command_timeout_ms;
+    c->buf = buf;
+    c->buf_size = buf_size;
+    c->readbuf = readbuf;
+    c->readbuf_size = readbuf_size;
+    c->isconnected = 0;
+    c->ping_outstanding = 0;
+    c->defaultMessageHandler = NULL;
+    InitTimer(&c->ping_timer);
+}
+
+
+int decodePacket(Client* c, int* value, int timeout)
+{
+    unsigned char i;
+    int multiplier = 1;
+    int len = 0;
+    const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+    *value = 0;
+    do
+    {
+        int rc = MQTTPACKET_READ_ERROR;
+
+        if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+        {
+            rc = MQTTPACKET_READ_ERROR; /* bad data */
+            goto exit;
+        }
+        rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);
+        if (rc != 1)
+            goto exit;
+        *value += (i & 127) * multiplier;
+        multiplier *= 128;
+    } while ((i & 128) != 0);
+exit:
+    return len;
+}
+
+
+int readPacket(Client* c, Timer* timer) 
+{
+    int rc = FAILURE;
+    MQTTHeader header = {0};
+    int len = 0;
+    int rem_len = 0;
+
+    /* 1. read the header byte.  This has the packet type in it */
+    memset(c->readbuf,0x0,c->readbuf_size);
+    if ((rc = c->ipstack->mqttread(c->ipstack, c->readbuf, 1, left_ms(timer))) != 1)
+        goto exit;
+
+    len = 1;
+    /* 2. read the remaining length.  This is variable in itself */
+    decodePacket(c, &rem_len, left_ms(timer));
+    len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+    /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+    if (rem_len > 0 && ((rc = c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, left_ms(timer)) )!= rem_len))
+        goto exit;
+
+    header.byte = c->readbuf[0];
+    rc = header.bits.type;
+exit:
+    return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+char isTopicMatched(char* topicFilter, MQTTString* topicName)
+{
+    char* curf = topicFilter;
+    char* curn = topicName->lenstring.data;
+    char* curn_end = curn + topicName->lenstring.len;
+    
+    while (*curf && curn < curn_end)
+    {
+        if (*curn == '/' && *curf != '/')
+            break;
+        if (*curf != '+' && *curf != '#' && *curf != *curn)
+            break;
+        if (*curf == '+')
+        {   // skip until we meet the next separator, or end of string
+            char* nextpos = curn + 1;
+            while (nextpos < curn_end && *nextpos != '/')
+                nextpos = ++curn + 1;
+        }
+        else if (*curf == '#')
+            curn = curn_end - 1;    // skip until end of string
+        curf++;
+        curn++;
+    };
+    
+    return (curn == curn_end) && (*curf == '\0');
+}
+
+
+int deliverMessage(Client* c, MQTTString* topicName, MQTTMessage* message)
+{
+    int i;
+    int rc = FAILURE;
+
+    // we have to find the right message handler - indexed by topic
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||
+                isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName)))
+        {
+            if (c->messageHandlers[i].fp != NULL)
+            {
+                MessageData md;
+                NewMessageData(&md, topicName, message);
+                c->messageHandlers[i].fp(&md);
+                rc = SUCCESS;
+            }
+        }
+    }
+    
+    if (rc == FAILURE && c->defaultMessageHandler != NULL) 
+    {
+        MessageData md;
+        NewMessageData(&md, topicName, message);
+        c->defaultMessageHandler(&md);
+        rc = SUCCESS;
+    }   
+    
+    return rc;
+}
+
+
+int keepalive(Client* c)
+{
+    int rc = SUCCESS;
+    if (c->keepAliveInterval == 0)
+    {
+        rc = SUCCESS;
+        goto exit;
+    }
+    
+    if (expired(&c->ping_timer))
+    {
+        if (!c->ping_outstanding)
+        {
+            Timer timer;
+            InitTimer(&timer);
+            countdown_ms(&timer, 1000);
+            int len = MQTTSerialize_pingreq(c->buf, c->buf_size);
+            printf("len %d\n",len);
+            if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) // send the ping packet
+                c->ping_outstanding = 1;
+            printf("sendPacket---------------------------------------------\n");
+        }
+    	else
+    	{
+    	    printf("fail_count-------------\n",c->fail_count);
+            ++(c->fail_count);
+            if (c->fail_count >= MAX_FAIL_ALLOWED)
+            {
+                rc = DISCONNECTED;
+                goto exit;
+            }
+
+    	}
+	 countdown(&(c->ping_timer), c->keepAliveInterval);
+    }
+    //printf("keepalive rc is %d\n",rc);
+exit:
+    return rc;
+}
+
+
+int cycle(Client* c, Timer* timer)
+{
+	int len = 0,
+	rc = SUCCESS;
+    // read the socket, see what work is due
+	short packet_type = readPacket(c, timer);
+
+	if(packet_type <= 0)
+	{
+		//printf("[%s][%d]readPacket retrun socket close \n",__FUNCTION__, __LINE__);
+        //printf("[%s]....packet_type = %d\n", __FUNCTION__, packet_type);
+		rc =  DISCONNECTED;
+		goto exit;
+	}
+    
+    switch (packet_type)
+    {
+        case CONNACK:
+        case PUBACK:
+        case SUBACK:
+            break;
+        case PUBLISH:
+        {
+            memset(regnwl_info.deviceToken,0,sizeof(regnwl_info.deviceToken));
+            memset(regnwl_info.clientId,0,sizeof(regnwl_info.clientId));
+            MQTTString topicName;
+            MQTTMessage msg;
+            if (MQTTDeserialize_publish((unsigned char*)&msg.dup, (int*)&msg.qos, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName,
+               (unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
+                goto exit;
+           if(memcmp(topicName.lenstring.data,"/ext/regnwl",strlen("/ext/regnwl")) == 0)
+            {
+                mbtk_ali_auth_regnwl_sava(msg);
+            }
+            deliverMessage(c, &topicName, &msg);
+            if (msg.qos != QOS0)
+            {
+                if (msg.qos == QOS1)
+                    len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
+                else if (msg.qos == QOS2)
+                    len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
+                if (len <= 0)
+                    rc = FAILURE;
+                   else
+                       rc = sendPacket(c, len, timer);
+                if (rc == FAILURE)
+                {
+                    goto exit; // there was a problem
+		   }
+
+            }
+            break;
+        }
+        case PUBREC:
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+            else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREL, 0, mypacketid)) <= 0)
+                rc = FAILURE;
+            else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packet
+                rc = FAILURE; // there was a problem
+            if (rc == FAILURE)
+            	{
+			 goto exit; // there was a problem
+		}
+
+            break;
+        }
+        case PUBCOMP:
+            break;
+        case PINGRESP:
+            c->ping_outstanding = 0;
+	     c->fail_count = 0;
+            break;
+    }
+
+exit:
+    if (rc == SUCCESS)
+        rc = packet_type;
+
+;
+    return rc;
+}
+
+
+int MQTTYield(Client* c, int timeout_ms)
+{
+    int rc = SUCCESS;
+    Timer timer;
+
+    InitTimer(&timer);    
+    countdown_ms(&timer, timeout_ms);
+    static int i = 0;
+    if (c->isconnected)
+    		rc = keepalive(c);
+    if(rc < 0)
+    {
+        return rc;
+    }
+/*
+    while (!expired(&timer))
+    {
+    	 rc = cycle(c, &timer);
+        if (rc == DISCONNECTED)
+        {
+            printf("cycle DISCONNECTED \n");
+            break;
+        }
+	 rc = SUCCESS;
+    }
+*/
+    do
+    {
+            if (expired(&timer)) 
+            break; // we timed out
+    }
+    while ((rc = cycle(c, &timer)) != PUBLISH);  
+    rc = SUCCESS;
+    return rc;
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+int waitfor(Client* c, int packet_type, Timer* timer)
+{
+    int rc = FAILURE;
+    do
+    {
+            if (expired(timer)) 
+            break; // we timed out
+    }
+    while ((rc = cycle(c, timer)) != packet_type &&  (rc = cycle(c, timer)) != DISCONNECTED);  
+    
+    return rc;
+}
+
+
+int MQTTConnect(Client* c, MQTTPacket_connectData* options)
+{
+    Timer connect_timer;
+    int rc = FAILURE;
+    MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+    int len = 0;
+    InitTimer(&connect_timer);
+    countdown_ms(&connect_timer, c->command_timeout_ms);
+
+    if (c->isconnected) // don't send connect packet again if we are already connected
+        goto exit;
+
+    if (options == 0)
+        options = &default_options; // set default options if none were supplied
+    
+    c->keepAliveInterval = options->keepAliveInterval;
+    countdown(&c->ping_timer, c->keepAliveInterval);
+    printf("[%s]c->keepAliveInterval = %d", __FUNCTION__,c->keepAliveInterval);
+    if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS)  // send the connect packet
+        goto exit; // there was a problem
+    
+    // this will be a blocking call, wait for the connack
+    if (waitfor(c, CONNACK, &connect_timer) == CONNACK)
+    {
+        unsigned char connack_rc = 255;
+        char sessionPresent = 0;
+        if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1)
+            rc = connack_rc;
+        else
+            rc = FAILURE;
+    }
+    else
+        rc = FAILURE;
+    
+exit:
+    if (rc == SUCCESS)
+        c->isconnected = 1;
+    return rc;
+}
+
+
+int MQTTSubscribe(Client* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{ 
+    int rc = FAILURE;  
+    Timer timer;
+    int len = 0;
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicFilter;
+    
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+
+    if (!c->isconnected)
+        goto exit;
+    
+    len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos);
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit;             // there was a problem
+    
+    if (waitfor(c, SUBACK, &timer) == SUBACK)      // wait for suback 
+    {
+        int count = 0, grantedQoS = -1;
+        unsigned short mypacketid;
+        if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1)
+            rc = grantedQoS; // 0, 1, 2 or 0x80 
+        if (rc != 0x80)
+        {
+            int i;
+            for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+            {
+                if (c->messageHandlers[i].topicFilter == 0)
+                {
+                    c->messageHandlers[i].topicFilter = topicFilter;
+                    c->messageHandlers[i].fp = messageHandler;
+                    rc = 0;
+                    break;
+                }
+            }
+        }
+    }
+    else 
+        rc = FAILURE;
+        
+exit:
+    return rc;
+}
+
+int messageHandlersFindIndex(Client* c, const char* topicFilter)
+{
+    int i;
+    for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+    {
+        if ((c->messageHandlers[i].topicFilter != NULL)
+            && (strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0))
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int MQTTUnsubscribe(Client* c, const char* topicFilter)
+{   
+    int rc = FAILURE;
+    Timer timer;    
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicFilter;
+    int len = 0;
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+    
+    if (!c->isconnected)
+        goto exit;
+    if(messageHandlersFindIndex(c,topicFilter) < 0)
+    {
+        printf("This topic is not subscribed and cannot be unsubscribed.\n");
+        goto exit;
+    }
+    if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit; // there was a problem
+    if (waitfor(c, UNSUBACK, &timer) == UNSUBACK)
+    {
+        unsigned short mypacketid;  // should be the same as the packetid above
+        if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1)
+        {
+            int i;
+            for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+            {
+                if ((c->messageHandlers[i].topicFilter != NULL)
+                && (strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0))
+                {
+                    c->messageHandlers[i].topicFilter=NULL;
+                    rc = 0; 
+                }
+            }
+        }
+    }
+    else
+        rc = FAILURE;
+    
+exit:
+    return rc;
+}
+
+
+int MQTTPublish(Client* c, const char* topicName, MQTTMessage* message)
+{
+    int rc = FAILURE;
+    Timer timer;   
+    MQTTString topic = MQTTString_initializer;
+    topic.cstring = (char *)topicName;
+    int len = 0;
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+    
+    if (!c->isconnected)
+        goto exit;
+    if (message->qos == QOS1 || message->qos == QOS2)
+        message->id = getNextPacketId(c);
+    
+    len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id, 
+              topic, (unsigned char*)message->payload, message->payloadlen);
+
+    if (len <= 0)
+        goto exit;
+    if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+        goto exit; // there was a problem
+
+    if (message->qos == QOS1)
+    {
+        if (waitfor(c, PUBACK, &timer) == PUBACK)
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+        }
+        else
+            rc = FAILURE;
+    }
+    else if (message->qos == QOS2)
+    {
+        if (waitfor(c, PUBCOMP, &timer) == PUBCOMP)
+        {
+            unsigned short mypacketid;
+            unsigned char dup, type;
+            if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+                rc = FAILURE;
+        }
+        else
+            rc = FAILURE;
+    }
+    
+exit:
+    return rc;
+}
+
+
+int MQTTDisconnect(Client* c ,Network * n)
+{  
+    int rc = FAILURE;
+    Timer timer;     // we might wait for incomplete incoming publishes to complete
+    int len = MQTTSerialize_disconnect(c->buf, c->buf_size);
+
+    InitTimer(&timer);
+    countdown_ms(&timer, c->command_timeout_ms);
+
+    if (len > 0)
+        rc = sendPacket(c, len, &timer);            // send the disconnect packet
+        
+    c->isconnected = 0;
+    n->disconnect(n);
+    return rc;
+}
+
diff --git a/mbtk/mbtk_mqtt/MQTTClient.h b/mbtk/mbtk_mqtt/MQTTClient.h
new file mode 100755
index 0000000..890a11b
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTClient.h
@@ -0,0 +1,100 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#ifndef __MQTT_CLIENT_C_

+#define __MQTT_CLIENT_C_

+

+#include "MQTTPacket.h"

+#include "stdio.h"

+#include "MQTTLinux.h" 

+

+#define MAX_PACKET_ID 65535

+#define MAX_MESSAGE_HANDLERS 5

+#define MAX_FAIL_ALLOWED  2

+

+enum QoS { QOS0, QOS1, QOS2 };

+

+// all failure return codes must be negative

+enum returnCode {DISCONNECTED = -3,  BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };

+

+void NewTimer(Timer*);

+

+typedef struct MQTTMessage MQTTMessage;

+

+typedef struct MessageData MessageData;

+

+struct MQTTMessage

+{

+    enum QoS qos;

+    char retained;

+    char dup;

+    unsigned short id;

+    void *payload;

+    size_t payloadlen;

+};

+

+struct MessageData

+{

+    MQTTMessage* message;

+    MQTTString* topicName;

+};

+

+typedef struct {

+    char clientId[255];

+    char deviceToken[255];

+} regnwl_info_t;

+

+typedef void (*messageHandler)(MessageData*);

+

+typedef struct Client Client;

+

+int MQTTConnect (Client*, MQTTPacket_connectData*);

+int MQTTPublish (Client*, const char*, MQTTMessage*);

+int MQTTSubscribe (Client*, const char*, enum QoS, messageHandler);

+int MQTTUnsubscribe (Client*, const char*);

+int MQTTDisconnect (Client*,Network*);

+int MQTTYield (Client*, int);

+

+void setDefaultMessageHandler(Client*, messageHandler);

+

+void MQTTClient(Client*, Network*, unsigned int, unsigned char*, size_t, unsigned char*, size_t);

+

+struct Client {

+    unsigned int next_packetid;

+    unsigned int command_timeout_ms;

+    size_t buf_size, readbuf_size;

+    unsigned char *buf;  

+    unsigned char *readbuf; 

+    unsigned int keepAliveInterval;

+    char ping_outstanding;

+    int fail_count;

+    int isconnected;

+

+    struct MessageHandlers

+    {

+        const char* topicFilter;

+        void (*fp) (MessageData*);

+    } messageHandlers[MAX_MESSAGE_HANDLERS];      // Message handlers are indexed by subscription topic

+    

+    void (*defaultMessageHandler) (MessageData*);

+    

+    Network* ipstack;

+    Timer ping_timer;

+};

+

+#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}

+

+#endif

diff --git a/mbtk/mbtk_mqtt/MQTTLinux.c b/mbtk/mbtk_mqtt/MQTTLinux.c
new file mode 100755
index 0000000..cdfd548
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTLinux.c
@@ -0,0 +1,204 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+// #include <openssl/ssl.h>

+// #include <openssl/err.h>

+#include "MQTTLinux.h"

+//#include "global.h"

+//#include "DC_iot_port.h"

+#include "mbtk_sock2.h"

+#define TIMEOUT 60*1000

+

+char expired(Timer* timer)

+{

+	struct timeval now, res;

+	gettimeofday(&now, NULL);

+	timersub(&timer->end_time, &now, &res);

+	return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);

+}

+

+

+void countdown_ms(Timer* timer, unsigned int timeout)

+{

+	struct timeval now;

+	gettimeofday(&now, NULL);

+	struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};

+	timeradd(&now, &interval, &timer->end_time);

+}

+

+

+void countdown(Timer* timer, unsigned int timeout)

+{

+	struct timeval now;

+	gettimeofday(&now, NULL);

+	struct timeval interval = {timeout, 0};

+	timeradd(&now, &interval, &timer->end_time);

+}

+

+

+int left_ms(Timer* timer)

+{

+	struct timeval now, res;

+	gettimeofday(&now, NULL);

+	timersub(&timer->end_time, &now, &res);

+	//printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);

+	return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;

+}

+

+

+void InitTimer(Timer* timer)

+{

+	timer->end_time = (struct timeval){0, 0};

+}

+

+

+int linux_read(Network* n, unsigned char* buffer, int len, int timeout_ms)

+{

+

+    int err;

+    int read_len = mbtk_sock_read(n->handle,n->my_socket, buffer, len, TIMEOUT, &err);

+    if(read_len < 0) {

+        if(err == MBTK_SOCK_ETIMEOUT) {

+            return -2;

+        } else {

+            return -1;

+        }

+    } else {

+        return read_len;

+    }

+

+

+

+#if 0

+

+	struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};

+	//mDEBUG("[%s]timeout_ms = %d \n", __FUNCTION__, timeout_ms);

+	if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))

+	{

+		interval.tv_sec = 0;

+		interval.tv_usec = 100;

+	}

+

+	setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));

+

+	int bytes = 0;

+	while (bytes < len)

+	{

+

+		int rc = recv(n->my_socket, &buffer[bytes], (size_t)(len - bytes), 0);

+		//mDEBUG("[%s]socket recv rc = %d \n", __FUNCTION__, rc);

+

+		if(rc == 0)

+		{

+			 //mDEBUG("[%s]socket close \n", __FUNCTION__);

+			 bytes = 0;

+			 break;

+		}

+		

+		if (rc == -1)

+		{

+			if (errno != ENOTCONN && errno != ECONNRESET)

+			{

+				bytes = -1;

+				break;

+			}

+		}

+		else

+			bytes += rc;

+	}

+	return bytes;

+#endif

+}

+

+

+int linux_write(Network* n, unsigned char* buffer, int len, int timeout_ms)

+{

+

+    int err;

+    printf("Write[%d]:%s",len,(char*)buffer);

+    return mbtk_sock_write(n->handle, n->my_socket, buffer, len, TIMEOUT, &err);

+

+#if 0

+	struct timeval tv;

+

+	tv.tv_sec = 0;  /* 30 Secs Timeout */

+	tv.tv_usec = timeout_ms * 1000;  // Not init'ing this can cause strange errors

+

+	setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));

+

+	int	rc = write(n->my_socket, buffer, len);

+

+	return rc;

+#endif

+}

+

+

+void linux_disconnect(Network* n)

+{

+    int errno;

+    mbtk_sock_close(n->handle,n->my_socket,TIMEOUT,&errno);

+}

+

+

+void NewNetwork(Network* n)

+{

+

+	n->my_socket = 0;

+	n->mqttread = linux_read;

+	n->mqttwrite = linux_write;

+	n->disconnect = linux_disconnect;

+    n->ingnore_cert = true;

+    n->is_support_ssl = false;

+}

+

+

+int ConnectNetwork(Network* n, char* addr, int port, bool is_support_ssl, bool ingnore_cert)

+{

+    mbtk_init_info *info ;

+    mbtk_sock_info *sock_info;

+    int rc = 0;

+    int errno;

+    info = NULL;

+    sock_info = (mbtk_sock_info *)malloc(sizeof(mbtk_sock_info));

+    if(sock_info ==NULL)

+    {

+        rc = -1;

+        return rc;

+    }

+    memcpy(sock_info->address, addr, strlen(addr));

+    sock_info->port = port;

+    sock_info->is_support_ssl = is_support_ssl;

+    sock_info->ingnore_cert = ingnore_cert;

+

+    printf("host %s\nport %d\nis_support_ssl %d\ningnore_cert %d\n",sock_info->address,sock_info->port,sock_info->is_support_ssl,sock_info->ingnore_cert);

+

+	mbtk_sock_handle handle = mbtk_sock_init(info);

+    if (handle < 0 )

+    {

+        rc = -1;

+        return rc;

+    }

+

+    int fd  = mbtk_sock_open(handle, sock_info, TIMEOUT, &errno);

+    if(fd < 0)

+    {

+        rc = -1;

+        return rc;

+    }

+

+    n->my_socket = fd;

+    n->handle = handle;

+	return rc;

+}

diff --git a/mbtk/mbtk_mqtt/MQTTLinux.h b/mbtk/mbtk_mqtt/MQTTLinux.h
new file mode 100755
index 0000000..6ca888a
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTLinux.h
@@ -0,0 +1,74 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Allan Stockdill-Mander - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#ifndef __MQTT_LINUX_

+#define __MQTT_LINUX_

+

+#include <sys/types.h>

+#include <sys/socket.h>

+#include <sys/param.h>

+#include <sys/time.h>

+#include <sys/select.h>

+#include <netinet/in.h>

+#include <netinet/tcp.h>

+#include <arpa/inet.h>

+#include <netdb.h>

+#include <stdio.h>

+#include <unistd.h>

+#include <errno.h>

+#include <fcntl.h>

+#include <stdbool.h>

+#include <stdlib.h>

+#include <string.h>

+#include <signal.h>

+

+// #include <openssl/ssl.h>

+// #include <openssl/err.h>

+//#include "DC_iot_port.h"

+

+typedef struct Timer Timer;

+

+struct Timer {

+	struct timeval end_time;

+};

+

+typedef struct Network Network;

+struct Network

+{

+	int my_socket;

+    bool is_support_ssl;

+    bool ingnore_cert;

+    int handle;

+	int (*mqttread) (Network*, unsigned char*, int, int);

+	int (*mqttwrite) (Network*, unsigned char*, int, int);

+	void (*disconnect) (Network*);

+};

+

+char expired(Timer*);

+void countdown_ms(Timer*, unsigned int);

+void countdown(Timer*, unsigned int);

+int left_ms(Timer*);

+

+void InitTimer(Timer*);

+

+int linux_read(Network*, unsigned char*, int, int);

+int linux_write(Network*, unsigned char*, int, int);

+void linux_disconnect(Network*);

+void NewNetwork(Network*);

+

+int ConnectNetwork(Network*, char*, int, bool ,bool );

+

+#endif
\ No newline at end of file
diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnect.h b/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnect.h
new file mode 100755
index 0000000..d77f18c
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnect.h
@@ -0,0 +1,136 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTCONNECT_H_

+#define MQTTCONNECT_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+

+typedef union

+{

+	unsigned char all;	/**< all connect flags */

+#if defined(REVERSED)

+	struct

+	{

+		unsigned int username : 1;			/**< 3.1 user name */

+		unsigned int password : 1; 			/**< 3.1 password */

+		unsigned int willRetain : 1;		/**< will retain setting */

+		unsigned int willQoS : 2;				/**< will QoS value */

+		unsigned int will : 1;			    /**< will flag */

+		unsigned int cleansession : 1;	  /**< clean session flag */

+		unsigned int : 1;	  	          /**< unused */

+	} bits;

+#else

+	struct

+	{

+		unsigned int : 1;	     					/**< unused */

+		unsigned int cleansession : 1;	  /**< cleansession flag */

+		unsigned int will : 1;			    /**< will flag */

+		unsigned int willQoS : 2;				/**< will QoS value */

+		unsigned int willRetain : 1;		/**< will retain setting */

+		unsigned int password : 1; 			/**< 3.1 password */

+		unsigned int username : 1;			/**< 3.1 user name */

+	} bits;

+#endif

+} MQTTConnectFlags;	/**< connect flags byte */

+

+

+

+/**

+ * Defines the MQTT "Last Will and Testament" (LWT) settings for

+ * the connect packet.

+ */

+typedef struct

+{

+	/** The eyecatcher for this structure.  must be MQTW. */

+	char struct_id[4];

+	/** The version number of this structure.  Must be 0 */

+	int struct_version;

+	/** The LWT topic to which the LWT message will be published. */

+	MQTTString topicName;

+	/** The LWT payload. */

+	MQTTString message;

+	/**

+      * The retained flag for the LWT message (see MQTTAsync_message.retained).

+      */

+	unsigned char retained;

+	/**

+      * The quality of service setting for the LWT message (see

+      * MQTTAsync_message.qos and @ref qos).

+      */

+	char qos;

+} MQTTPacket_willOptions;

+

+

+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }

+

+

+typedef struct

+{

+	/** The eyecatcher for this structure.  must be MQTC. */

+	char struct_id[4];

+	/** The version number of this structure.  Must be 0 */

+	int struct_version;

+	/** Version of MQTT to be used.  3 = 3.1 4 = 3.1.1

+	  */

+	unsigned char MQTTVersion;

+	MQTTString clientID;

+	unsigned short keepAliveInterval;

+	unsigned char cleansession;

+	unsigned char willFlag;

+	MQTTPacket_willOptions will;

+	MQTTString username;

+	MQTTString password;

+} MQTTPacket_connectData;

+

+typedef union

+{

+	unsigned char all;	/**< all connack flags */

+#if defined(REVERSED)

+	struct

+	{

+		unsigned int sessionpresent : 1;    /**< session present flag */

+		unsigned int : 7;	  	          /**< unused */

+	} bits;

+#else

+	struct

+	{

+		unsigned int : 7;	     			/**< unused */

+		unsigned int sessionpresent : 1;    /**< session present flag */

+	} bits;

+#endif

+} MQTTConnackFlags;	/**< connack flags byte */

+

+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \

+		MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }

+

+DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);

+DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);

+DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);

+

+DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);

+DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);

+

+#endif /* MQTTCONNECT_H_ */

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnectClient.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnectClient.c
new file mode 100755
index 0000000..405c23e
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnectClient.c
@@ -0,0 +1,211 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "MQTTPacket.h"

+#include "StackTrace.h"

+

+#include <string.h>

+

+/**

+  * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.

+  * @param options the options to be used to build the connect packet

+  * @return the length of buffer needed to contain the serialized version of the packet

+  */

+int MQTTSerialize_connectLength(MQTTPacket_connectData* options)

+{

+	int len = 0;

+

+	FUNC_ENTRY;

+

+	if (options->MQTTVersion == 3)

+		len = 12; /* variable depending on MQTT or MQIsdp */

+	else if (options->MQTTVersion == 4)

+		len = 10;

+

+	len += MQTTstrlen(options->clientID)+2;

+	if (options->willFlag)

+		len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;

+	if (options->username.cstring || options->username.lenstring.data)

+		len += MQTTstrlen(options->username)+2;

+	if (options->password.cstring || options->password.lenstring.data)

+		len += MQTTstrlen(options->password)+2;

+

+	FUNC_EXIT_RC(len);

+	return len;

+}

+

+

+/**

+  * Serializes the connect options into the buffer.

+  * @param buf the buffer into which the packet will be serialized

+  * @param len the length in bytes of the supplied buffer

+  * @param options the options to be used to build the connect packet

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)

+{

+	unsigned char *ptr = buf;

+	MQTTHeader header = {0};

+	MQTTConnectFlags flags = {0};

+	int len = 0;

+	int rc = -1;

+

+	FUNC_ENTRY;

+	if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+

+	header.byte = 0;

+	header.bits.type = CONNECT;

+	writeChar(&ptr, header.byte); /* write header */

+	ptr += MQTTPacket_encode(ptr, len); /* write remaining length */

+	if (options->MQTTVersion == 4)

+	{

+		writeCString(&ptr, "MQTT");

+		writeChar(&ptr, (char) 4);

+	}

+	else

+	{

+		writeCString(&ptr, "MQIsdp");

+		writeChar(&ptr, (char) 3);

+	}

+

+	flags.all = 0;

+	flags.bits.cleansession = options->cleansession;

+	flags.bits.will = (options->willFlag) ? 1 : 0;

+	if (flags.bits.will)

+	{

+		flags.bits.willQoS = options->will.qos;

+		flags.bits.willRetain = options->will.retained;

+	}

+

+	if (options->username.cstring || options->username.lenstring.data)

+		flags.bits.username = 1;

+	if (options->password.cstring || options->password.lenstring.data)

+		flags.bits.password = 1;

+	writeChar(&ptr, flags.all);

+	writeInt(&ptr, options->keepAliveInterval);

+	writeMQTTString(&ptr, options->clientID);

+	if (options->willFlag)

+	{

+		writeMQTTString(&ptr, options->will.topicName);

+		writeMQTTString(&ptr, options->will.message);

+	}

+	if (flags.bits.username)

+		writeMQTTString(&ptr, options->username);

+	if (flags.bits.password)

+		writeMQTTString(&ptr, options->password);

+

+	rc = ptr - buf;

+    

+	exit: FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Deserializes the supplied (wire) buffer into connack data - return code

+  * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)

+  * @param connack_rc returned integer value of the connack return code

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param len the length in bytes of the data in the supplied buffer

+  * @return error code.  1 is success, 0 is failure

+  */

+int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)

+{

+	MQTTHeader header = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = NULL;

+	int rc = 0;

+	int mylen;

+	MQTTConnackFlags flags = {0};

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	if (header.bits.type != CONNACK)

+		goto exit;

+

+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */

+	enddata = curdata + mylen;

+	if (enddata - curdata < 2)

+		goto exit;

+

+	flags.all = readChar(&curdata);

+	*sessionPresent = flags.bits.sessionpresent;

+	*connack_rc = readChar(&curdata);

+

+	rc = 1;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns

+  * @param packettype the message type

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)

+{

+	MQTTHeader header = {0};

+	int rc = -1;

+	unsigned char *ptr = buf;

+

+	FUNC_ENTRY;

+	if (buflen < 2)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+	header.byte = 0;

+	header.bits.type = packettype;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_disconnect(unsigned char* buf, int buflen)

+{

+	return MQTTSerialize_zero(buf, buflen, DISCONNECT);

+}

+

+

+/**

+  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer, to avoid overruns

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_pingreq(unsigned char* buf, int buflen)

+{

+	return MQTTSerialize_zero(buf, buflen, PINGREQ);

+}

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnectServer.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnectServer.c
new file mode 100755
index 0000000..7c1fe50
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTConnectServer.c
@@ -0,0 +1,148 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "StackTrace.h"

+#include "MQTTPacket.h"

+#include <string.h>

+

+#define min(a, b) ((a < b) ? a : b)

+

+

+/**

+  * Validates MQTT protocol name and version combinations

+  * @param protocol the MQTT protocol name as an MQTTString

+  * @param version the MQTT protocol version number, as in the connect packet

+  * @return correct MQTT combination?  1 is true, 0 is false

+  */

+int MQTTPacket_checkVersion(MQTTString* protocol, int version)

+{

+	int rc = 0;

+

+	if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",

+			min(6, protocol->lenstring.len)) == 0)

+		rc = 1;

+	else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",

+			min(4, protocol->lenstring.len)) == 0)

+		rc = 1;

+	return rc;

+}

+

+

+/**

+  * Deserializes the supplied (wire) buffer into connect data structure

+  * @param data the connect data structure to be filled out

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param len the length in bytes of the data in the supplied buffer

+  * @return error code.  1 is success, 0 is failure

+  */

+int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)

+{

+	MQTTHeader header = {0};

+	MQTTConnectFlags flags = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = &buf[len];

+	int rc = 0;

+	MQTTString Protocol;

+	int version;

+	int mylen = 0;

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	if (header.bits.type != CONNECT)

+		goto exit;

+

+	curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */

+

+	if (!readMQTTLenString(&Protocol, &curdata, enddata) ||

+		enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */

+		goto exit;

+

+	version = (int)readChar(&curdata); /* Protocol version */

+	/* If we don't recognize the protocol version, we don't parse the connect packet on the

+	 * basis that we don't know what the format will be.

+	 */

+	if (MQTTPacket_checkVersion(&Protocol, version))

+	{

+		flags.all = readChar(&curdata);

+		data->cleansession = flags.bits.cleansession;

+		data->keepAliveInterval = readInt(&curdata);

+		if (!readMQTTLenString(&data->clientID, &curdata, enddata))

+			goto exit;

+		data->willFlag = flags.bits.will;

+		if (flags.bits.will)

+		{

+			data->will.qos = flags.bits.willQoS;

+			data->will.retained = flags.bits.willRetain;

+			if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||

+				  !readMQTTLenString(&data->will.message, &curdata, enddata))

+				goto exit;

+		}

+		if (flags.bits.username)

+		{

+			if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))

+				goto exit; /* username flag set, but no username supplied - invalid */

+			if (flags.bits.password &&

+				(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))

+				goto exit; /* password flag set, but no password supplied - invalid */

+		}

+		else if (flags.bits.password)

+			goto exit; /* password flag set without username - invalid */

+		rc = 1;

+	}

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Serializes the connack packet into the supplied buffer.

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param connack_rc the integer connack return code to be used 

+  * @param sessionPresent the MQTT 3.1.1 sessionPresent flag

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)

+{

+	MQTTHeader header = {0};

+	int rc = 0;

+	unsigned char *ptr = buf;

+	MQTTConnackFlags flags = {0};

+

+	FUNC_ENTRY;

+	if (buflen < 2)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+	header.byte = 0;

+	header.bits.type = CONNACK;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */

+

+	flags.all = 0;

+	flags.bits.sessionpresent = sessionPresent;

+	writeChar(&ptr, flags.all); 

+	writeChar(&ptr, connack_rc);

+

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTDeserializePublish.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTDeserializePublish.c
new file mode 100755
index 0000000..dbc9e5d
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTDeserializePublish.c
@@ -0,0 +1,107 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "StackTrace.h"

+#include "MQTTPacket.h"

+#include <string.h>

+

+#define min(a, b) ((a < b) ? 1 : 0)

+

+/**

+  * Deserializes the supplied (wire) buffer into publish data

+  * @param dup returned integer - the MQTT dup flag

+  * @param qos returned integer - the MQTT QoS value

+  * @param retained returned integer - the MQTT retained flag

+  * @param packetid returned integer - the MQTT packet identifier

+  * @param topicName returned MQTTString - the MQTT topic in the publish

+  * @param payload returned byte buffer - the MQTT publish payload

+  * @param payloadlen returned integer - the length of the MQTT payload

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @return error code.  1 is success

+  */

+int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,

+		unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)

+{

+	MQTTHeader header = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = NULL;

+	int rc = 0;

+	int mylen = 0;

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	if (header.bits.type != PUBLISH)

+		goto exit;

+	*dup = header.bits.dup;

+	*qos = header.bits.qos;

+	*retained = header.bits.retain;

+

+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */

+	enddata = curdata + mylen;

+

+	if (!readMQTTLenString(topicName, &curdata, enddata) ||

+		enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */

+		goto exit;

+

+	if (*qos > 0)

+		*packetid = readInt(&curdata);

+

+	*payloadlen = enddata - curdata;

+	*payload = curdata;

+	rc = 1;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+

+/**

+  * Deserializes the supplied (wire) buffer into an ack

+  * @param packettype returned integer - the MQTT packet type

+  * @param dup returned integer - the MQTT dup flag

+  * @param packetid returned integer - the MQTT packet identifier

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @return error code.  1 is success, 0 is failure

+  */

+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)

+{

+	MQTTHeader header = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = NULL;

+	int rc = 0;

+	int mylen;

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	*dup = header.bits.dup;

+	*packettype = header.bits.type;

+

+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */

+	enddata = curdata + mylen;

+

+	if (enddata - curdata < 2)

+		goto exit;

+	*packetid = readInt(&curdata);

+

+	rc = 1;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTFormat.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTFormat.c
new file mode 100755
index 0000000..3015a0e
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTFormat.c
@@ -0,0 +1,258 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "StackTrace.h"

+#include "MQTTPacket.h"

+

+#include <string.h>

+

+

+const char* MQTTPacket_names[] =

+{

+	"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",

+	"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",

+	"PINGREQ", "PINGRESP", "DISCONNECT"

+};

+

+

+const char* MQTTPacket_getName(unsigned short packetid)

+{

+	return MQTTPacket_names[packetid];

+}

+

+

+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)

+{

+	int strindex = 0;

+

+	strindex = snprintf(strbuf, strbuflen,

+			"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",

+			(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,

+			(int)data->cleansession, data->keepAliveInterval);

+	if (data->willFlag)

+		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,

+				", will QoS %d, will retain %d, will topic %.*s, will message %.*s",

+				data->will.qos, data->will.retained,

+				data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,

+				data->will.message.lenstring.len, data->will.message.lenstring.data);

+	if (data->username.lenstring.data && data->username.lenstring.len > 0)

+		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,

+				", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);

+	if (data->password.lenstring.data && data->password.lenstring.len > 0)

+		strindex += snprintf(&strbuf[strindex], strbuflen - strindex,

+				", password %.*s", data->password.lenstring.len, data->password.lenstring.data);

+	return strindex;

+}

+

+

+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)

+{

+	int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);

+	return strindex;

+}

+

+

+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,

+		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)

+{

+	int strindex = snprintf(strbuf, strbuflen,

+				"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",

+				dup, qos, retained, packetid,

+				(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,

+				payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);

+	return strindex;

+}

+

+

+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)

+{

+	int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);

+	if (dup)

+		strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);

+	return strindex;

+}

+

+

+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,

+		MQTTString topicFilters[], int requestedQoSs[])

+{

+	return snprintf(strbuf, strbuflen,

+		"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",

+		dup, packetid, count,

+		topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,

+		requestedQoSs[0]);

+}

+

+

+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)

+{

+	return snprintf(strbuf, strbuflen,

+		"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);

+}

+

+

+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[])

+{

+	return snprintf(strbuf, strbuflen,

+					"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",

+					dup, packetid, count,

+					topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);

+}

+

+

+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)

+{

+	int index = 0;

+	int rem_length = 0;

+	MQTTHeader header = {0};

+	int strindex = 0;

+

+	header.byte = buf[index++];

+	index += MQTTPacket_decodeBuf(&buf[index], &rem_length);

+

+	switch (header.bits.type)

+	{

+	case CONNACK:

+	{

+		unsigned char sessionPresent, connack_rc;

+		if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)

+			strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);

+	}

+	break;

+	case PUBLISH:

+	{

+		unsigned char dup, retained, *payload;

+		unsigned short packetid;

+		int qos, payloadlen;

+		MQTTString topicName = MQTTString_initializer;

+		if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,

+				&payload, &payloadlen, buf, buflen) == 1)

+			strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,

+					topicName, payload, payloadlen);

+	}

+	break;

+	case PUBACK:

+	case PUBREC:

+	case PUBREL:

+	case PUBCOMP:

+	{

+		unsigned char packettype, dup;

+		unsigned short packetid;

+		if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)

+			strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);

+	}

+	break;

+	case SUBACK:

+	{

+		unsigned short packetid;

+		int maxcount = 1, count = 0;

+		int grantedQoSs[1];

+		if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)

+			strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);

+	}

+	break;

+	case UNSUBACK:

+	{

+		unsigned short packetid;

+		if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)

+			strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);

+	}

+	break;

+	case PINGREQ:

+	case PINGRESP:

+	case DISCONNECT:

+		strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);

+		break;

+	}

+	return strbuf;

+}

+

+

+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)

+{

+	int index = 0;

+	int rem_length = 0;

+	MQTTHeader header = {0};

+	int strindex = 0;

+

+	header.byte = buf[index++];

+	index += MQTTPacket_decodeBuf(&buf[index], &rem_length);

+

+	switch (header.bits.type)

+	{

+	case CONNECT:

+	{

+		MQTTPacket_connectData data;

+		int rc;

+		if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)

+			strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);

+	}

+	break;

+	case PUBLISH:

+	{

+		unsigned char dup, retained, *payload;

+		unsigned short packetid;

+		int qos, payloadlen;

+		MQTTString topicName = MQTTString_initializer;

+		if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,

+				&payload, &payloadlen, buf, buflen) == 1)

+			strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,

+					topicName, payload, payloadlen);

+	}

+	break;

+	case PUBACK:

+	case PUBREC:

+	case PUBREL:

+	case PUBCOMP:

+	{

+		unsigned char packettype, dup;

+		unsigned short packetid;

+		if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)

+			strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);

+	}

+	break;

+	case SUBSCRIBE:

+	{

+		unsigned char dup;

+		unsigned short packetid;

+		int maxcount = 1, count = 0;

+		MQTTString topicFilters[1];

+		int requestedQoSs[1];

+		if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,

+				topicFilters, requestedQoSs, buf, buflen) == 1)

+			strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;

+	}

+	break;

+	case UNSUBSCRIBE:

+	{

+		unsigned char dup;

+		unsigned short packetid;

+		int maxcount = 1, count = 0;

+		MQTTString topicFilters[1];

+		if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)

+			strindex =  MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);

+	}

+	break;

+	case PINGREQ:

+	case PINGRESP:

+	case DISCONNECT:

+		strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);

+		break;

+	}

+	strbuf[strbuflen] = '\0';

+	return strbuf;

+}

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTFormat.h b/mbtk/mbtk_mqtt/MQTTPacket/MQTTFormat.h
new file mode 100755
index 0000000..f7bd0d1
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTFormat.h
@@ -0,0 +1,37 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#if !defined(MQTTFORMAT_H)

+#define MQTTFORMAT_H

+

+#include "StackTrace.h"

+#include "MQTTPacket.h"

+

+const char* MQTTPacket_getName(unsigned short packetid);

+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);

+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);

+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,

+		unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);

+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);

+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,

+		MQTTString topicFilters[], int requestedQoSs[]);

+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);

+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[]);

+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);

+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);

+

+#endif

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTPacket.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTPacket.c
new file mode 100755
index 0000000..c100f55
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTPacket.c
@@ -0,0 +1,410 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Sergio R. Caprile - non-blocking packet read functions for stream transport

+ *******************************************************************************/

+

+#include "StackTrace.h"

+#include "MQTTPacket.h"

+

+#include <string.h>

+

+/**

+ * Encodes the message length according to the MQTT algorithm

+ * @param buf the buffer into which the encoded data is written

+ * @param length the length to be encoded

+ * @return the number of bytes written to buffer

+ */

+int MQTTPacket_encode(unsigned char* buf, int length)

+{

+	int rc = 0;

+

+	FUNC_ENTRY;

+	do

+	{

+		char d = length % 128;

+		length /= 128;

+		/* if there are more digits to encode, set the top bit of this digit */

+		if (length > 0)

+			d |= 0x80;

+		buf[rc++] = d;

+	} while (length > 0);

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+ * Decodes the message length according to the MQTT algorithm

+ * @param getcharfn pointer to function to read the next character from the data source

+ * @param value the decoded length returned

+ * @return the number of bytes read from the socket

+ */

+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)

+{

+	unsigned char c;

+	int multiplier = 1;

+	int len = 0;

+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4

+

+	FUNC_ENTRY;

+	*value = 0;

+	do

+	{

+		int rc = MQTTPACKET_READ_ERROR;

+

+		if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)

+		{

+			rc = MQTTPACKET_READ_ERROR;	/* bad data */

+			goto exit;

+		}

+		rc = (*getcharfn)(&c, 1);

+		if (rc != 1)

+			goto exit;

+		*value += (c & 127) * multiplier;

+		multiplier *= 128;

+	} while ((c & 128) != 0);

+exit:

+	FUNC_EXIT_RC(len);

+	return len;

+}

+

+

+int MQTTPacket_len(int rem_len)

+{

+	rem_len += 1; /* header byte */

+

+	/* now remaining_length field */

+	if (rem_len < 128)

+		rem_len += 1;

+	else if (rem_len < 16384)

+		rem_len += 2;

+	else if (rem_len < 2097151)

+		rem_len += 3;

+	else

+		rem_len += 4;

+	return rem_len;

+}

+

+

+static unsigned char* bufptr;

+

+int bufchar(unsigned char* c, int count)

+{

+	int i;

+

+	for (i = 0; i < count; ++i)

+		*c = *bufptr++;

+	return count;

+}

+

+

+int MQTTPacket_decodeBuf(unsigned char* buf, int* value)

+{

+	bufptr = buf;

+	return MQTTPacket_decode(bufchar, value);

+}

+

+

+/**

+ * Calculates an integer from two bytes read from the input buffer

+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned

+ * @return the integer value calculated

+ */

+int readInt(unsigned char** pptr)

+{

+	unsigned char* ptr = *pptr;

+	int len = 256*(*ptr) + (*(ptr+1));

+	*pptr += 2;

+	return len;

+}

+

+

+/**

+ * Reads one character from the input buffer.

+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned

+ * @return the character read

+ */

+char readChar(unsigned char** pptr)

+{

+	char c = **pptr;

+	(*pptr)++;

+	return c;

+}

+

+

+/**

+ * Writes one character to an output buffer.

+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned

+ * @param c the character to write

+ */

+void writeChar(unsigned char** pptr, char c)

+{

+	**pptr = c;

+	(*pptr)++;

+}

+

+

+/**

+ * Writes an integer as 2 bytes to an output buffer.

+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned

+ * @param anInt the integer to write

+ */

+void writeInt(unsigned char** pptr, int anInt)

+{

+	**pptr = (unsigned char)(anInt / 256);

+	(*pptr)++;

+	**pptr = (unsigned char)(anInt % 256);

+	(*pptr)++;

+}

+

+

+/**

+ * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.

+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned

+ * @param string the C string to write

+ */

+void writeCString(unsigned char** pptr, const char* string)

+{

+	int len = strlen(string);

+	writeInt(pptr, len);

+	memcpy(*pptr, string, len);

+	*pptr += len;

+}

+

+

+int getLenStringLen(char* ptr)

+{

+	int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));

+	return len;

+}

+

+

+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)

+{

+	if (mqttstring.lenstring.len > 0)

+	{

+		writeInt(pptr, mqttstring.lenstring.len);

+		memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);

+		*pptr += mqttstring.lenstring.len;

+	}

+	else if (mqttstring.cstring)

+		writeCString(pptr, mqttstring.cstring);

+	else

+		writeInt(pptr, 0);

+}

+

+

+/**

+ * @param mqttstring the MQTTString structure into which the data is to be read

+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned

+ * @param enddata pointer to the end of the data: do not read beyond

+ * @return 1 if successful, 0 if not

+ */

+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)

+{

+	int rc = 0;

+

+	FUNC_ENTRY;

+	/* the first two bytes are the length of the string */

+	if (enddata - (*pptr) > 1) /* enough length to read the integer? */

+	{

+		mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */

+		if (&(*pptr)[mqttstring->lenstring.len] <= enddata)

+		{

+			mqttstring->lenstring.data = (char*)*pptr;

+			*pptr += mqttstring->lenstring.len;

+			rc = 1;

+		}

+	}

+	mqttstring->cstring = NULL;

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+ * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string

+ * @param mqttstring the string to return the length of

+ * @return the length of the string

+ */

+int MQTTstrlen(MQTTString mqttstring)

+{

+	int rc = 0;

+

+	if (mqttstring.cstring)

+		rc = strlen(mqttstring.cstring);

+	else

+		rc = mqttstring.lenstring.len;

+	return rc;

+}

+

+

+/**

+ * Compares an MQTTString to a C string

+ * @param a the MQTTString to compare

+ * @param bptr the C string to compare

+ * @return boolean - equal or not

+ */

+int MQTTPacket_equals(MQTTString* a, char* bptr)

+{

+	int alen = 0,

+		blen = 0;

+	char *aptr;

+	

+	if (a->cstring)

+	{

+		aptr = a->cstring;

+		alen = strlen(a->cstring);

+	}

+	else

+	{

+		aptr = a->lenstring.data;

+		alen = a->lenstring.len;

+	}

+	blen = strlen(bptr);

+	

+	return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);

+}

+

+

+/**

+ * Helper function to read packet data from some source into a buffer

+ * @param buf the buffer into which the packet will be serialized

+ * @param buflen the length in bytes of the supplied buffer

+ * @param getfn pointer to a function which will read any number of bytes from the needed source

+ * @return integer MQTT packet type, or -1 on error

+ * @note  the whole message must fit into the caller's buffer

+ */

+int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))

+{

+	int rc = -1;

+	MQTTHeader header = {0};

+	int len = 0;

+	int rem_len = 0;

+

+	/* 1. read the header byte.  This has the packet type in it */

+	if ((*getfn)(buf, 1) != 1)

+		goto exit;

+

+	len = 1;

+	/* 2. read the remaining length.  This is variable in itself */

+	MQTTPacket_decode(getfn, &rem_len);

+	len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */

+

+	/* 3. read the rest of the buffer using a callback to supply the rest of the data */

+	if((rem_len + len) > buflen)

+		goto exit;

+	if ((*getfn)(buf + len, rem_len) != rem_len)

+		goto exit;

+

+	header.byte = buf[0];

+	rc = header.bits.type;

+exit:

+	return rc;

+}

+

+/**

+ * Decodes the message length according to the MQTT algorithm, non-blocking

+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it

+ * @param value the decoded length returned

+ * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error

+ */

+static int MQTTPacket_decodenb(MQTTTransport *trp)

+{

+	unsigned char c;

+	int rc = MQTTPACKET_READ_ERROR;

+

+	FUNC_ENTRY;

+	if(trp->len == 0){		/* initialize on first call */

+		trp->multiplier = 1;

+		trp->rem_len = 0;

+	}

+	do {

+		int frc;

+		if (++(trp->len) > MAX_NO_OF_REMAINING_LENGTH_BYTES)

+			goto exit;

+		if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)

+			goto exit;

+		if (frc == 0){

+			rc = 0;

+			goto exit;

+		}

+		trp->rem_len += (c & 127) * trp->multiplier;

+		trp->multiplier *= 128;

+	} while ((c & 128) != 0);

+	rc = trp->len;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+/**

+ * Helper function to read packet data from some source into a buffer, non-blocking

+ * @param buf the buffer into which the packet will be serialized

+ * @param buflen the length in bytes of the supplied buffer

+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it

+ * @return integer MQTT packet type, 0 for call again, or -1 on error

+ * @note  the whole message must fit into the caller's buffer

+ */

+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)

+{

+	int rc = -1, frc;

+	MQTTHeader header = {0};

+

+	switch(trp->state){

+	default:

+		trp->state = 0;

+		/*FALLTHROUGH*/

+	case 0:

+		/* read the header byte.  This has the packet type in it */

+		if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)

+			goto exit;

+		if (frc == 0)

+			return 0;

+		trp->len = 0;

+		++trp->state;

+		/*FALLTHROUGH*/

+		/* read the remaining length.  This is variable in itself */

+	case 1:

+		if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)

+			goto exit;

+		if(frc == 0)

+			return 0;

+		trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */

+		if((trp->rem_len + trp->len) > buflen)

+			goto exit;

+		++trp->state;

+		/*FALLTHROUGH*/

+	case 2:

+		/* read the rest of the buffer using a callback to supply the rest of the data */

+		if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)

+			goto exit;

+		if (frc == 0)

+			return 0;

+		trp->rem_len -= frc;

+		trp->len += frc;

+		if(trp->rem_len)

+			return 0;

+

+		header.byte = buf[0];

+		rc = header.bits.type;

+		break;

+	}

+

+exit:

+	trp->state = 0;

+	return rc;

+}

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTPacket.h b/mbtk/mbtk_mqtt/MQTTPacket/MQTTPacket.h
new file mode 100755
index 0000000..f417929
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTPacket.h
@@ -0,0 +1,133 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTPACKET_H_

+#define MQTTPACKET_H_

+

+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */

+extern "C" {

+#endif

+

+#if defined(WIN32_DLL) || defined(WIN64_DLL)

+  #define DLLImport __declspec(dllimport)

+  #define DLLExport __declspec(dllexport)

+#elif defined(LINUX_SO)

+  #define DLLImport extern

+  #define DLLExport  __attribute__ ((visibility ("default")))

+#else

+  #define DLLImport

+  #define DLLExport  

+#endif

+

+enum errors

+{

+	MQTTPACKET_BUFFER_TOO_SHORT = -2,

+	MQTTPACKET_READ_ERROR = -1,

+	MQTTPACKET_READ_COMPLETE

+};

+

+enum msgTypes

+{

+	CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,

+	PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,

+	PINGREQ, PINGRESP, DISCONNECT

+};

+

+/**

+ * Bitfields for the MQTT header byte.

+ */

+typedef union

+{

+	unsigned char byte;	                /**< the whole byte */

+#if defined(REVERSED)

+	struct

+	{

+		unsigned int type : 4;			/**< message type nibble */

+		unsigned int dup : 1;				/**< DUP flag bit */

+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */

+		unsigned int retain : 1;		/**< retained flag bit */

+	} bits;

+#else

+	struct

+	{

+		unsigned int retain : 1;		/**< retained flag bit */

+		unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */

+		unsigned int dup : 1;				/**< DUP flag bit */

+		unsigned int type : 4;			/**< message type nibble */

+	} bits;

+#endif

+} MQTTHeader;

+

+typedef struct

+{

+	int len;

+	char* data;

+} MQTTLenString;

+

+typedef struct

+{

+	char* cstring;

+	MQTTLenString lenstring;

+} MQTTString;

+

+#define MQTTString_initializer {NULL, {0, NULL}}

+

+int MQTTstrlen(MQTTString mqttstring);

+

+#include "MQTTConnect.h"

+#include "MQTTPublish.h"

+#include "MQTTSubscribe.h"

+#include "MQTTUnsubscribe.h"

+#include "MQTTFormat.h"

+

+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);

+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);

+

+int MQTTPacket_len(int rem_len);

+int MQTTPacket_equals(MQTTString* a, char* b);

+

+int MQTTPacket_encode(unsigned char* buf, int length);

+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);

+int MQTTPacket_decodeBuf(unsigned char* buf, int* value);

+

+int readInt(unsigned char** pptr);

+char readChar(unsigned char** pptr);

+void writeChar(unsigned char** pptr, char c);

+void writeInt(unsigned char** pptr, int anInt);

+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);

+void writeCString(unsigned char** pptr, const char* string);

+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);

+

+DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));

+

+typedef struct {

+	int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */

+	void *sck;	/* pointer to whatever the system may use to identify the transport */

+	int multiplier;

+	int rem_len;

+	int len;

+	char state;

+}MQTTTransport;

+

+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);

+

+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */

+}

+#endif

+

+

+#endif /* MQTTPACKET_H_ */

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTPublish.h b/mbtk/mbtk_mqtt/MQTTPacket/MQTTPublish.h
new file mode 100755
index 0000000..d62dddb
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTPublish.h
@@ -0,0 +1,38 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTPUBLISH_H_

+#define MQTTPUBLISH_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,

+		MQTTString topicName, unsigned char* payload, int payloadlen);

+

+DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,

+		unsigned char** payload, int* payloadlen, unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);

+DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);

+DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);

+

+#endif /* MQTTPUBLISH_H_ */

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTSerializePublish.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSerializePublish.c
new file mode 100755
index 0000000..236791f
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSerializePublish.c
@@ -0,0 +1,169 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144

+ *******************************************************************************/

+

+#include "MQTTPacket.h"

+#include "StackTrace.h"

+

+#include <string.h>

+

+

+/**

+  * Determines the length of the MQTT publish packet that would be produced using the supplied parameters

+  * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)

+  * @param topicName the topic name to be used in the publish  

+  * @param payloadlen the length of the payload to be sent

+  * @return the length of buffer needed to contain the serialized version of the packet

+  */

+int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)

+{

+	int len = 0;

+

+	len += 2 + MQTTstrlen(topicName) + payloadlen;

+	if (qos > 0)

+		len += 2; /* packetid */

+	return len;

+}

+

+

+/**

+  * Serializes the supplied publish data into the supplied buffer, ready for sending

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param dup integer - the MQTT dup flag

+  * @param qos integer - the MQTT QoS value

+  * @param retained integer - the MQTT retained flag

+  * @param packetid integer - the MQTT packet identifier

+  * @param topicName MQTTString - the MQTT topic in the publish

+  * @param payload byte buffer - the MQTT publish payload

+  * @param payloadlen integer - the length of the MQTT payload

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,

+		MQTTString topicName, unsigned char* payload, int payloadlen)

+{

+	unsigned char *ptr = buf;

+	MQTTHeader header = {0};

+	int rem_len = 0;

+	int rc = 0;

+

+	FUNC_ENTRY;

+	if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+

+	header.bits.type = PUBLISH;

+	header.bits.dup = dup;

+	header.bits.qos = qos;

+	header.bits.retain = retained;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;

+

+	writeMQTTString(&ptr, topicName);

+

+	if (qos > 0)

+		writeInt(&ptr, packetid);

+

+	memcpy(ptr, payload, payloadlen);

+	ptr += payloadlen;

+

+	rc = ptr - buf;

+

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+

+/**

+  * Serializes the ack packet into the supplied buffer.

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param type the MQTT packet type

+  * @param dup the MQTT dup flag

+  * @param packetid the MQTT packet identifier

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)

+{

+	MQTTHeader header = {0};

+	int rc = 0;

+	unsigned char *ptr = buf;

+

+	FUNC_ENTRY;

+	if (buflen < 4)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+	header.bits.type = packettype;

+	header.bits.dup = dup;

+	header.bits.qos = (packettype == PUBREL) ? 1 : 0;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */

+	writeInt(&ptr, packetid);

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Serializes a puback packet into the supplied buffer.

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param packetid integer - the MQTT packet identifier

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)

+{

+	return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);

+}

+

+

+/**

+  * Serializes a pubrel packet into the supplied buffer.

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param dup integer - the MQTT dup flag

+  * @param packetid integer - the MQTT packet identifier

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)

+{

+	return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);

+}

+

+

+/**

+  * Serializes a pubrel packet into the supplied buffer.

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param packetid integer - the MQTT packet identifier

+  * @return serialized length, or error if 0

+  */

+int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)

+{

+	return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);

+}

+

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribe.h b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribe.h
new file mode 100755
index 0000000..383ca0d
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribe.h
@@ -0,0 +1,39 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTSUBSCRIBE_H_

+#define MQTTSUBSCRIBE_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[], int requestedQoSs[]);

+

+DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,

+		int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);

+

+DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);

+

+

+#endif /* MQTTSUBSCRIBE_H_ */

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribeClient.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribeClient.c
new file mode 100755
index 0000000..5b1ca28
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribeClient.c
@@ -0,0 +1,137 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "MQTTPacket.h"

+#include "StackTrace.h"

+

+#include <string.h>

+

+/**

+  * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters

+  * @param count the number of topic filter strings in topicFilters

+  * @param topicFilters the array of topic filter strings to be used in the publish

+  * @return the length of buffer needed to contain the serialized version of the packet

+  */

+int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])

+{

+	int i;

+	int len = 2; /* packetid */

+

+	for (i = 0; i < count; ++i)

+		len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */

+	return len;

+}

+

+

+/**

+  * Serializes the supplied subscribe data into the supplied buffer, ready for sending

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied bufferr

+  * @param dup integer - the MQTT dup flag

+  * @param packetid integer - the MQTT packet identifier

+  * @param count - number of members in the topicFilters and reqQos arrays

+  * @param topicFilters - array of topic filter names

+  * @param requestedQoSs - array of requested QoS

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,

+		MQTTString topicFilters[], int requestedQoSs[])

+{

+	unsigned char *ptr = buf;

+	MQTTHeader header = {0};

+	int rem_len = 0;

+	int rc = 0;

+	int i = 0;

+

+	FUNC_ENTRY;

+	if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+

+	header.byte = 0;

+	header.bits.type = SUBSCRIBE;

+	header.bits.dup = dup;

+	header.bits.qos = 1;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;

+

+	writeInt(&ptr, packetid);

+

+	for (i = 0; i < count; ++i)

+	{

+		writeMQTTString(&ptr, topicFilters[i]);

+		writeChar(&ptr, requestedQoSs[i]);

+	}

+

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+

+/**

+  * Deserializes the supplied (wire) buffer into suback data

+  * @param packetid returned integer - the MQTT packet identifier

+  * @param maxcount - the maximum number of members allowed in the grantedQoSs array

+  * @param count returned integer - number of members in the grantedQoSs array

+  * @param grantedQoSs returned array of integers - the granted qualities of service

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @return error code.  1 is success, 0 is failure

+  */

+int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)

+{

+	MQTTHeader header = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = NULL;

+	int rc = 0;

+	int mylen;

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	if (header.bits.type != SUBACK)

+		goto exit;

+

+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */

+	enddata = curdata + mylen;

+	if (enddata - curdata < 2)

+		goto exit;

+

+	*packetid = readInt(&curdata);

+

+	*count = 0;

+	while (curdata < enddata)

+	{

+		if (*count > maxcount)

+		{

+			rc = -1;

+			goto exit;

+		}

+		grantedQoSs[(*count)++] = readChar(&curdata);

+	}

+

+	rc = 1;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribeServer.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribeServer.c
new file mode 100755
index 0000000..15bb15d
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTSubscribeServer.c
@@ -0,0 +1,112 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "MQTTPacket.h"

+#include "StackTrace.h"

+

+#include <string.h>

+

+

+/**

+  * Deserializes the supplied (wire) buffer into subscribe data

+  * @param dup integer returned - the MQTT dup flag

+  * @param packetid integer returned - the MQTT packet identifier

+  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays

+  * @param count - number of members in the topicFilters and requestedQoSs arrays

+  * @param topicFilters - array of topic filter names

+  * @param requestedQoSs - array of requested QoS

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],

+	int requestedQoSs[], unsigned char* buf, int buflen)

+{

+	MQTTHeader header = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = NULL;

+	int rc = -1;

+	int mylen = 0;

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	if (header.bits.type != SUBSCRIBE)

+		goto exit;

+	*dup = header.bits.dup;

+

+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */

+	enddata = curdata + mylen;

+

+	*packetid = readInt(&curdata);

+

+	*count = 0;

+	while (curdata < enddata)

+	{

+		if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))

+			goto exit;

+		if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */

+			goto exit;

+		requestedQoSs[*count] = readChar(&curdata);

+		(*count)++;

+	}

+

+	rc = 1;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Serializes the supplied suback data into the supplied buffer, ready for sending

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param packetid integer - the MQTT packet identifier

+  * @param count - number of members in the grantedQoSs array

+  * @param grantedQoSs - array of granted QoS

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)

+{

+	MQTTHeader header = {0};

+	int rc = -1;

+	unsigned char *ptr = buf;

+	int i;

+

+	FUNC_ENTRY;

+	if (buflen < 2 + count)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+	header.byte = 0;

+	header.bits.type = SUBACK;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */

+

+	writeInt(&ptr, packetid);

+

+	for (i = 0; i < count; ++i)

+		writeChar(&ptr, grantedQoSs[i]);

+

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribe.h b/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribe.h
new file mode 100755
index 0000000..1644ae5
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribe.h
@@ -0,0 +1,38 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Xiang Rong - 442039 Add makefile to Embedded C client

+ *******************************************************************************/

+

+#ifndef MQTTUNSUBSCRIBE_H_

+#define MQTTUNSUBSCRIBE_H_

+

+#if !defined(DLLImport)

+  #define DLLImport 

+#endif

+#if !defined(DLLExport)

+  #define DLLExport

+#endif

+

+DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[]);

+

+DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],

+		unsigned char* buf, int len);

+

+DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);

+

+DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);

+

+#endif /* MQTTUNSUBSCRIBE_H_ */

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribeClient.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribeClient.c
new file mode 100755
index 0000000..0f8db7b
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribeClient.c
@@ -0,0 +1,106 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "MQTTPacket.h"

+#include "StackTrace.h"

+

+#include <string.h>

+

+/**

+  * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters

+  * @param count the number of topic filter strings in topicFilters

+  * @param topicFilters the array of topic filter strings to be used in the publish

+  * @return the length of buffer needed to contain the serialized version of the packet

+  */

+int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])

+{

+	int i;

+	int len = 2; /* packetid */

+

+	for (i = 0; i < count; ++i)

+		len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/

+	return len;

+}

+

+

+/**

+  * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @param dup integer - the MQTT dup flag

+  * @param packetid integer - the MQTT packet identifier

+  * @param count - number of members in the topicFilters array

+  * @param topicFilters - array of topic filter names

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,

+		int count, MQTTString topicFilters[])

+{

+	unsigned char *ptr = buf;

+	MQTTHeader header = {0};

+	int rem_len = 0;

+	int rc = -1;

+	int i = 0;

+

+	FUNC_ENTRY;

+	if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+

+	header.byte = 0;

+	header.bits.type = UNSUBSCRIBE;

+	header.bits.dup = dup;

+	header.bits.qos = 1;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;

+

+	writeInt(&ptr, packetid);

+

+	for (i = 0; i < count; ++i)

+		writeMQTTString(&ptr, topicFilters[i]);

+

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Deserializes the supplied (wire) buffer into unsuback data

+  * @param packetid returned integer - the MQTT packet identifier

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @return error code.  1 is success, 0 is failure

+  */

+int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)

+{

+	unsigned char type = 0;

+	unsigned char dup = 0;

+	int rc = 0;

+

+	FUNC_ENTRY;

+	rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);

+	if (type == UNSUBACK)

+		rc = 1;

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribeServer.c b/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribeServer.c
new file mode 100755
index 0000000..b0e427d
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/MQTTUnsubscribeServer.c
@@ -0,0 +1,102 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *******************************************************************************/

+

+#include "MQTTPacket.h"

+#include "StackTrace.h"

+

+#include <string.h>

+

+

+/**

+  * Deserializes the supplied (wire) buffer into unsubscribe data

+  * @param dup integer returned - the MQTT dup flag

+  * @param packetid integer returned - the MQTT packet identifier

+  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays

+  * @param count - number of members in the topicFilters and requestedQoSs arrays

+  * @param topicFilters - array of topic filter names

+  * @param buf the raw buffer data, of the correct length determined by the remaining length field

+  * @param buflen the length in bytes of the data in the supplied buffer

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],

+		unsigned char* buf, int len)

+{

+	MQTTHeader header = {0};

+	unsigned char* curdata = buf;

+	unsigned char* enddata = NULL;

+	int rc = 0;

+	int mylen = 0;

+

+	FUNC_ENTRY;

+	header.byte = readChar(&curdata);

+	if (header.bits.type != UNSUBSCRIBE)

+		goto exit;

+	*dup = header.bits.dup;

+

+	curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */

+	enddata = curdata + mylen;

+

+	*packetid = readInt(&curdata);

+

+	*count = 0;

+	while (curdata < enddata)

+	{

+		if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))

+			goto exit;

+		(*count)++;

+	}

+

+	rc = 1;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

+/**

+  * Serializes the supplied unsuback data into the supplied buffer, ready for sending

+  * @param buf the buffer into which the packet will be serialized

+  * @param buflen the length in bytes of the supplied buffer

+  * @param packetid integer - the MQTT packet identifier

+  * @return the length of the serialized data.  <= 0 indicates error

+  */

+int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)

+{

+	MQTTHeader header = {0};

+	int rc = 0;

+	unsigned char *ptr = buf;

+

+	FUNC_ENTRY;

+	if (buflen < 2)

+	{

+		rc = MQTTPACKET_BUFFER_TOO_SHORT;

+		goto exit;

+	}

+	header.byte = 0;

+	header.bits.type = UNSUBACK;

+	writeChar(&ptr, header.byte); /* write header */

+

+	ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */

+

+	writeInt(&ptr, packetid);

+

+	rc = ptr - buf;

+exit:

+	FUNC_EXIT_RC(rc);

+	return rc;

+}

+

+

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/StackTrace.h b/mbtk/mbtk_mqtt/MQTTPacket/StackTrace.h
new file mode 100755
index 0000000..c65a2ef
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/StackTrace.h
@@ -0,0 +1,78 @@
+/*******************************************************************************

+ * Copyright (c) 2014 IBM Corp.

+ *

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * and Eclipse Distribution License v1.0 which accompany this distribution.

+ *

+ * The Eclipse Public License is available at

+ *    http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ *   http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *    Ian Craggs - initial API and implementation and/or initial documentation

+ *    Ian Craggs - fix for bug #434081

+ *******************************************************************************/

+

+#ifndef STACKTRACE_H_

+#define STACKTRACE_H_

+

+#include <stdio.h>

+#define NOSTACKTRACE 1

+

+#if defined(NOSTACKTRACE)

+#define FUNC_ENTRY

+#define FUNC_ENTRY_NOLOG

+#define FUNC_ENTRY_MED

+#define FUNC_ENTRY_MAX

+#define FUNC_EXIT

+#define FUNC_EXIT_NOLOG

+#define FUNC_EXIT_MED

+#define FUNC_EXIT_MAX

+#define FUNC_EXIT_RC(x)

+#define FUNC_EXIT_MED_RC(x)

+#define FUNC_EXIT_MAX_RC(x)

+

+#else

+

+#if defined(WIN32)

+#define inline __inline

+#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)

+#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)

+#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)

+#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)

+#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)

+#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)

+#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)

+#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)

+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)

+#else

+#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)

+#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)

+#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)

+#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)

+#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)

+#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)

+#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)

+#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)

+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)

+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)

+

+void StackTrace_entry(const char* name, int line, int trace);

+void StackTrace_exit(const char* name, int line, void* return_value, int trace);

+

+void StackTrace_printStack(FILE* dest);

+char* StackTrace_get(unsigned long);

+

+#endif

+

+#endif

+

+

+

+

+#endif /* STACKTRACE_H_ */

diff --git a/mbtk/mbtk_mqtt/MQTTPacket/core_sha1.c b/mbtk/mbtk_mqtt/MQTTPacket/core_sha1.c
new file mode 100644
index 0000000..dfd3a3d
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/core_sha1.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2015-2018 Alibaba Group Holding Limited
+ */
+//#include "infra_config.h"
+
+//#ifdef INFRA_SHA1
+
+#include <stdlib.h>
+#include <string.h>
+#include "core_sha1.h"
+//#include "infra_sha1.h"
+
+#define SHA1_KEY_IOPAD_SIZE (64)
+#define SHA1_DIGEST_SIZE    (20)
+
+
+/* Implementation that should never be optimized out by the compiler */
+static void core_sha1_zeroize( void *v, uint32_t n ) {
+    volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+        | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+        | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+        | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+void core_sha1_init(iot_sha1_context *ctx)
+{
+    memset(ctx, 0, sizeof(iot_sha1_context));
+}
+
+void core_sha1_free(iot_sha1_context *ctx)
+{
+    if (ctx == NULL) {
+        return;
+    }
+
+    core_sha1_zeroize(ctx, sizeof(iot_sha1_context));
+}
+
+void core_sha1_clone(iot_sha1_context *dst,
+                      const iot_sha1_context *src)
+{
+    *dst = *src;
+}
+
+/*
+ * SHA-1 context setup
+ */
+void core_sha1_starts(iot_sha1_context *ctx)
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void core_sha1_process(iot_sha1_context *ctx, const unsigned char data[64])
+{
+    uint32_t temp, W[16], A, B, C, D, E;
+
+    GET_UINT32_BE( W[ 0], data,  0 );
+    GET_UINT32_BE( W[ 1], data,  4 );
+    GET_UINT32_BE( W[ 2], data,  8 );
+    GET_UINT32_BE( W[ 3], data, 12 );
+    GET_UINT32_BE( W[ 4], data, 16 );
+    GET_UINT32_BE( W[ 5], data, 20 );
+    GET_UINT32_BE( W[ 6], data, 24 );
+    GET_UINT32_BE( W[ 7], data, 28 );
+    GET_UINT32_BE( W[ 8], data, 32 );
+    GET_UINT32_BE( W[ 9], data, 36 );
+    GET_UINT32_BE( W[10], data, 40 );
+    GET_UINT32_BE( W[11], data, 44 );
+    GET_UINT32_BE( W[12], data, 48 );
+    GET_UINT32_BE( W[13], data, 52 );
+    GET_UINT32_BE( W[14], data, 56 );
+    GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[( t -  3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
+           W[( t - 14 ) & 0x0F] ^ W[  t       & 0x0F],  \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void core_sha1_update(iot_sha1_context *ctx, const unsigned char *input, uint32_t ilen)
+{
+    uint32_t fill;
+    uint32_t left;
+
+    if( ilen == 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += (uint32_t) ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (uint32_t) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left), input, fill );
+        core_sha1_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        core_sha1_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+        memcpy( (void *) (ctx->buffer + left), input, ilen );
+}
+
+static const unsigned char sha1_padding[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+void core_sha1_finish(iot_sha1_context *ctx, unsigned char output[20])
+{
+    uint32_t last, padn;
+    uint32_t high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_UINT32_BE( high, msglen, 0 );
+    PUT_UINT32_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    core_sha1_update( ctx, sha1_padding, padn );
+    core_sha1_update( ctx, msglen, 8 );
+
+    PUT_UINT32_BE( ctx->state[0], output,  0 );
+    PUT_UINT32_BE( ctx->state[1], output,  4 );
+    PUT_UINT32_BE( ctx->state[2], output,  8 );
+    PUT_UINT32_BE( ctx->state[3], output, 12 );
+    PUT_UINT32_BE( ctx->state[4], output, 16 );
+}
+
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void core_sha1(const unsigned char *input, uint32_t ilen, unsigned char output[20])
+{
+    iot_sha1_context ctx;
+
+    core_sha1_init(&ctx);
+    core_sha1_starts(&ctx);
+    core_sha1_update(&ctx, input, ilen);
+    core_sha1_finish(&ctx, output);
+    core_sha1_free(&ctx);
+}
+
+static int8_t core_hb2hex(uint8_t hb)
+{
+    hb = hb & 0xF;
+    return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
+}
+
+void core_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
+{
+    iot_sha1_context context;
+    unsigned char k_ipad[SHA1_KEY_IOPAD_SIZE];    /* inner padding - key XORd with ipad  */
+    unsigned char k_opad[SHA1_KEY_IOPAD_SIZE];    /* outer padding - key XORd with opad */
+    unsigned char out[SHA1_DIGEST_SIZE];
+    int i;
+
+    if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
+        return;
+    }
+
+    if (key_len > SHA1_KEY_IOPAD_SIZE) {
+        return;
+    }
+
+    /* start out by storing key in pads */
+    memset(k_ipad, 0, sizeof(k_ipad));
+    memset(k_opad, 0, sizeof(k_opad));
+    memcpy(k_ipad, key, key_len);
+    memcpy(k_opad, key, key_len);
+
+    /* XOR key with ipad and opad values */
+    for (i = 0; i < SHA1_KEY_IOPAD_SIZE; i++) {
+        k_ipad[i] ^= 0x36;
+        k_opad[i] ^= 0x5c;
+    }
+
+    /* perform inner SHA */
+    core_sha1_init(&context);                                      /* init context for 1st pass */
+    core_sha1_starts(&context);                                    /* setup context for 1st pass */
+    core_sha1_update(&context, k_ipad, SHA1_KEY_IOPAD_SIZE);            /* start with inner pad */
+    core_sha1_update(&context, (unsigned char *) msg, msg_len);    /* then text of datagram */
+    core_sha1_finish(&context, out);                               /* finish up 1st pass */
+
+    /* perform outer SHA */
+    core_sha1_init(&context);                              /* init context for 2nd pass */
+    core_sha1_starts(&context);                            /* setup context for 2nd pass */
+    core_sha1_update(&context, k_opad, SHA1_KEY_IOPAD_SIZE);    /* start with outer pad */
+    core_sha1_update(&context, out, SHA1_DIGEST_SIZE);     /* then results of 1st hash */
+    core_sha1_finish(&context, out);                       /* finish up 2nd pass */
+
+    for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
+        digest[i * 2] = core_hb2hex(out[i] >> 4);
+        digest[i * 2 + 1] = core_hb2hex(out[i]);
+    }
+}
+
+void core_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len)
+{
+    iot_sha1_context context;
+    unsigned char k_ipad[SHA1_KEY_IOPAD_SIZE];    /* inner padding - key XORd with ipad  */
+    unsigned char k_opad[SHA1_KEY_IOPAD_SIZE];    /* outer padding - key XORd with opad */
+    unsigned char out[SHA1_DIGEST_SIZE];
+    int i;
+
+    if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
+        return;
+    }
+
+    if (key_len > SHA1_KEY_IOPAD_SIZE) {
+        return;
+    }
+
+    /* start out by storing key in pads */
+    memset(k_ipad, 0, sizeof(k_ipad));
+    memset(k_opad, 0, sizeof(k_opad));
+    memcpy(k_ipad, key, key_len);
+    memcpy(k_opad, key, key_len);
+
+    /* XOR key with ipad and opad values */
+    for (i = 0; i < SHA1_KEY_IOPAD_SIZE; i++) {
+        k_ipad[i] ^= 0x36;
+        k_opad[i] ^= 0x5c;
+    }
+
+    /* perform inner SHA */
+    core_sha1_init(&context);                                      /* init context for 1st pass */
+    core_sha1_starts(&context);                                    /* setup context for 1st pass */
+    core_sha1_update(&context, k_ipad, SHA1_KEY_IOPAD_SIZE);            /* start with inner pad */
+    core_sha1_update(&context, (unsigned char *) msg, msg_len);    /* then text of datagram */
+    core_sha1_finish(&context, out);                               /* finish up 1st pass */
+
+    /* perform outer SHA */
+    core_sha1_init(&context);                              /* init context for 2nd pass */
+    core_sha1_starts(&context);                            /* setup context for 2nd pass */
+    core_sha1_update(&context, k_opad, SHA1_KEY_IOPAD_SIZE);    /* start with outer pad */
+    core_sha1_update(&context, out, SHA1_DIGEST_SIZE);     /* then results of 1st hash */
+    core_sha1_finish(&context, out);                       /* finish up 2nd pass */
+    memcpy(digest, out, SHA1_DIGEST_SIZE);
+}
+
+//#endif
diff --git a/mbtk/mbtk_mqtt/MQTTPacket/core_sha1.h b/mbtk/mbtk_mqtt/MQTTPacket/core_sha1.h
new file mode 100644
index 0000000..0260002
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/core_sha1.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015-2018 Alibaba Group Holding Limited
+ */
+
+
+
+
+#ifndef _CORE_SHA1_H_
+#define _CORE_SHA1_H_
+
+//#include "infra_types.h"
+
+#define SHA1_DIGEST_SIZE    (20)
+
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+        | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+        | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+        | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/**
+ * \brief          SHA-1 context structure
+ */
+typedef struct {
+    uint32_t total[2];          /*!< number of bytes processed  */
+    uint32_t state[5];          /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+} iot_sha1_context;
+
+/**
+ * \brief          Initialize SHA-1 context
+ *
+ * \param ctx      SHA-1 context to be initialized
+ */
+void core_sha1_init(iot_sha1_context *ctx);
+
+/**
+ * \brief          Clear SHA-1 context
+ *
+ * \param ctx      SHA-1 context to be cleared
+ */
+void core_sha1_free(iot_sha1_context *ctx);
+
+/**
+ * \brief          Clone (the state of) a SHA-1 context
+ *
+ * \param dst      The destination context
+ * \param src      The context to be cloned
+ */
+void core_sha1_clone(iot_sha1_context *dst,
+                      const iot_sha1_context *src);
+
+/**
+ * \brief          SHA-1 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void core_sha1_starts(iot_sha1_context *ctx);
+
+/**
+ * \brief          SHA-1 process buffer
+ *
+ * \param ctx      SHA-1 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void core_sha1_update(iot_sha1_context *ctx, const unsigned char *input, uint32_t ilen);
+
+/**
+ * \brief          SHA-1 final digest
+ *
+ * \param ctx      SHA-1 context
+ * \param output   SHA-1 checksum result
+ */
+void core_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]);
+
+/* Internal use */
+void core_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]);
+
+/**
+ * \brief          Output = SHA-1( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-1 checksum result
+ */
+void core_sha1(const unsigned char *input, uint32_t ilen, unsigned char output[20]);
+void core_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len);
+void core_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len);
+
+#endif
diff --git a/mbtk/mbtk_mqtt/MQTTPacket/core_sha256.c b/mbtk/mbtk_mqtt/MQTTPacket/core_sha256.c
new file mode 100755
index 0000000..d819047
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/core_sha256.c
@@ -0,0 +1,329 @@
+#include "core_sha256.h"
+
+#define MINI_SHA256_SMALLER
+#define SHA256_KEY_IOPAD_SIZE   (64)
+#define SHA256_DIGEST_SIZE      (32)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+    do {                                                    \
+        (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+              | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+              | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+              | ( (uint32_t) (b)[(i) + 3]       );            \
+    } while( 0 )
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+    do {                                                    \
+        (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+        (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+        (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+        (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+    } while( 0 )
+#endif
+
+
+static void utils_sha256_zeroize(void *v, uint32_t n)
+{
+    volatile unsigned char *p = v;
+    while (n--) {
+        *p++ = 0;
+    }
+}
+
+void core_sha256_init(core_sha256_context_t *ctx)
+{
+    memset(ctx, 0, sizeof(core_sha256_context_t));
+}
+
+void core_sha256_free(core_sha256_context_t *ctx)
+{
+    if (NULL == ctx) {
+        return;
+    }
+
+    utils_sha256_zeroize(ctx, sizeof(core_sha256_context_t));
+}
+
+void core_sha256_starts(core_sha256_context_t *ctx)
+{
+    uint8_t is224 = 0;
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    if (is224 == 0) {
+        /* SHA-256 */
+        ctx->state[0] = 0x6A09E667;
+        ctx->state[1] = 0xBB67AE85;
+        ctx->state[2] = 0x3C6EF372;
+        ctx->state[3] = 0xA54FF53A;
+        ctx->state[4] = 0x510E527F;
+        ctx->state[5] = 0x9B05688C;
+        ctx->state[6] = 0x1F83D9AB;
+        ctx->state[7] = 0x5BE0CD19;
+    }
+
+    ctx->is224 = is224;
+}
+
+static const uint32_t K[] = {
+    0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+    0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+    0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+    0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+    0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+    0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+    0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+    0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+    0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+    0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+    0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+    0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+    0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+    0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+    0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+    0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+#define  SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^  SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^  SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t)                                    \
+    (                                               \
+            W[t] = S1(W[t -  2]) + W[t -  7] +          \
+                   S0(W[t - 15]) + W[t - 16]            \
+    )
+
+#define P(a,b,c,d,e,f,g,h,x,K)                  \
+    {                                               \
+        temp1 = h + S3(e) + F1(e,f,g) + K + x;      \
+        temp2 = S2(a) + F0(a,b,c);                  \
+        d += temp1; h = temp1 + temp2;              \
+    }
+
+void core_sha256_process(core_sha256_context_t *ctx, const unsigned char data[64])
+{
+    uint32_t temp1, temp2, W[64];
+    uint32_t A[8];
+    unsigned int i;
+
+    for (i = 0; i < 8; i++) {
+        A[i] = ctx->state[i];
+    }
+
+#if defined(MINI_SHA256_SMALLER)
+    for (i = 0; i < 64; i++) {
+        if (i < 16) {
+            GET_UINT32_BE(W[i], data, 4 * i);
+        } else {
+            R(i);
+        }
+
+        P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]);
+
+        temp1 = A[7];
+        A[7] = A[6];
+        A[6] = A[5];
+        A[5] = A[4];
+        A[4] = A[3];
+        A[3] = A[2];
+        A[2] = A[1];
+        A[1] = A[0];
+        A[0] = temp1;
+    }
+#else /* MINI_SHA256_SMALLER */
+    for (i = 0; i < 16; i++) {
+        GET_UINT32_BE(W[i], data, 4 * i);
+    }
+
+    for (i = 0; i < 16; i += 8) {
+        P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i + 0], K[i + 0]);
+        P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i + 1], K[i + 1]);
+        P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i + 2], K[i + 2]);
+        P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i + 3], K[i + 3]);
+        P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i + 4], K[i + 4]);
+        P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i + 5], K[i + 5]);
+        P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i + 6], K[i + 6]);
+        P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i + 7], K[i + 7]);
+    }
+
+    for (i = 16; i < 64; i += 8) {
+        P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i + 0), K[i + 0]);
+        P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i + 1), K[i + 1]);
+        P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i + 2), K[i + 2]);
+        P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i + 3), K[i + 3]);
+        P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i + 4), K[i + 4]);
+        P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i + 5), K[i + 5]);
+        P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i + 6), K[i + 6]);
+        P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i + 7), K[i + 7]);
+    }
+#endif /* MINI_SHA256_SMALLER */
+
+    for (i = 0; i < 8; i++) {
+        ctx->state[i] += A[i];
+    }
+}
+void core_sha256_update(core_sha256_context_t *ctx, const unsigned char *input, uint32_t ilen)
+{
+    size_t fill;
+    uint32_t left;
+
+    if (ilen == 0) {
+        return;
+    }
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += (uint32_t) ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if (ctx->total[0] < (uint32_t) ilen) {
+        ctx->total[1]++;
+    }
+
+    if (left && ilen >= fill) {
+        memcpy((void *)(ctx->buffer + left), input, fill);
+        core_sha256_process(ctx, ctx->buffer);
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while (ilen >= 64) {
+        core_sha256_process(ctx, input);
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if (ilen > 0) {
+        memcpy((void *)(ctx->buffer + left), input, ilen);
+    }
+}
+
+static const unsigned char sha256_padding[64] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void core_sha256_finish(core_sha256_context_t *ctx, uint8_t output[32])
+{
+    uint32_t last, padn;
+    uint32_t high, low;
+    unsigned char msglen[8];
+
+    high = (ctx->total[0] >> 29)
+           | (ctx->total[1] <<  3);
+    low  = (ctx->total[0] <<  3);
+
+    PUT_UINT32_BE(high, msglen, 0);
+    PUT_UINT32_BE(low,  msglen, 4);
+
+    last = ctx->total[0] & 0x3F;
+    padn = (last < 56) ? (56 - last) : (120 - last);
+
+    core_sha256_update(ctx, sha256_padding, padn);
+    core_sha256_update(ctx, msglen, 8);
+
+    PUT_UINT32_BE(ctx->state[0], output,  0);
+    PUT_UINT32_BE(ctx->state[1], output,  4);
+    PUT_UINT32_BE(ctx->state[2], output,  8);
+    PUT_UINT32_BE(ctx->state[3], output, 12);
+    PUT_UINT32_BE(ctx->state[4], output, 16);
+    PUT_UINT32_BE(ctx->state[5], output, 20);
+    PUT_UINT32_BE(ctx->state[6], output, 24);
+
+    if (ctx->is224 == 0) {
+        PUT_UINT32_BE(ctx->state[7], output, 28);
+    }
+}
+
+void core_sha256(const uint8_t *input, uint32_t ilen, uint8_t output[32])
+{
+    core_sha256_context_t ctx;
+
+    core_sha256_init(&ctx);
+    core_sha256_starts(&ctx);
+    core_sha256_update(&ctx, input, ilen);
+    core_sha256_finish(&ctx, output);
+    core_sha256_free(&ctx);
+}
+
+void core_hmac_sha256(const uint8_t *msg, uint32_t msg_len, const uint8_t *key, uint32_t key_len, uint8_t output[32])
+{
+    core_sha256_context_t context;
+    uint8_t k_ipad[SHA256_KEY_IOPAD_SIZE];    /* inner padding - key XORd with ipad  */
+    uint8_t k_opad[SHA256_KEY_IOPAD_SIZE];    /* outer padding - key XORd with opad */
+    int32_t i;
+
+    if ((NULL == msg) || (NULL == key) || (NULL == output)) {
+        return;
+    }
+
+    if (key_len > SHA256_KEY_IOPAD_SIZE) {
+        return;
+    }
+
+    /* start out by storing key in pads */
+    memset(k_ipad, 0, sizeof(k_ipad));
+    memset(k_opad, 0, sizeof(k_opad));
+    memcpy(k_ipad, key, key_len);
+    memcpy(k_opad, key, key_len);
+
+    /* XOR key with ipad and opad values */
+    for (i = 0; i < SHA256_KEY_IOPAD_SIZE; i++) {
+        k_ipad[i] ^= 0x36;
+        k_opad[i] ^= 0x5c;
+    }
+
+    /* perform inner SHA */
+    core_sha256_init(&context);                                      /* init context for 1st pass */
+    core_sha256_starts(&context);                                    /* setup context for 1st pass */
+    core_sha256_update(&context, k_ipad, SHA256_KEY_IOPAD_SIZE);     /* start with inner pad */
+    core_sha256_update(&context, msg, msg_len);                      /* then text of datagram */
+    core_sha256_finish(&context, output);                            /* finish up 1st pass */
+
+    /* perform outer SHA */
+    core_sha256_init(&context);                              /* init context for 2nd pass */
+    core_sha256_starts(&context);                            /* setup context for 2nd pass */
+    core_sha256_update(&context, k_opad, SHA256_KEY_IOPAD_SIZE);    /* start with outer pad */
+    core_sha256_update(&context, output, SHA256_DIGEST_SIZE);     /* then results of 1st hash */
+    core_sha256_finish(&context, output);                       /* finish up 2nd pass */
+}
+
+int32_t core_hex2str(uint8_t *input, uint32_t input_len, char *output, uint8_t lowercase)
+{
+    char *upper = "0123456789ABCDEF";
+    char *lower = "0123456789abcdef";
+    char *encode = upper;
+    int i = 0, j = 0;
+
+    if (lowercase) {
+        encode = lower;
+    }
+
+    for (i = 0; i < input_len; i++) {
+        output[j++] = encode[(input[i] >> 4) & 0xf];
+        output[j++] = encode[(input[i]) & 0xf];
+    }
+
+    return 0;
+}
+
+
diff --git a/mbtk/mbtk_mqtt/MQTTPacket/core_sha256.h b/mbtk/mbtk_mqtt/MQTTPacket/core_sha256.h
new file mode 100755
index 0000000..2141941
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/core_sha256.h
@@ -0,0 +1,86 @@
+#ifndef _CORE_SHA256_H_
+#define _CORE_SHA256_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "core_stdinc.h"
+
+#define CORE_SHA256_DIGEST_LENGTH            (32)
+#define CORE_SHA256_BLOCK_LENGTH             (64)
+#define CORE_SHA256_SHORT_BLOCK_LENGTH       (CORE_SHA256_BLOCK_LENGTH - 8)
+#define CORE_SHA256_DIGEST_STRING_LENGTH     (CORE_SHA256_DIGEST_LENGTH * 2 + 1)
+
+/**
+ * \brief          SHA-256 context structure
+ */
+typedef struct {
+    uint32_t total[2];          /*!< number of bytes processed  */
+    uint32_t state[8];          /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+    uint8_t is224;                  /*!< 0 => SHA-256, else SHA-224 */
+} core_sha256_context_t;
+
+/**
+ * \brief          Initialize SHA-256 context
+ *
+ * \param ctx      SHA-256 context to be initialized
+ */
+void core_sha256_init(core_sha256_context_t *ctx);
+
+/**
+ * \brief          Clear SHA-256 context
+ *
+ * \param ctx      SHA-256 context to be cleared
+ */
+void core_sha256_free(core_sha256_context_t *ctx);
+
+
+/**
+ * \brief          SHA-256 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void core_sha256_starts(core_sha256_context_t *ctx);
+
+/**
+ * \brief          SHA-256 process buffer
+ *
+ * \param ctx      SHA-256 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void core_sha256_update(core_sha256_context_t *ctx, const unsigned char *input, uint32_t ilen);
+
+/**
+ * \brief          SHA-256 final digest
+ *
+ * \param ctx      SHA-256 context
+ * \param output   SHA-256 checksum result
+ */
+void core_sha256_finish(core_sha256_context_t *ctx, uint8_t output[32]);
+
+/* Internal use */
+void core_sha256_process(core_sha256_context_t *ctx, const unsigned char data[64]);
+
+/**
+ * \brief          Output = SHA-256( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-256 checksum result
+ */
+void core_sha256(const uint8_t *input, uint32_t ilen, uint8_t output[32]);
+
+void core_hmac_sha256(const uint8_t *msg, uint32_t msg_len, const uint8_t *key, uint32_t key_len, uint8_t output[32]);
+
+int core_hex2str(uint8_t *input, uint32_t input_len, char *output, uint8_t lowercase);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
diff --git a/mbtk/mbtk_mqtt/MQTTPacket/core_stdinc.h b/mbtk/mbtk_mqtt/MQTTPacket/core_stdinc.h
new file mode 100755
index 0000000..d58acbc
--- /dev/null
+++ b/mbtk/mbtk_mqtt/MQTTPacket/core_stdinc.h
@@ -0,0 +1,16 @@
+#ifndef _CORE_STDINC_H_
+#define _CORE_STDINC_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <string.h>
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
diff --git a/mbtk/mbtk_mqtt/Makefile b/mbtk/mbtk_mqtt/Makefile
new file mode 100755
index 0000000..9102863
--- /dev/null
+++ b/mbtk/mbtk_mqtt/Makefile
@@ -0,0 +1,44 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_mqtt
+
+INC_DIR += -I. \
+	-I$(LOCAL_PATH)/MQTTPacket
+
+LIB_DIR +=
+
+LIBS += -llog -lmbtk_lib
+
+CFLAGS += -shared -Wl,-shared,-Bsymbolic
+
+DEFINE +=
+
+MY_FILES_PATH:=$(LOCAL_PATH)
+#MY_FILES_PATH += $(LOCAL_PATH)/MQTTPacket
+
+#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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/lib/libmbtk_mqtt_lib.so
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
+
diff --git a/mbtk/mbtk_mqtt/mbtk_mqtt.c b/mbtk/mbtk_mqtt/mbtk_mqtt.c
new file mode 100755
index 0000000..3af31f2
--- /dev/null
+++ b/mbtk/mbtk_mqtt/mbtk_mqtt.c
@@ -0,0 +1,669 @@
+/*************************************************************************
+	> File Name: main.c
+	> Author: LFJ
+	> Mail: 
+	> Created Time: 2018年09月05日 星期三 13时48分17秒
+ ************************************************************************/
+
+#include <stdio.h>
+
+#include "MQTTClient.h"
+#include "mbtk_mqtt.h"
+#include "pthread.h"
+#include "string.h"
+#include "unistd.h"
+#include "sys/stat.h"
+#include "sys/types.h"
+#include "sys/socket.h"
+#include "netinet/in.h"
+#include "arpa/inet.h"
+#include "fcntl.h"
+#include "mbtk_sock2.h"
+
+#include "mbtk_type.h"
+#include "mbtk_http.h"
+
+/*
+static Cloud_MQTT_t *iot_mqtt;
+
+void set_mqtt_t(Cloud_MQTT_t *piot_mqtt)
+{
+    iot_mqtt = piot_mqtt;
+}
+Cloud_MQTT_t * get_mqtt_t()
+{
+    return iot_mqtt;
+}
+*/
+
+extern regnwl_info_t regnwl_info;
+
+
+#define CORE_AUTH_SDK_VERSION "sdk-c-4.1.0"
+#define CORE_AUTH_TIMESTAMP   "2524608000000"
+#define MBTK_MQTT_HTTP_AUTH_PATH               "/auth/register/device"
+#define MBTK_MQTT_HTTP_SIGN_METHOD_HMACSHA256  "hmacsha256"
+
+
+const char * mqtt_url[7] = {
+                   "iot-as-mqtt.cn-shanghai.aliyuncs.com",        /* Shanghai */
+                   "iot-as-mqtt.ap-southeast-1.aliyuncs.com",    /* Singapore */
+                    "iot-as-mqtt.ap-northeast-1.aliyuncs.com",    /* Japan */
+                    "iot-as-mqtt.us-west-1.aliyuncs.com",         /* America */
+                    "iot-as-mqtt.eu-central-1.aliyuncs.com",      /* Germany */
+                    "118.114.239.159",      /* me */
+                    NULL,                                         /* Custom */
+   };
+
+
+const char    *http_host[6] = {
+    "iot-auth.cn-shanghai.aliyuncs.com",          /* Shanghai */
+    "iot-auth.ap-southeast-1.aliyuncs.com",      /* Singapore */
+    "iot-auth.ap-northeast-1.aliyuncs.com",      /* Japan */
+    "iot-auth.us-west-1.aliyuncs.com",           /* America */
+    "iot-auth.eu-central-1.aliyuncs.com",         /* Germany */
+    NULL,                                         /* Custom */
+ };
+
+mbtk_mqtt_device_session_t mbtk_mqtt_device ={0};
+
+
+char mbtk_mqtt_http_url[255] ={0};
+char mbtk_mqtt_http_content[1024] ={0};
+
+char Device_Secret[255] = {0};
+
+
+int mbtk_imqtt_http_dynreg_sign(char *product_key,char* product_secret,char*device_name,char* random,char* sign)
+{
+    int sign_source_len = 0;
+    uint8_t signnum[32];
+    uint8_t  *sign_source = NULL;
+    const char *dynamic_register_sign_fmt = "deviceName%sproductKey%srandom%s";
+
+    /* Start Dynamic Register */
+    /* Calculate SHA256 Value */
+    sign_source_len = strlen(dynamic_register_sign_fmt) + strlen(device_name) + strlen(product_key) + strlen(random) + 1;
+    sign_source = malloc(sign_source_len);
+    if (sign_source == NULL)
+    {
+        return -1;
+    }
+    memset(sign_source, 0, sign_source_len);
+    snprintf((char *)sign_source, sign_source_len, dynamic_register_sign_fmt, device_name, product_key, random);
+
+    core_hmac_sha256(sign_source, strlen((const char *)sign_source), (uint8_t *)product_secret, strlen(product_secret),
+                      signnum);
+    core_hex2str(signnum, 32, sign,0);
+    free(sign_source);
+    sign_source = NULL;
+
+    return 0;
+
+}
+
+
+int mbtk_imqtt_send_post_request(char *product_key, char *product_secret, char *device_name, int host)
+{
+
+    printf("product_key: %s\n", product_key);
+    printf("product_secret: %s\n", product_secret);
+    printf("device_name: %s\n", device_name);
+
+    int32_t res = 0, content_len = 0;
+    char content[255] = {0};
+    char random[15+1]={0};;
+    char  sign[65] = {0};
+    int dynamic_register_request_len = 0;
+//    char *content_fmt = "productKey=%s&deviceName=%s&random=%s&sign=%s&signMethod=%s";
+    char *signMethod = MBTK_MQTT_HTTP_SIGN_METHOD_HMACSHA256;
+
+
+    memcpy(random, "8Ygb7ULYh53B6OA", strlen("8Ygb7ULYh53B6OA"));
+    char *content_src[] = { product_key, device_name, random,sign,signMethod};
+    mbtk_imqtt_http_dynreg_sign(product_key,product_secret,device_name,random,sign);
+
+    sprintf(content, "productKey=%s&deviceName=%s&random=%s&sign=%s&signMethod=%s",
+                    product_key, device_name, random, sign, MBTK_MQTT_HTTP_SIGN_METHOD_HMACSHA256);
+
+    memset(mbtk_mqtt_http_url, 0, sizeof(mbtk_mqtt_http_url));
+    sprintf(mbtk_mqtt_http_url, "https://%s:443/auth/register/device", http_host[host]);
+
+    memset(mbtk_mqtt_http_content, 0, sizeof(mbtk_mqtt_http_content));
+    memcpy(mbtk_mqtt_http_content, content, strlen(content));
+
+    printf("mbtk_mqtt_http_url:%s\n", mbtk_mqtt_http_url);
+    printf("mbtk_mqtt_http_content:%s\n", mbtk_mqtt_http_content);
+
+    return 0;
+}
+
+void mbtk_mqt_http_device_secret_response(void *data,int data_len)
+{
+    if(data != NULL && data_len != 0)
+    {
+        char* ptr_start = NULL;
+        char* ptr_end = NULL;
+        char fac[64] = {'\0'};
+        ptr_start = strstr(data, "deviceSecret");
+        if(ptr_start != NULL)
+        {
+            ptr_end = strstr(ptr_start, "\",");
+            if(ptr_end != NULL)
+            {
+                strncpy(Device_Secret, ptr_start + 15, ptr_end - ptr_start - 15);
+                printf("device_secret:%s\n", Device_Secret);
+            }
+            printf("ptr_start:%s,\n ptr_end:%s\n", ptr_start, ptr_end);
+        }
+
+    }
+
+	return;
+}
+
+
+static void mbtk_mqtt_http_data_cb_func(
+    int session_id, mbtk_http_data_type_enum type,
+    void *data,int data_len)
+{
+    if(type == MBTK_HTTP_DATA_HEADER) {
+        printf("Header(%d):%s\n",data_len,(char*)data);
+        mbtk_mqt_http_device_secret_response((char*)data, data_len);
+    } else if(type == MBTK_HTTP_DATA_CONTENT) {
+        printf("Data(%d):%s\n",data_len,(char*)data);
+        mbtk_mqt_http_device_secret_response((char*)data, data_len);
+    } else {
+        printf(">>>>>Complete<<<<<\n");
+    }
+}
+
+int mbtk_aliyun_mqtt_one_type_one_secret_regint_get_info(mbtk_mqtt_device_session_t *mbtk_mqtt_device_t)
+{
+    printf("mbtk_mqtt_http_request    1111111");
+    char product_key[255] = {0};
+    char product_secret[255] = {0};
+    char device_name[255] = {0};
+
+    int http_handle = mbtk_http_handle_get(TRUE, mbtk_mqtt_http_data_cb_func);
+    if(http_handle < 0)
+    {
+        printf("mbtk_http_handle_get() fail.");
+        return -1;
+    }
+
+    int http_session = mbtk_http_session_create(http_handle,HTTP_OPTION_POST,HTTP_VERSION_1_1);
+    if(http_handle < 0)
+    {
+        printf("mbtk_http_session_create() fail.");
+        return -1;
+    }
+
+//    mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_HEAD_ONLY);
+//    mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_POST);
+
+    memcpy(product_key, mbtk_mqtt_device_t->product_key, strlen(mbtk_mqtt_device_t->product_key));
+    memcpy(product_secret, mbtk_mqtt_device_t->product_secret, strlen(mbtk_mqtt_device_t->product_secret));
+    memcpy(device_name, mbtk_mqtt_device_t->device_name, strlen(mbtk_mqtt_device_t->device_name));
+
+    mbtk_imqtt_send_post_request(product_key, product_secret,device_name, 0);
+
+    if(mbtk_http_session_url_set(http_handle, http_session, mbtk_mqtt_http_url)) {
+        printf("mbtk_http_session_url_set() fail.\n");
+        return -1;
+    }
+
+    const mbtk_http_session_t* session = mbtk_http_session_get(http_handle, http_session);
+    printf("HTTP:%d,%s,%d,%s\n",session->option,session->host,session->port,session->uri);
+
+    char *header = "Accept: text/xml,text/javascript,text/html,application/json\r\n" \
+                          "Content-Type: application/x-www-form-urlencoded\r\n";
+
+
+    mbtk_http_session_head_add(http_handle, http_session, "Accept", "text/xml,text/javascript,text/html,application/json");
+
+    mbtk_http_session_head_add(http_handle, http_session, "Content-Type", "application/x-www-form-urlencoded");
+
+    mbtk_http_session_content_set(http_handle, http_session, mbtk_mqtt_http_content, strlen(mbtk_mqtt_http_content) );
+
+//    mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_HEAD_ONLY);
+//    mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_POST);
+
+    memset(Device_Secret, 0, sizeof(Device_Secret));
+    if(mbtk_http_session_start(http_handle, http_session)) {
+        printf("mbtk_http_session_start() fail.\n");
+        return -1;
+    }
+
+    if(mbtk_http_handle_free(http_handle))
+    {
+        printf("mbtk_http_handle_free() fail.");
+        return -1;
+    }
+
+    if(strlen(Device_Secret ) > 0)
+    {
+        printf("\nstrlen(Device_Secret :%d\n )", strlen(Device_Secret ));
+        memcpy(mbtk_mqtt_device_t->device_secret,Device_Secret, strlen(Device_Secret) );
+    }else{
+        printf("get Device_Secret fail\n");
+        return -1;
+    }
+
+    printf("MBTK_HTTP exit.");
+    return 0;
+
+}
+
+
+void mbtk_aliyun_mqtt_get_connect_para(char *password,char *cliendid,char *username, mbtk_mqtt_device_session_t *mbtk_mqtt_device_t)
+{
+  /*********password.mqttClientId.user_name *************/
+    char content[MBTK_IMQTT_PASSWORD_LEN] = {0};
+
+    printf("mbtk_mqtt_device_t->device_name: %s\n", mbtk_mqtt_device_t->device_name);
+    printf("mbtk_mqtt_device_t->product_key: %s\n", mbtk_mqtt_device_t->product_key);
+    printf("mbtk_mqtt_device_t->product_secret: %s\n", mbtk_mqtt_device_t->product_secret);
+
+    sprintf(content,"deviceName%sproductKey%srandom123",mbtk_mqtt_device_t->device_name,mbtk_mqtt_device_t->product_key);
+    core_hmac_sha1((const char*)content,strlen((const char*)content),(char *)password,mbtk_mqtt_device_t->product_secret,strlen(mbtk_mqtt_device_t->product_secret));
+
+
+//    snprintf((char *)cliendid,MBTK_IMQTT_CLIENT_ID_LEN,"%s|securemode=-2,authType=regnwl,random=123,signmethod=hmacsha1,instanceId=%s|",mbtk_mqtt_device_t->device_name,"iot-06z00ag5qidat54");
+
+    snprintf((char *)cliendid,MBTK_IMQTT_CLIENT_ID_LEN,"%s|securemode=-2,authType=regnwl,random=123,signmethod=hmacsha1|",mbtk_mqtt_device_t->device_name);
+    snprintf((char *)username,MBTK_IMQTT_USER_NAME_LEN,"%s&%s",mbtk_mqtt_device_t->device_name,mbtk_mqtt_device_t->product_key);
+}
+
+
+void mbtk_imqtt_auth_hostname(char *dest, char *product_key, int host)
+{
+//  char *host = "&product_key.iot-as-mqtt.cn-shanghai.aliyuncs.com";
+    int8_t      public_instance = 1;
+
+    snprintf(dest, 100, "%s.%s", product_key, mqtt_url[host]);
+}
+
+
+void mbtk_imqtt_auth_clientid(char *dest,char *product_key, char *device_name)
+{
+//	char *clientid = "gyj01ZAd7HF.MATT1|securemode=3,signmethod=hmacsha256,timestamp=1647830635443|";
+
+    sprintf(dest, "%s.%s|securemode=3,signmethod=hmacsha256,timestamp=%s|", product_key,device_name,CORE_AUTH_TIMESTAMP);
+}
+
+void mbtk_imqtt_auth_clientid_yixinyimi_unregin(char *dest,char *client_id)
+{
+//	char *clientid = "client_id|securemode=-2,authType=connwl|";
+
+    sprintf(dest, "%s|securemode=-2,authType=connwl|", client_id);
+
+}
+
+
+void mbtk_aliyun_imqtt_auth_clientid(char *dest, char *product_key, char *device_name)
+{
+
+    sprintf(dest, "%s.%s|timestamp=%s,_ss=1,_v=%s,securemode=2,signmethod=hmacsha256,ext=3|", product_key,device_name,CORE_AUTH_TIMESTAMP,CORE_AUTH_SDK_VERSION);
+
+    //instanceId 实例id
+//    sprintf(dest, "%s.%s|timestamp=%s,_ss=1,_v=%s,securemode=2,signmethod=hmacsha256,ext=3,instanceId=%s|", product_key,device_name,CORE_AUTH_TIMESTAMP,CORE_AUTH_SDK_VERSION,"iot-06z00ag5qidat54");
+}
+
+
+void mbtk_imqtt_auth_username(char *dest,char *device_name, char *product_key)
+{
+	//data.username.cstring="$deviceName&$productKey";
+
+    snprintf(dest,128, "%s&%s", device_name, product_key );
+}
+
+void mbtk_imqtt_auth_password(char *dest, char *device_name, char *product_key, char *device_secret)
+{
+//	> data.password.cstring=hmacsha1($deviceSecret,$content);
+//	$content为productKey,deviceName,timestamp,clientId按照手母顺序排序,然后将参数值依次拼接例如
+
+
+    char content[300] = {0};
+    uint8_t source_temp[65]={0};
+    sprintf(content,"clientId%s.%sdeviceName%sproductKey%stimestamp%s",product_key, device_name, device_name, product_key,CORE_AUTH_TIMESTAMP);
+	
+//    sprintf(content,"clientId%sdeviceName%sproductKey%stimestamp%s",client_id, device_name, product_key,CORE_AUTH_TIMESTAMP);
+    core_hmac_sha256((uint8_t *)content, strlen((const char *)content), (uint8_t *)device_secret, strlen(device_secret),
+                      source_temp);
+		  
+    core_hex2str(source_temp, 32, dest,0);
+}
+
+void iot_aliyun_mqtt_init(Cloud_MQTT_t *piot_mqtt,int host,int port ,char *device_name,char *product_key, 
+		char * DeviceSecret,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb) 
+{
+    mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,product_key,host);
+    mbtk_imqtt_auth_clientid(piot_mqtt->mqtt_client_id,product_key,device_name);
+    mbtk_imqtt_auth_username(piot_mqtt->mqtt_user,device_name,product_key);
+    mbtk_imqtt_auth_password(piot_mqtt->mqtt_pass,device_name,product_key,DeviceSecret);
+    piot_mqtt->mqtt_port = port;
+    piot_mqtt->keepAliveInterval = keepAliveInterval;
+    //    piot_mqtt->mqtt_version = version;
+    piot_mqtt->mqtt_version = 3;
+
+    printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+    memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+    
+    sprintf(piot_mqtt->sub_topic, "%s", sub_topic);	//将初始化好的订阅主题填到数组中
+    printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+    sprintf(piot_mqtt->pub_topic, "%s", pub_topic);	//将初始化好的发布主题填到数组中
+    printf("pub:%s\n", piot_mqtt->pub_topic);
+    
+    piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;		//设置接收到数据回调函数
+    printf("iot_mqtt_init end\n");
+}
+
+void mbtk_aliyun_mqtt_one_type_one_secret_unregin_set_info_init(Cloud_MQTT_t *piot_mqtt,mbtk_mqtt_device_session_t *device,int keepAliveInterval,int version,pMessageArrived_Fun mqtt_data_rx_cb) 
+{
+
+    mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,device->product_key,device->host);
+    mbtk_aliyun_mqtt_get_connect_para(piot_mqtt->mqtt_pass, piot_mqtt->mqtt_client_id, piot_mqtt->mqtt_user, device);
+
+    piot_mqtt->mqtt_port = device->port;
+    piot_mqtt->keepAliveInterval = keepAliveInterval;
+    piot_mqtt->mqtt_version = version;
+
+    printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    printf("piot_mqtt->mqtt_version:%d\n", piot_mqtt->mqtt_version);
+    memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+    memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+    
+    piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;		//设置接收到数据回调函数
+    printf("iot_mqtt_init end\n");
+}
+
+int mbtk_aliyun_mqtt_one_type_one_secret_unregin_get_regin_info(char *clientId, char *deviceToken)
+{
+    int ret = 0;
+    if(strlen(regnwl_info.deviceToken) > 5)
+    {
+        memcpy(clientId, regnwl_info.clientId, strlen(regnwl_info.clientId));
+        memcpy(deviceToken, regnwl_info.deviceToken , strlen(regnwl_info.deviceToken));
+    }else{
+        ret=  -1;
+    }
+
+    printf("regnwl_info.clientId:%s\n", regnwl_info.clientId);
+    printf("regn->deviceToken:%s\n", regnwl_info.deviceToken);
+    return ret;
+}
+
+
+void iot_aliyun_mqtt_one_type_one_secret_unregin_connect_init(Cloud_MQTT_t *piot_mqtt,mbtk_mqtt_device_session_t *device, char *clientId, char *deviceToken,
+         int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb) 
+{
+    mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,device->product_key,device->host);
+    mbtk_imqtt_auth_clientid_yixinyimi_unregin(piot_mqtt->mqtt_client_id, clientId);
+    mbtk_imqtt_auth_username(piot_mqtt->mqtt_user,device->device_name,device->product_key);
+    sprintf(piot_mqtt->mqtt_pass, "%s", deviceToken);
+    piot_mqtt->mqtt_port = device->port;
+    piot_mqtt->keepAliveInterval = keepAliveInterval;
+    //    piot_mqtt->mqtt_version = version;
+    piot_mqtt->mqtt_version = 3;
+
+    printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+    memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+    
+    sprintf(piot_mqtt->sub_topic, "%s", sub_topic);	//将初始化好的订阅主题填到数组中
+    printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+    sprintf(piot_mqtt->pub_topic, "%s", pub_topic);	//将初始化好的发布主题填到数组中
+    printf("pub:%s\n", piot_mqtt->pub_topic);
+    
+    piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;		//设置接收到数据回调函数
+    printf("iot_mqtt_init end\n");
+}
+
+
+void mbtk_aliyun_mqtt_one_type_one_secret_regint_connect_init(Cloud_MQTT_t *piot_mqtt,int host,int port ,char *device_name,char *product_key, 
+		char * DeviceSecret,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb) 
+{
+    mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,product_key,host);
+    mbtk_aliyun_imqtt_auth_clientid(piot_mqtt->mqtt_client_id,product_key,device_name);
+    mbtk_imqtt_auth_username(piot_mqtt->mqtt_user,device_name,product_key);
+    mbtk_imqtt_auth_password(piot_mqtt->mqtt_pass,device_name,product_key,DeviceSecret);
+    piot_mqtt->mqtt_port = port;
+    piot_mqtt->keepAliveInterval = keepAliveInterval;
+    //    piot_mqtt->mqtt_version = version;
+    piot_mqtt->mqtt_version = 3;
+
+    printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+    memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+    
+    sprintf(piot_mqtt->sub_topic, "%s", sub_topic);	//将初始化好的订阅主题填到数组中
+    printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+    sprintf(piot_mqtt->pub_topic, "%s", pub_topic);	//将初始化好的发布主题填到数组中
+    printf("pub:%s\n", piot_mqtt->pub_topic);
+    
+    piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;		//设置接收到数据回调函数
+    printf("iot_mqtt_init end\n");
+}
+
+
+void iot_mqtt_init(Cloud_MQTT_t *piot_mqtt,char *host,int port ,char *clientid,char *user,char *pass,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb) 
+{
+
+    memcpy(piot_mqtt->mqtt_host,host,strlen(host));
+    memcpy(piot_mqtt->mqtt_client_id,clientid,strlen(clientid));
+    memcpy(piot_mqtt->mqtt_user,user,strlen(user));
+    memcpy(piot_mqtt->mqtt_pass,pass,strlen(pass));
+    piot_mqtt->mqtt_port = port;
+    piot_mqtt->keepAliveInterval = keepAliveInterval;
+    piot_mqtt->mqtt_version = version;
+
+    
+    printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+    memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+    
+    sprintf(piot_mqtt->sub_topic, "%s", sub_topic);	//将初始化好的订阅主题填到数组中
+    printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+    sprintf(piot_mqtt->pub_topic, "%s", pub_topic);	//将初始化好的发布主题填到数组中
+    printf("pub:%s\n", piot_mqtt->pub_topic);
+    
+    piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;		//设置接收到数据回调函数
+    printf("iot_mqtt_init end\n");
+}
+/*
+void MQTTMessageArrived_Cb(MessageData* md)
+{
+    MQTTMessage *message = md->message; 
+
+    Cloud_MQTT_t *piot_mqtt = get_mqtt_t();
+
+    if (NULL != piot_mqtt->DataArrived_Cb) {
+        piot_mqtt->DataArrived_Cb((void *)message->payload, message->payloadlen);//异步消息体
+    }
+}
+*/
+
+int mbtk_aliyun_mqtt_one_type_one_secret_unregin_device_connect(Cloud_MQTT_t *piot_mqtt)
+{
+    int rc = 0, ret = 0;
+    Network* network = (Network*)malloc(sizeof(Network));
+    memset(network ,0x0, sizeof(Network));
+    NewNetwork(network);
+    piot_mqtt->network = network;
+
+    printf("topic = %s\n", piot_mqtt->sub_topic);
+//    set_mqtt_t(piot_mqtt);
+    piot_mqtt->network->is_support_ssl = 1;
+    printf("23131mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    rc = ConnectNetwork(piot_mqtt->network, piot_mqtt->mqtt_host, piot_mqtt->mqtt_port,piot_mqtt->network->is_support_ssl,piot_mqtt->network->ingnore_cert);
+    if (rc != 0) {
+        ret = -101;
+        goto __END;
+    }
+    MQTTClient(&piot_mqtt->Client, piot_mqtt->network, 1000*30, piot_mqtt->mqtt_buffer, MQTT_BUF_SIZE, piot_mqtt->mqtt_read_buffer, MQTT_BUF_SIZE);
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+    data.MQTTVersion = piot_mqtt->mqtt_version;
+    data.clientID.cstring = piot_mqtt->mqtt_client_id;
+    data.username.cstring = piot_mqtt->mqtt_user;
+    data.password.cstring = piot_mqtt->mqtt_pass;
+    data.keepAliveInterval = piot_mqtt->keepAliveInterval;
+    data.willFlag = 0;
+    data.will.qos = 0;
+    data.will.retained     =                    0;
+    data.will.topicName.cstring =            NULL;
+    data.will.message.cstring   =            NULL;
+
+    data.cleansession = 1;
+    rc = MQTTConnect(&piot_mqtt->Client, &data);
+    if (rc) {
+        printf("mqtt connect broker fail \n");
+        printf("rc = %d\n", rc);
+        ret = -102;
+        goto __END;
+    }
+__END:
+    return ret;
+}
+
+int mqtt_device_connect(Cloud_MQTT_t *piot_mqtt)
+{
+    int rc = 0, ret = 0;
+    Network* network = (Network*)malloc(sizeof(Network));
+    memset(network ,0x0, sizeof(Network));
+    NewNetwork(network);
+    piot_mqtt->network = network;
+
+    printf("topic = %s\n", piot_mqtt->sub_topic);
+//    set_mqtt_t(piot_mqtt);
+    printf("23131mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+    rc = ConnectNetwork(piot_mqtt->network, piot_mqtt->mqtt_host, piot_mqtt->mqtt_port,piot_mqtt->network->is_support_ssl,piot_mqtt->network->ingnore_cert);
+    if (rc != 0) {
+        ret = -101;
+        goto __END;
+    }
+    MQTTClient(&piot_mqtt->Client, piot_mqtt->network, 1000, piot_mqtt->mqtt_buffer, MQTT_BUF_SIZE, piot_mqtt->mqtt_read_buffer, MQTT_BUF_SIZE);
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+    if (piot_mqtt->willFlag) {
+        data.willFlag = 1;
+        memcpy(&data.will, &piot_mqtt->will, sizeof(MQTTPacket_willOptions));
+    } else {
+        data.willFlag = 0;
+    }
+    data.MQTTVersion = piot_mqtt->mqtt_version;
+    data.clientID.cstring = piot_mqtt->mqtt_client_id;
+    data.username.cstring = piot_mqtt->mqtt_user;
+    data.password.cstring = piot_mqtt->mqtt_pass;
+    data.keepAliveInterval = piot_mqtt->keepAliveInterval;
+    data.cleansession = 1;
+    rc = MQTTConnect(&piot_mqtt->Client, &data);
+    if (rc) {
+        printf("mqtt connect broker fail \n");
+        printf("rc = %d\n", rc);
+        ret = -102;
+        goto __END;
+    }
+__END:
+    return ret;
+}
+
+int mqtt_device_disconnect(Cloud_MQTT_t *piot_mqtt)//断开mqtt连接
+{
+    int ret = 0;
+
+    ret = MQTTDisconnect(&piot_mqtt->Client,piot_mqtt->network);
+    printf("disconnectNetwork ret = %d\n", ret);
+
+    return ret;
+}
+
+void iot_yield(Cloud_MQTT_t *piot_mqtt,iot_device_info_t *gateway)
+{
+    int ret;
+    switch (gateway->iotstatus) {
+        case IOT_STATUS_LOGIN:
+        ret = mqtt_device_connect(piot_mqtt);
+        if (ret < 0) {
+            printf("iot connect error code %d\n", ret);
+            sleep(1);
+        }
+        break;
+        case IOT_STATUS_CONNECT:
+        ret = MQTTYield(&piot_mqtt->Client, 200);
+        //printf("iot_yield ret %d\n",ret);
+        if (ret != SUCCESS) {
+            printf("why???\n");
+            gateway->iotstatus = IOT_STATUS_DROP;
+        }
+        break;
+        case IOT_STATUS_DROP:
+        mqtt_device_disconnect(piot_mqtt);
+        //gateway.iotstatus = IOT_STATUS_LOGIN;
+        usleep(1000);
+        break;
+        default:
+        break;
+    }
+}
+
+int mqtt_will_msg_set(Cloud_MQTT_t *piot_mqtt, char *pbuf, int len)//设置遗嘱函数
+{
+    memset(piot_mqtt->will_topic, '\0', MQTT_TOPIC_SIZE);
+    MQTTPacket_willOptions mqtt_will = MQTTPacket_willOptions_initializer;
+
+    strcpy(piot_mqtt->will_topic, piot_mqtt->pub_topic);
+    memcpy(&piot_mqtt->will, &mqtt_will, sizeof(MQTTPacket_willOptions));
+
+    piot_mqtt->willFlag = 1;
+    piot_mqtt->will.retained = 0;
+    piot_mqtt->will.topicName.cstring = (char *)piot_mqtt->will_topic;
+    piot_mqtt->will.message.cstring = (char *)pbuf;
+    piot_mqtt->will.qos = QOS2;
+    return 0;
+
+}
+
+int mbtk_MQTTSubscribe(Client* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+    return MQTTSubscribe(c, topicFilter, qos, messageHandler);
+}
+int mbtk_MQTTUnsubscribe(Client* c, const char* topicFilter)
+{
+    return MQTTUnsubscribe(c,topicFilter);
+}
+/*
+int mbtk_MQTTPublish(Client* c, const char* topicName, MQTTMessage* message)
+{
+    return MQTTPublish(c,topicName,message);
+}
+*/
+int mbtk_MQTTPublish(char *pbuf, int len, char retain,Client* c,const char* pub_topic,enum QoS qos,char dup)
+{
+    int ret = 0;
+    MQTTMessage message;
+    char my_topic[128] = {0};
+
+    strcpy(my_topic, pub_topic);
+
+    message.payload = (void *)pbuf;
+    message.payloadlen = len;
+    message.dup = dup;
+    message.qos = qos;
+    if (retain) {
+        message.retained = 1;
+    } else {
+        message.retained = 0;
+    }
+
+    ret = MQTTPublish(c, my_topic, &message);	//发布一个主题
+
+    return ret;
+}
+
diff --git a/mbtk/mbtk_ril/Makefile b/mbtk/mbtk_ril/Makefile
new file mode 100755
index 0000000..813d94b
--- /dev/null
+++ b/mbtk/mbtk_ril/Makefile
@@ -0,0 +1,44 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_ril
+
+INC_DIR += \
+		-I$(LOCAL_PATH)/inc \
+		-I$(BUILD_ROOT)/mbtk_lib/inc
+	
+LIB_DIR +=
+
+LIBS += -lmbtk_lib -lrilutil -lprop2uci -lmtel -laudio-apu -lcutils -ltinyalsa -lacm
+
+CFLAGS += 
+
+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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/bin/mbtk_ril
+
+all: $(dtarget)
+
+$(dtarget):
+	@echo "  BIN     $@"
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
+
diff --git a/mbtk/mbtk_ril/inc/at_tok.h b/mbtk/mbtk_ril/inc/at_tok.h
new file mode 100755
index 0000000..a9725c0
--- /dev/null
+++ b/mbtk/mbtk_ril/inc/at_tok.h
@@ -0,0 +1,31 @@
+/* //device/system/reference-ril/at_tok.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef AT_TOK_H
+#define AT_TOK_H 1
+
+int at_tok_start(char **p_cur);
+int at_tok_nextint(char **p_cur, int *p_out);
+int at_tok_nexthexint(char **p_cur, int *p_out);
+
+int at_tok_nextbool(char **p_cur, char *p_out);
+int at_tok_nextstr(char **p_cur, char **out);
+
+int at_tok_hasmore(char **p_cur);
+
+#endif /*AT_TOK_H */
+
diff --git a/mbtk/mbtk_ril/inc/atchannel.h b/mbtk/mbtk_ril/inc/atchannel.h
new file mode 100755
index 0000000..b97cb27
--- /dev/null
+++ b/mbtk/mbtk_ril/inc/atchannel.h
@@ -0,0 +1,148 @@
+/* //device/system/reference-ril/atchannel.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ATCHANNEL_H
+#define ATCHANNEL_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "mbtk_type.h"
+
+/* define AT_DEBUG to send AT traffic to /tmp/radio-at.log" */
+#define AT_DEBUG  0
+
+#if AT_DEBUG
+extern void  AT_DUMP(const char* prefix, const char*  buff, int  len);
+#else
+#define  AT_DUMP(prefix,buff,len)  do{}while(0)
+#endif
+
+#define AT_ERROR_GENERIC          (-1)
+#define AT_ERROR_COMMAND_PENDING  (-2)
+#define AT_ERROR_CHANNEL_CLOSED   (-3)
+#define AT_ERROR_TIMEOUT          (-4)
+#define AT_ERROR_INVALID_THREAD   (-5) /* AT commands may not be issued from
+                                          reader thread (or unsolicited response
+                                          callback */
+#define AT_ERROR_INVALID_RESPONSE (-6) /* eg an at_send_command_singleline that
+                                          did not get back an intermediate
+                                          response */
+#define AT_ERROR_TIMEOUT_CLOSE    (-7)
+
+
+typedef enum
+{
+    NO_RESULT,   /* no intermediate response expected */
+    NUMERIC,     /* a single intermediate response starting with a 0-9 */
+    SINGLELINE,  /* a single intermediate response starting with a prefix */
+    MULTILINE    /* multiple line intermediate response
+                    starting with a prefix */
+} ATCommandType;
+
+/** a singly-lined list of intermediate responses */
+typedef struct ATLine
+{
+    struct ATLine *p_next;
+    char *line;
+} ATLine;
+
+/** Free this with at_response_free() */
+typedef struct
+{
+    int success;              /* true if final response indicates
+                                    success (eg "OK") */
+    char *finalResponse;      /* eg OK, ERROR */
+    ATLine  *p_intermediates; /* any intermediate responses */
+} ATResponse;
+
+typedef enum
+{
+    RIL_AT_STATE_CLOSED = 0,
+    RIL_AT_STATE_OPENED,
+    RIL_AT_STATE_CONNECTED,
+    RIL_AT_STATE_READY,
+    RIL_AT_STATE_BUSY
+} mbtk_ril_at_state_enum;
+
+/**
+ * a user-provided unsolicited response handler function
+ * this will be called from the reader thread, so do not block
+ * "s" is the line, and "sms_pdu" is either NULL or the PDU response
+ * for multi-line TS 27.005 SMS PDU responses (eg +CMT:)
+ */
+typedef void (*ATUnsolHandler)(const char *s, const char *sms_pdu);
+
+int at_open(int at_fd, int uart_fd, ATUnsolHandler h);
+void at_close();
+
+/* This callback is invoked on the command thread.
+   You should reset or handshake here to avoid getting out of sync */
+void at_set_on_timeout(void (*onTimeout)(void));
+/* This callback is invoked on the reader thread (like ATUnsolHandler)
+   when the input stream closes before you call at_close
+   (not when you call at_close())
+   You should still call at_close()
+   It may also be invoked immediately from the current thread if the read
+   channel is already closed */
+void at_set_on_reader_closed(void (*onClose)(void));
+
+int at_send_command_singleline (const char *command,
+                                const char *responsePrefix,
+                                ATResponse **pp_outResponse);
+int at_send_command_singleline_with_timeout (const char *command,
+        const char *responsePrefix,
+        ATResponse **pp_outResponse,long long timeoutMsec);
+
+int at_send_command_numeric (const char *command,
+                             ATResponse **pp_outResponse);
+
+int at_send_command_multiline (const char *command,
+                               const char *responsePrefix,
+                               ATResponse **pp_outResponse);
+
+
+int at_handshake();
+
+int at_send_command (const char *command, ATResponse **pp_outResponse);
+
+int at_send_command_sms (const char *command, const char *pdu,
+                         const char *responsePrefix,
+                         ATResponse **pp_outResponse);
+
+void at_response_free(ATResponse *p_response);
+
+typedef enum
+{
+    CME_ERROR_NON_CME = -1,
+    CME_SUCCESS = 0,
+    CME_SIM_NOT_INSERTED = 10,
+    CME_ERROR_UNKNOWN
+} AT_CME_Error;
+
+AT_CME_Error at_get_cme_error(const ATResponse *p_response);
+
+mbtk_ril_at_state_enum at_state_get();
+void at_state_set(mbtk_ril_at_state_enum state);
+bool at_rsp_check(ATResponse *p_response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*ATCHANNEL_H*/
+
diff --git a/mbtk/mbtk_ril/inc/info_data.h b/mbtk/mbtk_ril/inc/info_data.h
new file mode 100755
index 0000000..c17cd80
--- /dev/null
+++ b/mbtk/mbtk_ril/inc/info_data.h
@@ -0,0 +1,65 @@
+/*
+*
+* Data : 2022/11/1 18:27:39
+* Author : LiuBin
+*/
+#ifndef _info_data_H
+#define _info_data_H
+#include "mbtk_type.h"
+#include "mbtk_list.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+
+#define SOCK_CLIENT_MAX 100
+#define EPOLL_LISTEN_MAX 100
+#define IND_REGISTER_MAX 10
+#define PACK_PROCESS_QUEUE_MAX 20
+
+#define MBTK_APN_PROP "persist.mbtk.apn"
+#define MBTK_LTE_B28_SUPPORT 1
+
+typedef struct
+{
+    int fd;
+
+    uint32 ind_num;
+    uint16 ind_register[IND_REGISTER_MAX];
+} sock_client_info_t;
+
+typedef struct
+{
+    sock_client_info_t *cli_info;
+    void* pack;
+} info_queue_item_t;
+
+typedef struct
+{
+    int cid;
+
+    bool ipv4_valid;
+    uint8 ipv4[20];
+    bool ipv6_valid;
+    uint8 ipv6[50];
+} info_apn_ip_t;
+
+typedef enum {
+    INFO_URC_MSG_RADIO_STATE,
+    INFO_URC_MSG_CGEV,
+    INFO_URC_MSG_NET_CS_REG_STATE,
+    INFO_URC_MSG_NET_PS_REG_STATE,
+    INFO_URC_MSG_CALL_STATE,
+    INFO_URC_MSG_SIM_STATE,
+    INFO_URC_MSG_PDP_STATE,
+    INFO_URC_MSG_SMS_STATE,
+    INFO_URC_MSG_NET_STATE_LOG      // Save Network state into file.
+} info_urc_msg_id_enum;
+
+typedef struct {
+    info_urc_msg_id_enum msg;
+
+    void *data;
+    int data_len;
+} info_urc_msg_t;
+
+
+#endif /* _info_data_H */
diff --git a/mbtk/mbtk_ril/src/at_tok.c b/mbtk/mbtk_ril/src/at_tok.c
new file mode 100755
index 0000000..531afff
--- /dev/null
+++ b/mbtk/mbtk_ril/src/at_tok.c
@@ -0,0 +1,194 @@
+/* //device/system/reference-ril/at_tok.c
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "at_tok.h"
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "mbtk_log.h"
+/**
+ * Starts tokenizing an AT response string
+ * returns -1 if this is not a valid response string, 0 on success.
+ * updates *p_cur with current position
+ */
+int at_tok_start(char **p_cur)
+{
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    // skip prefix
+    // consume "^[^:]:"
+
+    *p_cur = strchr(*p_cur, ':');
+
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    (*p_cur)++;
+/*
+    while(**p_cur == ' ') {
+        (*p_cur)++;
+    }
+*/
+    return 0;
+}
+
+static void skipWhiteSpace(char **p_cur)
+{
+    if (*p_cur == NULL) return;
+
+    while (**p_cur != '\0' && isspace(**p_cur)) {
+        (*p_cur)++;
+    }
+}
+
+static void skipNextComma(char **p_cur)
+{
+    if (*p_cur == NULL) return;
+
+    while (**p_cur != '\0' && **p_cur != ',') {
+        (*p_cur)++;
+    }
+
+    if (**p_cur == ',') {
+        (*p_cur)++;
+    }
+}
+
+static char * nextTok(char **p_cur)
+{
+    char *ret = NULL;
+
+    skipWhiteSpace(p_cur);
+
+    if (*p_cur == NULL) {
+        ret = NULL;
+    } else if (**p_cur == '"') {
+        (*p_cur)++;
+        ret = strsep(p_cur, "\"");
+        skipNextComma(p_cur);
+    } else {
+        ret = strsep(p_cur, ",");
+    }
+
+    return ret;
+}
+
+
+/**
+ * Parses the next integer in the AT response line and places it in *p_out
+ * returns 0 on success and -1 on fail
+ * updates *p_cur
+ * "base" is the same as the base param in strtol
+ */
+
+static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int  uns)
+{
+    char *ret;
+
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    ret = nextTok(p_cur);
+
+    if (ret == NULL) {
+        return -1;
+    } else {
+        long l;
+        char *end;
+
+        if (uns)
+            l = strtoul(ret, &end, base);
+        else
+            l = strtol(ret, &end, base);
+
+        *p_out = (int)l;
+
+        if (end == ret) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Parses the next base 10 integer in the AT response line
+ * and places it in *p_out
+ * returns 0 on success and -1 on fail
+ * updates *p_cur
+ */
+int at_tok_nextint(char **p_cur, int *p_out)
+{
+    return at_tok_nextint_base(p_cur, p_out, 10, 0);
+}
+
+/**
+ * Parses the next base 16 integer in the AT response line
+ * and places it in *p_out
+ * returns 0 on success and -1 on fail
+ * updates *p_cur
+ */
+int at_tok_nexthexint(char **p_cur, int *p_out)
+{
+    return at_tok_nextint_base(p_cur, p_out, 16, 1);
+}
+
+int at_tok_nextbool(char **p_cur, char *p_out)
+{
+    int ret;
+    int result;
+
+    ret = at_tok_nextint(p_cur, &result);
+
+    if (ret < 0) {
+        return -1;
+    }
+
+    // booleans should be 0 or 1
+    if (!(result == 0 || result == 1)) {
+        return -1;
+    }
+
+    if (p_out != NULL) {
+        *p_out = (char)result;
+    }
+
+    return ret;
+}
+
+int at_tok_nextstr(char **p_cur, char **p_out)
+{
+    if (*p_cur == NULL) {
+        return -1;
+    }
+
+    *p_out = nextTok(p_cur);
+
+    return 0;
+}
+
+/** returns 1 on "has more tokens" and 0 if no */
+int at_tok_hasmore(char **p_cur)
+{
+    return ! (*p_cur == NULL || **p_cur == '\0');
+}
+
diff --git a/mbtk/mbtk_ril/src/atchannel.c b/mbtk/mbtk_ril/src/atchannel.c
new file mode 100755
index 0000000..a1a9f21
--- /dev/null
+++ b/mbtk/mbtk_ril/src/atchannel.c
@@ -0,0 +1,1349 @@
+/* //device/system/reference-ril/atchannel.c
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "atchannel.h"
+#include "at_tok.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_utils.h"
+
+#define MAX_AT_RESPONSE (8 * 1024)
+#define HANDSHAKE_RETRY_COUNT 20
+#define HANDSHAKE_TIMEOUT_MSEC 500
+#define AT_BUFF_MAX 100
+
+static pthread_t s_tid_reader;
+static int s_at_fd = -1;    /* fd of the AT channel */
+static int s_uart_fd = -1;    /* fd of the UART channel */
+
+static ATUnsolHandler s_unsolHandler;
+
+/* for input buffering */
+
+static char s_ATBuffer[MAX_AT_RESPONSE+1];
+static char *s_ATBufferCur = s_ATBuffer;
+static char s_UartBuffer[MAX_AT_RESPONSE+1];
+static char *s_UartBufferCur = s_UartBuffer;
+
+static mbtk_ril_at_state_enum at_state = RIL_AT_STATE_CLOSED;
+
+#if AT_DEBUG
+void  AT_DUMP(const char*  prefix, const char*  buff, int  len)
+{
+    if (len < 0)
+        len = strlen(buff);
+    LOGD("%.*s", len, buff);
+}
+#endif
+
+/*
+ * There is one reader thread |s_tid_reader| and potentially multiple writer
+ * threads. |s_commandmutex| and |s_commandcond| are used to maintain the
+ * condition that the writer thread will not read from |sp_response| until the
+ * reader thread has signaled itself is finished, etc. |s_writeMutex| is used to
+ * prevent multiple writer threads from calling at_send_command_full_nolock
+ * function at the same time.
+ */
+
+// "Wait" when AT process...
+static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER;
+
+static ATCommandType s_type;
+static const char *s_responsePrefix = NULL;
+static const char *s_smsPDU = NULL;
+static ATResponse *sp_response = NULL;
+static char s_curr_at[AT_BUFF_MAX];
+
+static void (*s_onTimeout)(void) = NULL;
+static void (*s_onReaderClosed)(void) = NULL;
+static int s_readerClosed;
+
+static void onReaderClosed();
+static int writeCtrlZ (const char *s);
+static int writeline (const char *s);
+
+typedef struct
+{
+    char *at_command;
+    long long timeout;  // ms
+    bool timeout_close; // Close AT or not while AT response timeout.
+} at_timeout_t;
+
+static at_timeout_t at_timeout_list[] =
+{
+    {"AT+CRSM", 10000, false},
+//    {"AT+COPS", 60000, false}
+};
+
+#define NS_PER_S 1000000000
+static void setTimespecRelative(struct timespec *p_ts, long long msec)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, (struct timezone *) NULL);
+
+    p_ts->tv_sec = tv.tv_sec + (msec / 1000);
+    p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
+    /* assuming tv.tv_usec < 10^6 */
+    if (p_ts->tv_nsec >= NS_PER_S)
+    {
+        p_ts->tv_sec++;
+        p_ts->tv_nsec -= NS_PER_S;
+    }
+}
+
+static void sleepMsec(long long msec)
+{
+    struct timespec ts;
+    int err;
+
+    ts.tv_sec = (msec / 1000);
+    ts.tv_nsec = (msec % 1000) * 1000 * 1000;
+
+    do
+    {
+        err = nanosleep (&ts, &ts);
+    }
+    while (err < 0 && errno == EINTR);
+}
+
+
+
+/** add an intermediate response to sp_response*/
+static void addIntermediate(const char *line)
+{
+    ATLine *p_new;
+
+    p_new = (ATLine  *) malloc(sizeof(ATLine));
+
+    p_new->line = strdup(line);
+
+//    LOGD("line:%s", line);
+//    LOGD("line-1:%s", p_new->line);
+
+    /* note: this adds to the head of the list, so the list
+       will be in reverse order of lines received. the order is flipped
+       again before passing on to the command issuer */
+    p_new->p_next = sp_response->p_intermediates;
+    sp_response->p_intermediates = p_new;
+}
+
+
+/**
+ * returns 1 if line is a final response indicating error
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static const char * s_finalResponsesError[] =
+{
+    "ERROR",
+    "+CMS ERROR:",
+    "+CME ERROR:",
+//    "NO CARRIER", /* sometimes! */ // Only for ATD ?
+    "NO ANSWER",
+    "NO DIALTONE",
+};
+static int isFinalResponseError(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesError) ; i++)
+    {
+        if (strStartsWith(line, s_finalResponsesError[i]))
+        {
+            return 1;
+        }
+    }
+
+    if(!strncasecmp(s_curr_at, "ATD", 3) && strStartsWith(line, "NO CARRIER"))
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * returns 1 if line is a final response indicating success
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static const char * s_finalResponsesSuccess[] =
+{
+    "OK",
+//    "CONNECT"       /* some stacks start up data on another channel */
+};
+static int isFinalResponseSuccess(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < ARRAY_SIZE(s_finalResponsesSuccess) ; i++)
+    {
+        if (strStartsWith(line, s_finalResponsesSuccess[i]))
+        {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * returns 1 if line is a final response, either  error or success
+ * See 27.007 annex B
+ * WARNING: NO CARRIER and others are sometimes unsolicited
+ */
+static int isFinalResponse(const char *line)
+{
+    return isFinalResponseSuccess(line) || isFinalResponseError(line);
+}
+
+/**
+ * returns 1 if line is the first line in (what will be) a two-line
+ * SMS unsolicited response
+ */
+static const char * s_smsUnsoliciteds[] =
+{
+    "+CMT:",
+    "+CDS:",
+    "+CBM:"
+};
+static int isSMSUnsolicited(const char *line)
+{
+    size_t i;
+
+    for (i = 0 ; i < ARRAY_SIZE(s_smsUnsoliciteds) ; i++)
+    {
+        if (strStartsWith(line, s_smsUnsoliciteds[i]))
+        {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
+/** assumes s_commandmutex is held */
+static void handleFinalResponse(const char *line)
+{
+    sp_response->finalResponse = strdup(line);
+
+    //LOGD("AT complete (pthread_cond_signal): %s",line);
+    pthread_cond_signal(&s_commandcond);
+}
+
+static void handleUnsolicited(const char *line)
+{
+    if (s_unsolHandler != NULL)
+    {
+        s_unsolHandler(line, NULL);
+    }
+}
+
+static void processLine(const char *line)
+{
+    pthread_mutex_lock(&s_commandmutex);
+//    LOGD("LINE : %s", line);
+    if (sp_response == NULL)
+    {
+        /* no command pending */
+        handleUnsolicited(line);
+    }
+    else if (isFinalResponseSuccess(line))
+    {
+        sp_response->success = 1;
+        handleFinalResponse(line);
+    }
+    else if (isFinalResponseError(line))
+    {
+        sp_response->success = 0;
+        handleFinalResponse(line);
+    }
+    else if (s_smsPDU != NULL && 0 == strcmp(line, "> "))
+    {
+        // See eg. TS 27.005 4.3
+        // Commands like AT+CMGS have a "> " prompt
+        writeCtrlZ(s_smsPDU);
+        s_smsPDU = NULL;
+    }
+    else switch (s_type)
+        {
+            case NO_RESULT:
+                handleUnsolicited(line);
+                break;
+            case NUMERIC:
+                if (sp_response->p_intermediates == NULL
+                    && isdigit(line[0])
+                   )
+                {
+                    addIntermediate(line);
+                }
+                else
+                {
+                    /* either we already have an intermediate response or
+                       the line doesn't begin with a digit */
+                    handleUnsolicited(line);
+                }
+                break;
+            case SINGLELINE:
+                if (sp_response->p_intermediates == NULL
+                    && strStartsWith (line, s_responsePrefix)
+                   )
+                {
+                    if(*line == '"')
+                    {
+                        char *line_temp = strdup(line);
+                        line_temp++;
+                        if(strlen(line_temp) > 0)
+                        {
+                            char *ptr = line_temp + strlen(line_temp) - 1;
+                            while(ptr >= line_temp && *ptr == '"')
+                            {
+                                *ptr = '\0';
+                                ptr--;
+                            }
+                        }
+                        addIntermediate(line_temp);
+                        free(line_temp);
+                    }
+                    else
+                    {
+                        addIntermediate(line);
+                    }
+                }
+                else
+                {
+                    /* we already have an intermediate response */
+                    handleUnsolicited(line);
+                }
+                break;
+            case MULTILINE:
+                if (strStartsWith (line, s_responsePrefix))
+                {
+                    addIntermediate(line);
+                }
+                else
+                {
+                    handleUnsolicited(line);
+                }
+                break;
+
+            default: /* this should never be reached */
+                LOGE("Unsupported AT command type %d\n", s_type);
+                handleUnsolicited(line);
+                break;
+        }
+
+    pthread_mutex_unlock(&s_commandmutex);
+}
+
+
+/**
+ * Returns a pointer to the end of the next line
+ * special-cases the "> " SMS prompt
+ *
+ * returns NULL if there is no complete line
+ */
+static char * findNextEOL(char *cur)
+{
+    if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0')
+    {
+        /* SMS prompt character...not \r terminated */
+        return cur+2;
+    }
+
+    // Find next newline
+    while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
+
+    return *cur == '\0' ? NULL : cur;
+}
+
+
+/**
+ * Reads a line from the AT channel, returns NULL on timeout.
+ * Assumes it has exclusive read access to the FD
+ *
+ * This line is valid only until the next call to readline
+ *
+ * This function exists because as of writing, android libc does not
+ * have buffered stdio.
+ */
+
+static const char *readline()
+{
+    ssize_t count;
+
+    char *p_read = NULL;
+    char *p_eol = NULL;
+    char *ret;
+
+    /* this is a little odd. I use *s_ATBufferCur == 0 to
+     * mean "buffer consumed completely". If it points to a character, than
+     * the buffer continues until a \0
+     */
+    if (*s_ATBufferCur == '\0')
+    {
+        /* empty buffer */
+        s_ATBufferCur = s_ATBuffer;
+        *s_ATBufferCur = '\0';
+        p_read = s_ATBuffer;
+    }
+    else       /* *s_ATBufferCur != '\0' */
+    {
+        /* there's data in the buffer from the last read */
+
+        // skip over leading newlines
+        while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
+            s_ATBufferCur++;
+
+        p_eol = findNextEOL(s_ATBufferCur);
+
+        if (p_eol == NULL)
+        {
+            /* a partial line. move it up and prepare to read more */
+            size_t len;
+
+            len = strlen(s_ATBufferCur);
+
+            memmove(s_ATBuffer, s_ATBufferCur, len + 1);
+            p_read = s_ATBuffer + len;
+            s_ATBufferCur = s_ATBuffer;
+        }
+        /* Otherwise, (p_eol !- NULL) there is a complete line  */
+        /* that will be returned the while () loop below        */
+    }
+
+    while (p_eol == NULL)
+    {
+        if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer))
+        {
+            LOGE("ERROR: Input line exceeded buffer\n");
+            /* ditch buffer and start over again */
+            s_ATBufferCur = s_ATBuffer;
+            *s_ATBufferCur = '\0';
+            p_read = s_ATBuffer;
+        }
+
+        do
+        {
+            count = read(s_at_fd, p_read,
+                         MAX_AT_RESPONSE - (p_read - s_ATBuffer));
+            usleep(10000);
+        }
+        while (count < 0 && errno == EINTR);
+
+        if (count > 0)
+        {
+            AT_DUMP( "<< ", p_read, count );
+
+            p_read[count] = '\0';
+
+            // skip over leading newlines
+            while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
+                s_ATBufferCur++;
+
+            p_eol = findNextEOL(s_ATBufferCur);
+            p_read += count;
+        }
+        else if (count <= 0)
+        {
+            /* read error encountered or EOF reached */
+            if(count == 0)
+            {
+                LOGD("atchannel: EOF reached");
+            }
+            else
+            {
+                LOGD("atchannel: read error %s", strerror(errno));
+            }
+            return NULL;
+        }
+    }
+
+    /* a full line in the buffer. Place a \0 over the \r and return */
+
+    ret = s_ATBufferCur;
+    *p_eol = '\0';
+    s_ATBufferCur = p_eol + 1; /* this will always be <= p_read,    */
+    /* and there will be a \0 at *p_read */
+
+    LOGD("AT< %s", ret);
+    return ret;
+}
+
+static const char *readlineUrc()
+{
+    ssize_t count;
+
+    char *p_read = NULL;
+    char *p_eol = NULL;
+    char *ret;
+
+    /* this is a little odd. I use *s_ATBufferCur == 0 to
+     * mean "buffer consumed completely". If it points to a character, than
+     * the buffer continues until a \0
+     */
+    if (*s_UartBufferCur == '\0')
+    {
+        /* empty buffer */
+        s_UartBufferCur = s_UartBuffer;
+        *s_UartBufferCur = '\0';
+        p_read = s_UartBuffer;
+    }
+    else       /* *s_ATBufferCur != '\0' */
+    {
+        /* there's data in the buffer from the last read */
+
+        // skip over leading newlines
+        while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
+            s_UartBufferCur++;
+
+        p_eol = findNextEOL(s_UartBufferCur);
+
+        if (p_eol == NULL)
+        {
+            /* a partial line. move it up and prepare to read more */
+            size_t len;
+
+            len = strlen(s_UartBufferCur);
+
+            memmove(s_UartBuffer, s_UartBufferCur, len + 1);
+            p_read = s_UartBuffer + len;
+            s_UartBufferCur = s_UartBuffer;
+        }
+        /* Otherwise, (p_eol !- NULL) there is a complete line  */
+        /* that will be returned the while () loop below        */
+    }
+
+    while (p_eol == NULL)
+    {
+        if (0 == MAX_AT_RESPONSE - (p_read - s_UartBuffer))
+        {
+            LOGE("ERROR: Input line exceeded buffer\n");
+            /* ditch buffer and start over again */
+            s_UartBufferCur = s_UartBuffer;
+            *s_UartBufferCur = '\0';
+            p_read = s_UartBuffer;
+        }
+
+        do
+        {
+            count = read(s_uart_fd, p_read,
+                         MAX_AT_RESPONSE - (p_read - s_UartBuffer));
+            usleep(10000);
+        }
+        while (count < 0 && errno == EINTR);
+
+        if (count > 0)
+        {
+            AT_DUMP( "<< ", p_read, count );
+
+            p_read[count] = '\0';
+
+            // skip over leading newlines
+            while (*s_UartBufferCur == '\r' || *s_UartBufferCur == '\n')
+                s_UartBufferCur++;
+
+            p_eol = findNextEOL(s_UartBufferCur);
+            p_read += count;
+        }
+        else if (count <= 0)
+        {
+            /* read error encountered or EOF reached */
+            if(count == 0)
+            {
+                LOGD("atchannel: EOF reached");
+            }
+            else
+            {
+                LOGD("atchannel: read error %s", strerror(errno));
+            }
+            return NULL;
+        }
+    }
+
+    /* a full line in the buffer. Place a \0 over the \r and return */
+
+    ret = s_UartBufferCur;
+    *p_eol = '\0';
+    s_UartBufferCur = p_eol + 1; /* this will always be <= p_read,    */
+    /* and there will be a \0 at *p_read */
+
+    LOGD("URC< %s", ret);
+    return ret;
+}
+
+
+
+static void onReaderClosed()
+{
+    LOGD("onReaderClosed()");
+    if (s_onReaderClosed != NULL && s_readerClosed == 0)
+    {
+
+        pthread_mutex_lock(&s_commandmutex);
+
+        s_readerClosed = 1;
+
+        pthread_cond_signal(&s_commandcond);
+
+        pthread_mutex_unlock(&s_commandmutex);
+
+        s_onReaderClosed();
+    }
+}
+
+typedef struct
+{
+    int cid;
+    bool act;
+    bool waitting;
+} info_cgact_wait_t;
+extern info_cgact_wait_t cgact_wait;
+
+static void *readerLoop(void *arg)
+{
+    UNUSED(arg);
+    for (;;)
+    {
+        const char * line;
+
+        line = readline();
+
+        if (line == NULL)
+        {
+            break;
+        }
+
+        if(strStartsWith(line, "MBTK_AT_READY")) {
+            //handleUnsolicited(line);
+            continue;
+        } else if(strStartsWith(line, "CONNECT")) {
+            if(cgact_wait.waitting && cgact_wait.act) {
+                cgact_wait.waitting = false;
+            }
+        }
+
+        if(isSMSUnsolicited(line))
+        {
+            char *line1;
+            const char *line2;
+
+            // The scope of string returned by 'readline()' is valid only
+            // till next call to 'readline()' hence making a copy of line
+            // before calling readline again.
+            line1 = strdup(line);
+            line2 = readline();
+
+            if (line2 == NULL)
+            {
+                free(line1);
+                break;
+            }
+
+            if (s_unsolHandler != NULL)
+            {
+                s_unsolHandler (line1, line2);
+            }
+            free(line1);
+        }
+        else
+        {
+            processLine(line);
+        }
+    }
+
+    onReaderClosed();
+
+    return NULL;
+}
+
+static void *readerUrcLoop(void *arg)
+{
+    UNUSED(arg);
+    for (;;)
+    {
+        const char *line;
+
+        line = readlineUrc();
+
+        if (line == NULL)
+        {
+            break;
+        }
+
+        handleUnsolicited(line);
+    }
+
+    onReaderClosed();
+
+    return NULL;
+}
+
+
+/**
+ * Sends string s to the radio with a \r appended.
+ * Returns AT_ERROR_* on error, 0 on success
+ *
+ * This function exists because as of writing, android libc does not
+ * have buffered stdio.
+ */
+static int writeline (const char *s)
+{
+    size_t cur = 0;
+    size_t len = strlen(s);
+    ssize_t written;
+
+    if (s_at_fd < 0 || s_readerClosed > 0)
+    {
+        return AT_ERROR_CHANNEL_CLOSED;
+    }
+
+    LOGD("AT> %s", s);
+
+    AT_DUMP( ">> ", s, strlen(s) );
+
+    memset(s_curr_at, 0x0, AT_BUFF_MAX);
+    memcpy(s_curr_at, s, strlen(s));
+
+    /* the main string */
+    while (cur < len)
+    {
+        do
+        {
+            written = write (s_at_fd, s + cur, len - cur);
+        }
+        while (written < 0 && errno == EINTR);
+
+        if (written < 0)
+        {
+            return AT_ERROR_GENERIC;
+        }
+
+        cur += written;
+    }
+
+    /* the \r  */
+
+    do
+    {
+        written = write (s_at_fd, "\r", 1);
+    }
+    while ((written < 0 && errno == EINTR) || (written == 0));
+
+    if (written < 0)
+    {
+        return AT_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+static int writeCtrlZ (const char *s)
+{
+    size_t cur = 0;
+    size_t len = strlen(s);
+    ssize_t written;
+
+    if (s_at_fd < 0 || s_readerClosed > 0)
+    {
+        return AT_ERROR_CHANNEL_CLOSED;
+    }
+
+    LOGD("AT> %s^Z\n", s);
+
+    AT_DUMP( ">* ", s, strlen(s) );
+
+    /* the main string */
+    while (cur < len)
+    {
+        do
+        {
+            written = write (s_at_fd, s + cur, len - cur);
+        }
+        while (written < 0 && errno == EINTR);
+
+        if (written < 0)
+        {
+            return AT_ERROR_GENERIC;
+        }
+
+        cur += written;
+    }
+
+    /* the ^Z  */
+
+    do
+    {
+        written = write (s_at_fd, "\032", 1);
+    }
+    while ((written < 0 && errno == EINTR) || (written == 0));
+
+    if (written < 0)
+    {
+        return AT_ERROR_GENERIC;
+    }
+
+    return 0;
+}
+
+static void clearPendingCommand()
+{
+    if (sp_response != NULL)
+    {
+        at_response_free(sp_response);
+    }
+
+    sp_response = NULL;
+    s_responsePrefix = NULL;
+    s_smsPDU = NULL;
+}
+
+
+/**
+ * Starts AT handler on stream "fd'
+ * returns 0 on success, -1 on error
+ */
+int at_open(int at_fd, int uart_fd, ATUnsolHandler h)
+{
+    int ret;
+    pthread_attr_t attr;
+
+    s_at_fd = at_fd;
+    s_uart_fd = uart_fd;
+    s_unsolHandler = h;
+    s_readerClosed = 0;
+    s_responsePrefix = NULL;
+    s_smsPDU = NULL;
+    sp_response = NULL;
+
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
+    if (ret < 0)
+    {
+        LOGE("AT thread create fail.");
+        return -1;
+    }
+
+    pthread_t uart_tid_reader;
+    ret = pthread_create(&uart_tid_reader, &attr, readerUrcLoop, &attr);
+    if (ret < 0)
+    {
+        LOGE("Uart thread create fail.");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* FIXME is it ok to call this from the reader and the command thread? */
+void at_close()
+{
+    LOGD("at_close()");
+    if (s_at_fd >= 0)
+    {
+        close(s_at_fd);
+    }
+    if (s_uart_fd >= 0)
+    {
+        close(s_uart_fd);
+    }
+    s_at_fd = -1;
+    s_uart_fd = -1;
+
+    pthread_mutex_lock(&s_commandmutex);
+    s_readerClosed = 1;
+    pthread_cond_signal(&s_commandcond);
+    pthread_mutex_unlock(&s_commandmutex);
+    /* the reader thread should eventually die */
+
+    at_state = RIL_AT_STATE_CLOSED;
+}
+
+static ATResponse * at_response_new()
+{
+    return (ATResponse *) calloc(1, sizeof(ATResponse));
+}
+
+void at_response_free(ATResponse *p_response)
+{
+    ATLine *p_line;
+
+    if (p_response == NULL) return;
+
+    p_line = p_response->p_intermediates;
+
+    while (p_line != NULL)
+    {
+        ATLine *p_toFree;
+
+        p_toFree = p_line;
+        p_line = p_line->p_next;
+
+        free(p_toFree->line);
+        free(p_toFree);
+    }
+
+    free (p_response->finalResponse);
+    free (p_response);
+}
+
+/**
+ * The line reader places the intermediate responses in reverse order
+ * here we flip them back
+ */
+static void reverseIntermediates(ATResponse *p_response)
+{
+    ATLine *pcur,*pnext;
+
+    pcur = p_response->p_intermediates;
+    p_response->p_intermediates = NULL;
+
+    while (pcur != NULL)
+    {
+        pnext = pcur->p_next;
+        pcur->p_next = p_response->p_intermediates;
+        p_response->p_intermediates = pcur;
+        pcur = pnext;
+    }
+}
+
+static long long at_timeout_get(const char *at_command, bool *timeout_close)
+{
+    long long timeout = 0;
+    int i;
+    for(i = 0; i <  ARRAY_SIZE(at_timeout_list); i++)
+    {
+        if(!strncasecmp(at_command, at_timeout_list[i].at_command, strlen(at_timeout_list[i].at_command)))
+        {
+            timeout = at_timeout_list[i].timeout;
+            *timeout_close = at_timeout_list[i].timeout_close;
+            break;
+        }
+    }
+
+    return timeout;
+}
+
+/**
+ * Internal send_command implementation
+ * Doesn't lock or call the timeout callback
+ *
+ * timeoutMsec == 0 means infinite timeout
+ */
+static int at_send_command_full_nolock (const char *command, ATCommandType type,
+                                        const char *responsePrefix, const char *smspdu,
+                                        long long timeoutMsec, ATResponse **pp_outResponse)
+{
+    int err = 0;
+    bool tiemout_close = true;
+    struct timespec ts;
+    if(at_state == RIL_AT_STATE_READY)
+        at_state = RIL_AT_STATE_BUSY;
+
+    if(sp_response != NULL)
+    {
+        err = AT_ERROR_COMMAND_PENDING;
+        goto error;
+    }
+
+    err = writeline (command);
+
+    if (err < 0)
+    {
+        goto error;
+    }
+
+    s_type = type;
+    s_responsePrefix = responsePrefix;
+    s_smsPDU = smspdu;
+    sp_response = at_response_new();
+
+    if(timeoutMsec == 0)
+    {
+        timeoutMsec = at_timeout_get(command, &tiemout_close);
+    }
+
+    if (timeoutMsec != 0)
+    {
+        setTimespecRelative(&ts, timeoutMsec);
+    }
+
+    while (sp_response->finalResponse == NULL && s_readerClosed == 0)
+    {
+        //LOGD("AT wait time:%lld",timeoutMsec);
+        if (timeoutMsec != 0)
+        {
+            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
+        }
+        else
+        {
+            err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
+        }
+
+        //LOGD("AT continue:err - %d",err);
+        if (err == ETIMEDOUT)
+        {
+            if(tiemout_close)
+            {
+                err = AT_ERROR_TIMEOUT_CLOSE;
+            }
+            else
+            {
+                err = AT_ERROR_TIMEOUT;
+            }
+            goto error;
+        }
+    }
+
+    if (pp_outResponse == NULL)
+    {
+        at_response_free(sp_response);
+    }
+    else
+    {
+        /* line reader stores intermediate responses in reverse order */
+        reverseIntermediates(sp_response);
+        *pp_outResponse = sp_response;
+    }
+
+    sp_response = NULL;
+
+    if(s_readerClosed > 0)
+    {
+        err = AT_ERROR_CHANNEL_CLOSED;
+        goto error;
+    }
+
+    err = 0;
+error:
+    if(at_state == RIL_AT_STATE_BUSY)
+        at_state = RIL_AT_STATE_READY;
+    clearPendingCommand();
+
+    return err;
+}
+
+/**
+ * Internal send_command implementation
+ *
+ * timeoutMsec == 0 means infinite timeout
+ */
+static int at_send_command_full (const char *command, ATCommandType type,
+                                 const char *responsePrefix, const char *smspdu,
+                                 long long timeoutMsec, ATResponse **pp_outResponse)
+{
+    int err;
+
+    if (0 != pthread_equal(s_tid_reader, pthread_self()))
+    {
+        /* cannot be called from reader thread */
+        LOGE("cannot be called from reader thread.");
+        return AT_ERROR_INVALID_THREAD;
+    }
+
+    // Waitting for previous AT complete.
+    while(at_state == RIL_AT_STATE_BUSY)
+    {
+        usleep(10000);
+    }
+
+    pthread_mutex_lock(&s_commandmutex);
+
+    err = at_send_command_full_nolock(command, type,
+                                      responsePrefix, smspdu,
+                                      timeoutMsec, pp_outResponse);
+
+    pthread_mutex_unlock(&s_commandmutex);
+
+    if (err == AT_ERROR_TIMEOUT_CLOSE && s_onTimeout != NULL)
+    {
+        s_onTimeout();
+    }
+
+    return err;
+}
+
+
+/**
+ * Issue a single normal AT command with no intermediate response expected
+ *
+ * "command" should not include \r
+ * pp_outResponse can be NULL
+ *
+ * if non-NULL, the resulting ATResponse * must be eventually freed with
+ * at_response_free
+ */
+int at_send_command (const char *command, ATResponse **pp_outResponse)
+{
+    return at_send_command_full (command, NO_RESULT, NULL,
+                                 NULL, 0, pp_outResponse);
+}
+
+
+int at_send_command_singleline (const char *command,
+                                const char *responsePrefix,
+                                ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                NULL, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+int at_send_command_singleline_with_timeout (const char *command,
+        const char *responsePrefix,
+        ATResponse **pp_outResponse,long long timeoutMsec)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                NULL, timeoutMsec, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+
+int at_send_command_numeric (const char *command,
+                             ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, NUMERIC, NULL,
+                                NULL, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_sms (const char *command,
+                         const char *pdu,
+                         const char *responsePrefix,
+                         ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, SINGLELINE, responsePrefix,
+                                pdu, 0, pp_outResponse);
+
+    if (err == 0 && pp_outResponse != NULL
+        && (*pp_outResponse)->success > 0
+        && (*pp_outResponse)->p_intermediates == NULL
+       )
+    {
+        /* successful command must have an intermediate response */
+        at_response_free(*pp_outResponse);
+        *pp_outResponse = NULL;
+        return AT_ERROR_INVALID_RESPONSE;
+    }
+
+    return err;
+}
+
+
+int at_send_command_multiline (const char *command,
+                               const char *responsePrefix,
+                               ATResponse **pp_outResponse)
+{
+    int err;
+
+    err = at_send_command_full (command, MULTILINE, responsePrefix,
+                                NULL, 0, pp_outResponse);
+
+    return err;
+}
+
+
+/** This callback is invoked on the command thread */
+void at_set_on_timeout(void (*onTimeout)(void))
+{
+    s_onTimeout = onTimeout;
+}
+
+/**
+ *  This callback is invoked on the reader thread (like ATUnsolHandler)
+ *  when the input stream closes before you call at_close
+ *  (not when you call at_close())
+ *  You should still call at_close()
+ */
+
+void at_set_on_reader_closed(void (*onClose)(void))
+{
+    s_onReaderClosed = onClose;
+}
+
+
+/**
+ * Periodically issue an AT command and wait for a response.
+ * Used to ensure channel has start up and is active
+ */
+int at_handshake()
+{
+    int i;
+    int err = 0;
+
+    if (0 != pthread_equal(s_tid_reader, pthread_self()))
+    {
+        /* cannot be called from reader thread */
+        return AT_ERROR_INVALID_THREAD;
+    }
+    pthread_mutex_lock(&s_commandmutex);
+
+#if 0
+    for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++)
+    {
+        /* some stacks start with verbose off */
+        err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
+                                          NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
+
+        if (err == 0)
+        {
+            break;
+        }
+    }
+#else
+    err = at_send_command_full_nolock("ATE0Q0V1", NO_RESULT,
+                                          NULL, NULL, 0, NULL);
+#endif
+
+    if (err == 0)
+    {
+        /* pause for a bit to let the input buffer drain any unmatched OK's
+           (they will appear as extraneous unsolicited responses) */
+        sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
+    }
+
+    pthread_mutex_unlock(&s_commandmutex);
+
+
+    return err;
+}
+
+/**
+ * Returns error code from response
+ * Assumes AT+CMEE=1 (numeric) mode
+ */
+int at_get_cme_error(const ATResponse *p_response)
+{
+    int ret;
+    int err;
+    char *p_cur;
+
+    if (p_response->success > 0)
+    {
+        return CME_SUCCESS;
+    }
+
+    if (p_response->finalResponse == NULL
+        || !strStartsWith(p_response->finalResponse, "+CME ERROR:")
+       )
+    {
+        return CME_ERROR_NON_CME;
+    }
+
+    p_cur = p_response->finalResponse;
+    err = at_tok_start(&p_cur);
+
+    if (err < 0)
+    {
+        return CME_ERROR_NON_CME;
+    }
+
+    err = at_tok_nextint(&p_cur, &ret);
+
+    if (err < 0)
+    {
+        return CME_ERROR_NON_CME;
+    }
+
+    return ret;
+}
+
+mbtk_ril_at_state_enum at_state_get()
+{
+    return at_state;
+}
+
+void at_state_set(mbtk_ril_at_state_enum state)
+{
+    at_state = state;
+}
+
+bool at_rsp_check(ATResponse *p_response)
+{
+    if(!p_response || !p_response->success)
+        return false;
+
+    return true;
+}
+
+void unused_func()
+{
+    isFinalResponse(NULL);
+}
+
diff --git a/mbtk/mbtk_ril/src/main.c b/mbtk/mbtk_ril/src/main.c
new file mode 100755
index 0000000..2c5922d
--- /dev/null
+++ b/mbtk/mbtk_ril/src/main.c
@@ -0,0 +1,1877 @@
+#include <stdio.h>

+#include <stdlib.h>

+#include <unistd.h>

+#include <sys/socket.h>

+#include <errno.h>

+#include <fcntl.h>

+#include <string.h>

+#include <netinet/in.h>

+#include <arpa/inet.h>

+#include <linux/un.h>

+#include <linux/netlink.h>

+#include <cutils/properties.h>

+#include <time.h>

+#include <sys/time.h>

+

+//#include "cploader.h"

+#include "mbtk_log.h"

+#include "mbtk_ifc.h"

+#include "mbtk_type.h"

+#include "atchannel.h"

+#include "at_tok.h"

+#include "mbtk_utils.h"

+#include "mbtk_task.h"

+#include "mbtk_info.h"

+#include "mbtk_ntp.h"

+#include "mbtk_net_control.h"

+#include "info_data.h"

+

+#define TEMP_FAILURE_RETRY(exp) ({         \

+    typeof (exp) _rc;                      \

+    do {                                   \

+        _rc = (exp);                       \

+    } while (_rc == -1 && errno == EINTR); \

+    _rc; })

+

+#define BUFFER_SIZE 2048

+#define UEVENT_USIM_DEV "/devices/virtual/usim_event/usim0"

+#define MBTK_BOOT_SERVER_READY "/etc/init.d/mbtk_boot_server_ready"

+

+struct cooling_device

+{

+    const char *name;

+    const char *action;

+    const char *path;

+    const char *event;

+    const char *subsystem;

+};

+static pthread_t uevnet_task_id;

+extern net_info_t net_info;

+extern mbtK_cell_pack_info_t cell_info;

+extern info_cgact_wait_t cgact_wait;

+extern bool at_process;

+

+void setRadioPower(int isOn);

+int urc_msg_distribute(bool async_process, info_urc_msg_id_enum msg, void *data, int data_len);

+int mbtk_signal_log(char *data);

+

+/* Called on command thread */

+static void onATTimeout()

+{

+    LOGI("AT channel timeout; closing\n");

+    at_close();

+}

+

+/* Called on command or reader thread */

+static void onATReaderClosed()

+{

+    LOGI("AT channel closed\n");

+    at_close();

+}

+

+//int req_time_set(int type, char *time, int *cme_err);

+static int metis_strptime(char *str_time)

+{

+    struct tm stm;

+    char dateTime[30];

+    struct timeval tv;

+    if(strptime(str_time, "%Y-%m-%d %H:%M:%S",&stm) != NULL)

+    {

+        time_t _t = mktime(&stm);

+        tv.tv_sec = _t;

+        if(settimeofday(&tv, NULL)) {

+            LOG("Set time fail:%d", errno);

+            return -1;

+        } else {

+            LOG("Set time to %s.", str_time);

+            return 0;

+        }

+    } else {

+        LOG("Set time fail.");

+        return -1;

+    }

+}

+

+static void* ntp_pthread_run(void* arg)

+{

+    // Waitting for network connected.

+    while(mbtk_net_state_get() == MBTK_NET_STATE_OFF) {

+        sleep(1);

+    }

+    LOG("Network is connected.");

+

+    char time_type[10];

+    while(1){

+        memset(time_type, 0, 10);

+        property_get("persist.mbtk.time_type", time_type, "0");

+    	if(atoi(time_type) == MBTK_TIME_TYPE_NTP) // NTP time

+    	{

+            char time_str[100] = {0};

+            time_t time = 0;

+            while((time = (time_t)mbtk_at_systime()) == 0) {

+                usleep(100000);

+            }

+            struct tm *tm_t;

+            tm_t = localtime(&time);

+            strftime(time_str,128,"%F %T",tm_t);

+

+            // NTP time

+            metis_strptime(time_str);

+    	} else {

+            break;

+    	}

+

+        sleep(64); // Sleep 64s.

+    }

+    return NULL;

+}

+

+static void ntp_thread_start()

+{

+    pthread_t ntp_pid;

+    pthread_attr_t thread_attr;

+    pthread_attr_init(&thread_attr);

+    if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))

+    {

+        LOG("pthread_attr_setdetachstate() fail.");

+        return;

+    }

+

+    if(pthread_create(&ntp_pid, &thread_attr, ntp_pthread_run, NULL))

+    {

+        LOG("pthread_create() fail.");

+    }

+}

+

+bool sms_cmt = false;

+mbtk_sim_card_info sim_info_reg={0};

+static void onUnsolicited(const char *s, const char *sms_pdu)

+{

+    LOGV("URC : %s", s);

+    // MBTK_AT_READY

+    if (strStartsWith(s, "MBTK_AT_READY")) // AT ready.

+    {

+

+    }

+#if 0

+    else if(strStartsWith(s, "*SIMDETEC:")) // *SIMDETEC:1,SIM

+    {

+        const char* ptr = strstr(s, ",");

+        if(ptr)

+        {

+            ptr++; // Jump ','

+            if(memcmp(ptr, "SIM", 3) == 0)

+                net_info.sim_state = MBTK_SIM_STATE_READY;

+            else

+                net_info.sim_state = MBTK_SIM_STATE_ABSENT;

+        }

+    }

+#endif

+    else if(strStartsWith(s, "*RADIOPOWER:")) // "*RADIOPOWER: 1"

+    {

+        const char* ptr = s + strlen("*RADIOPOWER:");

+        while(*ptr != '\0' && *ptr == ' ' )

+        {

+            ptr++;

+        }

+

+        uint8 state;

+        if(*ptr == '1') {

+            //net_info.radio_state = MBTK_RADIO_STATE_ON;

+            // mbtk_radio_ready_cb();

+            state = (uint8)1;

+        } else {

+            //net_info.radio_state = MBTK_RADIO_STATE_OFF;

+            state = (uint8)0;

+        }

+        urc_msg_distribute(true, INFO_URC_MSG_RADIO_STATE, &state, sizeof(uint8));

+    }

+    // "CONNECT"

+    else if(strStartsWith(s, "CONNECT"))

+    {

+        if(cgact_wait.waitting && cgact_wait.act) {

+            cgact_wait.waitting = false;

+        }

+

+        uint8 data_pdp;

+        data_pdp = 1;       //

+        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+    }

+    // +CGEV:

+    // +CGEV: NW DEACT <cid>,<cid>

+    // +CGEV: ME DEACT <cid>,<cid>

+    // +CGEV: NW PDN DEACT <cid>

+    // +CGEV: ME PDN DEACT <cid>

+    // +CGEV: NW DETACH

+    // +CGEV: ME DETACH

+    //

+    // +CGEV: NW ACT <cid>,<cid>

+    // +CGEV: ME ACT <cid>,<cid>

+    // +CGEV: EPS PDN ACT <cid>

+    // +CGEV: ME PDN ACT <cid>,<reason>,<cid>

+    // +CGEV: ME PDN ACT <cid>,<reason>

+    // +CGEV: NW PDN ACT <cid>

+    // +CGEV: EPS ACT <cid>

+    // +CGEV: NW MODIFY <cid>,<reason>

+    // +CGEV: NW REATTACH

+    else if(strStartsWith(s, "+CGEV:"))

+    {

+        if(at_process) {

+            if(cgact_wait.act) {

+                if(strStartsWith(s, "+CGEV: ME PDN ACT ")) { // +CGEV: ME PDN ACT 15,4

+                    if(cgact_wait.cid == atoi(s + 18)) {

+                        cgact_wait.waitting = false;

+                    }

+

+                    uint8 data_pdp;

+                    char* tmp_s = memdup(s + 18,strlen(s + 18));

+                    char* free_ptr = tmp_s;

+                    char *line = tmp_s;

+                    int tmp_int;

+                    if (at_tok_start(&line) < 0)

+                    {

+                        goto at_PDP_CREG_EXIT;

+                    }

+                    if (at_tok_nextint(&line, &tmp_int) < 0)

+                    {

+                        goto at_PDP_CREG_EXIT;

+                    }

+                    if (at_tok_nextint(&line, &tmp_int) < 0)

+                    {

+                        goto at_PDP_CREG_EXIT;

+                    }

+                    data_pdp = tmp_int;

+at_PDP_CREG_EXIT:

+                    free(free_ptr);

+

+                    //data_pdp = (uint8)atoi(s + 20);  //reason

+                    if(cgact_wait.cid >= 1 && cgact_wait.cid < 8)

+                    {

+                        if(data_pdp == 0)

+                        {

+                            data_pdp = 25;

+                            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                            //data_pdp = cgact_wait.cid + 200;

+                        }

+                        else if(data_pdp == 1)

+                        {

+                            data_pdp = 26;

+                            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                        }

+                        else if(data_pdp == 2)

+                        {

+                            data_pdp = 27;

+                            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                        }

+                        else if(data_pdp == 3)

+                        {

+                            data_pdp = 27;

+                            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                        }

+                        else

+                        {

+

+                        }

+                        if(cgact_wait.cid != 0)

+                        {

+                            data_pdp = cgact_wait.cid + 200;

+                            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                        }

+                    }

+                } else if(strStartsWith(s, "+CGEV: NW MODIFY ")) { // +CGEV: NW MODIFY 1,4

+                    if(cgact_wait.cid == atoi(s + 17)) {

+                        cgact_wait.waitting = false;

+                    }

+                }

+            } else {

+                if(strStartsWith(s, "+CGEV: ME PDN DEACT ")) { // +CGEV: ME PDN DEACT 1

+                    if(cgact_wait.cid == atoi(s + 20)) {

+                        cgact_wait.waitting = false;

+                    }

+                    uint8 data_pdp;

+                    data_pdp = 0;       //

+                    urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    if(cgact_wait.cid != 0)

+                    {

+                        data_pdp = cgact_wait.cid + 100;

+                        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    }

+                }

+            }

+        } else {

+            // apn_state_set

+

+            // +CGEV: NW PDN DEACT <cid>

+

+            // +CGEV: EPS PDN ACT 1

+            // +CGEV: ME PDN ACT 8,1

+

+            // +CGEV: ME PDN ACT 2,4

+            uint8 data[2] = {0xFF};

+            if(strStartsWith(s, "+CGEV: NW PDN DEACT ")) { // +CGEV: NW PDN DEACT <cid>

+                //apn_state_set(atoi(s + 20), false);

+                data[0] = (uint8)0;

+                data[1] = (uint8)atoi(s + 20);

+

+                uint8 data_pdp;

+                data_pdp = 0;       //

+                urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                data_pdp = cgact_wait.cid + 100;

+                urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+            } else if(strStartsWith(s, "+CGEV: EPS PDN ACT ")) { // +CGEV: EPS PDN ACT <cid>

+                //apn_state_set(atoi(s + 19), true);

+                data[0] = (uint8)1;

+                data[1] = (uint8)atoi(s + 19);

+            } else if(strStartsWith(s, "+CGEV: ME PDN ACT ")) { // +CGEV: ME PDN ACT <cid>,1

+                //apn_state_set(atoi(s + 18), true);

+                data[0] = (uint8)1;

+                data[1] = (uint8)atoi(s + 18);

+

+                uint8 data_pdp;

+                char* tmp_s = memdup(s + 18,strlen(s + 18));

+                char* free_ptr = tmp_s;

+                char *line = tmp_s;

+                int tmp_int;

+                if (at_tok_start(&line) < 0)

+                {

+                    goto PDP_CREG_EXIT;

+                }

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto PDP_CREG_EXIT;

+                }

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto PDP_CREG_EXIT;

+                }

+                data_pdp = tmp_int;

+PDP_CREG_EXIT:

+                free(free_ptr);

+                //data_pdp = (uint8)atoi(s + 20);  //reason

+                if(data[1] >= 1 && data[1] < 8)

+                {

+                    if(data_pdp == 0)

+                    {

+                        data_pdp = 25;

+                        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    }

+                    else if(data_pdp == 1)

+                    {

+                        data_pdp = 26;

+                        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    }

+                    else if(data_pdp == 2)

+                    {

+                        data_pdp = 27;

+                        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    }

+                    else if(data_pdp == 3)

+                    {

+                        data_pdp = 27;

+                        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    }

+                    else

+                    {

+

+                    }

+                    if(cgact_wait.cid != 0)

+                    {

+                        data_pdp = cgact_wait.cid + 200;

+                        urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+                    }

+                }

+            } else {

+                LOGI("No process : %s", s);

+            }

+

+            urc_msg_distribute(true, INFO_URC_MSG_CGEV, data, sizeof(uint8) * 2);

+        }

+    }

+    // +CREG: 1, "8010", "000060a5", 0, 2, 0

+    // +CREG: 1, "8330", "06447347", 7, 2, 0

+    // +CEREG: 1, "8330", "06447347", 7

+    // $CREG: 1, "8330", "06447347", 7,"0d4", 2, 0

+    // $CREG: 1, "8010", "000060a7", 0,, 2, 0

+    // +CGREG: 1

+    else if(strStartsWith(s, "+CGREG:")     // GMS/WCDMA data registed.

+         || strStartsWith(s, "+CEREG:"))    // LTE data registed.

+    {

+        char* tmp_s = s + 7;

+        while(*tmp_s && *tmp_s == ' ')

+            tmp_s++;

+        uint8 data = (uint8)atoi(tmp_s); // Reg State.

+

+        urc_msg_distribute(true, INFO_URC_MSG_NET_PS_REG_STATE, &data, sizeof(uint8));

+    }

+    // +CREG: 1, "8010", "000060a5", 0, 2, 0

+    // +CREG: 1, "8330", "06447347", 7, 2, 0

+    // +CREG: 0

+    else if(strStartsWith(s, "+CREG:"))     // GMS/WCDMA/LTE CS registed.

+    {

+        uint8 data[3];

+        data[0] = (uint8)MBTK_NET_CS_STATE;

+        char* tmp_s = memdup(s,strlen(s));

+        char* free_ptr = tmp_s;

+        char *line = tmp_s;

+        int tmp_int;

+        char *tmp_str;

+        if (at_tok_start(&line) < 0)

+        {

+            goto CREG_EXIT;

+        }

+        if (at_tok_nextint(&line, &tmp_int) < 0)

+        {

+            goto CREG_EXIT;

+        }

+        data[1] = (uint8)tmp_int; // Reg State.

+        if (data[1])

+        {

+            if (at_tok_nextstr(&line, &tmp_str) < 0)

+            {

+                goto CREG_EXIT;

+            }

+            if (at_tok_nextstr(&line, &tmp_str) < 0)

+            {

+                goto CREG_EXIT;

+            }

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto CREG_EXIT;

+            }

+            data[2] = (uint8)tmp_int; // AcT

+        } else {

+            data[2] = (uint8)0xFF; // AcT

+        }

+        if(data[1] == 5)

+        {

+            uint8 data_pdp;

+            data_pdp = 5;       //

+            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+        }

+        urc_msg_distribute(false, INFO_URC_MSG_NET_CS_REG_STATE, data, sizeof(data));

+CREG_EXIT:

+        free(free_ptr);

+    }

+    // +CLCC: 1, 1, 6, 0, 0, "18981911691", 129, "",, 0

+    else if(strStartsWith(s, "+CLCC:"))

+    {

+        mbtk_call_info_t reg;

+        reg.call_wait = MBTK_CLCC;

+        char* tmp_s = memdup(s,strlen(s));

+        char* free_ptr = tmp_s;

+        char *line = tmp_s;

+        int tmp_int;

+        char *tmp_str;

+        int err;

+

+        err = at_tok_start(&line);

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        err = at_tok_nextint(&line, &tmp_int); // dir1

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        reg.dir1 = (uint8)tmp_int;

+        err = at_tok_nextint(&line, &tmp_int);// dir

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        reg.dir = (uint8)tmp_int;

+        err = at_tok_nextint(&line, &tmp_int);// state

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        reg.state = (uint8)tmp_int;

+        err = at_tok_nextint(&line, &tmp_int);// mode

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        reg.mode = (uint8)tmp_int;

+        err = at_tok_nextint(&line, &tmp_int);// mpty

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        reg.mpty = (uint8)tmp_int;

+        err = at_tok_nextstr(&line, &tmp_str); // phone_number

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+

+        memset(reg.phone_number,0,sizeof(reg.phone_number));

+        memcpy(reg.phone_number, tmp_str, strlen(tmp_str));

+        err = at_tok_nextint(&line, &tmp_int);// tpye

+        if (err < 0)

+        {

+            goto CLCC_EXIT;

+        }

+        reg.type = (uint8)tmp_int;

+

+        urc_msg_distribute(false, INFO_URC_MSG_CALL_STATE, &reg, sizeof(mbtk_call_info_t));

+CLCC_EXIT:

+        free(free_ptr);

+    }

+    // +CPAS: 4

+    else if(strStartsWith(s, "+CPAS:"))

+    {

+        mbtk_call_info_t reg;

+        reg.call_wait = 0;

+        char* tmp_s = memdup(s,strlen(s));

+        char* free_ptr = tmp_s;

+        char *line = tmp_s;

+        int tmp_int;

+        int err;

+

+        memset(&reg,0,sizeof(reg));

+

+        err = at_tok_start(&line);

+        if (err < 0)

+        {

+            goto CPAS_EXIT;

+        }

+        err = at_tok_nextint(&line, &tmp_int);

+        if (err < 0)

+        {

+            goto CPAS_EXIT;

+        }

+        reg.pas = (uint8)tmp_int;

+        reg.call_wait = MBTK_CPAS;

+        urc_msg_distribute(false, INFO_URC_MSG_CALL_STATE, &reg, sizeof(mbtk_call_info_t));

+CPAS_EXIT:

+        free(free_ptr);

+    }

+    // +CALLDISCONNECT: 1

+    else if(strStartsWith(s, "+CALLDISCONNECT:"))

+    {

+        mbtk_call_info_t reg;

+        reg.call_wait = 0;

+        char* tmp_s = memdup(s,strlen(s));

+        char* free_ptr = tmp_s;

+        char *line = tmp_s;

+        int tmp_int;

+        int err;

+

+        memset(&reg,0,sizeof(reg));

+

+        err = at_tok_start(&line);

+        if (err < 0)

+        {

+            goto CALLDISCONNECTED_EXIT;

+        }

+        err = at_tok_nextint(&line, &tmp_int);

+        if (err < 0)

+        {

+            goto CALLDISCONNECTED_EXIT;

+        }

+        reg.disconnected_id = tmp_int;

+        reg.call_wait = MBTK_DISCONNECTED;

+        urc_msg_distribute(false, INFO_URC_MSG_CALL_STATE, &reg, sizeof(mbtk_call_info_t));

+

+CALLDISCONNECTED_EXIT:

+        free(free_ptr);

+    }

+    // *SIMDETEC:1,SIM

+    else if(strStartsWith(s, "*SIMDETEC:"))

+    {

+        sim_info_reg.sim = -1;

+        if(strStartsWith(s, "*SIMDETEC:1,NOS"))

+            sim_info_reg.sim = 0;

+        else if(strStartsWith(s, "*SIMDETEC:1,SIM"))

+            sim_info_reg.sim = 1;

+        if(sim_info_reg.sim == 0)

+        {

+            uint8 data_pdp;

+            data_pdp = 11;       //

+            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+        }

+        urc_msg_distribute(false, INFO_URC_MSG_SIM_STATE, &sim_info_reg, sizeof(mbtk_sim_card_info));

+    }

+    // *EUICC:1

+/*0: SIM

+1: USIM

+2: TEST SIM

+3: TEST USIM

+4: UNKNOWN

+Note: *EUICC:

+*/

+    else if(strStartsWith(s, "*EUICC:"))

+    {

+        sim_info_reg.sim_card_type = -1;

+        if(strStartsWith(s, "*EUICC: 0"))

+            sim_info_reg.sim_card_type = 1;

+        else if(strStartsWith(s, "*EUICC: 1"))

+            sim_info_reg.sim_card_type = 2;

+        else if(strStartsWith(s, "*EUICC: 2"))

+            sim_info_reg.sim_card_type = 1;

+        else if(strStartsWith(s, "*EUICC: 3"))

+            sim_info_reg.sim_card_type = 2;

+        else if(strStartsWith(s, "*EUICC: 4"))

+            sim_info_reg.sim_card_type = 0;

+        urc_msg_distribute(false, INFO_URC_MSG_SIM_STATE, &sim_info_reg, sizeof(mbtk_sim_card_info));

+    }

+    // +CPIN: SIM PIN

+    else if(strStartsWith(s, "+CPIN:"))

+    {

+        sim_info_reg.sim = -1;

+        if(strStartsWith(s, "+CPIN: READY"))

+            sim_info_reg.sim = 1;

+        else if(strStartsWith(s, "+CPIN: SIM PIN"))

+            sim_info_reg.sim = 2;

+        else if(strStartsWith(s, "+CPIN: SIM PUK"))

+            sim_info_reg.sim = 3;

+        else if(strStartsWith(s, "+CPIN: PH-SIMLOCK PIN"))

+            sim_info_reg.sim = 4;

+        else if(strStartsWith(s, "+CPIN: PH-SIMLOCK PUK"))

+            sim_info_reg.sim = 5;

+        else if(strStartsWith(s, "+CPIN: PH-FSIM PIN"))

+            sim_info_reg.sim = 6;

+        else if(strStartsWith(s, "+CPIN: PH-FSIM PUK"))

+            sim_info_reg.sim = 7;

+        else if(strStartsWith(s, "+CPIN: SIM PIN2"))

+            sim_info_reg.sim = 8;

+        else if(strStartsWith(s, "+CPIN: SIM PUK2"))

+            sim_info_reg.sim = 9;

+        else if(strStartsWith(s, "+CPIN: PH-NET PIN"))

+            sim_info_reg.sim = 10;

+        else if(strStartsWith(s, "+CPIN: PH-NET PUK"))

+            sim_info_reg.sim = 11;

+        else if(strStartsWith(s, "+CPIN: PH-NETSUB PINMT"))

+            sim_info_reg.sim = 12;

+        else if(strStartsWith(s, "+CPIN: PH-NETSUB PUK"))

+            sim_info_reg.sim = 13;

+        else if(strStartsWith(s, "+CPIN: PH-SP PIN"))

+            sim_info_reg.sim = 14;

+        else if(strStartsWith(s, "+CPIN: PH-SP PUK"))

+            sim_info_reg.sim = 15;

+        else if(strStartsWith(s, "+CPIN: PH-CORP PIN"))

+            sim_info_reg.sim = 16;

+        else if(strStartsWith(s, "+CPIN: PH-CORP PUK"))

+            sim_info_reg.sim = 17;

+        else if(strStartsWith(s, "+CPIN: SIM REMOVED"))

+            sim_info_reg.sim = 18;

+        else

+            sim_info_reg.sim = 20;

+

+        if(sim_info_reg.sim == 18)

+        {

+            uint8 data_pdp;

+            data_pdp = 11;       //

+            urc_msg_distribute(false, INFO_URC_MSG_PDP_STATE, &data_pdp, sizeof(uint8));

+        }

+

+        urc_msg_distribute(false, INFO_URC_MSG_SIM_STATE, &sim_info_reg, sizeof(mbtk_sim_card_info));

+    }

+    // +CMT: ,23

+    // 0891683108200855F6240D91688189911196F10000221130717445230331D90C

+    else if(strStartsWith(s, "+CMT:") || sms_cmt)

+    {

+        if(!sms_cmt){

+            sms_cmt = true;

+        }else{

+            sms_cmt = false;

+        }

+        printf("+CMT() sms_cmt:%d, s:%s, len:%d\n",sms_cmt,  s, strlen(s));

+        urc_msg_distribute(false, INFO_URC_MSG_SMS_STATE, s, strlen(s));

+    }

+#if 0

+    // LTE data registed.

+    // +CEREG: 1, "8330", "06447347", 7

+    else if(strStartsWith(s, "+CEREG:"))

+    {

+        char* tmp_s = memdup(s,strlen(s));

+        char* free_ptr = tmp_s;

+        char *line = tmp_s;

+        int tmp_int;

+        char *tmp_str;

+        if (at_tok_start(&line) < 0)

+        {

+            goto CREG_EXIT;

+        }

+        if (at_tok_nextint(&line, &tmp_int) < 0)

+        {

+            goto CREG_EXIT;

+        }

+        uint8 data = (uint8)tmp_int; // Reg State.

+

+        urc_msg_distribute(INFO_URC_MSG_NET_REG_STATE, &data, sizeof(uint8));

+CREG_EXIT:

+        free(free_ptr);

+    }

+#endif

+    /*

+    // <mcc>, <length of mnc>, <mnc>, <tac>, <PCI>, <dlEuarfcn>, < ulEuarfcn >, <band>, <dlBandwidth>,

+    // <rsrp>,<rsrq>, <sinr>,

+    // errcModeState,emmState,serviceState,IsSingleEmmRejectCause,EMMRejectCause,mmeGroupId,mmeCode,mTmsi,

+    // cellId,subFrameAssignType,specialSubframePatterns,transMode

+    // mainRsrp,diversityRsrp,mainRsrq,diversityRsrq,rssi,cqi,pathLoss,tb0DlTpt,tb1DlTpt,tb0DlPeakTpt,tb1DlPeakTpt,tb0UlPeakTpt,

+    // tb1UlPeakTpt,dlThroughPut,dlPeakThroughPut,averDlPRB,averCQITb0,averCQITb1,rankIndex,grantTotal,ulThroughPut,ulPeakThroughPut,currPuschTxPower,averUlPRB,

+    // dlBer, ulBer,

+    // diversitySinr, diversityRssi

+    +EEMLTESVC: 1120, 2, 0, 33584, 430, 40936, 40936, 41, 20,

+    0, 0, 0,

+    1, 10, 0, 1, 0, 1059, 78, 3959566565,

+    105149248, 2, 7, 7,

+    0, 0, 0, 0, 0, 0, 0, 1190919, 0, 0, 0, 16779777,

+    0, 5112867, 3959566565, 2, 0, 0, 0, 0, 0, 0, 0, 0,

+    0, 0,

+    7, 44

+    */

+    else if(strStartsWith(s, "+EEMLTESVC:"))   // LTE Server Cell

+    {

+        // tac, PCI, dlEuarfcn, ulEuarfcn, band

+        if(cell_info.running) {

+            int tmp_int;

+            int i = 0;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value6 = (uint32)tmp_int;    //mcc

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value7 = (uint32)tmp_int;    //mnc

+            /*

+            // Jump 2 integer.

+            i = 0;

+            while(i < 2) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMLTESVC_EXIT;

+                }

+                i++;

+            }

+            */

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;    //tac

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;    //pci

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;    //dl arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value4 = (uint32)tmp_int;    //ul arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value5 = (uint32)tmp_int;    //band

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value8 = (uint32)tmp_int;    //cid

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTESVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value9 = (uint32)tmp_int;    //rsrp

+

+            for(i =0; i < 10; i++)

+            {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMLTESVC_EXIT;

+                }

+            }

+			cell_info.cell[cell_info.cell_num].value10 = (uint32)tmp_int;   //cell identiy

+

+            cell_info.cell_num++;

+

+EEMLTESVC_EXIT:

+            free(free_ptr);

+        }

+    }

+    /*

+    // index,phyCellId,euArfcn,rsrp,rsrq

+    +EEMLTEINTER: 0, 65535, 38950, 0, 0

+    */

+    else if(strStartsWith(s, "+EEMLTEINTER:") || strStartsWith(s, "+EEMLTEINTRA:")) // LTE ÒìÆµ/Í¬ÆµÐ¡Çø

+    {

+        // phyCellId,euArfcn,rsrp,rsrq

+        if(cell_info.running) {

+            int tmp_int;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMLTEINTER_EXIT;

+            }

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTEINTER_EXIT;

+            }

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int > 503)

+            {

+                goto EEMLTEINTER_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTEINTER_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTEINTER_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;

+            LOG("cell line : %s", line);

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMLTEINTER_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value4 = (uint32)tmp_int;

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                LOG("cell tmp_int : %d", tmp_int);

+                goto EEMLTEINTER_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value5 = (uint32)tmp_int;

+            LOG("cell value5 : %d", cell_info.cell[cell_info.cell_num].value5);

+            cell_info.cell_num++;

+EEMLTEINTER_EXIT:

+            free(free_ptr);

+        }

+    }

+    // Do nothing

+    else if(strStartsWith(s, "+EEMLTEINTERRAT:")) // LTE RATÐ¡ÇøÐÅÏ¢

+    {

+        if(cell_info.running) {

+

+        }

+    }

+    // WCDMA

+    /*

+    // Mode, sCMeasPresent, sCParamPresent, ueOpStatusPresent,

+

+    // if sCMeasPresent == 1

+    // cpichRSCP, utraRssi, cpichEcN0, sQual, sRxLev, txPower,

+    // endif

+

+    // if sCParamPresent == 1

+    // rac, nom, mcc, mnc_len, mnc, lac, ci,

+    // uraId, psc, arfcn, t3212, t3312, hcsUsed, attDetAllowed,

+    // csDrxCycleLen, psDrxCycleLen, utranDrxCycleLen, HSDPASupport, HSUPASupport,

+    // endif

+

+    // if ueOpStatusPresent == 1

+    // rrcState, numLinks, srncId, sRnti,

+    // algPresent, cipherAlg, cipherOn, algPresent, cipherAlg, cipherOn,

+    // HSDPAActive, HSUPAActive, MccLastRegisteredNetwork, MncLastRegisteredNetwork, TMSI, PTMSI, IsSingleMmRejectCause, IsSingleGmmRejectCause,

+    // MMRejectCause, GMMRejectCause, mmState, gmmState, gprsReadyState, readyTimerValueInSecs, NumActivePDPContext, ULThroughput, DLThroughput,

+    // serviceStatus, pmmState, LAU_status, LAU_count, RAU_status, RAU_count

+    // endif

+    //

+    +EEMUMTSSVC: 3, 1, 1, 1,

+    -80, 27, -6, -18, -115, -32768,

+    1, 1, 1120, 2, 1, 61697, 168432821,

+    15, 24, 10763, 0, 0, 0, 0,

+    128, 128, 65535, 0, 0,

+    2, 255, 65535, 4294967295,

+    0, 0, 0, 0, 0, 0,

+    0, 0, 0, 0, 0, 0, 1, 1,

+    28672, 28672, 0, 0, 0, 0, 0, 0, 0,

+    0, 0, 0, 0, 0, 0

+    */

+    else if(strStartsWith(s, "+EEMUMTSSVC:")) // WCDMA Server Cell

+    {

+        // lac, ci, arfcn

+        if(cell_info.running) {

+            int tmp_int;

+            int i = 0;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            // Jump 12 integer.

+            i = 0;

+            while(i < 12) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMUMTSSVC_EXIT;

+                }

+                i++;

+            }

+            // mcc

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value4= (uint32)tmp_int;

+            // mnc

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value5= (uint32)tmp_int;

+            // lac

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;

+            // ci

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;

+

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            // cpi

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value6= (uint32)tmp_int;

+            /*

+            // Jump 2 integer.

+            i = 0;

+            while(i < 2) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMUMTSSVC_EXIT;

+                }

+                i++;

+            }

+            */

+            // arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                goto EEMUMTSSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;

+

+            cell_info.cell_num++;

+EEMUMTSSVC_EXIT:

+            free(free_ptr);

+        }

+    }

+    /*

+    // index, cpichRSCP, utraRssi, cpichEcN0, sQual, sRxLev ,mcc, mnc, lac, ci, arfcn, psc

+    +EEMUMTSINTRA: 0, -32768, -1, -32768, -18, -115, 0, 0, 65534, 1, 10763, 32

+    */

+    else if(strStartsWith(s, "+EEMUMTSINTRA:")) // WCDMAÁÙ½üÐ¡Çø

+    {

+        // lac, ci, arfcn

+        if(cell_info.running) {

+            int tmp_int;

+            int i = 0;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMUMTSINTRA_EXIT;

+            }

+            // Jump 8 integer.

+            i = 0;

+            while(i < 8) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMUMTSINTRA_EXIT;

+                }

+                i++;

+            }

+

+            // lac

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMUMTSINTRA_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;

+

+            // ci

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMUMTSINTRA_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;

+

+            // arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMUMTSINTRA_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;

+

+            cell_info.cell_num++;

+EEMUMTSINTRA_EXIT:

+            free(free_ptr);

+        }

+    }

+    /*

+    // index,gsmRssi,rxLev,C1,C2,mcc,mnc,lac,ci,arfcn,bsic

+    +EEMUMTSINTERRAT: 0, -32768, -107, -1, -1, 0, 0, 65534, 0, 117, 36

+    */

+    else if(strStartsWith(s, "+EEMUMTSINTERRAT:")) // WCDMA RATÐ¡ÇøÐÅÏ¢

+    {

+        // lac, ci, arfcn

+        if(cell_info.running) {

+            int tmp_int;

+            int i = 0;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMUMTSINTERRAT_EXIT;

+            }

+            // Jump 7 integer.

+            i = 0;

+            while(i < 7) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMUMTSINTERRAT_EXIT;

+                }

+                i++;

+            }

+

+            // lac

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMUMTSINTERRAT_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;

+

+            // ci

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMUMTSINTERRAT_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;

+

+            // arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMUMTSINTERRAT_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;

+

+            cell_info.cell_num++;

+EEMUMTSINTERRAT_EXIT:

+            free(free_ptr);

+        }

+    }

+    // GSM

+    // +EEMGINFOBASIC: 2

+    // Do nothing.

+    else if(strStartsWith(s, "+EEMGINFOBASIC:")) // Basic information in GSM

+        // 0: ME in Idle mode   1: ME in Dedicated mode   2: ME in PS PTM mode

+    {

+        if(cell_info.running) {

+

+        }

+    }

+    /*

+    // mcc, mnc_len, mnc, lac, ci, nom, nco,

+    // bsic, C1, C2, TA, TxPwr,

+    // RxSig, RxSigFull, RxSigSub, RxQualFull, RxQualSub,

+    // ARFCB_tch, hopping_chnl, chnl_type, TS, PacketIdle, rac, arfcn,

+    // bs_pa_mfrms, C31, C32, t3212, t3312, pbcch_support, EDGE_support,

+    // ncc_permitted, rl_timeout, ho_count, ho_succ, chnl_access_count, chnl_access_succ_count,

+    // gsmBand,channelMode

+    +EEMGINFOSVC: 1120, 2, 0, 32784, 24741, 2, 0,

+    63, 36, 146, 1, 7,

+    46, 42, 42, 7, 0,

+    53, 0, 8, 0, 1, 6, 53,

+    2, 0, 146, 42, 54, 0, 1,

+    1, 32, 0, 0, 0, 0,

+    0, 0

+    */

+    else if(strStartsWith(s, "+EEMGINFOSVC:")) // GSM Server Cell

+    {

+        // lac, ci, arfcn, bsic

+        LOG("+EEMGINFOSVC: 1= %d\n.",cell_info.running);

+        if(cell_info.running) {

+            int tmp_int;

+            int i = 0;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+

+            // mcc

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value5 = (uint32)tmp_int;

+

+            //mnc_len

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            // mnc

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int <= 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value6 = (uint32)tmp_int;

+

+            /*

+            // Jump 3 integer.

+            i = 0;

+            while(i < 3) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMGINFOSVC_EXIT;

+                }

+                i++;

+            }

+            */

+            // lac

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;

+

+            // ci

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;

+

+            // Jump 2 integer.

+            i = 0;

+            while(i < 2) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMGINFOSVC_EXIT;

+                }

+                i++;

+            }

+

+            // bsic

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value4 = (uint32)tmp_int;

+

+            // Jump 15 integer.

+            i = 0;

+            while(i < 15) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    goto EEMGINFOSVC_EXIT;

+                }

+                i++;

+            }

+

+            // arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                goto EEMGINFOSVC_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;

+

+            cell_info.cell_num++;

+EEMGINFOSVC_EXIT:

+            free(free_ptr);

+        }

+    }

+    /*

+    // PS_attached, attach_type, service_type, tx_power, c_value,

+    // ul_ts, dl_ts, ul_cs, dl_cs, ul_modulation, dl_modulation,

+    // gmsk_cv_bep, 8psk_cv_bep, gmsk_mean_bep, 8psk_mean_bep, EDGE_bep_period, single_gmm_rej_cause

+    // pdp_active_num, mac_mode, network_control, network_mode, EDGE_slq_measurement_mode, edge_status

+    +EEMGINFOPS: 1, 255, 0, 0, 0,

+    0, 0, 268435501, 1, 0, 0,

+    4, 0, 96, 0, 0, 0,

+    0, 0, 0, 65535, 0, 13350

+    */

+    // Do nothing.

+    else if(strStartsWith(s, "+EEMGINFOPS:")) // PSÐÅÏ¢

+    {

+        if(cell_info.running) {

+

+        }

+    }

+    else if(strStartsWith(s, "+EEMGINFONC:")) // cell

+    {

+        if(cell_info.running) {

+            int tmp_int;

+            int i = 0;

+            char* tmp_s = memdup(s,strlen(s));

+            char* free_ptr = tmp_s;

+            char *line = tmp_s;

+            if (at_tok_start(&line) < 0)

+            {

+                goto EEMGINFOPS_EXIT;

+            }

+

+            // nc_num

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 1= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            // mcc

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 2= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value5 = (uint32)tmp_int;

+

+            // mnc

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 3= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value6 = (uint32)tmp_int;

+

+            // lac

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 4= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value1 = (uint32)tmp_int;

+

+            // rac

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 5= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+

+            // ci

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 6= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value2 = (uint32)tmp_int;

+

+            // rx_lv

+            if (at_tok_nextint(&line, &tmp_int) < 0)

+            {

+                LOG("cell_info.running 7= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+

+            // bsic

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 8= %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value4 = (uint32)tmp_int;

+

+            // Jump 2 integer.

+            i = 0;

+            while(i < 2) {

+                if (at_tok_nextint(&line, &tmp_int) < 0)

+                {

+                    LOG("cell_info.running 9= %d\n.",cell_info.running);

+                    goto EEMGINFOPS_EXIT;

+                }

+                i++;

+            }

+

+            // arfcn

+            if (at_tok_nextint(&line, &tmp_int) < 0 || tmp_int < 0 || tmp_int >= 65536)

+            {

+                LOG("cell_info.running 10 = %d\n.",cell_info.running);

+                goto EEMGINFOPS_EXIT;

+            }

+            cell_info.cell[cell_info.cell_num].value3 = (uint32)tmp_int;

+

+            cell_info.cell_num++;

+EEMGINFOPS_EXIT:

+            free(free_ptr);

+        }

+    }

+    else if(strStartsWith(s, "+ZGIPDNS:")) // +ZGIPDNS: 1,"IPV4V6","10.156.239.245","10.156.239.246","223.87.253.100","223.87.253.253","fe80:0000:0000:0000:0001:0001:9b8c:7c0c","fe80::1:1:9b8c:7c0d","2409:8062:2000:2::1","2409:8062:2000:2::2"

+    {

+

+    }

+    else

+    {

+        LOGV("Unknown URC : %s", s);

+    }

+}

+

+static int openSocket(const char* sockname)

+{

+    int sock = socket(AF_UNIX, SOCK_STREAM, 0);

+    if (sock < 0)

+    {

+        LOGE("Error create socket: %s\n", strerror(errno));

+        return -1;

+    }

+    struct sockaddr_un addr;

+    memset(&addr, 0, sizeof(addr));

+    addr.sun_family = AF_UNIX;

+    strncpy(addr.sun_path, sockname, sizeof(addr.sun_path));

+    while (TEMP_FAILURE_RETRY(connect(sock,(const struct sockaddr*)&addr, sizeof(addr))) != 0)

+    {

+        LOGE("Error connect to socket %s: %s, try again", sockname, strerror(errno));

+        sleep(1);

+    }

+

+#if 0

+    int sk_flags = fcntl(sock, F_GETFL, 0);

+    fcntl(sock, F_SETFL, sk_flags | O_NONBLOCK);

+#endif

+

+    return sock;

+}

+

+static void ril_get_cgpaddr_ip_process()

+{

+    int err, skip;

+    ATResponse *p_response = NULL;

+    char *line;

+    char *ipv4 = NULL, *ipv6 = NULL;

+    err = at_send_command_singleline("AT+CGPADDR", "+CGPADDR:", &p_response);

+    if ((err < 0) || (p_response == NULL) || (p_response->success == 0))

+    {

+        LOGE("+CGPADDR exec error.");

+        goto error;

+    }

+

+    // +CGPADDR: 1, "10.51.59.229", "254.128.0.0.0.0.0.0.0.1.0.0.111.176.63.99"

+    // +CGPADDR: 1, "10.124.139.131"

+    line = p_response->p_intermediates->line;

+    err = at_tok_start(&line);

+    if (err < 0)

+    {

+        goto error;

+    }

+

+    err = at_tok_nextint(&line, &skip);

+    if (err < 0)

+    {

+        goto error;

+    }

+

+    if (!at_tok_hasmore(&line))

+    {

+        goto error;

+    }

+

+    err = at_tok_nextstr(&line, &ipv4);

+    if (err < 0)

+    {

+        LOGE("Get IPv4 fail.");

+        goto error;

+    }

+

+    if (at_tok_hasmore(&line))

+    {

+        err = at_tok_nextstr(&line, &ipv6);

+        if (err < 0)

+        {

+            LOGE("Get IPv6 fail.");

+            goto error;

+        }

+    }

+    else

+    {

+        LOGD("No IPv6 Found.");

+    }

+

+    if(ipv6)

+    {

+        LOGD("IPv6 : %s", ipv6);

+    }

+

+    if(ipv4)

+    {

+        LOGD("IPv4 : %s", ipv4);

+

+//        ril_net_dev_config("ccinet0", ipv4, NULL);

+    }

+error:

+    at_response_free(p_response);

+}

+

+static void sim_state_change(bool plug_in) {

+    if(plug_in) {

+        // If radio on,must off in the first.

+        if(net_info.radio_state == MBTK_RADIO_STATE_ON) {

+            setRadioPower(0);

+        }

+        setRadioPower(1);

+    } else {

+        setRadioPower(0);

+    }

+}

+

+static int open_uevent_socket()

+{

+    struct sockaddr_nl addr;

+    int sz = 64*1024;

+    int s = 0;

+

+    memset(&addr, 0, sizeof(addr));

+    addr.nl_family = AF_NETLINK;

+    addr.nl_pid = getpid();

+    addr.nl_groups = 0xffffffff;

+

+    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

+    if (s < 0)

+    {

+        LOGE("socket() fail.[%d]", errno);

+        return -1;

+    }

+

+    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));

+

+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)

+    {

+        close(s);

+        return -1;

+    }

+

+    return s;

+}

+

+static void parse_uevent(const char *msg, int msg_len, struct cooling_device *cdev)

+{

+    // change@/devices/virtual/usim_event/usim0\0

+    // ACTION=change\0

+    // DEVPATH=/devices/virtual/usim_event/usim0\0

+    // SUBSYSTEM=usim_event\0

+    // USIM_NAME=usim0\0

+    // USIM_EVENT=plugout\0

+    // SEQNUM=704

+    int i = 0;

+    while (i < msg_len)

+    {

+        if(*(msg + i) == '\0')

+        {

+            i++;

+            continue;

+        }

+        if (!strncmp(msg + i, "USIM_NAME=", 10))

+        {

+            i += 10;

+            cdev->name = msg + i;

+            i += strlen(msg + i);

+        }

+        else if (!strncmp(msg + i, "ACTION=", 7))

+        {

+            i += 7;

+            cdev->action = msg + i;

+            i += strlen(msg + i);

+        }

+        else if (!strncmp(msg + i, "DEVPATH=", 8))

+        {

+            i += 8;

+            cdev->path = msg + i;

+            i += strlen(msg + i);

+        }

+        else if (!strncmp(msg + i, "USIM_EVENT=", 11))

+        {

+            i += 11;

+            cdev->event = msg + i;

+            i += strlen(msg + i);

+        }

+        else if (!strncmp(msg + i, "SUBSYSTEM=", 10))

+        {

+            i += 10;

+            cdev->subsystem = msg + i;

+            i += strlen(msg + i);

+        }

+        else

+        {

+            i++;

+        }

+    }

+

+    if(!strncmp(cdev->path, UEVENT_USIM_DEV, sizeof(UEVENT_USIM_DEV))

+       && !strncmp(cdev->action, "change", 5))

+    {

+        LOGD("event { name=%s, action=%s, path=%s, subsystem=%s, event=%s}",

+             cdev->name,    cdev->action, cdev->path, cdev->subsystem, cdev->event);

+        if(!strcmp(cdev->event, "plugout"))

+        {

+            sim_state_change(FALSE);

+        }

+        else if(!strcmp(cdev->event, "plugin"))

+        {

+            sim_state_change(TRUE);

+        }

+        else

+        {

+            LOGE("usim evnet error!");

+        }

+    }

+}

+

+static void* uevnet_run(void *payload)

+{

+    int socket_fd = -1;

+    char msg[BUFFER_SIZE+2];

+    int n;

+

+    socket_fd = open_uevent_socket();

+    if(socket_fd > 0)

+    {

+        while(1)

+        {

+            if((n = recv(socket_fd, msg, BUFFER_SIZE, 0)) > 0)

+            {

+                struct cooling_device cdev;

+                memset(&cdev, 0x0, sizeof(cdev));

+

+                if(n == BUFFER_SIZE)

+                    continue;

+                msg[n] = '\0';

+                // change@/devices/virtual/usim_event/usim0\0ACTION=change\0DEVPATH=/devices/virtual/usim_event/usim0\0SUBSYSTEM=usim_event\0USIM_NAME=usim0\0USIM_EVENT=plugout\0SEQNUM=704

+                log_hex("UEVENT", msg, n);

+                parse_uevent(msg, n, &cdev);

+            }

+            else

+            {

+                LOGE("recv msg error.");

+            }

+        }

+    }

+

+    LOGD("UEVENT Thread exit!!!");

+    return NULL;

+}

+

+int uevent_main()

+{

+    mbtk_task_info task;

+    task.task_id = &uevnet_task_id;

+    task.thread_run = uevnet_run;

+    task.args = NULL;

+    return mbtk_task_start(&task);

+}

+

+/*

+int ril_main()

+{

+    return mbtk_task_queue_start(&ril_task, ril_main_run);

+}

+*/

+

+int mbtk_info_server_start();

+int InProduction_Mode(void);

+void server_ready_set(void);

+

+
+/*
+ *Get mtdblock which name is ASR_FLAG
+ *return path if found, else return NULL
+ */
+static int asrFlagPathGet(char *asr_flag_path)

+{
+	char buf[128];
+	unsigned char find = 0;
+	FILE *fd = fopen("/proc/mtd", "r");

+	if (fd == NULL) {
+		LOGE("Open MTD failed!");

+		return -1;

+	}
+
+	memset(buf, '\0', 128);
+	while (fgets(buf, 128, fd) != NULL) {
+		if(strstr(buf, "asr_flag")) {
+			char *p = strstr(buf, "mtd");
+			if(p)
+			{
+				int bln;
+				sscanf(p, "mtd%d", &bln);
+				sprintf(asr_flag_path, "/dev/mtdblock%d", bln);
+				find = 1;
+				break;
+			}
+		}
+		memset(buf, '\0', 128);
+	}
+
+	fclose(fd);
+	return ((find == 1) ? 0 : -1);

+}
+
+static int readFromMTD(const char *path, unsigned int offset, void *buf, int size)

+{
+	int ret, fd;
+	if (!path)
+		return -1;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		LOGE("readFromMTD open error,%d", errno);

+		return -1;
+	}
+
+	ret = lseek(fd, offset, SEEK_SET);
+	if (ret < 0) {
+		close(fd);
+		LOGE("readFromMTD lseek error,%d", errno);

+		return -1;
+	}
+	ret = read(fd, buf, size);
+	if (ret < 0) {
+		close(fd);
+		LOGE("readFromMTD read error,%d", errno);

+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+static int writeToMTD(const char *path, unsigned int offset, void *buf, int size)

+{
+	int ret, fd;
+
+	if (!path)
+		return -1;
+
+	fd = open(path, O_RDWR | O_SYNC);
+	if (fd < 0)
+		return -1;
+
+	ret = lseek(fd, offset, SEEK_SET);
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+	ret = write(fd, buf, size);
+	if (ret < 0) {
+		LOGE("writetomtd:write error:%d", errno);

+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}

+

+static void fota_result_check()

+{

+#if 0

+    ASR_flag tag;

+    char asr_flag_path[30] = {0};

+    if(asrFlagPathGet(asr_flag_path)) {

+        LOGE("getAsrFlagPath() fail.");

+        return;

+    }

+

+    if(readFromMTD(asr_flag_path, ASR_FLAG_OFFSET, &tag, sizeof(tag)) < 0)

+    {

+        LOGE("Get FOTA result fail.");

+    }

+    else

+    {

+        LOGD("FOTA result : %d, %d", tag.fota_result[0], tag.fota_result[1]);

+        tag.fota_result[0] = 0;

+        tag.fota_result[1] = 0;

+        if(writeToMTD(asr_flag_path, ASR_FLAG_OFFSET, &tag, sizeof(tag)) < 0)

+        {

+            LOGE("FOTA result update fail.");

+        } else {

+            LOGD("FOTA result update success.");

+        }

+    }

+#endif

+}

+

+static void mbtk_server_ready()

+{

+    // /etc/init.d/mbtk_boot_server_ready

+    if(access(MBTK_BOOT_SERVER_READY , X_OK) == 0) {

+        system(MBTK_BOOT_SERVER_READY);

+    } else {

+        LOGE("%s can not exec.", MBTK_BOOT_SERVER_READY);

+    }

+}

+

+#if 1

+int main(int argc, char *argv[])

+{

+    mbtk_log_init("radio", "MBTK_RIL");

+    LOGI("mbtk_ril start.");

+

+    if(InProduction_Mode()) {

+        LOGI("Is Production Mode, will exit...");

+        exit(0);

+    }

+

+    int at_sock = openSocket("/tmp/atcmd_at");

+    if(at_sock < 0)

+    {

+        LOGE("Open AT Socket Fail[%d].", errno);

+        return -1;

+    }

+    int uart_sock = openSocket("/tmp/atcmd_urc");

+    if(uart_sock < 0)

+    {

+        LOGE("Open Uart Socket Fail[%d].", errno);

+        return -1;

+    }

+

+    at_set_on_reader_closed(onATReaderClosed);

+    at_set_on_timeout(onATTimeout);

+

+    if(at_open(at_sock, uart_sock, onUnsolicited))

+    {

+        LOGE("Start AT thread fail.");

+        return -1;

+    }

+

+#if 1

+    if(at_handshake())

+    {

+        LOGE("AT handshake fail.");

+        return -1;

+    }

+#endif

+

+    LOGD("AT OK.");

+

+    if(mbtk_info_server_start())

+    {

+        LOGE("mbtk_info_server_start() fail.");

+        return -1;

+    }

+

+#if 0

+    if(uevent_main())

+    {

+        LOGE("Start uevent thread fail.");

+        return -1;

+    }

+#endif

+

+    char time_type[10];

+    memset(time_type, 0, 10);

+    property_get("persist.mbtk.time_type", time_type, "0");

+    if(atoi(time_type) == MBTK_TIME_TYPE_NTP) { // NTP time

+        LOG("Start NTP thread.");

+        ntp_thread_start();

+    }

+

+    fota_result_check();

+

+    mbtk_server_ready();

+

+    server_ready_set();//Set the server readiness state

+    while(1)

+    {

+        sleep(24 * 60 * 60);

+    }

+

+    LOGD("!!!mbtk_ril exit!!!");

+    return 0;

+}

+

+#else

+int main()

+{

+    char buff[BUFFER_SIZE + 1] = {0};

+    if(!mbtk_at("AT+CFUN=1", buff, BUFFER_SIZE))

+    {

+        LOGD("+CFUN RSP:%s", buff);

+        while(1)

+        {

+            sleep(1);

+            memset(buff, 0x0, BUFFER_SIZE + 1);

+            if(!mbtk_at("AT+CGPADDR", buff, BUFFER_SIZE))

+            {

+                LOGD("+CGPADDR RSP:%s", buff);

+                if(strstr(buff, "+CGPADDR:"))

+                {

+                    // +CGPADDR: 1, "10.99.223.168", "254.128.0.0.0.0.0.0.0.1.0.0.117.9.250.59"

+                    //

+                    // OK

+                    char *ip_start = NULL;

+                    char *ip_end = NULL;

+                    char ipv4[50] = {0};

+                    ip_start = strstr(buff,"\"");

+                    if(ip_start)

+                        ip_end = strstr(ip_start + 1, "\"");

+                    if(ip_start && ip_end && ip_end - ip_start - 1 > 0)

+                    {

+                        memcpy(ipv4, ip_start + 1, ip_end - ip_start - 1);

+                        LOGD("IP : %s", ipv4);

+                        if(!mbtk_ifc_open())

+                        {

+                            in_addr_t addr;

+                            inet_aton(ipv4,(struct in_addr *)&addr);

+                            LOGD("IP : %s -> %x", ipv4, addr);

+                            if(!mbtk_ifc_set_addr("ccinet0", addr, 0))

+                            {

+                                mbtk_ifc_up("ccinet0");

+                            }

+

+                            mbtk_ifc_close();

+                        }

+

+                        system("route add default dev ccinet0");

+

+                        LOGD("Set IP success.");

+                    }

+                    else

+                    {

+                        LOGD("Get IP fail.");

+                    }

+

+                    break;

+                }

+            }

+        }

+    }

+

+    return 0;

+}

+#endif

diff --git a/mbtk/mbtk_ril/src/mbtk_call.c b/mbtk/mbtk_ril/src/mbtk_call.c
new file mode 100755
index 0000000..94c835f
--- /dev/null
+++ b/mbtk/mbtk_ril/src/mbtk_call.c
@@ -0,0 +1,570 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_type.h"
+#include "mbtk_info.h"
+#include "atchannel.h"
+#include "at_tok.h"
+#include "mbtk_utils.h"
+#include "info_data.h"
+
+void pack_rsp_send(int fd, int info_id, const void* data, int data_len);
+
+
+/*
+ATDXXXXXXX;
+OK
+
+*/
+static int req_call_start(char *phont_number, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    char *tmp_str = NULL;
+    char cmd[100] = {0};
+    sprintf(cmd, "ATD%s;", phont_number);
+    int err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+
+AT+CHLD=2
+OK
+
+*/
+static int req_answer_call(int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command("AT+CHLD=2", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+ATH
+OK
+
+*/
+static int req_hangup_call(int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command("ATH", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CHLD=1x
+OK
+
+*/
+static int req_hangup_a_call(int phone_id, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[100] = {0};
+    sprintf(cmd, "AT+CHLD=1%d", phone_id);
+    int err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CHLD=0
+OK
+
+*/
+static int req_hangup_waiting_or_background_call(int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command("AT+CHLD=0", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CHLD=1
+OK
+
+*/
+static int req_hangup_foreground_resume_background_call(int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command("AT+CHLD=1", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CLCC
+OK
+
+*/
+static int req_waitin_call(mbtk_call_info_t *reg, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    char *tmp_str = NULL;
+    
+    int err = at_send_command_multiline("AT+CLCC", "+CLCC:", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    if(response->success == 1 && !response->p_intermediates)
+    {
+        reg->call_wait = 0;
+        goto exit;
+    }
+
+    reg->call_wait = 1;
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int); // dir1
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->dir1 = (uint8)tmp_int;
+    err = at_tok_nextint(&line, &tmp_int);// dir
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->dir = (uint8)tmp_int;
+    err = at_tok_nextint(&line, &tmp_int);// state
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->state = (uint8)tmp_int;
+    err = at_tok_nextint(&line, &tmp_int);// mode
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->mode = (uint8)tmp_int;
+    err = at_tok_nextint(&line, &tmp_int);// mpty
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->mpty = (uint8)tmp_int;
+    err = at_tok_nextstr(&line, &tmp_str); // phone_number
+    if (err < 0)
+    {
+        goto exit;
+    }
+    memcpy(reg->phone_number, tmp_str, strlen(tmp_str));
+    err = at_tok_nextint(&line, &tmp_int);// tpye
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->type = (uint8)tmp_int;
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CMUT?
++CMUT: 0
+
+OK
+*/
+static int req_mute_get(int *state, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    int err = at_send_command_singleline("AT+CMUT?", "+CMUT:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    *state = tmp_int;
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CMUT=0;
+OK
+
+*/
+static int req_mute_set(int state, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[100] = {0};
+    sprintf(cmd, "AT+CMUT=%d", state);
+    LOG("Set the mute command is = %s.\n", cmd);
+    int err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+VTS=0; //0, 1, ..., 9, A, B, C, D, *, #
+OK
+
+*/
+static int req_dtmf_set(mbtk_call_dtmf_info_t *state, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[100] = {0};
+    sprintf(cmd, "AT+VTS=%c,%d", state->character, state->duration);
+    LOG("Set the DTMF command is = %s.\n", cmd);
+    int err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+//void net_list_free(void *data);
+// Return MBTK_INFO_ERR_SUCCESS,will call pack_error_send() to send RSP.
+// Otherwise, do not call pack_error_send().
+mbtk_info_err_enum call_pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack)
+{
+    mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+    int cme_err = MBTK_INFO_ERR_CME_NON;
+    switch(pack->info_id)
+    {
+        case MBTK_INFO_ID_CALL_START_REQ: // <string> phone number
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set
+            {
+                char *pn = (char*)(pack->data);
+                if(req_call_start(pn, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("ATD fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_START_RSP, NULL, 0);
+                }
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_ANSWER_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+               if(req_answer_call(&cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Answer call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_ANSWER_RSP, NULL, 0);
+                }
+            }
+            else     // Set
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Answer call fail. NO DATA\n");
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_HANGUP_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                if(req_hangup_call(&cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Hang up call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_HANGUP_RSP, NULL, 0);
+                }
+            }
+            else     // Set
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Hang up call fail.");
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_HANGUP_A_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Hang up a call fail.");
+            }
+            else
+            {
+                uint8 phone_id = *(pack->data);
+                if(req_hangup_a_call(phone_id, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Hang up a call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_HANGUP_A_RSP, NULL, 0);
+                }
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_HANGUP_B_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                if(req_hangup_waiting_or_background_call(&cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Hang up waiting_or_background call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_HANGUP_B_RSP, NULL, 0);
+                }
+            }
+            else
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Hang up waiting_or_background call fail.");
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_HANGUP_C_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                if(req_hangup_foreground_resume_background_call(&cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Hang up waiting_or_background call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_HANGUP_C_RSP, NULL, 0);
+                }
+            }
+            else
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Hang up waiting_or_background call fail.");
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_WAITIN_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                mbtk_call_info_t reg;
+                memset(&reg, 0, sizeof(mbtk_call_info_t));
+                if(req_waitin_call(&reg, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Wait incoing call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_WAITIN_RSP, &reg, sizeof(mbtk_call_info_t));
+                }
+            }
+            else     // Set
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Wait incoing call fail.");
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_MUTE_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                int state;
+                if(req_mute_get(&state, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Get mute state fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_MUTE_RSP, &state, sizeof(uint8));
+                }
+            }
+            else     // Set mute state.
+            {
+                uint8 on = *(pack->data);
+                if(pack->data_len != sizeof(uint8) || (on != 0 && on != 1))
+                {
+                    err = MBTK_INFO_ERR_REQ_PARAMETER;
+                    LOG("Set mute parameter error.");
+                    break;
+                }
+
+                if(req_mute_set(on, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set mute state fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_MUTE_RSP, NULL, 0);
+                }
+            }
+            break;
+        }
+        case MBTK_INFO_ID_CALL_DTMF_REQ:
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+                LOG("Wait incoing call fail.");
+            }
+            else     // Set
+            {
+                mbtk_call_dtmf_info_t *reg = (mbtk_call_dtmf_info_t *)pack->data;
+                if(req_dtmf_set(reg, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Wait incoing call fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_CALL_DTMF_RSP, NULL, 0);
+                }
+            }
+            break;
+
+
+        default:
+        {
+            err = MBTK_INFO_ERR_REQ_UNKNOWN;
+            LOG("Unknown request : %s", id2str(pack->info_id));
+            break;
+        }
+    }
+
+    return err;
+}
+
diff --git a/mbtk/mbtk_ril/src/mbtk_info_server.c b/mbtk/mbtk_ril/src/mbtk_info_server.c
new file mode 100755
index 0000000..7c92094
--- /dev/null
+++ b/mbtk/mbtk_ril/src/mbtk_info_server.c
@@ -0,0 +1,6251 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <cutils/properties.h>
+
+#include "mbtk_type.h"
+#include "mbtk_info.h"
+#include "mbtk_queue.h"
+#include "atchannel.h"
+#include "at_tok.h"
+#include "mbtk_utils.h"
+#include "mbtk_ifc.h"
+#include "info_data.h"
+
+static int sock_listen_fd = -1;
+static int epoll_fd = -1;
+static list_node_t *sock_client_list = NULL;
+static mbtk_queue_node_t info_queue;
+static pthread_cond_t info_cond;
+static pthread_mutex_t info_mutex;
+static mbtk_queue_node_t urc_queue;
+static pthread_cond_t urc_cond;
+static pthread_mutex_t urc_mutex;
+
+static mbtk_band_info_t band_support;
+net_info_t net_info;
+mbtK_cell_pack_info_t cell_info;
+info_cgact_wait_t cgact_wait;
+static int cid_active[MBTK_APN_CID_MAX + 1] = {0};
+bool at_process = false;
+//mbtk wyq for data_call_ex add start
+//  |2----7|
+//"00000000"+'\0'
+static char cid_bootconn[MBTK_APN_CID_MAX + 2] = {0};
+#define DATA_CALL_BOOTCONN_FD 0x5f6f7f8f
+//mbtk wyq for data_call_ex add end
+
+//mbtk wyq for server_ready_status add start
+static char server_ready_status = 0;
+//mbtk wyq for server_ready_status add end
+
+static void sock_cli_free_func(void *data)
+{
+    if (data)
+    {
+        sock_client_info_t *info = (sock_client_info_t*) data;
+        LOG("Free Socket client[fd = %d].", info->fd);
+        free(info);
+    }
+}
+
+static void cli_close(sock_client_info_t* client)
+{
+    struct epoll_event ev;
+    memset(&ev,0,sizeof(struct epoll_event));
+    ev.data.fd = client->fd;
+    ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client->fd, &ev);
+
+    close(client->fd);
+
+    if(list_remove(sock_client_list, client))
+    {
+        sock_cli_free_func(client);
+    }
+}
+
+static void pack_error_send(int fd, int info_id, int err)
+{
+    mbtk_info_pack_t* pack = mbtk_info_pack_creat(info_id);
+    if(pack)
+    {
+        pack->info_err = (uint16)err;
+        mbtk_info_pack_send(fd, pack);
+        mbtk_info_pack_free(&pack);
+    }
+    else
+    {
+        LOG("mbtk_info_pack_creat() fail.");
+    }
+}
+
+void pack_rsp_send(int fd, int info_id, const void* data, int data_len)
+{
+    mbtk_info_pack_t* pack = mbtk_info_pack_creat(info_id);
+    if(pack)
+    {
+        pack->info_err = (uint16)MBTK_INFO_ERR_SUCCESS;
+        if(data != NULL && data_len > 0)
+        {
+            //mbtk_info_pack_data_set(pack, data, data_len);
+            pack->data_len = (uint16)data_len;
+            pack->data = (const uint8*)data;
+        }
+        mbtk_info_pack_send(fd, pack);
+        mbtk_info_pack_free(&pack);
+    }
+    else
+    {
+        LOG("mbtk_info_pack_creat() fail.");
+    }
+}
+
+static int apn_prop_set(mbtk_apn_info_t *apn)
+{
+    char prop_name[20] = {0};
+    char prop_data[300] = {0};
+    sprintf(prop_name, "%s_%d",MBTK_APN_PROP,apn->cid);
+    snprintf(prop_data, 300, "%d,%s,%s,%s,%s", apn->ip_type, apn->apn,
+        str_empty(apn->user) ? "NULL" : apn->user,
+        str_empty(apn->pass) ? "NULL" : apn->pass,
+        str_empty(apn->auth) ? "NULL" : apn->auth);
+
+    return property_set(prop_name, prop_data);
+}
+
+/*
+AT*BAND=?
+*BAND:(0-18),79,147,482,524503
+
+
+OK
+
+AT*BAND=15,78,147,482,134742231
+
+
+*/
+static void band_support_get()
+{
+    // Support band has get.
+    if(band_support.net_pref != 0xFF) {
+        return;
+    }
+
+#if 1
+    // 79,147,482,524503
+    band_support.gsm_band = (uint16)79;
+    band_support.umts_band = (uint16)147;
+    band_support.tdlte_band = (uint32)482;
+#if MBTK_LTE_B28_SUPPORT
+    band_support.fddlte_band = (uint32)134742231;
+#else
+    band_support.fddlte_band = (uint32)524503;
+#endif
+    band_support.net_pref = (uint8)0;
+#else
+    ATResponse *response = NULL;
+    int tmp_int;
+    char *tmp_str;
+    int err = at_send_command_singleline("AT*BAND=?", "*BAND:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates)
+        goto exit;
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_str);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band_support.gsm_band = (uint16)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band_support.umts_band = (uint16)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band_support.tdlte_band = (uint32)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band_support.fddlte_band = (uint32)tmp_int;
+    band_support.net_pref = (uint8)0;
+exit:
+    at_response_free(response);
+#endif
+}
+
+static int parseRegistrationState(char *str, int *items, int **response)
+{
+    int err;
+    char *line = str, *p;
+    int *resp = NULL;
+    int skip;
+    int commas;
+
+    LOGD("parseRegistrationState. Parsing: %s",str);
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    /* Ok you have to be careful here
+     * The solicited version of the CREG response is
+     * +CREG: n, stat, [lac, cid]
+     * and the unsolicited version is
+     * +CREG: stat, [lac, cid]
+     * The <n> parameter is basically "is unsolicited creg on?"
+     * which it should always be
+     *
+     * Now we should normally get the solicited version here,
+     * but the unsolicited version could have snuck in
+     * so we have to handle both
+     *
+     * Also since the LAC and CID are only reported when registered,
+     * we can have 1, 2, 3, or 4 arguments here
+     *
+     * finally, a +CGREG: answer may have a fifth value that corresponds
+     * to the network type, as in;
+     *
+     *   +CGREG: n, stat [,lac, cid [,networkType]]
+     */
+
+    /* count number of commas */
+    commas = 0;
+    for (p = line ; *p != '\0' ; p++)
+    {
+        if (*p == ',') commas++;
+    }
+
+    resp = (int *)calloc(commas + 1, sizeof(int));
+    if (!resp) goto error;
+    switch (commas)
+    {
+        case 0: /* +CREG: <stat> */
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            //resp[1] = -1;
+            //resp[2] = -1;
+            break;
+
+        case 1: /* +CREG: <n>, <stat> */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            resp[1] = -1;
+            //resp[2] = -1;
+            if (err < 0) goto error;
+            break;
+
+        case 2: /* +CREG: <stat>, <lac>, <cid> */
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+            break;
+        case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
+            /* +CEREG: 1,"8330","06447340",7 */
+#if 0
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+#else
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[3]);
+            if (err < 0) goto error;
+#endif
+            break;
+        /* special case for CGREG, there is a fourth parameter
+         * that is the network type (unknown/gprs/edge/umts)
+         */
+        case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
+            /* +CEREG: 2,1,"8330","06447340",7 */
+            err = at_tok_nextint(&line, &skip);
+            if (err < 0) goto error;
+            err = at_tok_nextint(&line, &resp[0]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[1]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[2]);
+            if (err < 0) goto error;
+            err = at_tok_nexthexint(&line, &resp[3]);
+            if (err < 0) goto error;
+            break;
+        default:
+            goto error;
+    }
+    /*
+        if(commas > 1) {
+            s_lac = resp[1];
+            s_cid = resp[2];
+        }*/
+    if (response)
+        *response = resp;
+    if (items)
+        *items = commas + 1;
+    return 0;
+error:
+    free(resp);
+    return -1;
+}
+
+/*
+0: minimum functionality
+1: full functionality
+3: disable phone receive RF circuits.
+4: disable phone both transmit and receive RF circuits
+5: disable SIM
+6: turn off full secondary receive.
+-1: fail
+*/
+static int isRadioOn()
+{
+    ATResponse *p_response = NULL;
+    int err;
+    char *line;
+    int ret;
+
+    err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
+
+    if (err < 0 || p_response->success == 0 || !p_response->p_intermediates)
+    {
+        // assume radio is off
+        goto error;
+    }
+
+    line = p_response->p_intermediates->line;
+
+    err = at_tok_start(&line);
+    if (err < 0) goto error;
+
+    err = at_tok_nextint(&line, &ret);
+    if (err < 0) goto error;
+
+    at_response_free(p_response);
+
+    if(ret == 1) {
+        net_info.radio_state = MBTK_RADIO_STATE_ON;
+    } else {
+        net_info.radio_state = MBTK_RADIO_STATE_OFF;
+    }
+
+    return ret;
+
+error:
+
+    at_response_free(p_response);
+    return -1;
+}
+
+/** Returns SIM_NOT_READY on error */
+static mbtk_sim_state_enum getSIMStatus()
+{
+    ATResponse *p_response = NULL;
+    int err;
+    mbtk_sim_state_enum ret;
+    char *cpinLine;
+    char *cpinResult;
+
+    err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
+
+    if (err < 0 || p_response->success == 0 || !p_response->p_intermediates)
+    {
+        ret = MBTK_SIM_NOT_READY;
+        goto done;
+    }
+
+    switch (at_get_cme_error(p_response))
+    {
+        case CME_SUCCESS:
+            break;
+
+        case CME_SIM_NOT_INSERTED:
+            ret = MBTK_SIM_ABSENT;
+            goto done;
+
+        default:
+            ret = MBTK_SIM_NOT_READY;
+            goto done;
+    }
+
+    /* CPIN? has succeeded, now look at the result */
+
+    cpinLine = p_response->p_intermediates->line;
+    err = at_tok_start (&cpinLine);
+
+    if (err < 0)
+    {
+        ret = MBTK_SIM_NOT_READY;
+        goto done;
+    }
+
+    err = at_tok_nextstr(&cpinLine, &cpinResult);
+
+    if (err < 0)
+    {
+        ret = MBTK_SIM_NOT_READY;
+        goto done;
+    }
+
+    if (0 == strcmp (cpinResult, "SIM PIN"))
+    {
+        ret = MBTK_SIM_PIN;
+        goto done;
+    }
+    else if (0 == strcmp (cpinResult, "SIM PUK"))
+    {
+        ret = MBTK_SIM_PUK;
+        goto done;
+    }
+    else if (0 == strcmp (cpinResult, "PH-NET PIN"))
+    {
+        return MBTK_SIM_NETWORK_PERSONALIZATION;
+    }
+    else if (0 != strcmp (cpinResult, "READY"))
+    {
+        /* we're treating unsupported lock types as "sim absent" */
+        ret = MBTK_SIM_ABSENT;
+        goto done;
+    }
+
+    at_response_free(p_response);
+    p_response = NULL;
+    cpinResult = NULL;
+
+    // ret = net_info.radio_state == MBTK_RADIO_STATE_ON ? MBTK_SIM_READY : MBTK_SIM_NOT_READY;
+    net_info.sim_state = MBTK_SIM_READY;
+    return MBTK_SIM_READY;
+done:
+    at_response_free(p_response);
+    net_info.sim_state = ret;
+    return ret;
+}
+
+void setRadioPower(int isOn)
+{
+    int err;
+    ATResponse *p_response = NULL;
+
+    LOGI("RadioPower - %s", isOn == 0 ? "OFF" : "ON");
+
+    if(isOn == 0 && net_info.radio_state == MBTK_RADIO_STATE_ON)
+    {
+        err = at_send_command("AT+CFUN=0", &p_response);
+        if (err || !p_response->success)
+            goto error;
+
+        net_info.radio_state = MBTK_RADIO_STATE_OFF;
+    }
+    else if(isOn && net_info.radio_state != MBTK_RADIO_STATE_ON)
+    {
+        err = at_send_command("AT+CFUN=1", &p_response);
+        if (err || !p_response->success)
+        {
+            if(isRadioOn() == 1)
+            {
+                net_info.radio_state = MBTK_RADIO_STATE_ON;
+            }
+            goto error;
+        }
+
+        net_info.radio_state = MBTK_RADIO_STATE_ON;
+    }
+
+    at_response_free(p_response);
+    return;
+error:
+    at_response_free(p_response);
+}
+
+static int apn_user_pass_set_by_cid(int cid, mbtk_apn_info_t *apn)
+{
+    char prop_name[20] = {0};
+    char prop_data[300] = {0};
+    sprintf(prop_name, "%s_%d",MBTK_APN_PROP,cid);
+    if(property_get(prop_name, prop_data, "") > 0 && !str_empty(prop_data)) {
+        char apn_name[128] = {0};
+        char *ptr_1 = prop_data;
+        mbtk_ip_type_enum ip_type = (mbtk_ip_type_enum)atoi(ptr_1);
+        ptr_1 = strstr(ptr_1, ",");
+        if(!ptr_1) {
+            return -1;
+        }
+        ptr_1++; // Jump ',' to apn
+
+        char *ptr_2 = strstr(ptr_1, ",");
+        if(!ptr_2) {
+            return -1;
+        }
+        memcpy(apn_name, ptr_1, ptr_2 - ptr_1); // apn
+
+        // Check ip_type and apn_name
+        if(ip_type != apn->ip_type || strcmp(apn_name, apn->apn)) {
+            LOGD("APN Changed, not get user/pass/auth.");
+            return -1;
+        }
+
+        ptr_2++; // Jump ',' to user
+        ptr_1 = strstr(ptr_2, ",");
+        if(!ptr_1) {
+            return -1;
+        }
+        if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
+            memcpy(apn->user, ptr_2, ptr_1 - ptr_2); // user
+        }
+
+        ptr_1++; // Jump ',' to pass
+        ptr_2 = strstr(ptr_1, ",");
+        if(!ptr_2) {
+            return -1;
+        }
+        if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
+            memcpy(apn->pass, ptr_1, ptr_2 - ptr_1); // pass
+        }
+
+        ptr_2++; // Jump ',' to auth (Is last item)
+        if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
+            memcpy(apn->auth, ptr_2, strlen(ptr_2)); // auth
+        }
+
+        return 0;
+    }
+    return -1;
+}
+
+
+/*
+AT+CPOL?
+*EUICC: 1
+
+OK
+*/
+static int req_plmn_get(mbtk_plmn_info *type, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_multiline("AT+CPOL?", "+CPOL:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    int mccmnc_type = -1;
+    int count = -1;
+    char *mccmnc_name = NULL;
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        //if(strStartsWith(line, "+CPOL:"))
+        {
+            err = at_tok_start(&line);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            err = at_tok_nextint(&line, &count);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            type->count = count;
+
+            err = at_tok_nextint(&line, &mccmnc_type);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            type->mbtk_plmn_name[count-1].format = mccmnc_type;
+
+            err = at_tok_nextstr(&line, &mccmnc_name);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            memcpy(type->mbtk_plmn_name[count-1].plmn_name, mccmnc_name, strlen(mccmnc_name));
+            mccmnc_name = NULL;
+        }
+        lines_ptr = lines_ptr->p_next;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+AT*EUICC?
+*EUICC: 1
+
+OK
+*/
+static int req_sim_card_type_get(uint8 *type, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT*EUICC?", "*EUICC:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    int sim_card_type = -1;
+    err = at_tok_nextint(&line, &sim_card_type);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    if(sim_card_type != -1)
+        *type = sim_card_type;
+    goto exit;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+EPIN?
++EPIN: 3,0,10,0
+
+OK
+*/
+static int req_pin_puk_last_times_get(mbtk_pin_puk_last_times *times, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+EPIN?", "+EPIN:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    mbtk_pin_puk_last_times last_times={0};
+    err = at_tok_nextint(&line, &(last_times.p1_retry));
+    if (err < 0)
+    {
+        goto exit;
+    }
+    times->p1_retry = last_times.p1_retry;
+    err = at_tok_nextint(&line, &(last_times.p2_retry));
+    if (err < 0)
+    {
+        goto exit;
+    }
+    times->p2_retry = last_times.p2_retry;
+    err = at_tok_nextint(&line, &(last_times.puk1_retry));
+    if (err < 0)
+    {
+        goto exit;
+    }
+    times->puk1_retry = last_times.puk1_retry;
+    err = at_tok_nextint(&line, &(last_times.puk2_retry));
+    if (err < 0)
+    {
+        goto exit;
+    }
+    times->puk2_retry = last_times.puk2_retry;
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+AT+CGSN
+864788050901201
+
+OK
+*/
+static int req_imei_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command_numeric("AT+CGSN", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates) {
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    memcpy(data, response->p_intermediates->line, strlen(response->p_intermediates->line));
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+MRD_SN=R
++MRD_SN:0101,Thu Nov 12 00:00:00 2020,G4M32301020006
+
+OK
+
+*/
+static int req_sn_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+MRD_SN=R", "+MRD_SN:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    memcpy(data, tmp_ptr, strlen(tmp_ptr));
+
+    goto exit;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+SYSTIME?
++SYSTIME: 1
+
+OK
+
+*/
+static int req_time_get(int *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    int err = at_send_command_singleline("AT+SYSTIME?", "+SYSTIME:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    *data = tmp_int;
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CCLK?
++CCLK: "23/03/20,01:58:00+32"
+
+OK
+
+*/
+static int req_net_time_get(char *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+CCLK?", "+CCLK:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    memcpy(data, tmp_ptr, strlen(tmp_ptr));
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CFUN?
++CFUN: 1
+OK
+*/
+static int req_modem_get(int *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int modem;
+    int err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &modem);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    *data = modem;
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CFUN=<fun>[,<rst>]
+OK
+*/
+static int req_modem_set(mbtk_modem_info_t* modem, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+    int err = -1;
+
+    sprintf(cmd, "AT+CFUN=%d,%d", modem->fun, modem->rst);
+    err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+/*
+    ATResponse *response = NULL;
+    int err = at_send_command_multiline(cmd, "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        if(strStartsWith(line, "Revision"))
+        {
+            err = at_tok_start(&line);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            memcpy(data, line, strlen(line));
+            break;
+        }
+        lines_ptr = lines_ptr->p_next;
+    }
+
+    goto exit;
+*/
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+AT+SYSTIME=0,"2022-01-25-11:15:30"
+OK
+
+AT+SYSTIME=1
+OK
+*/
+static int req_time_set(int type, char *time, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    char cmd[200] = {0};
+    if(str_empty(time)){
+        sprintf(cmd, "AT+SYSTIME=%d", type);
+    } else {
+        sprintf(cmd, "AT+SYSTIME=%d,\"%s\"", type, time);
+    }
+    int err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+ATI
+Manufacturer:"LYNQ"
+Model:"LYNQ_L508TLC"
+Revision:L508TLCv02.01b01.00
+IMEI:864788050901201
+
+OK
+
+*/
+static int req_version_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command_multiline("ATI", "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        if(strStartsWith(line, "Revision"))
+        {
+            err = at_tok_start(&line);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            memcpy(data, line, strlen(line));
+            break;
+        }
+        lines_ptr = lines_ptr->p_next;
+    }
+
+    goto exit;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+ATI
+Manufacturer:"LYNQ"
+Model:"LYNQ_L508TLC"
+Revision:L508TLCv02.01b01.00
+IMEI:864788050901201
+
+OK
+
+*/
+static int req_model_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command_multiline("ATI", "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        if(strStartsWith(line, "Model"))
+        {
+            err = at_tok_start(&line);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            memcpy(data, line, strlen(line));
+            break;
+        }
+        lines_ptr = lines_ptr->p_next;
+    }
+
+    goto exit;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+ACONFIG="IMSD=1"
+or
+AT+ACONFIG="IMSD=0"
+
+OK
+*/
+static int req_volte_set(int state, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+    if(state)
+    {
+        strcpy(cmd, "AT+ACONFIG=\"IMSD=1\"");
+    }
+    else
+    {
+        strcpy(cmd, "AT+ACONFIG=\"IMSD=0\"");
+    }
+    int err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0) {
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+ACONFIG?
+PID=0,VID=0,IMSD=1,PIPE=0,FAST=0,RDUP=1,NOCP=0,GEFL=-1237040617
+
+OK
+*/
+static int req_volte_get(int *state, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+ACONFIG?", "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    char* ptr = strstr(line, "IMSD=");
+    if(ptr)
+    {
+        *state = atoi(ptr + strlen("IMSD="));
+    }
+    else
+    {
+        err = -1;
+    }
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+* Get system temperature.
+*
+* type[IN]:
+*   0: Soc temperature.
+*   1: RF temperature.
+* temp[OUT]:
+*   temperature in celsius.
+*
+
+AT*RFTEMP
+*RFTEMP:0,28
+OK
+
+AT*SOCTEMP
+*SOCTEMP:24000
+OK
+
+*/
+static int req_temp_get(int type, int *temp, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = -1;
+    int tmp_int;
+    if(type == 0) { // Soc
+        err = at_send_command_singleline("AT*SOCTEMP", "*SOCTEMP:", &response);
+    } else { // RF
+        err = at_send_command_singleline("AT*RFTEMP", "*RFTEMP:", &response);
+    }
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    if(type == 1) { // RF
+        err = at_tok_nextint(&line, &tmp_int);
+        if (err < 0)
+        {
+            goto exit;
+        }
+        *temp = tmp_int;
+    } else {
+        *temp = tmp_int / 1000;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT*BAND=15
+OK
+
+*/
+static int req_band_set(mbtk_band_info_t* band, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+    int err = -1;
+
+    if(band->gsm_band == 0 && band->umts_band == 0
+        && band->tdlte_band == 0 && band->fddlte_band == 0) {
+        sprintf(cmd, "AT*BAND=%d", band->net_pref);
+    } else {
+        band_support_get();
+
+        log_hex("BAND_SUPPORT", &band_support, sizeof(mbtk_band_info_t));
+        log_hex("BAND", band, sizeof(mbtk_band_info_t));
+
+        if(band->gsm_band == 0) {
+            band->gsm_band = band_support.gsm_band;
+        }
+        if(band->umts_band == 0) {
+            band->umts_band = band_support.umts_band;
+        }
+        if(band->tdlte_band == 0) {
+            band->tdlte_band = band_support.tdlte_band;
+        }
+        if(band->fddlte_band == 0) {
+            band->fddlte_band = band_support.fddlte_band;
+        }
+
+        if((band->gsm_band & band_support.gsm_band) != band->gsm_band) {
+            LOG("GSM band error.");
+            goto exit;
+        }
+
+        if((band->umts_band & band_support.umts_band) != band->umts_band) {
+            LOG("UMTS band error.");
+            goto exit;
+        }
+
+        if((band->tdlte_band & band_support.tdlte_band) != band->tdlte_band) {
+            LOG("TDLTE band error.");
+            goto exit;
+        }
+
+        if((band->fddlte_band & band_support.fddlte_band) != band->fddlte_band) {
+            LOG("FDDLTE band error.");
+            goto exit;
+        }
+
+        if(band->net_pref == 0xFF) { // No change net_pref.
+            int tmp_int;
+            err = at_send_command_singleline("AT*BAND?", "*BAND:", &response);
+            if (err < 0 || response->success == 0 || !response->p_intermediates){
+                *cme_err = at_get_cme_error(response);
+                goto exit;
+            }
+
+            char *line = response->p_intermediates->line;
+            err = at_tok_start(&line);
+            if (err < 0)
+            {
+                goto exit;
+            }
+
+            err = at_tok_nextint(&line, &tmp_int);
+            if (err < 0)
+            {
+                goto exit;
+            }
+            band->net_pref = (uint8)tmp_int; // Set to current net_pref.
+
+            at_response_free(response);
+        }
+
+        sprintf(cmd, "AT*BAND=%d,%d,%d,%d,%d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band);
+    }
+    err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+// ???????
+AT*BAND=?
+*BAND:(0-18),79,147,482,524503
+
+OK
+
+// ???????????
+AT*BAND?
+*BAND: 15, 78, 147, 482, 524503, 0, 2, 2, 0, 0
+
+OK
+
+// ?????????
+AT*BAND=5,79,147,128,1
+OK
+
+net_prefferred??
+    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)
+GSM band??
+    1 ?C PGSM 900 (standard or primary)
+    2 ?C DCS GSM 1800
+    4 ?C PCS GSM 1900
+    8 ?C EGSM 900 (extended)
+    16 ?C GSM 450
+    32 ?C GSM 480
+    64 ?C GSM 850
+    512 - BAND_LOCK_BIT // used for GSM band setting
+UMTS band??
+    1 ?C UMTS_BAND_1
+    2 ?C UMTS_BAND_2
+    4 ?C UMTS_BAND_3
+    8 ?C UMTS_BAND_4
+    16 ?C UMTS_BAND_5
+    32 ?C UMTS_BAND_6
+    64 ?C UMTS_BAND_7
+    128 ?C UMTS_BAND_8
+    256 ?C UMTS_BAND_9
+LTEbandH(TDD-LTE band)
+    32 ?C TDLTE_BAND_38
+    64 ?C TDLTE_BAND_39
+    128 ?C TDLTE_BAND_40
+    256 ?C TDLTE_BAND_41
+LTEbandL(FDD-LTE band)
+    1 ?C FDDLTE_BAND_1
+    4 ?C FDDLTE _BAND_3
+    8 ?C FDDLTE _BAND_4
+    64 ?C FDDLTE _BAND_7
+    65536 ?C FDDLTE _BAND_17
+    524288 ?C FDDLTE _BAND_20
+*/
+static int req_band_get(mbtk_band_info_t *band, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+
+    band_support_get();
+
+    log_hex("BAND_SUPPORT", &band_support, sizeof(mbtk_band_info_t));
+    int err = at_send_command_singleline("AT*BAND?", "*BAND:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band->net_pref = (uint8)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band->gsm_band = (uint16)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band->umts_band = (uint16)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band->tdlte_band = (uint32)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    band->fddlte_band = (uint32)tmp_int;
+
+    log_hex("BAND", band, sizeof(mbtk_band_info_t));
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+ICCID
++ICCID: 89860621330065648041
+
+OK
+*/
+static int req_iccid_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+ICCID", "+ICCID:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    memcpy(data, tmp_ptr, strlen(tmp_ptr));
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CNUM?
++CNUM: "","13980414101",129
+
+OK
+
+*/
+static int req_phone_number_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+CNUM?", "+CNUM:", &response);
+    if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+        if(response) {
+            *cme_err = at_get_cme_error(response);
+        }
+        LOGD("AT+CNUM? fail.");
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    if(line == NULL) {
+        LOGD("line is NULL");
+        goto exit;
+    }
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    memcpy(data, tmp_ptr, strlen(tmp_ptr));
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+AT+CIMI
+460068103383304
+
+OK
+
+*/
+static int req_imsi_get(void *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command_numeric("AT+CIMI", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    memcpy(data, response->p_intermediates->line, strlen(response->p_intermediates->line));
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+AT+CLCK=SC,1/0,1234
++CLCK:1/0
+
+OK
+
+*/
+static int req_pin_enable(mbtk_enable_pin_info *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[64]={0};
+    sprintf(cmd, "AT+CLCK=SC,%d,%s", data->enable, data->pin_value);
+
+    int err = at_send_command_singleline(cmd, "+CLCK:", &response);
+    if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+        if(response) {
+            *cme_err = at_get_cme_error(response);
+        }
+        LOGD("AT+CLCK? fail.");
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    if(line == NULL) {
+        LOGD("line is NULL");
+        goto exit;
+    }
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    int clck;
+    err = at_tok_nextint(&line, &clck);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CPIN=1234
+
+OK
+
+*/
+static int req_pin_verify(char *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[64]={0};
+    sprintf(cmd, "AT+CPIN=%s", data);
+    int err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        if(cme_err) {
+            *cme_err = at_get_cme_error(response);
+        }
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CLCK=SC,2
++CLCK: 1
+
+OK
+
+AT+CLCK="SC",1,"1234"
++CLCK:1
+
+OK
+
+AT+CPWD="SC","1234","4321"
+
+OK
+
+*/
+static int req_pin_change(mbtk_change_pin_info *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[64]={0};
+
+    int err = at_send_command_singleline("AT+CLCK=SC,2", "+CLCK:", &response);
+    if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+        if(response) {
+            *cme_err = at_get_cme_error(response);
+        }
+        LOGD("AT+CLCK fail.");
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    if(line == NULL) {
+        LOGD("line is NULL");
+        goto exit;
+    }
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    int clck;
+    err = at_tok_nextint(&line, &clck);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    at_response_free(response);
+
+    if(clck==0)
+    {
+        sprintf(cmd, "AT+CLCK=SC,1,%s", data->old_pin_value);
+        err = at_send_command_singleline(cmd, "+CLCK:", &response);
+        if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+            if(response) {
+                *cme_err = at_get_cme_error(response);
+            }
+            LOGD("AT+CLCK fail.");
+            goto exit;
+        }
+        line = response->p_intermediates->line;
+        if(line == NULL) {
+            LOGD("line is NULL");
+            goto exit;
+        }
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+        clck = -1;
+        err = at_tok_nextint(&line, &clck);
+        if (err < 0)
+        {
+            goto exit;
+        }
+        at_response_free(response);
+        if(clck != 1)
+            return err;
+    }
+    memset(cmd, 0, 64);
+    sprintf(cmd, "AT+CPWD=SC,%s,%s", data->old_pin_value,data->new_pin_value);
+    err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        if(cme_err) {
+            *cme_err = at_get_cme_error(response);
+        }
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CPIN?
++CPIN:SIM PUK
+
+OK
+
+AT+CPIN="PUK","PIN"
++CPIN: READY
+
+OK
+*/
+static int req_puk_unlock_pin(mbtk_unlock_pin_info *data, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[64]={0};
+#if 0
+    int err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &response);
+    if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+        if(response) {
+            *cme_err = at_get_cme_error(response);
+        }
+        LOGD("AT+CNUM? fail.");
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    if(line == NULL) {
+        LOGD("line is NULL");
+        goto exit;
+    }
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    char *tmp_ptr = NULL;
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    at_response_free(response);
+
+    if(!strstr(tmp_ptr,"SIM PUK"))
+    {
+        sprintf(cmd, "AT+CPIN=%s,%s", data->puk_value, data->pin_value);
+        err = at_send_command_singleline(cmd, "+CPIN:", &response);
+        if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+            if(response) {
+                *cme_err = at_get_cme_error(response);
+            }
+            LOGD("AT+CNUM? fail.");
+            goto exit;
+        }
+        line = response->p_intermediates->line;
+        if(line == NULL) {
+            LOGD("line is NULL");
+            goto exit;
+        }
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+        memset(tmp_ptr, 0, strlen(tmp_ptr));
+        err = at_tok_nextstr(&line, &tmp_ptr);
+        if (err < 0)
+        {
+            goto exit;
+        }
+        at_response_free(response);
+        if(strstr(tmp_ptr, "READY"))
+            return err;
+    }
+    else
+        return err;
+#else
+    sprintf(cmd, "AT+CPIN=%s,%s", data->puk_value, data->pin_value);
+    int err = at_send_command_singleline(cmd, "+CPIN: READY:", &response);
+    if (err < 0 || response == NULL || response->success == 0 || !response->p_intermediates){
+        if(response) {
+            *cme_err = at_get_cme_error(response);
+        }
+        LOGD("AT+CPIN fail.");
+        goto exit;
+    }
+#endif
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+COPS=?
+
++COPS: (2, "CHINA MOBILE", "CMCC", "46000", 7),(3, "CHN-CT", "CT", "46011", 7),(3, "CHN-UNICOM", "UNICOM", "46001", 7),(1, "460 15", "460 15", "46015", 7),,(0,1,2,3,4),(0,1,2)
+
+OK
+
+// Return [sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)]
+*/
+#if 0
+static int req_available_net_get(mbtk_net_array_info_t *data_ptr)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int tmp_int;
+    int err = at_send_command_singleline("AT+COPS=?", "+COPS:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates)
+        goto exit;
+#if 1
+    char *line_ptr = response->p_intermediates->line;
+    if(line_ptr == NULL) {
+        LOG("line is NULL");
+        goto exit;
+    }
+    //LOG("Line:%s",line_ptr);
+    line_ptr = strstr(line_ptr, "(");
+    while(line_ptr) {
+        line_ptr++;
+        // Only for available/current net.
+        if(*line_ptr == '1' || *line_ptr == '2') {
+            //LOG("Temp:%s",line_ptr);
+            //sleep(1);
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+            line_ptr++;
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+            line_ptr++;
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+
+            while(*line_ptr != '\0' && (*line_ptr == ',' || *line_ptr == ' ' || *line_ptr == '"'))
+                line_ptr++;
+
+            mbtk_net_info_t *net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+            if(net == NULL) {
+                LOG("malloc() fail.");
+                goto exit;
+            }
+            memset(net, 0, sizeof(mbtk_net_info_t));
+
+            // Point to "46000"
+            //LOG("PLMN:%s",line_ptr);
+            //sleep(1);
+            net->plmn = (uint32)atoi(line_ptr);
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+
+            while(*line_ptr != '\0' && (*line_ptr == ',' || *line_ptr == ' '))
+                line_ptr++;
+
+            // Point to "7"
+            if(*line_ptr == '\0') {
+                free(net);
+                goto exit;
+            }
+            //LOG("Type:%s",line_ptr);
+            //sleep(1);
+            net->net_type = (uint8)atoi(line_ptr);
+            list_add(data_ptr->net_list, net);
+            data_ptr->count++;
+        }
+
+        line_ptr = strstr(line_ptr, "(");
+    }
+#endif
+exit:
+    at_response_free(response);
+    return err;
+}
+#else
+static int req_available_net_get(void* buff, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int tmp_int;
+    int buff_size = 0;
+    int err = at_send_command_singleline("AT+COPS=?", "+COPS:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+    char *line_ptr = response->p_intermediates->line;
+    if(line_ptr == NULL) {
+        LOG("line is NULL");
+        goto exit;
+    }
+    uint8* buff_ptr = (uint8*)buff;
+    //LOG("Line:%s",line_ptr);
+    line_ptr = strstr(line_ptr, "(");
+    while(line_ptr) {
+        line_ptr++;
+        // Only for available/current net.
+        if(*line_ptr == '1' || *line_ptr == '2' || *line_ptr == '3') {
+            *(buff_ptr + 2) = (uint8)atoi(line_ptr); // net_state
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+            line_ptr++;
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+            line_ptr++;
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+
+            while(*line_ptr != '\0' && (*line_ptr == ',' || *line_ptr == ' ' || *line_ptr == '"'))
+                line_ptr++;
+
+            // set sel_mode to 0
+            *buff_ptr = (uint8)0;
+            // Point to "46000"
+            //LOG("PLMN:%s",line_ptr);
+            //sleep(1);
+            uint32_2_byte((uint32)atoi(line_ptr), buff_ptr + 3, false); // plmn
+
+            line_ptr = strstr(line_ptr, ",");
+            if(line_ptr == NULL)
+                goto exit;
+
+            while(*line_ptr != '\0' && (*line_ptr == ',' || *line_ptr == ' '))
+                line_ptr++;
+
+            // Point to "7"
+            if(*line_ptr == '\0') {
+                goto exit;
+            }
+            //LOG("Type:%s",line_ptr);
+            //sleep(1);
+            *(buff_ptr + 1) = (uint8)atoi(line_ptr); // net_type
+
+            buff_size += sizeof(mbtk_net_info_t);
+            buff_ptr += sizeof(mbtk_net_info_t);
+        }
+
+        line_ptr = strstr(line_ptr, "(");
+    }
+exit:
+    at_response_free(response);
+    return buff_size;
+}
+#endif
+
+/*
+AT+COPS?
++COPS: 1
+
+OK
+
+or
+
+AT+COPS?
++COPS: 0,2,"46001",7
+
+OK
+
+*/
+static int req_net_sel_mode_get(mbtk_net_info_t *net, int *cme_err)
+{
+    //LOG("req_net_sel_mode_get() 0");
+    //sleep(1);
+    ATResponse *response = NULL;
+    int tmp_int;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+COPS?", "+COPS:", &response);
+    //LOG("req_net_sel_mode_get() 00");
+    //sleep(1);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        if(cme_err != NULL)
+            *cme_err = at_get_cme_error(response);
+        err = -1;
+        goto exit;
+    }
+    //LOG("req_net_sel_mode_get() 1");
+    //sleep(1);
+    char *line = response->p_intermediates->line;
+    if(line == NULL) {
+        LOG("line is NULL");
+        goto exit;
+    }
+    //LOG("req_net_sel_mode_get() 2");
+    //sleep(1);
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    //LOG("req_net_sel_mode_get() 3");
+    //sleep(1);
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    net->net_sel_mode = (uint8)tmp_int;
+    //LOG("req_net_sel_mode_get() 4");
+    //sleep(1);
+    // +COPS: 1
+    if(!at_tok_hasmore(&line)) {
+        goto exit;
+    }
+    //LOG("req_net_sel_mode_get() 5");
+    //sleep(1);
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    //LOG("req_net_sel_mode_get() 6");
+    //sleep(1);
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    // memcpy(net->plmn, tmp_ptr, strlen(tmp_ptr));
+    net->plmn = (uint32)atoi(tmp_ptr);
+    //LOG("req_net_sel_mode_get() 7");
+    //sleep(1);
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    net->net_type = (uint8)tmp_int;
+
+    net->net_state = (uint8)MBTK_NET_AVIL_STATE_CURRENT;
+
+exit:
+    //LOG("req_net_sel_mode_get() 8");
+    //sleep(1);
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+COPS=0
+or
+AT+COPS=1,2,"46000",7
+
+OK
+
+*/
+static int req_net_sel_mode_set(mbtk_net_info_t* net, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[50] = {0};
+    char* cmp_ptr = cmd;
+    if(net == NULL) {
+        cmp_ptr += sprintf(cmp_ptr, "AT+COPS=0");
+     } else {
+        if(net->net_sel_mode == 0) {
+            cmp_ptr += sprintf(cmp_ptr, "AT+COPS=0");
+        } else if(net->net_type == 0xFF) {
+            cmp_ptr += sprintf(cmp_ptr, "AT+COPS=1,2,\"%d\"",net->plmn);
+        } else {
+            cmp_ptr += sprintf(cmp_ptr, "AT+COPS=1,2,\"%d\",%d",net->plmn, net->net_type);
+        }
+     }
+
+    int err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0) {
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+EEMOPT=1
+OK
+
+// LTE
+AT+EEMGINFO?
+// <mcc>, <length of mnc>, <mnc>, <tac>, <PCI>, <dlEuarfcn>, < ulEuarfcn >, <band>, <dlBandwidth>,
+// <rsrp>,<rsrq>, <sinr>,
+// errcModeState,emmState,serviceState,IsSingleEmmRejectCause,EMMRejectCause,mmeGroupId,mmeCode,mTmsi,
+// cellId,subFrameAssignType,specialSubframePatterns,transMode
+// mainRsrp,diversityRsrp,mainRsrq,diversityRsrq,rssi,cqi,pathLoss,tb0DlTpt,tb1DlTpt,tb0DlPeakTpt,tb1DlPeakTpt,tb0UlPeakTpt,
+// tb1UlPeakTpt,dlThroughPut,dlPeakThroughPut,averDlPRB,averCQITb0,averCQITb1,rankIndex,grantTotal,ulThroughPut,ulPeakThroughPut,currPuschTxPower,averUlPRB,
+// dlBer, ulBer,
+// diversitySinr, diversityRssi
++EEMLTESVC: 1120, 2, 0, 33584, 430, 40936, 40936, 41, 20,
+0, 0, 0,
+1, 10, 0, 1, 0, 1059, 78, 3959566565,
+105149248, 2, 7, 7,
+0, 0, 0, 0, 0, 0, 0, 1190919, 0, 0, 0, 16779777,
+0, 5112867, 3959566565, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0,
+7, 44
+
+// index,phyCellId,euArfcn,rsrp,rsrq
++EEMLTEINTER: 0, 65535, 38950, 0, 0
+
++EEMLTEINTER: 1, 0, 0, 0, 0
+
++EEMLTEINTER: 2, 0, 4294967295, 255, 255
+
++EEMLTEINTER: 3, 65535, 1300, 0, 0
+
++EEMLTEINTER: 4, 0, 0, 0, 0
+
++EEMLTEINTER: 5, 0, 4294967295, 247, 0
+
++EEMLTEINTER: 6, 197, 41332, 24, 9
+
++EEMLTEINTER: 7, 0, 0, 0, 0
+
++EEMLTEINTER: 8, 0, 0, 0, 0
+
++EEMLTEINTRA: 0, 429, 40936, 56, 12
+
++EEMLTEINTERRAT: 0,0
+
++EEMLTEINTERRAT: 1,0
+
++EEMGINFO: 3, 2         // <state>:
+                        // 0: ME in Idle mode
+                        // 1: ME in Dedicated mode
+                        // 2: ME in PS PTM mode
+                        // 3: invalid state
+                        // <nw_type>:
+                        // 0: GSM 1: UMTS 2: LTE
+
+OK
+
+// WCDMA
+AT+EEMGINFO?
+// Mode, sCMeasPresent, sCParamPresent, ueOpStatusPresent,
+
+// if sCMeasPresent == 1
+// cpichRSCP, utraRssi, cpichEcN0, sQual, sRxLev, txPower,
+// endif
+
+// if sCParamPresent == 1
+// rac, nom, mcc, mnc_len, mnc, lac, ci,
+// uraId, psc, arfcn, t3212, t3312, hcsUsed, attDetAllowed,
+// csDrxCycleLen, psDrxCycleLen, utranDrxCycleLen, HSDPASupport, HSUPASupport,
+// endif
+
+// if ueOpStatusPresent == 1
+// rrcState, numLinks, srncId, sRnti,
+// algPresent, cipherAlg, cipherOn, algPresent, cipherAlg, cipherOn,
+// HSDPAActive, HSUPAActive, MccLastRegisteredNetwork, MncLastRegisteredNetwork, TMSI, PTMSI, IsSingleMmRejectCause, IsSingleGmmRejectCause,
+// MMRejectCause, GMMRejectCause, mmState, gmmState, gprsReadyState, readyTimerValueInSecs, NumActivePDPContext, ULThroughput, DLThroughput,
+// serviceStatus, pmmState, LAU_status, LAU_count, RAU_status, RAU_count
+// endif
+//
++EEMUMTSSVC: 3, 1, 1, 1,
+-80, 27, -6, -18, -115, -32768,
+1, 1, 1120, 2, 1, 61697, 168432821,
+15, 24, 10763, 0, 0, 0, 0,
+128, 128, 65535, 0, 0,
+2, 255, 65535, 4294967295,
+0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 1, 1,
+28672, 28672, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0
+
+// index, cpichRSCP, utraRssi, cpichEcN0, sQual, sRxLev ,mcc, mnc, lac, ci, arfcn, psc
++EEMUMTSINTRA: 0, -32768, -1, -32768, -18, -115, 0, 0, 65534, 1, 10763, 32
+
++EEMUMTSINTRA: 1, -1, -32768, -18, -115, 0, 0, 65534, 2, 10763, 40, 32768
+
++EEMUMTSINTRA: 2, -32768, -18, -115, 0, 0, 65534, 3, 10763, 278, 32768, 65535
+
++EEMUMTSINTRA: 3, -18, -115, 0, 0, -2, 4, 10763, 28, 32768, 65535, 32768
+
++EEMUMTSINTRA: 4, -115, 0, 0, -2, 5, 10763, 270, 32768, 65535, 32768, 65518
+
++EEMUMTSINTRA: 5, 0, 0, -2, 6, 10763, 286, 32768, 65535, 32768, 65518, 65421
+
++EEMUMTSINTRA: 6, 0, -2, 7, 10763, 80, 32768, 65535, 32768, 65518, 65421, 0
+
++EEMUMTSINTRA: 7, -2, 8, 10763, 206, -32768, 65535, 32768, 65518, 65421, 0, 0
+
++EEMUMTSINTRA: 8, 9, 10763, 11, -32768, -1, 32768, 65518, 65421, 0, 0, 65534
+
++EEMUMTSINTRA: 9, 10763, 19, -32768, -1, -32768, 65518, 65421, 0, 0, 65534, 11
+
++EEMUMTSINTRA: 10, 232, -32768, -1, -32768, -18, 65421, 0, 0, 65534, 12, 10763
+
++EEMUMTSINTRA: 11, -32768, -1, -32768, -18, -115, 0, 0, 65534, 13, 10763, 66
+
++EEMUMTSINTRA: 12, -1, -32768, -18, -115, 0, 0, 65534, 14, 10763, 216, 32768
+
++EEMUMTSINTRA: 13, -32768, -18, -115, 0, 0, 65534, 15, 10763, 183, 32768, 65535
+
++EEMUMTSINTRA: 14, -18, -115, 0, 0, -2, 16, 10763, 165, 32768, 65535, 32768
+
++EEMUMTSINTRA: 15, -115, 0, 0, -2, 17, 10763, 151, 32768, 65535, 32768, 65518
+
++EEMUMTSINTRA: 16, 0, 0, -2, 18, 10763, 43, 32768, 65535, 32768, 65518, 65421
+
++EEMUMTSINTRA: 17, 0, -2, 19, 10763, 72, 32768, 65535, 32768, 65518, 65421, 0
+
++EEMUMTSINTRA: 18, -2, 20, 10763, 157, -32768, 65535, 32768, 65518, 65421, 0, 0
+
++EEMUMTSINTRA: 19, 21, 10763, 165, -32768, -1, 32768, 65518, 65421, 0, 0, 65534
+
++EEMUMTSINTRA: 20, 10763, 301, -32768, -1, -32768, 65518, 65421, 0, 0, 65534, 23
+
++EEMUMTSINTRA: 21, 23, -32768, -1, -32768, -18, 65421, 0, 0, 65534, 24, 10763
+
++EEMUMTSINTRA: 22, -32768, -1, -32768, -18, -115, 0, 0, 65534, 25, 10763, 0
+
++EEMUMTSINTRA: 23, -1, -32768, -18, -115, 0, 0, 65534, 26, 10763, 167, 32768
+
++EEMUMTSINTRA: 24, -32768, -18, -115, 0, 0, 65534, 27, 10763, 34, 32768, 65535
+
++EEMUMTSINTRA: 25, -18, -115, 0, 0, -2, 28, 10763, 313, 32768, 65535, 32768
+
++EEMUMTSINTRA: 26, -115, 0, 0, -2, 29, 10763, 152, 32768, 65535, 32768, 65518
+
++EEMUMTSINTRA: 27, 0, 0, -2, 30, 10763, 239, 0, 0, 0, 0, 0
+
++EEMUMTSINTRA: 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+
++EEMUMTSINTRA: 29, 0, 0, 0, 0, -115, 0, 0, 65534, 30, 10763, 239
+
+// index,gsmRssi,rxLev,C1,C2,mcc,mnc,lac,ci,arfcn,bsic
++EEMUMTSINTERRAT: 0, -32768, -107, -1, -1, 0, 0, 65534, 0, 117, 36
+
++EEMUMTSINTERRAT: 1, -107, -1, -1, 0, 0, 65534, 1, 72, 49, 0
+
++EEMUMTSINTERRAT: 2, -1, -1, 0, 0, 65534, 2, 119, 15, 32768, 149
+
++EEMUMTSINTERRAT: 3, -1, 0, 0, -2, 3, 121, 23, 0, 0, 0
+
++EEMGINFO: 3, 1
+
+OK
+
+
+// GSM
+AT+EEMGINFO?
++EEMGINFOBASIC: 2
+
+// mcc, mnc_len, mnc, lac, ci, nom, nco,
+// bsic, C1, C2, TA, TxPwr,
+// RxSig, RxSigFull, RxSigSub, RxQualFull, RxQualSub,
+// ARFCB_tch, hopping_chnl, chnl_type, TS, PacketIdle, rac, arfcn,
+// bs_pa_mfrms, C31, C32, t3212, t3312, pbcch_support, EDGE_support,
+// ncc_permitted, rl_timeout, ho_count, ho_succ, chnl_access_count, chnl_access_succ_count,
+// gsmBand,channelMode
++EEMGINFOSVC: 1120, 2, 0, 32784, 24741, 2, 0,
+63, 36, 146, 1, 7,
+46, 42, 42, 7, 0,
+53, 0, 8, 0, 1, 6, 53,
+2, 0, 146, 42, 54, 0, 1,
+1, 32, 0, 0, 0, 0,
+0, 0
+
+// PS_attached, attach_type, service_type, tx_power, c_value,
+// ul_ts, dl_ts, ul_cs, dl_cs, ul_modulation, dl_modulation,
+// gmsk_cv_bep, 8psk_cv_bep, gmsk_mean_bep, 8psk_mean_bep, EDGE_bep_period, single_gmm_rej_cause
+// pdp_active_num, mac_mode, network_control, network_mode, EDGE_slq_measurement_mode, edge_status
++EEMGINFOPS: 1, 255, 0, 0, 0,
+0, 0, 268435501, 1, 0, 0,
+4, 0, 96, 0, 0, 0,
+0, 0, 0, 65535, 0, 13350
+
++EEMGINFO: 0, 0
+
+OK
+
+*/
+static int req_cell_info_get(int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    int buff_size = 0;
+    // AT+EEMOPT=1 in the first.
+    int err = at_send_command("AT+EEMOPT=1", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    // Reset buffer in the first.
+    memset(&cell_info, 0xFF, sizeof(mbtK_cell_pack_info_t));
+    cell_info.running = true;
+    cell_info.cell_num = 0;
+
+    err = at_send_command_singleline("AT+EEMGINFO?", "+EEMGINFO:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    // Now, cell infomation has get from URC message.
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+
+    cell_info.type = (uint8)tmp_int;
+    cell_info.running = false;
+
+#if 0
+    while(lines_ptr)
+    {
+        // LTE
+        if(strStartsWith(line, "+EEMLTESVC:")) // LTE Server Cell
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMLTEINTER:")) // LTE ???§³??
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMLTEINTRA:")) // LTE ??§³??
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMLTEINTERRAT:")) // LTE RAT§³?????
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMGINFO:")) // <state>: 0: ME in Idle mode 1: ME in Dedicated mode 2: ME in PS PTM mode 3: invalid state
+                                                   // <nw_type>: 0: GSM 1: UMTS 2: LTE
+        {
+
+        }
+        // WCDMA
+        else if(strStartsWith(line, "+EEMUMTSSVC:")) // WCDMA Server Cell
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMUMTSINTRA:")) // WCDMA???§³??
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMUMTSINTERRAT:")) // WCDMA RAT§³?????
+        {
+
+        }
+        // GSM
+        else if(strStartsWith(line, "+EEMGINFOBASIC:")) // Basic information in GSM
+        // 0: ME in Idle mode   1: ME in Dedicated mode   2: ME in PS PTM mode
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMGINFOSVC:")) // GSM Server Cell
+        {
+
+        }
+        else if(strStartsWith(line, "+EEMGINFOPS:")) // PS???
+        {
+
+        }
+
+
+        lines_ptr = lines_ptr->p_next;
+    }
+#endif
+
+exit:
+    at_response_free(response);
+    return buff_size;
+}
+
+static int req_cell_info_set(const char *cmgl, char *reg, int len, int *cme_err)
+{
+    printf("req_cmgl_set(2)-----------------start\n");
+    printf("cmgl:%s\n", cmgl);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+    int err = 0;
+
+	memcpy(data, cmgl, len);
+
+	sprintf(cmd, "at*cell=%s", data);
+	printf("cmd:%s\n", cmd);
+
+	if(strlen(cmd) > 0)
+	{
+        err = at_send_command_multiline(cmd, "", &response);
+		if (err < 0 || response->success == 0 || !response->p_intermediates){
+			*cme_err = at_get_cme_error(response);
+        //    printf("at_send_command_multiline() is err-----------------\n");
+			goto exit;
+		}
+
+        ATLine* lines_ptr = response->p_intermediates;
+        char *line = NULL;
+        int reg_len = 0;
+		bool flag = false;
+        while(lines_ptr)
+        {
+            line = lines_ptr->line;
+            if(line ==NULL)
+            {
+                printf("line is null----------------------\n");
+            }
+            printf("-----line:%s\n", line);
+
+            lines_ptr = lines_ptr->p_next;
+        }
+	}
+    err = 0;
+	memcpy(reg, "req_cell_info_set succss", strlen("req_cell_info_set succss"));
+exit:
+    at_response_free(response);
+    printf("req_cell_info_set()-----------------end\n");
+    return err;
+}
+
+
+
+/*
+AT+CSQ
++CSQ: 31,99
+
+OK
+
+AT+CESQ
++CESQ: 60,99,255,255,20,61
+
+OK
+
+AT+COPS?
++COPS: 0,2,"46001",7
+
+OK
+
+*/
+static int req_net_signal_get(mbtk_signal_info_t *signal, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    char *tmp_ptr = NULL;
+    // AT+EEMOPT=1 in the first.
+    int err = at_send_command_singleline("AT+CSQ", "+CSQ:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        if(cme_err != NULL)
+            *cme_err = at_get_cme_error(response);
+        err = -1;
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->rssi = (uint8)tmp_int;
+    at_response_free(response);
+
+    err = at_send_command_singleline("AT+CESQ", "+CESQ:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        if(cme_err != NULL)
+            *cme_err = at_get_cme_error(response);
+        err = -1;
+        goto exit;
+    }
+
+    line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->rxlev = (uint8)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->ber = (uint8)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->rscp = (uint8)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->ecno = (uint8)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->rsrq = (uint8)tmp_int;
+
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->rsrp = (uint8)tmp_int;
+
+    at_response_free(response);
+    err = at_send_command_singleline("AT+COPS?", "+COPS:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        if(cme_err != NULL)
+            *cme_err = at_get_cme_error(response);
+        err = -1;
+        goto exit;
+    }
+    line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    if(!at_tok_hasmore(&line)) {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextstr(&line, &tmp_ptr);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    signal->type = (uint8)tmp_int;
+    net_info.net_type = signal->type;
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CREG=3
+OK
+
+AT+CREG?
++CREG: 3,1,"8330","06447340",7
+
+OK
+
+AT+CREG?
++CREG: 3,0
+
+OK
+
+AT+CEREG?
++CEREG: 3,1,"8330","06447340",7
+
+OK
+
+
+AT+CIREG?
++CIREG: 2,1,15
+
+OK
+
+AT+CIREG?
++CIREG: 0
+
+OK
+
+
+*/
+static int req_net_reg_get(mbtk_net_reg_info_t *reg, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int tmp_int;
+    char *tmp_str = NULL;
+    int err = at_send_command("AT+CREG=3", &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+    at_response_free(response);
+
+    err = at_send_command_multiline("AT+CREG?", "+CREG:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int); // n
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);// stat
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->call_state = (uint8)tmp_int;
+
+    if(at_tok_hasmore(&line)) {
+        err = at_tok_nextstr(&line, &tmp_str); // lac
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->lac = strtol(tmp_str, NULL, 16);
+
+        err = at_tok_nextstr(&line, &tmp_str); // ci
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->ci = strtol(tmp_str, NULL, 16);
+
+        err = at_tok_nextint(&line, &tmp_int);// AcT
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->type = (uint8)tmp_int;
+    }
+    at_response_free(response);
+
+    err = at_send_command_multiline("AT+CEREG?", "+CEREG:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int); // n
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);// stat
+    if (err < 0)
+    {
+        goto exit;
+    }
+    reg->data_state = (uint8)tmp_int;
+
+    if(reg->lac == 0 && at_tok_hasmore(&line)) {
+        err = at_tok_nextstr(&line, &tmp_str); // lac
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->lac = strtol(tmp_str, NULL, 16);
+
+        err = at_tok_nextstr(&line, &tmp_str); // ci
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->ci = strtol(tmp_str, NULL, 16);
+
+        err = at_tok_nextint(&line, &tmp_int);// AcT
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->type = (uint8)tmp_int;
+    }
+    at_response_free(response);
+
+    err = at_send_command_multiline("AT+CIREG?", "+CIREG:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        reg->ims_state = (uint8)0;
+        err = 0;
+        goto exit;
+    }
+    line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int); // n/stat
+    if (err < 0)
+    {
+        goto exit;
+    }
+    if(at_tok_hasmore(&line)) {
+        err = at_tok_nextint(&line, &tmp_int);// stat
+        if (err < 0)
+        {
+            goto exit;
+        }
+        reg->ims_state = (uint8)tmp_int;
+    } else {
+        reg->ims_state = (uint8)tmp_int;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CGDCONT?
++CGDCONT: 1,"IPV4V6","cmnet.MNC000.MCC460.GPRS","10.131.67.146 254.128.0.0.0.0.0.0.0.1.0.2.200.2.158.0",0,0,,,,
+
++CGDCONT: 8,"IPV4V6","IMS","254.128.0.0.0.0.0.0.0.1.0.2.200.2.160.160",0,0,0,2,1,1
+
+OK
+
+
+*/
+static int req_apn_get(void *data, int *data_len, int *cme_err)
+{
+    ATResponse *response = NULL;
+    int err = at_send_command_multiline("AT+CGDCONT?", "+CGDCONT:", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    int tmp_int;
+    char *tmp_str = NULL;
+    /*
+    <apn_num[1]><cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>...
+                <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
+    */
+    uint8* apn_num = (uint8*)data;
+    uint8* data_ptr = (uint8*)(data + sizeof(uint8)); // Jump apn_num[1]
+    mbtk_apn_info_t apn;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        err = at_tok_nextint(&line, &tmp_int); // cid
+        if (err < 0)
+        {
+            goto exit;
+        }
+        // Only get CID 1-7
+        if(tmp_int >= MBTK_APN_CID_MIN && tmp_int <= MBTK_APN_CID_MAX) {
+            memset(&apn, 0x0, sizeof(mbtk_apn_info_t));
+            apn.cid = tmp_int;
+            *data_ptr++ = (uint8)tmp_int; // cid
+
+            err = at_tok_nextstr(&line, &tmp_str);// ip type
+            if (err < 0)
+            {
+                goto exit;
+            }
+            if(!strcasecmp(tmp_str, "IP")) {
+                *data_ptr++ = (uint8)MBTK_IP_TYPE_IP;
+                apn.ip_type = MBTK_IP_TYPE_IP;
+            } else if(!strcasecmp(tmp_str, "IPV6")) {
+                *data_ptr++ = (uint8)MBTK_IP_TYPE_IPV6;
+                apn.ip_type = MBTK_IP_TYPE_IPV6;
+            } else if(!strcasecmp(tmp_str, "IPV4V6")) {
+                *data_ptr++ = (uint8)MBTK_IP_TYPE_IPV4V6;
+                apn.ip_type = MBTK_IP_TYPE_IPV4V6;
+            } else {
+                *data_ptr++ = (uint8)MBTK_IP_TYPE_PPP;
+                apn.ip_type = MBTK_IP_TYPE_PPP;
+            }
+
+            err = at_tok_nextstr(&line, &tmp_str); // apn
+            if (err < 0)
+            {
+                goto exit;
+            }
+            if(str_empty(tmp_str)) {
+                uint16_2_byte((uint16)0, data_ptr, false);
+                data_ptr += sizeof(uint16);
+            } else {
+                uint16_2_byte((uint16)strlen(tmp_str), data_ptr, false);
+                data_ptr += sizeof(uint16);
+                memcpy(data_ptr, tmp_str, strlen(tmp_str));
+                data_ptr += strlen(tmp_str);
+                memcpy(apn.apn, tmp_str, strlen(tmp_str));
+            }
+
+            if(apn_user_pass_set_by_cid(apn.cid, &apn)) {
+                // user
+                uint16_2_byte((uint16)0, data_ptr, false);
+                data_ptr += sizeof(uint16);
+
+                // pass
+                uint16_2_byte((uint16)0, data_ptr, false);
+                data_ptr += sizeof(uint16);
+
+                // auth
+                uint16_2_byte((uint16)0, data_ptr, false);
+                data_ptr += sizeof(uint16);
+            } else {
+                // user
+                if(str_empty(apn.user)) {
+                    uint16_2_byte((uint16)0, data_ptr, false);
+                    data_ptr += sizeof(uint16);
+                } else {
+                    uint16_2_byte((uint16)strlen(apn.user), data_ptr, false);
+                    data_ptr += sizeof(uint16);
+                    memcpy(data_ptr, apn.user, strlen(apn.user));
+                    data_ptr += strlen(apn.user);
+                }
+
+                // pass
+                if(str_empty(apn.pass)) {
+                    uint16_2_byte((uint16)0, data_ptr, false);
+                    data_ptr += sizeof(uint16);
+                } else {
+                    uint16_2_byte((uint16)strlen(apn.pass), data_ptr, false);
+                    data_ptr += sizeof(uint16);
+                    memcpy(data_ptr, apn.pass, strlen(apn.pass));
+                    data_ptr += strlen(apn.pass);
+                }
+
+                // auth
+                if(str_empty(apn.auth)) {
+                    uint16_2_byte((uint16)0, data_ptr, false);
+                    data_ptr += sizeof(uint16);
+                } else {
+                    uint16_2_byte((uint16)strlen(apn.auth), data_ptr, false);
+                    data_ptr += sizeof(uint16);
+                    memcpy(data_ptr, apn.auth, strlen(apn.auth));
+                    data_ptr += strlen(apn.auth);
+                }
+            }
+
+            (*apn_num)++;
+        }
+
+        lines_ptr = lines_ptr->p_next;
+    }
+
+    *data_len = data_ptr - (uint8*)data;
+
+    goto exit;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+#if 0
+/*
+LTE APN
+AT+CFUN=4
+AT*CGDFLT=1,IP,"private.vpdn",1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1
+AT*CGDFAUTH=1,2,"noc@njcc.vpdn.js","123456"
+AT+CFUN=1
+AT+CEREG?
+AT+CGDCONT?
+
+2/3G APN
+AT+CGREG?
+AT+CGDCONT=6,IP,"private.vpdn"
+AT*AUTHREQ=6,2,"noc@njcc.vpdn.js","123456"
+AT+CGDATA="",6
+AT+CGDCONT?
+*/
+static int req_apn_set_username(mbtk_apn_info_t *apn, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[400] = {0};
+    int index = 0;
+    int err = 0;
+
+    err = at_send_command_singleline("AT+COPS?", "+COPS:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        if(cme_err != NULL)
+            *cme_err = at_get_cme_error(response);
+        err = -1;
+        goto apn_set;
+    }
+
+    int tmp_int = 0;
+    int state=0;
+    char cmd_buf[64];
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto apn_set;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto apn_set;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto apn_set;
+    }
+    err = at_tok_nextstr(&line, &cmd_buf);
+    if (err < 0)
+    {
+        goto apn_set;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto apn_set;
+    }
+    else
+        state = tmp_int;
+
+apn_set:
+    at_response_free(response);
+    *cme_err = MBTK_INFO_ERR_CME_NON;
+    //if(state == 7 && apn->cid == 1)    //LTE && cid = 1
+    if(0)    //LTE && cid = 1
+    {
+        err = at_send_command("AT+CFUN=4", &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+        at_response_free(response);
+
+        memset(cmd, 0, 400);
+        index = 0;
+        index += sprintf(cmd, "AT*CGDFLT=%d,", 1);
+        switch(apn->ip_type) {
+            case MBTK_IP_TYPE_IP: {
+                index += sprintf(cmd + index,"\"IP\",");
+                break;
+            }
+            case MBTK_IP_TYPE_IPV6: {
+                index += sprintf(cmd + index,"\"IPV6\",");
+                break;
+            }
+            case MBTK_IP_TYPE_IPV4V6: {
+                index += sprintf(cmd + index,"\"IPV4V6\",");
+                break;
+            }
+            default: {
+                index += sprintf(cmd + index,"\"PPP\",");
+                break;
+            }
+        }
+
+        index += sprintf(cmd + index,"\"%s\",1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1",apn->apn);
+        err = at_send_command(cmd, &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+        at_response_free(response);
+
+        memset(cmd, 0, 400);
+        int cmd_auth=0;
+        if(strstr(apn->auth,"NONE"))
+            cmd_auth = 0;
+        else if(strstr(apn->auth,"PAP"))
+            cmd_auth = 1;
+        else if(strstr(apn->auth,"CHAP"))
+            cmd_auth = 2;
+        else if(strstr(apn->auth,"PAP AND CHAP"))
+            cmd_auth = 3;
+        else
+            goto exit;
+
+        sprintf(cmd,"AT*CGDFAUTH=1,%d,%s,%s",cmd_auth,apn->user,apn->pass);
+
+        err = at_send_command(cmd, &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+    }
+    else                //2/3G
+    {
+        memset(cmd,0,400);
+        index = 0;
+        index += sprintf(cmd, "AT+CGDCONT=%d,", apn->cid);
+        switch(apn->ip_type) {
+            case MBTK_IP_TYPE_IP: {
+                index += sprintf(cmd + index,"\"IP\",");
+                break;
+            }
+            case MBTK_IP_TYPE_IPV6: {
+                index += sprintf(cmd + index,"\"IPV6\",");
+                break;
+            }
+            case MBTK_IP_TYPE_IPV4V6: {
+                index += sprintf(cmd + index,"\"IPV4V6\",");
+                break;
+            }
+            default: {
+                index += sprintf(cmd + index,"\"PPP\",");
+                break;
+            }
+        }
+        index += sprintf(cmd + index, "\"%s\"", apn->apn);
+
+        err = at_send_command(cmd, &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+        at_response_free(response);
+
+        memset(cmd,0,400);
+        int cmd_auth=0;
+        if(strstr(apn->auth,"NONE"))
+            cmd_auth = 0;
+        else if(strstr(apn->auth,"PAP"))
+            cmd_auth = 1;
+        else if(strstr(apn->auth,"CHAP"))
+            cmd_auth = 2;
+        else if(strstr(apn->auth,"PAP AND CHAP"))
+            cmd_auth = 3;
+        else
+            goto exit;
+
+        sprintf(cmd, "AT*AUTHREQ=%d,%d,%s,%s",apn->cid,cmd_auth,apn->user,apn->pass);
+        err = at_send_command(cmd, &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+#endif
+
+/*
+AT+CGDCONT=1,"IPV4V6","cmnet"
+OK
+
+AT*CGDFLT=1,"IPv4v6","reliance.grevpdn.zj",,,,,,,,,,,,,,,,,,1
+OK
+
+*/
+static int req_apn_set(mbtk_apn_info_t *apn, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[400] = {0};
+    int index = 0;
+    int err = 0;
+
+    index += sprintf(cmd, "AT+CGDCONT=%d,", apn->cid);
+    switch(apn->ip_type) {
+        case MBTK_IP_TYPE_IP: {
+            index += sprintf(cmd + index,"\"IP\",");
+            break;
+        }
+        case MBTK_IP_TYPE_IPV6: {
+            index += sprintf(cmd + index,"\"IPV6\",");
+            break;
+        }
+        case MBTK_IP_TYPE_IPV4V6: {
+            index += sprintf(cmd + index,"\"IPV4V6\",");
+            break;
+        }
+        default: {
+            index += sprintf(cmd + index,"\"PPP\",");
+            break;
+        }
+    }
+    if(strlen(apn->apn) > 0) {
+        index += sprintf(cmd + index,"\"%s\"", apn->apn);
+    } else {
+        LOGE("No set APN.");
+        err = -1;
+        goto exit;
+    }
+
+    err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        if(cme_err) {
+            *cme_err = at_get_cme_error(response);
+        }
+        goto exit;
+    }
+
+    if(!str_empty(apn->user) || !str_empty(apn->pass)) {
+        at_response_free(response);
+
+        memset(cmd,0,400);
+        int cmd_auth=0;
+        if(strstr(apn->auth,"NONE"))
+            cmd_auth = 0;
+        else if(strstr(apn->auth,"PAP"))
+            cmd_auth = 1;
+        else if(strstr(apn->auth,"CHAP"))
+            cmd_auth = 2;
+#if 0
+        else if(strstr(apn->auth,"PAP AND CHAP"))
+            cmd_auth = 3;
+#endif
+        else
+            goto exit;
+
+        sprintf(cmd, "AT*AUTHREQ=%d,%d,%s,%s",apn->cid,cmd_auth,apn->user,apn->pass);
+        err = at_send_command(cmd, &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+int wait_cgact_complete(int timeout)
+{
+    int count = timeout * 10; // timeout * 1000 / 100
+    int i = 0;
+
+    while(cgact_wait.waitting && i < count) {
+        i++;
+        usleep(100000); // 100ms
+    }
+
+    if(i == count) { // Timeout
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/*
+AT+CGDATA="",6
+CONNECT
+
+OK
+
+AT+CFUN=1
+
+OK
+
+*/
+static int req_data_call_user_start(int cid, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[400] = {0};
+    int index = 0;
+    int err = 0;
+
+    err = at_send_command_singleline("AT+COPS?", "+COPS:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        if(cme_err != NULL)
+            *cme_err = at_get_cme_error(response);
+        err = -1;
+        goto exit;
+    }
+
+    int tmp_int;
+    char cmd_buf[64];
+    char *line = response->p_intermediates->line;
+    err = at_tok_start(&line);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextstr(&line, &cmd_buf);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    err = at_tok_nextint(&line, &tmp_int);
+    if (err < 0)
+    {
+        goto exit;
+    }
+    at_response_free(response);
+
+    if(tmp_int == 7 && cid == 1)    //LTE && cid = 1
+    {
+        ATResponse *response = NULL;
+        char cmd[400] = {0};
+        int err = 0;
+
+        err = at_send_command("AT+CFUN=1", &response);
+        if (err < 0 || response->success == 0){
+            if(cme_err) {
+                *cme_err = at_get_cme_error(response);
+            }
+            goto exit;
+        }
+    }
+    else
+    {
+        ATResponse *response = NULL;
+        char cmd[400] = {0};
+        int err = 0;
+        sprintf(cmd, "AT+CGDATA=\"\",%d", cid);
+        err = at_send_command(cmd, &response);
+        if (err < 0 || response->success == 0){
+            if(cme_err) {
+                *cme_err = at_get_cme_error(response);
+            }
+            goto exit;
+        }
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CGACT?
++CGACT: 1,1
++CGACT: 8,1
+OK
+
+AT+CGACT=1,<cid>
+OK
+
+*/
+static int req_data_call_start(int cid, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[400] = {0};
+    int err = 0;
+#if 0
+    err = at_send_command_multiline("AT+CGACT?", "+CGACT:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    int tmp_int;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        err = at_tok_nextint(&line, &tmp_int); // cid
+        if (err < 0)
+        {
+            goto exit;
+        }
+        if(tmp_int == cid) { // Found cid
+            err = at_tok_nextint(&line, &tmp_int); // cid
+            if (err < 0)
+            {
+                goto exit;
+            }
+            if(tmp_int == 1) { // This cid has active.
+                goto net_config;
+            } else {
+                goto cid_active;
+            }
+            break;
+        }
+
+        lines_ptr = lines_ptr->p_next;
+    }
+
+    if(lines_ptr == NULL) { // No found this cid.
+        LOGE("No found cid : %d", cid);
+        goto exit;
+    }
+    at_response_free(response);
+
+    // Start active cid.
+cid_active:
+#endif
+
+    sprintf(cmd, "AT+CGACT=1,%d", cid);
+    err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        if(cme_err) {
+            *cme_err = at_get_cme_error(response);
+        }
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CGACT=0,<cid>
+OK
+
+*/
+static int req_data_call_stop(int cid, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[400] = {0};
+    int err = 0;
+#if 0
+    err = at_send_command_multiline("AT+CGACT?", "+CGACT:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    int tmp_int;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        err = at_tok_nextint(&line, &tmp_int); // cid
+        if (err < 0)
+        {
+            goto exit;
+        }
+        if(tmp_int == cid) { // Found cid
+            err = at_tok_nextint(&line, &tmp_int); // cid
+            if (err < 0)
+            {
+                goto exit;
+            }
+            if(tmp_int == 1) { // This cid has active.
+                goto net_config;
+            } else {
+                goto cid_active;
+            }
+            break;
+        }
+
+        lines_ptr = lines_ptr->p_next;
+    }
+
+    if(lines_ptr == NULL) { // No found this cid.
+        LOGE("No found cid : %d", cid);
+        goto exit;
+    }
+    at_response_free(response);
+
+    // Start active cid.
+cid_active:
+#endif
+
+    sprintf(cmd, "AT+CGACT=0,%d", cid);
+    err = at_send_command(cmd, &response);
+    if (err < 0 || response->success == 0){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+IPv4 : 10.255.74.26
+IPv6 : 254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239
+*/
+static bool is_ipv4(const char *ip)
+{
+    const char *ptr = ip;
+    int count = 0;
+    while(*ptr) {
+        if(*ptr == '.')
+            count++;
+        ptr++;
+    }
+
+    if(count == 3) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/*
+AT+CGCONTRDP=1
++CGCONTRDP: 1,7,"cmnet-2.MNC000.MCC460.GPRS","10.255.74.26","","223.87.253.100","223.87.253.253","","",0,0
++CGCONTRDP: 1,7,"cmnet-2.MNC000.MCC460.GPRS","254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239","","36.9.128.98.32.0.0.2.0.0.0.0.0.0.0.1","36.9.128.98.32.0.0.2.0.0.0.0.0.0.0.2","","",0,0
+
+OK
+
+*/
+static int req_data_call_state_get(int cid, mbtk_ipv4_info_t *ipv4, mbtk_ipv6_info_t *ipv6, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char cmd[50] = {0};
+    int err = 0;
+
+    sprintf(cmd, "AT+CGCONTRDP=%d", cid);
+
+    err = at_send_command_multiline(cmd, "+CGCONTRDP:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    int tmp_int;
+    char *tmp_ptr = NULL;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        err = at_tok_nextint(&line, &tmp_int); // cid
+        if (err < 0)
+        {
+            goto exit;
+        }
+        err = at_tok_nextint(&line, &tmp_int); // bearer_id
+        if (err < 0)
+        {
+            goto exit;
+        }
+        err = at_tok_nextstr(&line, &tmp_ptr); // APN
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        err = at_tok_nextstr(&line, &tmp_ptr); // IP
+        if (err < 0 || str_empty(tmp_ptr))
+        {
+            goto exit;
+        }
+        if(is_ipv4(tmp_ptr)) {
+            if(inet_pton(AF_INET, tmp_ptr, &(ipv4->IPAddr)) < 0) {
+                LOGE("inet_pton() fail.");
+                err = -1;
+                goto exit;
+            }
+
+            ipv4->valid = true;
+            //log_hex("IPv4", &(ipv4->IPAddr), sizeof(struct in_addr));
+        } else {
+            if(str_2_ipv6(tmp_ptr, &(ipv6->IPV6Addr))) {
+                LOGE("str_2_ipv6() fail.");
+                err = -1;
+                goto exit;
+            }
+
+            ipv6->valid = true;
+            //log_hex("IPv6", &(ipv6->IPV6Addr), 16);
+        }
+
+        err = at_tok_nextstr(&line, &tmp_ptr); // Gateway
+        if (err < 0)
+        {
+            goto exit;
+        }
+        if(!str_empty(tmp_ptr)) { // No found gateway
+            if(is_ipv4(tmp_ptr)) {
+                if(inet_pton(AF_INET, tmp_ptr, &(ipv4->GateWay)) < 0) {
+                    LOGE("inet_pton() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                //log_hex("IPv4", &(ipv4->GateWay), sizeof(struct in_addr));
+            } else {
+                if(str_2_ipv6(tmp_ptr, &(ipv6->GateWay))) {
+                    LOGE("str_2_ipv6() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                //log_hex("IPv6", &(ipv6->GateWay), 16);
+            }
+        }
+
+        err = at_tok_nextstr(&line, &tmp_ptr); // prim_DNS
+        if (err < 0)
+        {
+            goto exit;
+        }
+        if(!str_empty(tmp_ptr)) { // No found Primary DNS
+            if(is_ipv4(tmp_ptr)) {
+                if(inet_pton(AF_INET, tmp_ptr, &(ipv4->PrimaryDNS)) < 0) {
+                    LOGE("inet_pton() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                //log_hex("IPv4", &(ipv4->PrimaryDNS), sizeof(struct in_addr));
+            } else {
+                if(str_2_ipv6(tmp_ptr, &(ipv6->PrimaryDNS))) {
+                    LOGE("str_2_ipv6() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                //log_hex("IPv6", &(ipv6->PrimaryDNS), 16);
+            }
+        }
+
+        err = at_tok_nextstr(&line, &tmp_ptr); // sec_DNS
+        if (err < 0)
+        {
+            goto exit;
+        }
+        if(!str_empty(tmp_ptr)) { // No found Secondary DNS
+            if(is_ipv4(tmp_ptr)) {
+                if(inet_pton(AF_INET, tmp_ptr, &(ipv4->SecondaryDNS)) < 0) {
+                    LOGE("inet_pton() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                //log_hex("IPv4", &(ipv4->SecondaryDNS), sizeof(struct in_addr));
+            } else {
+                if(str_2_ipv6(tmp_ptr, &(ipv6->SecondaryDNS))) {
+                    LOGE("str_2_ipv6() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                //log_hex("IPv6", &(ipv6->SecondaryDNS), 16);
+            }
+        }
+
+        lines_ptr = lines_ptr->p_next;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CGCONTRDP
++CGCONTRDP: 1,5,"cmnet.MNC000.MCC460.GPRS","10.156.238.86","","223.87.253.100","223.87.253.253","","",0,0
++CGCONTRDP: 1,5,"cmnet.MNC000.MCC460.GPRS","254.128.0.0.0.0.0.0.0.1.0.1.181.5.77.221","","36.9.128.98.32.0.0.2.0.0.0.0.0.0.0.1","36.9.128.98.32.0.0.2.0,0,0
++CGCONTRDP: 8,6,"IMS.MNC000.MCC460.GPRS","254.128.0.0.0.0.0.0.0.1.0.1.181.5.79.116","","","","36.9.128.98.80.2.0.87.0.0.0.0.0.3.31.1","36.9.128.98.80.2,1,0
+OK
+
+*/
+static int apn_state_get(list_node_t **apn_list)
+{
+    ATResponse *response = NULL;
+    int err = 0;
+    *apn_list = list_create(NULL);
+    if(*apn_list == NULL)
+    {
+        LOG("list_create() fail.");
+        return -1;
+    }
+
+    err = at_send_command_multiline("AT+CGCONTRDP", "+CGCONTRDP:", &response);
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        goto exit;
+    }
+    ATLine* lines_ptr = response->p_intermediates;
+    char *line = NULL;
+    int tmp_int;
+    char *tmp_ptr = NULL;
+    int cid_current = 0;
+    info_apn_ip_t *apn = NULL;
+    while(lines_ptr)
+    {
+        line = lines_ptr->line;
+        err = at_tok_start(&line);
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        err = at_tok_nextint(&line, &tmp_int); // cid
+        if (err < 0)
+        {
+            goto exit;
+        }
+
+        if(tmp_int != 1 && tmp_int != 8) { // Not process cid 1 and 8.
+            if(cid_current != tmp_int) { // New cid.
+                apn = (info_apn_ip_t*)malloc(sizeof(info_apn_ip_t));
+                if(apn == NULL) {
+                    goto exit;
+                }
+                memset(apn, 0, sizeof(info_apn_ip_t));
+                apn->cid = tmp_int;
+                cid_current = tmp_int;
+
+                list_add(*apn_list, apn);
+            }
+            err = at_tok_nextint(&line, &tmp_int); // bearer_id
+            if (err < 0)
+            {
+                goto exit;
+            }
+            err = at_tok_nextstr(&line, &tmp_ptr); // APN
+            if (err < 0)
+            {
+                goto exit;
+            }
+
+            err = at_tok_nextstr(&line, &tmp_ptr); // IP
+            if (err < 0 || str_empty(tmp_ptr))
+            {
+                goto exit;
+            }
+            if(is_ipv4(tmp_ptr)) {
+                apn->ipv4_valid = true;
+                memcpy(apn->ipv4, tmp_ptr, strlen(tmp_ptr));
+            } else {
+                apn->ipv6_valid = true;
+                uint8 tmp_ipv6[16];
+                if(str_2_ipv6(tmp_ptr, tmp_ipv6)) {
+                    LOGE("str_2_ipv6() fail.");
+                    err = -1;
+                    goto exit;
+                }
+
+                if(inet_ntop(AF_INET6, tmp_ipv6, apn->ipv6, 50) == NULL) {
+                    err = -1;
+                    LOGE("inet_ntop ipv6 ip fail.");
+                    goto exit;
+                }
+            }
+        }
+
+        lines_ptr = lines_ptr->p_next;
+    }
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+mbtk_info_err_enum call_pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack);
+mbtk_info_err_enum sms_pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack);
+mbtk_info_err_enum pb_pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack);
+//mbtk wyq for data_call_ex add start
+void data_call_bootconn_save(int cid, int bootconn);
+//mbtk wyq for data_call_ex add end
+
+//void net_list_free(void *data);
+// Return MBTK_INFO_ERR_SUCCESS,will call pack_error_send() to send RSP.
+// Otherwise, do not call pack_error_send().
+static mbtk_info_err_enum pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack)
+{
+    if(pack->info_id > MBTK_INFO_ID_CALL_BEGIN && pack->info_id < MBTK_INFO_ID_CALL_END) {
+        return call_pack_req_process(cli_info, pack);
+    } else if(pack->info_id > MBTK_INFO_ID_SMS_BEGIN && pack->info_id < MBTK_INFO_ID_SMS_END) {
+        return sms_pack_req_process(cli_info, pack);
+    } else if(pack->info_id > MBTK_INFO_ID_PB_BEGIN && pack->info_id < MBTK_INFO_ID_PB_END) {
+        return pb_pack_req_process(cli_info, pack);
+    } else {
+        mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+        int cme_err = MBTK_INFO_ERR_CME_NON;
+        switch(pack->info_id)
+        {
+            case MBTK_INFO_ID_DEV_IMEI_REQ: // <string> IMEI
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get IMEI
+                {
+                    char imei[20] = {0};
+                    if(req_imei_get(imei, &cme_err) || strlen(imei) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMEI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_IMEI_RSP, imei, strlen(imei));
+                    }
+                }
+                else     // Set IMEI(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set IMEI.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_SN_REQ: // <string> SN
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get SN
+                {
+                    char sn[20] = {0};
+                    if(req_sn_get(sn, &cme_err) || strlen(sn) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get SN fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_SN_RSP, sn, strlen(sn));
+                    }
+                }
+                else     // Set SN(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set SN.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_MEID_REQ: // <string> MEID (Only for CDMA)
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get MEID
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Support only for CDMA.");
+                }
+                else     // Set MEID(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set MEID.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_VERSION_REQ: // <string> VERSION
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get VERSION
+                {
+                    char version[50] = {0};
+                    if(req_version_get(version, &cme_err) || strlen(version) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get Version fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_VERSION_RSP, version, strlen(version));
+                    }
+                }
+                else     // Set VERSION(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set VERSION.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_MODEL_REQ: //MODEL
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get MODEL
+                {
+                    char model[50] = {0};
+                    if(req_model_get(model, &cme_err) || strlen(model) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get model fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_VERSION_RSP, model, strlen(model));
+                    }
+                }
+                else     // Set model(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set model.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_MODEM_REQ: //MODEM
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get MODEM
+                {
+                    int modem = -1;
+                    if(req_modem_get(&modem, &cme_err) || modem < 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get modem fail.");
+                    }
+                    else
+                    {
+                        uint8 modem_type = (uint8)modem;
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_MODEM_RSP, &modem_type, sizeof(uint8));
+                    }
+                }
+                else     // Set modem
+                {
+                    mbtk_modem_info_t *modem = (mbtk_modem_info_t *)pack->data;
+                    if(pack->data_len != sizeof(mbtk_modem_info_t))
+                    {
+                        err = MBTK_INFO_ERR_REQ_PARAMETER;
+                        LOG("Set modem error.");
+                        break;
+                    }
+                    if(req_modem_set(modem, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        LOG("Set modem fail.");
+                        err = MBTK_INFO_ERR_FORMAT;
+                    } else {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_MODEM_RSP, NULL, 0);
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_TIME_REQ: // <uint8><string>  YYYY-MM-DD-HH:MM:SS
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get Time
+                {
+                    int type = -1;
+                    if(req_time_get(&type, &cme_err) || type < 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get Time fail.");
+                    }
+                    else
+                    {
+                        uint8 time_type = (uint8)type;
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_TIME_RSP, &time_type, sizeof(uint8));
+                    }
+                }
+                else     // Set Time
+                {
+                    if(pack->data_len == sizeof(uint8)) {
+                        if(req_time_set(*(pack->data), NULL, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                        {
+                            LOG("Set Time fail.");
+                            err = MBTK_INFO_ERR_FORMAT;
+                        } else {
+                            pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_TIME_RSP, NULL, 0);
+                        }
+                    } else {
+                        char time_ptr[100] = {0};
+                        memcpy(time_ptr, pack->data + sizeof(uint8), pack->data_len - sizeof(uint8));
+                        if(req_time_set(*(pack->data), time_ptr, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                        {
+                            LOG("Set Time fail.");
+                            err = MBTK_INFO_ERR_FORMAT;
+                        } else {
+                            pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_TIME_RSP, NULL, 0);
+                        }
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_TIME_REQ: // <string>  YYYY-MM-DD-HH:MM:SS
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get Time
+                {
+                    char time[100];
+                    if(req_net_time_get(time, &cme_err) || strlen(time) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get Time fail.");
+                    }
+                    else
+                    {
+                        char time_ser[100]={0};
+                        memcpy(time_ser,time,strlen(time));
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_TIME_RSP, time_ser, strlen(time_ser));
+                    }
+                }
+                else     // Set Time
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set TIME.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_VOLTE_REQ:  // <uint8> 0:Close 1:Open
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+                {
+                    int state;
+                    if(req_volte_get(&state, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get VoLTE state fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_VOLTE_RSP, &state, sizeof(uint8));
+                    }
+                }
+                else     // Set VoLTE state.
+                {
+                    uint8 on = *(pack->data);
+                    if(pack->data_len != sizeof(uint8) || (on != 0 && on != 1))
+                    {
+                        err = MBTK_INFO_ERR_REQ_PARAMETER;
+                        LOG("Set VOLTE parameter error.");
+                        break;
+                    }
+
+                    if(req_volte_set(on, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Set VoLTE state fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_VOLTE_RSP, NULL, 0);
+
+                        // Restart is required to take effect.
+                        LOG("Will reboot system...");
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_DEV_TEMP_REQ:  // <string> Temperature
+            {
+                if(pack->data_len == sizeof(uint8) && pack->data) {
+                    int temp;
+                    if(req_temp_get(*(pack->data), &temp, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get temperature fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_DEV_TEMP_RSP, &temp, sizeof(uint8));
+                    }
+                } else {
+                    err = MBTK_INFO_ERR_FORMAT;
+                    LOG("Unsupport get Temperature.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_PLMN_REQ: // plmn
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   //  plmn
+                {
+                    mbtk_plmn_info plmn;
+                    if(req_plmn_get(&plmn, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get PLMN fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_PLMN_RSP, &plmn, sizeof(mbtk_plmn_info));
+                    }
+                }
+                else     // Set
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Set sim state fail.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_STATE_REQ: // mbtk_sim_state_enum
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get sim state.
+                {
+                    uint8 sim_state = (uint8)getSIMStatus();
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_STATE_RSP, &sim_state, sizeof(uint8));
+                }
+                else     // Set
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Set sim state fail.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_STYPE_REQ: // mbtk_sim_card_type_enum
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get sim card type
+                {
+                    uint8 sim_card_type;
+                    if(req_sim_card_type_get(&sim_card_type, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMSI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_STYPE_RSP, &sim_card_type, sizeof(uint8));
+                    }
+                }
+                else     // Set
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Set sim state fail.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_PINPUK_TIMES_REQ: // mbtk_pin_puk_last_times
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get sim card type
+                {
+                    mbtk_pin_puk_last_times pin_puk_last_times;
+                    if(req_pin_puk_last_times_get(&pin_puk_last_times, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMSI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_PINPUK_TIMES_RSP, &pin_puk_last_times, sizeof(mbtk_pin_puk_last_times));
+                    }
+                }
+                else     // Set
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Set sim state fail.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_ENABLE_PIN_REQ:   // <string> PIN
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Enable PIN
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport GET PIN.");
+                }
+                else     // Enable PIN
+                {
+                    mbtk_enable_pin_info *pin = NULL;
+                    pin = (mbtk_enable_pin_info *)pack->data;
+                    if(req_pin_enable(pin, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMSI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_ENABLE_PIN_RSP, NULL, 0);
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_PIN_REQ:   // <string> PIN
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // PIN
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport GET PIN.");
+                }
+                else     // Set PIN
+                {
+                    char pin[16] = {0};
+                    memcpy(pin, pack->data, pack->data_len);
+                    if(req_pin_verify(pin, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Set PIN fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_PIN_RSP, NULL, 0);
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_PUK_REQ:   // <string> PUK
+            {
+                if(pack->data_len == 0 || pack->data == NULL)
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport.");
+                }
+                else     // change PIN
+                {
+                    mbtk_unlock_pin_info *pin_info = NULL;
+                    pin_info = (mbtk_unlock_pin_info *)pack->data;
+                    if(req_puk_unlock_pin(pin_info, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMSI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_CHANGE_PIN_RSP, NULL, 0);
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_CHANGE_PIN_REQ:   // <string> <string> old_PIN new_PIN
+            {
+                if(pack->data_len == 0 || pack->data == NULL)
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport.");
+                }
+                else     // change PIN
+                {
+                    mbtk_change_pin_info *pin_info = NULL;
+                    pin_info = (mbtk_change_pin_info *)pack->data;
+                    if(req_pin_change(pin_info, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMSI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_CHANGE_PIN_RSP, NULL, 0);
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_IMSI_REQ:  // <string> IMSI
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get IMSI
+                {
+                    char imsi[20] = {0};
+                    if(req_imsi_get(imsi, &cme_err) || strlen(imsi) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get IMSI fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_IMSI_RSP, imsi, strlen(imsi));
+                    }
+                }
+                else     // Set IMSI(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set IMSI.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_ICCID_REQ: // <string> ICCID
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get ICCID
+                {
+                    //log_hex("pack", pack, sizeof(mbtk_info_pack_t));
+                    //sleep(1);
+                    char iccid[50] = {0};
+                    if(req_iccid_get(iccid, &cme_err) || strlen(iccid) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get ICCID fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_ICCID_RSP, iccid, strlen(iccid));
+                    }
+                }
+                else     // Set ICCID(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set ICCID.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_SIM_PN_REQ: // <string> Phone Number
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get Phone Number
+                {
+                    //log_hex("pack", pack, sizeof(mbtk_info_pack_t));
+                    //sleep(1);
+                    char phone_number[50] = {0};
+                    if(req_phone_number_get(phone_number, &cme_err) || strlen(phone_number) == 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get Phone Number fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SIM_PN_RSP, phone_number, strlen(phone_number));
+                    }
+                }
+                else     // Set Phone Number(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set Phone Number.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_SEL_MODE_REQ: // <mbtk_net_info_t> Operator
+            {
+                if(pack->data_len == 0 || pack->data == NULL) // Get
+                {
+                    mbtk_net_info_t info;
+                    memset(&info, 0, sizeof(mbtk_net_info_t));
+                    if(req_net_sel_mode_get(&info, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get Net select mode fail.");
+                    }
+                    else
+                    {
+                        LOG("NET : %d, %d, %d, %d", info.net_sel_mode, info.net_type, info.net_state, info.plmn);
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_SEL_MODE_RSP, &info, sizeof(mbtk_net_info_t));
+                    }
+                }
+                else     // Set
+                {
+                    //LOG("1 pack-%p,data-%p,data_len-%d", pack, pack->data, pack->data_len);
+                    //log_hex("pack", pack, sizeof(mbtk_info_pack_t));
+                    //log_hex("data", pack->data, pack->data_len);
+
+                    mbtk_net_info_t* info = (mbtk_net_info_t*)pack->data;//(mbtk_net_info_t*)mbtk_info_pack_data_get(pack, NULL);
+                    if(info == NULL) {
+                        err = MBTK_INFO_ERR_FORMAT;
+                        LOG("Get Net select mode fail.");
+                    } else {
+                        LOG("NET : %d, %d, %d", info->net_sel_mode, info->net_type, info->plmn);
+                        if(req_net_sel_mode_set(info, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON) {
+                            if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                err = MBTK_INFO_ERR_CME + cme_err;
+                            } else {
+                                err = MBTK_INFO_ERR_UNKNOWN;
+                            }
+                            LOG("Get Net select mode fail.");
+                        } else {
+                            pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_SEL_MODE_RSP, NULL, 0);
+                        }
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_AVAILABLE_REQ:// sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+            {
+                if(pack->data_len == 0 || pack->data == NULL) // Get Available Net.
+                {
+                    int buffer_size;
+                    uint8 buffer[SOCK_MSG_LEN_MAX];
+                    memset(buffer, 0, SOCK_MSG_LEN_MAX);
+                    if((buffer_size = req_available_net_get(buffer, &cme_err)) <= 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get Available Net fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_AVAILABLE_RSP, buffer, buffer_size);
+                    }
+                }
+                else     // Set Available Net(Unsupport).
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Unsupport set available net.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_BAND_REQ:
+            {
+                if(pack->data_len == 0 || pack->data == NULL)
+                {
+                    err = MBTK_INFO_ERR_REQ_PARAMETER;
+                    LOG("No data found.");
+                }
+                else     // Get support/current bands.
+                {
+                    if(pack->data_len == sizeof(uint8)) {
+                        if(*(pack->data)) { // Get current bands.
+                            mbtk_band_info_t band;
+                            if(req_band_get(&band, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                            {
+                                if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                    err = MBTK_INFO_ERR_CME + cme_err;
+                                } else {
+                                    err = MBTK_INFO_ERR_UNKNOWN;
+                                }
+                                LOG("Get net band fail.");
+                            }
+                            else
+                            {
+                                pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_BAND_RSP, &band, sizeof(mbtk_band_info_t));
+                            }
+                        } else { // Get support bands.
+                            band_support_get();
+                            if(band_support.net_pref != 0)
+                            {
+                                err = MBTK_INFO_ERR_UNKNOWN;
+                                LOG("Get support bands fail.");
+                            }
+                            else
+                            {
+                                pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_BAND_RSP, &band_support, sizeof(mbtk_band_info_t));
+                            }
+                        }
+                    } else { // Set current bands.
+                        mbtk_band_info_t* band = (mbtk_band_info_t*)pack->data;
+                        if(pack->data_len != sizeof(mbtk_band_info_t))
+                        {
+                            err = MBTK_INFO_ERR_REQ_PARAMETER;
+                            LOG("Set net band error.");
+                            break;
+                        }
+
+                        if(req_band_set(band, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                        {
+                            if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                err = MBTK_INFO_ERR_CME + cme_err;
+                            } else {
+                                err = MBTK_INFO_ERR_UNKNOWN;
+                            }
+                            LOG("Set net band fail.");
+                        }
+                        else
+                        {
+                            pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_BAND_RSP, NULL, 0);
+                        }
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_CELL_REQ: // mbtk_cell_info_t[]
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get net cell.
+                {
+                    if(req_cell_info_get(&cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get net cell fail.");
+                    }
+                    else
+                    {
+                        LOG("req_cell_info_get() success,cell number: %d", cell_info.cell_num);
+                        //sleep(1);
+                        // mbtK_cell_pack_info_t
+                        if(cell_info.cell_num > 0 && cell_info.cell_num <= CELL_NUM_MAX && cell_info.type >= 0 && cell_info.type <= 2) {
+                            uint8 *data = (uint8*)malloc(sizeof(uint8) + sizeof(mbtk_cell_info_t) * cell_info.cell_num);
+                            if(data == NULL){
+                                err = MBTK_INFO_ERR_MEMORY;
+                                LOG("Get net cell fail.");
+                            } else {
+                                *data = cell_info.type; // Set network type.
+                                // Copy cell info item.
+                                #if 0
+                                int i = 0;
+                                while(i < cell_info.cell_num) {
+                                    memcpy(data + sizeof(uint8) + sizeof(mbtk_cell_info_t) * i,
+                                        &(cell_info.cell[i]),
+                                        sizeof(mbtk_cell_info_t));
+                                    i++;
+                                }
+                                #else
+                                memcpy(data + sizeof(uint8),
+                                        &(cell_info.cell),
+                                        sizeof(mbtk_cell_info_t) * cell_info.cell_num);
+                                #endif
+                                pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_CELL_RSP, data, sizeof(uint8) + sizeof(mbtk_cell_info_t) * cell_info.cell_num);
+                                free(data);
+                            }
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                            LOG("Get net cell fail.");
+                        }
+                    }
+                }
+                else     // Lock cell
+                {
+	                char *mem = (char*)(pack->data);
+					int len = pack->data_len;
+	                char reg[100] = {0};
+	                printf("mem:%s, len:%d", pack->data, pack->data_len);
+
+	                if(req_cell_info_set(mem, reg, len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+	                {
+	                //    printf("cpms_set fail\n");
+	                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+	                        err = MBTK_INFO_ERR_CME + cme_err;
+	                    } else {
+	                        err = MBTK_INFO_ERR_UNKNOWN;
+	                    }
+	                //    LOG("Set req_cell_info_set fail.");
+	                }
+	                else
+	                {
+
+	                    printf("req_cell_info_set success, reg:%s\n", reg);
+	                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_CELL_RSP, reg, strlen(reg));
+
+	                    // Restart is required to take effect.
+	                    LOG("Will reboot system...");
+	                }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_RADIO_REQ: // <uint8> 0:OFF 1:ON
+            {
+                if(pack->data_len == 0 || pack->data == NULL) // Get
+                {
+                    uint8 radio_on = (uint8)isRadioOn();
+                    if(radio_on < 0)
+                    {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                        LOG("Get radio state fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_RADIO_RSP, &radio_on, sizeof(uint8));
+                    }
+                }
+                else     // Set
+                {
+                    uint8 radio_on = *(pack->data);
+                    if(radio_on != 0 && radio_on != 1)
+                    {
+                        err = MBTK_INFO_ERR_REQ_PARAMETER;
+                        LOG("Set radio state fail.");
+                    }
+                    else
+                    {
+                        setRadioPower(radio_on);
+                        if((radio_on && net_info.radio_state == MBTK_RADIO_STATE_ON)
+                            || (!radio_on && net_info.radio_state == MBTK_RADIO_STATE_OFF)) {
+                            pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_RADIO_RSP, NULL, 0);
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                            LOG("Set radio state fail.");
+                        }
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_SIGNAL_REQ:  // mbtk_signal_info_t
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get net signal.
+                {
+                    mbtk_signal_info_t signal;
+                    memset(&signal, 0, sizeof(mbtk_signal_info_t));
+                    if(req_net_signal_get(&signal, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get net signal fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_SIGNAL_RSP, &signal, sizeof(mbtk_signal_info_t));
+                    }
+                }
+                else     // Set
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Set net signal fail.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_REG_REQ:  // mbtk_net_reg_info_t
+            {
+                if(pack->data_len == 0 || pack->data == NULL)   // Get net reg.
+                {
+                    mbtk_net_reg_info_t reg;
+                    memset(&reg, 0, sizeof(mbtk_net_reg_info_t));
+                    if(req_net_reg_get(&reg, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get net reg fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_REG_RSP, &reg, sizeof(mbtk_net_reg_info_t));
+                    }
+                }
+                else     // Set
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                    LOG("Set net reg fail.");
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_APN_REQ:   // mbtk_apn_info_t
+            {
+                if(pack->data_len == 0 || pack->data == NULL) // Get APN
+                {
+                    uint8 buff[SOCK_MSG_LEN_MAX];
+                    memset(buff, 0, SOCK_MSG_LEN_MAX);
+                    int data_len = 0;
+                    if(req_apn_get(buff, &data_len, &cme_err) || data_len <= 0 || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Get APN fail.");
+                    }
+                    else
+                    {
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_APN_RSP, buff, data_len);
+                    }
+                }
+                else     // Set
+                {
+                    // <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
+                    const uint8* ptr = pack->data;
+                    mbtk_apn_info_t apn;
+                    int len;
+                    memset(&apn, 0, sizeof(mbtk_apn_info_t));
+                    // cid
+                    apn.cid = *ptr++;
+
+                    // ip_type
+                    apn.ip_type = (mbtk_ip_type_enum)(*ptr++);
+
+                    // apn
+                    len = byte_2_uint16(ptr, false);
+                    ptr += sizeof(uint16);
+                    if(len > 0) {
+                        memcpy(apn.apn, ptr, len);
+                        ptr += len;
+                    }
+
+                    // user
+                    len = byte_2_uint16(ptr, false);
+                    ptr += sizeof(uint16);
+                    if(len > 0) {
+                        memcpy(apn.user, ptr, len);
+                        ptr += len;
+                    }
+
+                    // pass
+                    len = byte_2_uint16(ptr, false);
+                    ptr += sizeof(uint16);
+                    if(len > 0) {
+                        memcpy(apn.pass, ptr, len);
+                        ptr += len;
+                    }
+
+                    // auth
+                    len = byte_2_uint16(ptr, false);
+                    ptr += sizeof(uint16);
+                    if(len > 0) {
+                        memcpy(apn.auth, ptr, len);
+                        ptr += len;
+                    }
+
+                    LOGD("APN : %d, %d, %s, %s, %s, %s", apn.cid, apn.ip_type, str_empty(apn.apn) ? "NULL" : apn.apn,
+                        str_empty(apn.user) ? "NULL" : apn.user, str_empty(apn.pass) ? "NULL" : apn.pass, str_empty(apn.auth) ? "NULL" : apn.auth);
+                    if(req_apn_set(&apn, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                    {
+                        if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                            err = MBTK_INFO_ERR_CME + cme_err;
+                        } else {
+                            err = MBTK_INFO_ERR_UNKNOWN;
+                        }
+                        LOG("Set APN fail.");
+                    }
+                    else
+                    {
+                        // Save apn.
+                        apn_prop_set(&apn);
+
+                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_APN_RSP, NULL, 0);
+                    }
+                }
+                break;
+            }
+            case MBTK_INFO_ID_NET_DATA_CALL_REQ:
+            {
+                if(pack->data_len == 0 || pack->data == NULL)
+                {
+                    err = MBTK_INFO_ERR_UNSUPPORTED;
+                }
+                else
+                {
+                    /* <call_type[1]><cid[1]><auto_conn_interval[1]><boot_conn[1]><timeout[1]>
+                     call_type : mbtk_data_call_type_enum
+                     cid : 2 - 7
+                     timeout : second
+                    */
+                    mbtk_data_call_type_enum call_type = (mbtk_data_call_type_enum)pack->data[0];
+                    int cid = pack->data[1];
+                    int reconn = 0;
+
+                    if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+                        err = MBTK_INFO_ERR_CID;
+                        break;
+                    }
+
+                    LOG("cid_active[%d] = %d", cid, cid_active[cid]);
+                    memset(&cgact_wait, 0, sizeof(info_cgact_wait_t));
+                    switch(call_type) {
+                        case MBTK_DATA_CALL_START: {
+                            //mbtk wyq for data_call_ex add start
+                            int auto_conn_interval = pack->data[2];
+                            int boot_conn = pack->data[3];
+                            int timeout = pack->data[4];
+                            data_call_bootconn_save(cid, boot_conn);
+                            
+                            if(net_info.net_type != MBTK_RADIO_TECH_E_UTRAN)
+                            {
+                                err = MBTK_INFO_ERR_NET_NO_INIT;
+                                break;
+                            }
+                            
+                            if(cid_active[cid] == 1)
+                            {
+                                err = MBTK_INFO_ERR_CID_EXIST;
+                                break;
+                            }
+                            
+                            data_call_reconn:
+                            //mbtk wyq for data_call_ex add end
+                            cgact_wait.waitting = true;
+                            cgact_wait.cid = cid;
+                            cgact_wait.act = true;
+                            if(req_data_call_start(cid, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                            {
+                                //mbtk wyq for data_call_ex add start
+                                if(reconn < 5 && auto_conn_interval > 0)
+                                {
+                                    sleep(auto_conn_interval);
+                                    reconn++;
+                                    cme_err = MBTK_INFO_ERR_CME_NON;
+                                    LOG("data_call restart call.");
+                                    goto data_call_reconn;
+                                }
+                                //mbtk wyq for data_call_ex add end
+                                if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                    err = MBTK_INFO_ERR_CME + cme_err;
+                                } else {
+                                    err = MBTK_INFO_ERR_UNKNOWN;
+                                }
+                                LOG("%d active fail.", cid);
+                            }
+                            else
+                            {
+                                // Wait for "CONNECT" or "+CGEV:"
+                                if(wait_cgact_complete(timeout)) { // Timeout
+                                    err = MBTK_INFO_ERR_TIMEOUT;
+                                    break;
+                                }
+
+                                // Get IP information.
+                                mbtk_ipv4_info_t ipv4;
+                                mbtk_ipv6_info_t ipv6;
+                                memset(&ipv4, 0, sizeof(mbtk_ipv4_info_t));
+                                memset(&ipv6, 0, sizeof(mbtk_ipv6_info_t));
+                                if(req_data_call_state_get(cid, &ipv4, &ipv6, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                                {
+                                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                        err = MBTK_INFO_ERR_CME + cme_err;
+                                    } else {
+                                        err = MBTK_INFO_ERR_UNKNOWN;
+                                    }
+                                    LOG("Get %d state fail.", cid);
+                                }
+                                else
+                                {
+                                    // Config IPv4 address.
+#if 1
+                                    if(ipv4.valid) {
+                                        char dev[20] = {0};
+                                        sprintf(dev, "ccinet%d", cid - 1);
+
+                                        char ip[20] = {0};
+                                        char gateway[20] = {0};
+                                        char *gateway_ptr = NULL;
+                                        char netmask[20] = {0};
+                                        char *netmask_ptr = NULL;
+                                        if(inet_ntop(AF_INET, &(ipv4.IPAddr), ip, 20) == NULL) {
+                                            err = MBTK_INFO_ERR_UNKNOWN;
+                                            LOGE("inet_ntop ipv4 ip fail.");
+                                            log_hex("IPv4", &(ipv4.IPAddr), 4);
+                                            break;
+                                        }
+
+                                        if(ipv4.GateWay) {
+                                            if(inet_ntop(AF_INET, &(ipv4.GateWay), gateway, 20) == NULL) {
+                                                err = MBTK_INFO_ERR_UNKNOWN;
+                                                LOGE("inet_ntop ipv4 gateway fail.");
+                                                log_hex("IPv4", &(ipv4.IPAddr), 4);
+                                                break;
+                                            } else {
+                                                gateway_ptr = gateway;
+                                            }
+                                        }
+
+                                        if(ipv4.NetMask) {
+                                            if(inet_ntop(AF_INET, &(ipv4.NetMask), netmask, 20) == NULL) {
+                                                err = MBTK_INFO_ERR_UNKNOWN;
+                                                LOGE("inet_ntop ipv4 netmask fail.");
+                                                log_hex("IPv4", &(ipv4.IPAddr), 4);
+                                                break;
+                                            } else {
+                                                netmask_ptr = netmask;
+                                            }
+                                        }
+
+                                        if(netmask_ptr == NULL) {
+                                            netmask_ptr = netmask;
+                                            memcpy(netmask_ptr, "255.255.255.0", strlen("255.255.255.0"));
+                                        }
+
+                                        if(mbtk_ifc_configure2(dev, ip, 0, gateway_ptr, netmask_ptr)) {
+                                            LOGD("Config %s IPv4 %s fail.", dev, ip);
+                                        } else {
+                                            LOGD("Config %s IPv4 %s success.", dev, ip);
+                                        }
+
+                                    }
+#endif
+                                    // Config IPv6 address.
+                                    if(ipv6.valid) {
+                                        char ip[50] = {0};
+                                        char dev[20] = {0};
+                                        sprintf(dev, "ccinet%d", cid - 1);
+
+                                        if(inet_ntop(AF_INET6, &(ipv6.IPV6Addr), ip, 50) == NULL) {
+                                            err = MBTK_INFO_ERR_UNKNOWN;
+                                            LOGE("inet_ntop ipv6 ip fail.");
+                                            log_hex("IPv6", &(ipv6.IPV6Addr), 16);
+                                            break;
+                                        }
+
+                                        if(mbtk_ipv6_config(dev, ip, 64)) {
+                                            LOGD("Config %s IPv6 %s fail.", dev, ip);
+                                        } else {
+                                            LOGD("Config %s IPv6 %s success.", dev, ip);
+                                        }
+                                    }
+
+                                    cid_active[cid] = 1;
+                                    if(cli_info->fd != DATA_CALL_BOOTCONN_FD)
+                                    {
+                                        pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_DATA_CALL_RSP, NULL, 0);
+                                    }
+                                    else
+                                    {
+                                        free(pack->data);
+                                        free(cli_info);
+                                        LOG("data_call bootconn success.");
+                                    }
+                                }
+                            }
+                            break;
+                        }
+                        case MBTK_DATA_CALL_STOP: {
+                            //mbtk wyq for data_call_ex add start
+                            if(cid_active[cid] == 0)
+                            {
+                                err = MBTK_INFO_ERR_CID_NO_EXIST;
+                                break;
+                            }
+
+                            int timeout = pack->data[2];
+                            //mbtk wyq for data_call_ex add end
+                            
+                            cgact_wait.waitting = true;
+                            cgact_wait.cid = cid;
+                            cgact_wait.act = false;
+                            if(req_data_call_stop(cid, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                            {
+                                if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                    err = MBTK_INFO_ERR_CME + cme_err;
+                                } else {
+                                    err = MBTK_INFO_ERR_UNKNOWN;
+                                }
+                                LOG("%d deactive fail.", cid);
+                            }
+                            else
+                            {
+                                // Wait for "CONNECT" or "+CGEV:"
+                                if(wait_cgact_complete(timeout)) { // Timeout
+                                    err = MBTK_INFO_ERR_TIMEOUT;
+                                    break;
+                                }
+                                char dev[20] = {0};
+                                sprintf(dev, "ccinet%d", cid - 1);
+
+                                // Config network.
+                                if(mbtk_ifc_configure2(dev, NULL, 0, NULL, NULL)) {
+                                    LOGD("Config %s IPv4 0 fail.", dev);
+                                } else {
+                                    LOGD("Config %s IPv4 0 success.", dev);
+                                }
+
+#if 0
+                                if(mbtk_ipv6_config(dev, NULL, 64)) {
+                                    LOGD("Config %s IPv6 0 fail.", dev);
+                                } else {
+                                    LOGD("Config %s IPv6 0 success.", dev);
+                                }
+#endif
+                                cid_active[cid] = 0;
+                                pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_DATA_CALL_RSP, NULL, 0);
+                            }
+                            break;
+                        }
+                        case MBTK_DATA_CALL_STATE: {
+                            mbtk_ipv4_info_t ipv4;
+                            mbtk_ipv6_info_t ipv6;
+                            memset(&ipv4, 0, sizeof(mbtk_ipv4_info_t));
+                            memset(&ipv6, 0, sizeof(mbtk_ipv6_info_t));
+                            if(req_data_call_state_get(cid, &ipv4, &ipv6, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                            {
+                                if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                                    err = MBTK_INFO_ERR_CME + cme_err;
+                                } else {
+                                    err = MBTK_INFO_ERR_UNKNOWN;
+                                }
+                                LOG("Get %d state fail.", cid);
+                            }
+                            else
+                            {
+                                uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+                                int buff_len = 0;
+                                if(ipv4.valid && ipv6.valid) {
+                                    buff[0] = (uint8)2;
+                                    buff_len++;
+
+                                    memcpy(buff + buff_len, &ipv4, sizeof(mbtk_ipv4_info_t));
+                                    buff_len += sizeof(mbtk_ipv4_info_t);
+                                    memcpy(buff + buff_len, &ipv6, sizeof(mbtk_ipv6_info_t));
+                                    buff_len += sizeof(mbtk_ipv6_info_t);
+                                } else if(ipv4.valid) {
+                                    buff[0] = (uint8)0;
+                                    buff_len++;
+
+                                    memcpy(buff + buff_len, &ipv4, sizeof(mbtk_ipv4_info_t));
+                                    buff_len += sizeof(mbtk_ipv4_info_t);
+                                } else if(ipv6.valid) {
+                                    buff[0] = (uint8)1;
+                                    buff_len++;
+
+                                    memcpy(buff + buff_len, &ipv6, sizeof(mbtk_ipv6_info_t));
+                                    buff_len += sizeof(mbtk_ipv6_info_t);
+                                } else {
+                                    LOGE("Get IPv4/IPv6 fail.");
+                                    err = MBTK_INFO_ERR_UNKNOWN;
+                                    break;
+                                }
+                                pack_rsp_send(cli_info->fd, MBTK_INFO_ID_NET_DATA_CALL_RSP, buff, buff_len);
+                            }
+                            break;
+                        }
+                        default: {
+                            err = MBTK_INFO_ERR_FORMAT;
+                            break;
+                        }
+                    }
+                }
+                break;
+            }
+            default:
+            {
+                err = MBTK_INFO_ERR_REQ_UNKNOWN;
+                LOG("Unknown request : %s", id2str(pack->info_id));
+                break;
+            }
+        }
+
+        return err;
+    }
+}
+
+// Process AT URC data
+static int send_pack_to_queue(sock_client_info_t* cli_info, void* pack)
+{
+    if(info_queue.count >= PACK_PROCESS_QUEUE_MAX)
+    {
+        LOG("Packet process queue is full");
+        return -1;
+    }
+
+    info_queue_item_t *item = (info_queue_item_t*)malloc(sizeof(info_queue_item_t));
+    if(!item)
+    {
+        LOG("malloc() fail[%d].", errno);
+        return -1;
+    }
+    item->cli_info = cli_info;
+    item->pack = pack;
+    mbtk_queue_put(&info_queue, item);
+
+    // If thread is waitting,continue it.
+    if(1/*!is_running*/)
+    {
+        pthread_mutex_lock(&info_mutex);
+        pthread_cond_signal(&info_cond);
+        pthread_mutex_unlock(&info_mutex);
+    }
+    else
+    {
+        LOG("Packet process thread is process...");
+    }
+
+    return 0;
+}
+
+static void radio_state_change(void *data, int data_len)
+{
+    uint8 *data_ptr = (uint8*)data;
+    if(data_ptr[0]) {
+        net_info.radio_state = MBTK_RADIO_STATE_ON;
+    } else {
+        net_info.radio_state = MBTK_RADIO_STATE_OFF;
+    }
+
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            int i;
+            for(i = 0; i < IND_REGISTER_MAX; i++) {
+                // Registe MBTK_INFO_ID_IND_RADIO_STATE_CHANGE
+                if(cli->ind_register[i] == MBTK_INFO_ID_IND_RADIO_STATE_CHANGE) {
+                    pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_RADIO_STATE_CHANGE, data, data_len);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+static void pdp_state_change(void *data, int data_len)
+{
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            int i;
+            for(i = 0; i < IND_REGISTER_MAX; i++) {
+                if(cli->ind_register[i] == MBTK_INFO_ID_IND_PDP_STATE_CHANGE) {
+                    pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_PDP_STATE_CHANGE, data, data_len);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+static void net_state_change(void *data, int data_len)
+{
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            int i;
+            for(i = 0; i < IND_REGISTER_MAX; i++) {
+                // Registe MBTK_INFO_ID_IND_NET_STATE_CHANGE
+                if(cli->ind_register[i] == MBTK_INFO_ID_IND_NET_STATE_CHANGE) {
+                    pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_NET_STATE_CHANGE, data, data_len);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+static void call_state_change(void *data, int data_len)
+{
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            int i;
+            for(i = 0; i < IND_REGISTER_MAX; i++) {
+                // Registed MBTK_INFO_ID_IND_RADIO_STATE_CHANGE
+                if(cli->ind_register[i] == MBTK_INFO_ID_IND_CALL_STATE_CHANGE) {
+                    pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_CALL_STATE_CHANGE, data, data_len);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+static void sim_state_change(void *data, int data_len)
+{
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            int i;
+            for(i = 0; i < IND_REGISTER_MAX; i++) {
+                // Registed MBTK_INFO_ID_IND_RADIO_STATE_CHANGE
+                if(cli->ind_register[i] == MBTK_INFO_ID_IND_SIM_STATE_CHANGE) {
+                    pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_SIM_STATE_CHANGE, data, data_len);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+static void sms_state_change(void *data, int data_len)
+{
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            int i;
+            for(i = 0; i < IND_REGISTER_MAX; i++) {
+                // Registed MBTK_INFO_ID_IND_SMS_STATE_CHANGE
+                if(cli->ind_register[i] == MBTK_INFO_ID_IND_SMS_STATE_CHANGE) {
+                    pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_SMS_STATE_CHANGE, data, data_len);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+int urc_msg_distribute(bool async_process, info_urc_msg_id_enum msg, void *data, int data_len)
+{
+#if 0
+    if(urc_queue.count >= PACK_PROCESS_QUEUE_MAX)
+    {
+        LOG("Packet process queue is full");
+        return -1;
+    }
+
+    info_urc_msg_t *urc = (info_urc_msg_t*)malloc(sizeof(info_urc_msg_t));
+    if(!urc)
+    {
+        LOG("malloc() fail[%d].", errno);
+        return -1;
+    }
+    urc->msg = msg;
+    urc->data = memdup(data, data_len);
+    urc->data_len = data_len;
+
+    mbtk_queue_put(&urc_queue, urc);
+
+    // If thread is waitting,continue it.
+    if(1/*!is_running*/)
+    {
+        pthread_mutex_lock(&urc_mutex);
+        pthread_cond_signal(&urc_cond);
+        pthread_mutex_unlock(&urc_mutex);
+    }
+    else
+    {
+        LOG("Packet process thread is process...");
+    }
+
+    return 0;
+#else
+    if(async_process) {
+        info_urc_msg_t *urc = (info_urc_msg_t*)malloc(sizeof(info_urc_msg_t));
+        if(!urc)
+        {
+            LOG("malloc() fail[%d].", errno);
+            return -1;
+        }
+        urc->msg = msg;
+        if(data && data_len > 0) {
+            urc->data = memdup(data, data_len);
+            urc->data_len = data_len;
+        } else {
+            urc->data = NULL;
+            urc->data_len = 0;
+        }
+        return send_pack_to_queue(NULL, urc);
+    } else {
+        switch(msg) {
+            case INFO_URC_MSG_NET_CS_REG_STATE:
+            {
+                net_state_change(data, data_len);
+                break;
+            }
+            case INFO_URC_MSG_CALL_STATE:
+            {
+                call_state_change(data, data_len);
+                break;
+            }
+            case INFO_URC_MSG_SMS_STATE:
+            {
+                sms_state_change(data, data_len);
+                break;
+            }
+            case INFO_URC_MSG_SIM_STATE:
+            {
+                sim_state_change(data, data_len);
+                break;
+            }
+            case INFO_URC_MSG_PDP_STATE:
+            {
+                pdp_state_change(data, data_len);
+                break;
+            }
+            default: {
+                LOGE("Unknown msg : %d", msg);
+                break;
+            }
+        }
+
+        return 0;
+    }
+#endif
+}
+
+
+static void ind_regisger(sock_client_info_t* cli_info, uint16 ind)
+{
+    uint32 i = 0;
+    while(i < cli_info->ind_num)
+    {
+        if(cli_info->ind_register[i] == ind)
+            break;
+        i++;
+    }
+
+    if(i == cli_info->ind_num)   // No found IND
+    {
+        cli_info->ind_register[i] = ind;
+        cli_info->ind_num++;
+        LOG("Register IND : %s", id2str(ind));
+    }
+    else
+    {
+        LOG("IND had exist.");
+    }
+}
+
+static void pack_distribute(sock_client_info_t* cli_info, mbtk_info_pack_t* pack)
+{
+    // Register IND Message.
+    if(mbtk_info_type_get(pack->info_id) == MBTK_INFO_TYPE_IND)
+    {
+        mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+        if(cli_info->ind_num >= IND_REGISTER_MAX)
+        {
+            LOG("IND if full.");
+            err = MBTK_INFO_ERR_IND_FULL;
+        }
+        else
+        {
+            ind_regisger(cli_info, pack->info_id);
+        }
+
+        pack_error_send(cli_info->fd, pack->info_id, err);
+
+        mbtk_info_pack_free(&pack);
+    }
+    else     // Request Information.
+    {
+        LOG("Start process REQ(%s), Length : %d", id2str(pack->info_id), pack->data_len);
+        if(0 && pack->data_len > 0)
+        {
+            log_hex("DATA", pack->data, pack->data_len);
+        }
+
+        // Send to REQ_process_thread process.
+        send_pack_to_queue(cli_info, pack);
+
+        // For test.
+        // pack_error_send(cli_info->fd, pack->info_id + 1, MBTK_INFO_ERR_SUCCESS);
+    }
+}
+
+static sock_client_info_t* cli_find(int fd)
+{
+    sock_client_info_t *result = NULL;
+    list_first(sock_client_list);
+    while ((result = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if (result->fd == fd)
+            return result;
+    }
+
+    return NULL;
+}
+
+//mbtk wyq for server_ready_status add start
+void server_ready_set(void)
+{
+    server_ready_status = 1;
+}
+
+char server_ready_get(void)
+{
+    return server_ready_status;
+}
+
+static void server_state_send(void)
+{
+    sock_client_info_t *cli = NULL;
+    list_first(sock_client_list);
+    while ((cli = (sock_client_info_t*) list_next(sock_client_list)))
+    {
+        if(cli->ind_num > 0) {
+            if(cli->ind_register[0] == MBTK_INFO_ID_IND_SERVER_STATE_CHANGE) {
+                cli->ind_num = 0;
+                cli->ind_register[0] = 0;
+                pack_rsp_send(cli->fd , MBTK_INFO_ID_IND_SERVER_STATE_CHANGE, "1", 1);
+                break;
+            }
+        }
+        else
+        {
+            break;
+        }
+    }
+    LOG("handshake message send ok.");
+}
+
+//mbtk wyq for server_ready_status add end
+
+//mbtk wyq for data_call_ex add start
+//Save the cid that "DATA_CALL" needs to be automatically connected after startup
+void data_call_bootconn_save(int cid, int bootconn)
+{
+    if(cid_bootconn[cid] == bootconn + '0')
+    {
+        return;
+    }
+    cid_bootconn[cid] = bootconn + '0';
+
+    LOG("data_call_bootconn_set cid_bootconn = %s", cid_bootconn);
+    property_set("persist.mbtk.datacall.bootconn", cid_bootconn);
+}
+
+static void* data_call_bootconn_pthread(void *arg)
+{
+    UNUSED(arg);
+    LOG("data_call_bootconn_pthread enter.");
+    int i = 0;
+    int send_sum = 0;
+    int bootconn = 0;
+    
+    while(1)
+    {
+        if(server_ready_get() && send_sum == 0)
+        {
+            server_state_send();
+            send_sum = 1;
+        }
+        
+        if(net_info.sim_state == MBTK_SIM_READY && net_info.net_type == MBTK_RADIO_TECH_E_UTRAN && bootconn == 0)
+        {
+            //data_call_bootconn_exec();
+            property_get("persist.mbtk.datacall.bootconn", cid_bootconn, "00000000");
+            LOG("data_call_bootconn_exec cid_bootconn = %s", cid_bootconn);
+            
+            for(i = MBTK_APN_CID_MIN; i < MBTK_APN_CID_MAX + 1; i++)
+            {
+                if(cid_bootconn[i] == '1')
+                {
+                        sock_client_info_t *info = (sock_client_info_t*)malloc(sizeof(sock_client_info_t));
+                        if(info == NULL)
+                        {
+                            LOG("clinent_info  malloc() fail.");
+                            continue;
+                        }
+                        memset(info, 0, sizeof(sock_client_info_t));
+                        info->fd = DATA_CALL_BOOTCONN_FD;
+                        
+                        mbtk_info_pack_t* pack = mbtk_info_pack_creat(MBTK_INFO_ID_NET_DATA_CALL_REQ);
+                        if(pack == NULL)
+                        {
+                            free(info);
+                            LOG("Packet malloc() fail.");
+                            continue;
+                        }
+
+                        // "info_err"
+                        //pack->info_err = byte_2_uint16(ptr, false)
+
+                        // "data_len"
+                        pack->data_len = 5;
+
+                        char *p = (char *)malloc(5);
+                        p[0] = MBTK_DATA_CALL_START;
+                        p[1] = i;
+                        p[2] = 0;
+                        p[3] = 1;
+                        p[4] = 10;
+                        pack->data = p;
+                        send_pack_to_queue(info, pack);
+                }
+            }
+
+            bootconn = 1;
+        }
+
+        if(bootconn == 1 && send_sum == 1)
+        {
+            break;
+        }
+        else
+        {
+            sleep(1);
+        }
+    }
+
+    LOG("data_call_bootconn_pthread exit.");
+    return NULL;
+}
+
+//mbtk wyq for data_call_ex add end
+
+static void* info_main_pthread(void* arg)
+{
+    UNUSED(arg);
+    epoll_fd = epoll_create(SOCK_CLIENT_MAX + 1);
+    if(epoll_fd < 0)
+    {
+        LOG("epoll_create() fail[%d].", errno);
+        return NULL;
+    }
+
+    uint32 event = EPOLLIN | EPOLLET;
+    struct epoll_event ev;
+    ev.data.fd = sock_listen_fd;
+    ev.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+    epoll_ctl(epoll_fd,EPOLL_CTL_ADD,sock_listen_fd,&ev);
+
+    int nready = -1;
+    struct epoll_event epoll_events[EPOLL_LISTEN_MAX];
+    while(1)
+    {
+        nready = epoll_wait(epoll_fd, epoll_events, EPOLL_LISTEN_MAX, -1);
+        if(nready > 0)
+        {
+            sock_client_info_t *cli_info = NULL;
+            int i;
+            for(i = 0; i < nready; i++)
+            {
+                LOG("fd[%d] event = %x",epoll_events[i].data.fd, epoll_events[i].events);
+                if(epoll_events[i].events & EPOLLHUP)   // Client Close.
+                {
+                    if((cli_info = cli_find(epoll_events[i].data.fd)) != NULL)
+                    {
+                        cli_close(cli_info);
+                    }
+                    else
+                    {
+                        LOG("Unknown client[fd = %d].", epoll_events[i].data.fd);
+                    }
+                }
+                else if(epoll_events[i].events & EPOLLIN)
+                {
+                    if(epoll_events[i].data.fd == sock_listen_fd)   // New clients connected.
+                    {
+                        int client_fd = -1;
+                        while(1)
+                        {
+                            struct sockaddr_in cliaddr;
+                            socklen_t clilen = sizeof(cliaddr);
+                            client_fd = accept(epoll_events[i].data.fd, (struct sockaddr *) &cliaddr, &clilen);
+                            if(client_fd < 0)
+                            {
+                                if(errno == EAGAIN)
+                                {
+                                    LOG("All client connect get.");
+                                }
+                                else
+                                {
+                                    LOG("accept() error[%d].", errno);
+                                }
+                                break;
+                            }
+                            // Set O_NONBLOCK
+                            int flags = fcntl(client_fd, F_GETFL, 0);
+                            if (flags > 0)
+                            {
+                                flags |= O_NONBLOCK;
+                                if (fcntl(client_fd, F_SETFL, flags) < 0)
+                                {
+                                    LOG("Set flags error:%d", errno);
+                                }
+                            }
+
+                            memset(&ev,0,sizeof(struct epoll_event));
+                            ev.data.fd = client_fd;
+                            ev.events = event;//EPOLLIN | EPOLLERR | EPOLLET;
+                            epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev);
+
+                            sock_client_info_t *info = (sock_client_info_t*)malloc(sizeof(sock_client_info_t));
+                            if(info)
+                            {
+                                memset(info, 0, sizeof(sock_client_info_t));
+                                info->fd = client_fd;
+                                if(server_ready_get() == 1)
+                                {
+                                    info->ind_num = 0;
+                                    pack_rsp_send(info->fd , MBTK_INFO_ID_IND_SERVER_STATE_CHANGE, "1", 1);
+                                    LOG("server ready ok.");
+                                }
+                                else
+                                {
+                                    info->ind_num = 1;
+                                    info->ind_register[0] = MBTK_INFO_ID_IND_SERVER_STATE_CHANGE;
+                                    LOG("server ready no.");
+                                }
+                                list_add(sock_client_list, info);
+                                LOG("Add New Client FD Into List.");
+                            }
+                            else
+                            {
+                                LOG("malloc() fail.");
+                            }
+                        }
+                    }
+                    else if((cli_info = cli_find(epoll_events[i].data.fd)) != NULL)    // Client data arrive.
+                    {
+                        // Read and process every message.
+                        mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+                        mbtk_info_pack_t** pack = mbtk_info_pack_recv(cli_info->fd, true, &err);
+
+                        // Parse packet error,send error response to client.
+                        if(pack == NULL)
+                        {
+                            if(err != MBTK_INFO_ERR_SUCCESS)
+                            {
+                                pack_error_send(cli_info->fd, MBTK_INFO_ID_REQ_UNKNOWN, err);
+                            }
+                        }
+                        else
+                        {
+#if 0
+                            int i = 0;
+                            while(pack[i] != NULL)
+                            {
+                                pack_distribute(cli_info, pack[i]);
+                                // Not free,will free in pack_process() or packet process thread.
+                                //mbtk_info_pack_free(&(pack[i]));
+                                i++;
+                            }
+                            free(pack);
+#else
+                            mbtk_info_pack_t** pack_ptr = pack;
+                            while(*pack_ptr)
+                            {
+                                pack_distribute(cli_info, *pack_ptr);
+                                // Not free,will free in pack_process() or packet process thread.
+                                //mbtk_info_pack_free(pack_ptr);
+                                pack_ptr++;
+                            }
+
+                            free(pack);
+#endif
+                        }
+                    }
+                    else
+                    {
+                        LOG("Unknown socket : %d", epoll_events[i].data.fd);
+                    }
+                }
+                else
+                {
+                    LOG("Unknown event : %x", epoll_events[i].events);
+                }
+            }
+        }
+        else
+        {
+            LOG("epoll_wait() fail[%d].", errno);
+        }
+    }
+
+    return NULL;
+}
+
+static void data_call_restart()
+{
+#if 0
+    // Waitting for network ok.
+    mbtk_net_info_t info;
+    int cme_err;
+    int i = 0;
+    while(i < 15) { // 15s timeout
+        cme_err = MBTK_INFO_ERR_CME_NON;
+        memset(&info, 0, sizeof(mbtk_net_info_t));
+        if(!req_net_sel_mode_get(&info, &cme_err) && cme_err == MBTK_INFO_ERR_CME_NON)
+        {
+            if(info.net_type >= 2) {
+                break;
+            }
+        }
+
+        sleep(1);
+        i++;
+    }
+#endif
+    // +CGACT
+    int cid;
+    LOGD("Start active APN.");
+    for(cid = MBTK_APN_CID_MIN; cid <= MBTK_APN_CID_MAX && cid_active[cid]; cid++) {
+        LOG("Active cid : %d", cid);
+        req_data_call_start(cid, NULL);
+    }
+}
+
+/*
+void mbtk_radio_ready_cb()
+{
+    pthread_t radio_pid;
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+    {
+        LOG("pthread_attr_setdetachstate() fail.");
+        return;
+    }
+
+    if(pthread_create(&radio_pid, &thread_attr, radio_ready_thread, NULL))
+    {
+        LOG("pthread_create() fail.");
+    }
+
+    pthread_attr_destroy(&thread_attr);
+}
+*/
+
+static void net_ifc_state_change(bool act, int cid)
+{
+    if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) { // No nothing for cid 1 and 8
+        return;
+    }
+
+    char dev[20] = {0};
+    sprintf(dev, "ccinet%d", cid - 1);
+    if(act) { // Config IP.
+        // Get IP information.
+        mbtk_ipv4_info_t ipv4;
+        mbtk_ipv6_info_t ipv6;
+        memset(&ipv4, 0, sizeof(mbtk_ipv4_info_t));
+        memset(&ipv6, 0, sizeof(mbtk_ipv6_info_t));
+        int cme_err = MBTK_INFO_ERR_CME_NON;
+        if(!req_data_call_state_get(cid, &ipv4, &ipv6, &cme_err) && cme_err == MBTK_INFO_ERR_CME_NON)
+        {
+            // Config IPv4 address.
+            if(ipv4.valid) {
+                char ip[20] = {0};
+                if(inet_ntop(AF_INET, &(ipv4.IPAddr), ip, 20) == NULL) {
+                    LOGE("inet_ntop ipv4 ip fail.");
+                    return;
+                }
+
+                if(mbtk_ifc_configure2(dev, ip, 0, NULL, "255.255.255.0")) {
+                    LOGD("Config %s IPv4 %s fail.", dev, ip);
+                } else {
+                    LOGD("Config %s IPv4 %s success.", dev, ip);
+                }
+            }
+
+            // Config IPv6 address.
+            if(ipv6.valid) {
+                char ip[50] = {0};
+
+                if(inet_ntop(AF_INET6, &(ipv6.IPV6Addr), ip, 50) == NULL) {
+                    LOGE("inet_ntop ipv6 ip fail.");
+                    return;
+                }
+
+                if(mbtk_ipv6_config(dev, ip, 64)) {
+                    LOGD("Config %s IPv6 %s fail.", dev, ip);
+                } else {
+                    LOGD("Config %s IPv6 %s success.", dev, ip);
+                }
+            }
+        }
+    } else { // Del IP
+        if(mbtk_ifc_configure2(dev, NULL, 0, NULL, NULL)) {
+            LOGD("Config %s IPv4 0 fail.", dev);
+        } else {
+            LOGD("Config %s IPv4 0 success.", dev);
+        }
+    }
+}
+
+static void urc_msg_process(info_urc_msg_t *msg)
+{
+    uint8 *data = NULL;
+    if(msg->data) {
+        data = (uint8*)msg->data;
+    }
+    switch(msg->msg) {
+        case INFO_URC_MSG_RADIO_STATE:
+        {
+            radio_state_change(msg->data, msg->data_len);
+            // Reconfig APN while radio on.
+            if(data[0]) {
+                apn_prop_get();
+            }
+            break;
+        }
+        case INFO_URC_MSG_CGEV:
+        {
+            bool act = data[0];
+            int cid = data[1];
+            if(cid > 0) {
+                net_ifc_state_change(act, cid);
+            }
+            break;
+        }
+        case INFO_URC_MSG_NET_PS_REG_STATE:
+        {
+            uint8 net_data[3];
+            net_data[0] = (uint8)MBTK_NET_PS_STATE;
+            net_data[1] = data[0];
+            mbtk_net_reg_state_enum state = (mbtk_net_reg_state_enum)data[0];
+            if(state == MBTK_NET_REG_STATE_HOME
+                || state == MBTK_NET_REG_STATE_ROAMING) { // Registered, home network or roaming.
+                mbtk_net_info_t info;
+                int cme_err = MBTK_INFO_ERR_CME_NON;
+                memset(&info, 0, sizeof(mbtk_net_info_t));
+                if(!req_net_sel_mode_get(&info, &cme_err) && cme_err == MBTK_INFO_ERR_CME_NON)
+                {
+                    net_data[2] = info.net_type;
+                    net_state_change(net_data, sizeof(net_data));
+
+                    if(info.net_type >= MBTK_RADIO_TECH_UTRAN) {
+                        data_call_restart();
+                    }
+                } else {
+                    net_data[2] = (uint8)0xFF;
+                    net_state_change(net_data, sizeof(net_data));
+                }
+            } else {
+                net_data[2] = (uint8)0xFF;
+                net_state_change(net_data, sizeof(net_data));
+            }
+            break;
+        }
+        case INFO_URC_MSG_NET_STATE_LOG:
+        {
+            // Get network state and signal.
+            char buff[256] = {0};
+            mbtk_signal_info_t signal;
+            memset(&signal, 0xFF, sizeof(mbtk_signal_info_t));
+            if(!req_net_signal_get(&signal, NULL)) {
+                char tmp[50] = {0};
+                struct timeval log_time;
+                gettimeofday(&log_time, NULL);
+                struct tm* tm_t = localtime(&(log_time.tv_sec));
+                strftime(tmp, 50, "%F %T", tm_t);
+                snprintf(buff, sizeof(buff), "%s:%d,%d,%d,%d,%d,%d,%d,%d", tmp, signal.type, signal.rssi, signal.rxlev, signal.ber, signal.rscp, signal.ecno,
+                    signal.rsrq, signal.rsrp);
+                mbtk_signal_log(buff);
+            }
+            //
+            break;
+        }
+        default:
+        {
+            LOGE("Unknown URC : %d", msg->msg);
+            break;
+        }
+    }
+}
+
+static void* pack_process_thread(void* arg)
+{
+    UNUSED(arg);
+    info_queue_item_t* item = NULL;
+    mbtk_queue_init(&info_queue);
+    pthread_mutex_init(&info_mutex, NULL);
+    pthread_cond_init(&info_cond, NULL);
+
+    memset(&band_support, 0xFF, sizeof(mbtk_band_info_t));
+
+    pthread_mutex_lock(&info_mutex);
+    while(TRUE)
+    {
+        if(mbtk_queue_empty(&info_queue))
+        {
+            LOG("Packet process wait...");
+            pthread_cond_wait(&info_cond, &info_mutex);
+            LOG("Packet process continue...");
+        }
+        else
+        {
+            LOG("Packet process queue not empty,continue...");
+        }
+
+        // Process all information request.
+        mbtk_info_err_enum err;
+        while((item = (info_queue_item_t*)mbtk_queue_get(&info_queue)) != NULL)
+        {
+            if(item->cli_info) { // REQ form client.
+                mbtk_info_pack_t *pack = (mbtk_info_pack_t*)item->pack;
+                LOG("Process REQ %s.", id2str(pack->info_id));
+                at_process = true;
+                err = pack_req_process(item->cli_info, pack);
+                if(err != MBTK_INFO_ERR_SUCCESS)
+                {
+                    if(item->cli_info->fd != DATA_CALL_BOOTCONN_FD)
+                    {
+                        pack_error_send(item->cli_info->fd, pack->info_id + 1, err);
+                    }
+                    else
+                    {
+                        free(pack->data);
+                        free(item->cli_info);
+                    }
+                }
+                at_process = false;
+                mbtk_info_pack_free(&pack);
+                free(item);
+            } else { // REQ from myself.
+                info_urc_msg_t *urc = (info_urc_msg_t*)item->pack;
+                LOG("Process URC %d.", urc->msg);
+                urc_msg_process(urc);
+                if(!urc->data)
+                    free(urc->data);
+                free(urc);
+            }
+        }
+    }
+    pthread_mutex_unlock(&info_mutex);
+    return NULL;
+}
+
+void apn_prop_get()
+{
+    char prop_name[20];
+    char prop_data[300];
+    // cid : 2 - 7
+    int cid = MBTK_APN_CID_MIN;
+    mbtk_apn_info_t apn;
+    for(; cid <= MBTK_APN_CID_MAX; cid++) {
+        memset(prop_name, 0, 20);
+        memset(prop_data, 0, 300);
+        memset(&apn, 0, sizeof(mbtk_apn_info_t));
+        sprintf(prop_name, "%s_%d",MBTK_APN_PROP,cid);
+        if(property_get(prop_name, prop_data, "") > 0 && !str_empty(prop_data)) {
+            apn.cid = cid;
+            char *ptr_1 = prop_data;
+            apn.ip_type = (mbtk_ip_type_enum)atoi(ptr_1);
+            ptr_1 = strstr(ptr_1, ",");
+            if(!ptr_1) {
+                continue;
+            }
+            ptr_1++; // Jump ',' to apn
+
+            char *ptr_2 = strstr(ptr_1, ",");
+            if(!ptr_2) {
+                continue;
+            }
+            memcpy(apn.apn, ptr_1, ptr_2 - ptr_1); // apn
+
+            ptr_2++; // Jump ',' to user
+            ptr_1 = strstr(ptr_2, ",");
+            if(!ptr_1) {
+                continue;
+            }
+            if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
+                memcpy(apn.user, ptr_2, ptr_1 - ptr_2); // user
+            }
+
+            ptr_1++; // Jump ',' to pass
+            ptr_2 = strstr(ptr_1, ",");
+            if(!ptr_2) {
+                continue;
+            }
+            if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
+                memcpy(apn.pass, ptr_1, ptr_2 - ptr_1); // pass
+            }
+
+            ptr_2++; // Jump ',' to auth (Is last item)
+            if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
+                memcpy(apn.auth, ptr_2, strlen(ptr_2)); // auth
+            }
+
+            req_apn_set(&apn, NULL);
+        }
+    }
+}
+
+/*
+AT*BAND=15,78,147,482,134742231
+
+OK
+*/
+static int lte_b28_set()
+{
+    int err = -1;
+    ATResponse *p_response = NULL;
+    char *line;
+    char *ipv4 = NULL, *ipv6 = NULL;
+    err = at_send_command("AT*BAND=15,78,147,482,134742231", &p_response);
+    if ((err < 0) || (p_response == NULL) || (p_response->success == 0))
+    {
+        LOGE("*BAND exec error.");
+        err = -1;
+        goto error;
+    }
+
+    LOGD("Set B28 Success.");
+    err = 0;
+
+error:
+    at_response_free(p_response);
+    return err;
+}
+
+static void* net_monitor_thread(void* arg)
+{
+    UNUSED(arg);
+    // Start network monitor
+    int cid;
+    while(1) {
+#if 0
+        // Config IP
+        list_node_t* apn_list = NULL;
+        if(!apn_state_get(&apn_list) && apn_list != NULL) {
+            info_apn_ip_t *apn = NULL;
+            for(cid = MBTK_APN_CID_MIN; cid <= MBTK_APN_CID_MAX && cid_active[cid]; cid++) {
+                bool ip_found = false;
+                list_first(apn_list);
+                while ((apn = (info_apn_ip_t*) list_next(apn_list))) {
+                    if(cid == apn->cid) {
+                        ip_found = true;
+                        break;
+                    }
+                }
+
+                char dev[20] = {0};
+                sprintf(dev, "ccinet%d", cid - 1);
+                if(ip_found) { // Ip ok,set IP.
+                    if(apn->ipv4_valid) {
+                        if(mbtk_ifc_configure2(dev, (char*)apn->ipv4, 0, NULL, "255.255.255.0")) {
+                            LOGD("Config %s IPv4 %s fail.", dev, apn->ipv4);
+                        } else {
+                            LOGD("Config %s IPv4 %s success.", dev, apn->ipv4);
+                        }
+                    }
+
+                    if(apn->ipv6_valid) {
+                        if(mbtk_ipv6_config(dev, (char*)apn->ipv6, 64)) {
+                            LOGD("Config %s IPv6 %s fail.", dev, apn->ipv6);
+                        } else {
+                            LOGD("Config %s IPv6 %s success.", dev, apn->ipv6);
+                        }
+                    }
+                } else { // No ip
+                    if(mbtk_ifc_configure2(dev, NULL, 0, NULL, NULL)) {
+                        LOGD("Config %s IPv4 0 fail.", dev);
+                    } else {
+                        LOGD("Config %s IPv4 0 success.", dev);
+                    }
+                }
+            }
+
+            list_free(apn_list);
+        }
+#endif
+
+        if(net_info.radio_state == MBTK_RADIO_STATE_ON && net_info.sim_state == MBTK_SIM_READY) {
+#if 0
+            urc_msg_distribute(true, INFO_URC_MSG_NET_CS_REG_STATE, NULL, 0);
+#else
+            info_urc_msg_t *urc = (info_urc_msg_t*)malloc(sizeof(info_urc_msg_t));
+            if(!urc)
+            {
+                LOG("malloc() fail[%d].", errno);
+            } else {
+                urc->msg = INFO_URC_MSG_NET_STATE_LOG;
+                urc->data = NULL;
+                urc->data_len = 0;
+                send_pack_to_queue(NULL, urc);
+            }
+#endif
+        }
+
+        sleep(15);
+    }
+
+    LOGD("monitor_thread exit.");
+    return NULL;
+}
+
+static void* urc_process_thread(void* arg)
+{
+    UNUSED(arg);
+    info_urc_msg_t* item = NULL;
+    mbtk_queue_init(&urc_queue);
+    pthread_mutex_init(&urc_mutex, NULL);
+    pthread_cond_init(&urc_cond, NULL);
+
+    pthread_mutex_lock(&urc_mutex);
+    while(TRUE)
+    {
+        if(mbtk_queue_empty(&urc_queue))
+        {
+            LOG("URC process wait...");
+            pthread_cond_wait(&urc_cond, &urc_mutex);
+            LOG("URC process continue...");
+        }
+        else
+        {
+            LOG("URC process queue not empty,continue...");
+        }
+
+        // Process all information request.
+        while((item = (info_urc_msg_t*)mbtk_queue_get(&urc_queue)) != NULL)
+        {
+            LOG("Process URC %d.", item->msg);
+            uint8 *data = (uint8*)item->data;
+            switch(item->msg) {
+                case INFO_URC_MSG_RADIO_STATE:
+                {
+                    radio_state_change(item->data, item->data_len);
+                    break;
+                }
+                case INFO_URC_MSG_CGEV:
+                {
+                    bool act = data[0];
+                    int cid = data[1];
+                    if(cid > 0) {
+                        net_ifc_state_change(act, cid);
+                    }
+                    break;
+                }
+                default:
+                {
+                    LOGE("Unknown URC : %d", item->msg);
+                    break;
+                }
+            }
+            if(!item->data)
+                free(item->data);
+            free(item);
+        }
+    }
+    pthread_mutex_unlock(&urc_mutex);
+
+    return NULL;
+}
+
+static void ril_at_ready_process()
+{
+    net_info.radio_state = (isRadioOn() == 1) ? MBTK_RADIO_STATE_ON : MBTK_RADIO_STATE_OFF;
+#if 1
+    if (net_info.radio_state != MBTK_RADIO_STATE_ON)
+    {
+        setRadioPower(1);
+    } else { // Radio has ON
+        apn_prop_get();
+    }
+
+    if(net_info.radio_state == MBTK_RADIO_STATE_ON)
+    {
+        at_send_command("AT+CEREG=2", NULL);
+    }
+
+    int count = 0;
+#endif
+    net_info.sim_state = getSIMStatus();
+#if 0
+    while (net_info.sim_state != MBTK_SIM_READY && count < 30)
+    {
+        if(net_info.radio_state != MBTK_RADIO_STATE_ON)
+        {
+            setRadioPower(1);
+        }
+        LOGD("Waitting for SIM READY...");
+        sleep(1);
+        net_info.sim_state = getSIMStatus();
+        count++;
+    }
+#endif
+    if(net_info.sim_state == MBTK_SIM_READY)
+    {
+        LOGD("SIM READY!");
+    }
+    else
+    {
+        LOGE("SIM NOT READY!");
+    }
+
+    // Set B28
+    // AT*BAND=15,78,147,482,134742231
+#if MBTK_LTE_B28_SUPPORT
+    char b28_config[10];
+    memset(b28_config, 0, 10);
+    property_get("persist.mbtk.b28_config", b28_config, "0");
+    if(atoi(b28_config) == 0) {
+        if(!lte_b28_set()) { // Set B28 success.
+            property_set("persist.mbtk.b28_config", "1");
+        }
+    }
+#endif
+}
+
+int mbtk_info_server_start()
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    if(sock_listen_fd > 0)
+    {
+        LOG("Information Server Has Started.");
+        return -1;
+    }
+
+    struct sockaddr_un server_addr;
+    sock_listen_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if(sock_listen_fd < 0)
+    {
+        LOG("socket() fail[%d].", errno);
+        return -1;
+    }
+
+    // Set O_NONBLOCK
+    int flags = fcntl(sock_listen_fd, F_GETFL, 0);
+    if (flags < 0)
+    {
+        LOG("Get flags error:%d", errno);
+        goto error;
+    }
+    flags |= O_NONBLOCK;
+    if (fcntl(sock_listen_fd, F_SETFL, flags) < 0)
+    {
+        LOG("Set flags error:%d", errno);
+        goto error;
+    }
+
+    unlink(SOCK_INFO_PATH);
+    memset(&server_addr, 0, sizeof(struct sockaddr_un));
+    server_addr.sun_family = AF_LOCAL;
+    strcpy(server_addr.sun_path, SOCK_INFO_PATH);
+    if(bind(sock_listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)))
+    {
+        LOG("bind() fail[%d].", errno);
+        goto error;
+    }
+
+    if(listen(sock_listen_fd, SOCK_CLIENT_MAX))
+    {
+        LOG("listen() fail[%d].", errno);
+        goto error;
+    }
+
+    sock_client_list = list_create(sock_cli_free_func);
+    if(sock_client_list == NULL)
+    {
+        LOG("list_create() fail.");
+        goto error;
+    }
+
+    pthread_t info_pid, pack_pid, monitor_pid, urc_pid, bootconn_pid;
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+    {
+        LOG("pthread_attr_setdetachstate() fail.");
+        goto error;
+    }
+
+    if(pthread_create(&info_pid, &thread_attr, info_main_pthread, NULL))
+    {
+        LOG("pthread_create() fail.");
+        goto error;
+    }
+
+    if(pthread_create(&pack_pid, &thread_attr, pack_process_thread, NULL))
+    {
+        LOG("pthread_create() fail.");
+        goto error;
+    }
+
+#if 0
+    if(pthread_create(&urc_pid, &thread_attr, urc_process_thread, NULL))
+    {
+        LOG("pthread_create() fail.");
+        goto error;
+    }
+#endif
+
+    ril_at_ready_process();
+
+    if(pthread_create(&monitor_pid, &thread_attr, net_monitor_thread, NULL))
+    {
+        LOG("pthread_create() fail.");
+    }
+
+    //mbtk wyq for data_call_ex add start
+    if(pthread_create(&bootconn_pid, &thread_attr, data_call_bootconn_pthread, NULL))
+    {
+        LOG("pthread_create() fail.");
+    }
+    //mbtk wyq for data_call_ex add end
+
+    pthread_attr_destroy(&thread_attr);
+
+    LOG("MBTK Information Server Start...");
+
+    return 0;
+
+error:
+    close(sock_listen_fd);
+    sock_listen_fd = -1;
+    return -1;
+}
+
+#if 0
+int main(int argc, char *argv[])
+{
+    if(mbtk_info_server_start())
+    {
+        return -1;
+    }
+
+    while(1)
+    {
+        sleep(24 * 60 * 60);
+    }
+
+    return 0;
+}
+#endif
+
+
diff --git a/mbtk/mbtk_ril/src/mbtk_phonebook.c b/mbtk/mbtk_ril/src/mbtk_phonebook.c
new file mode 100755
index 0000000..215727c
--- /dev/null
+++ b/mbtk/mbtk_ril/src/mbtk_phonebook.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_type.h"
+#include "mbtk_info.h"
+#include "atchannel.h"
+#include "at_tok.h"
+#include "mbtk_utils.h"
+#include "info_data.h"
+
+void pack_rsp_send(int fd, int info_id, const void* data, int data_len);
+
+//void net_list_free(void *data);
+// Return MBTK_INFO_ERR_SUCCESS,will call pack_error_send() to send RSP.
+// Otherwise, do not call pack_error_send().
+mbtk_info_err_enum pb_pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack)
+{
+    mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+    int cme_err = MBTK_INFO_ERR_CME_NON;
+    switch(pack->info_id)
+    {
+        case MBTK_INFO_ID_PB_STATE_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set
+            {
+
+            }
+            break;
+        }
+        default:
+        {
+            err = MBTK_INFO_ERR_REQ_UNKNOWN;
+            LOG("Unknown request : %s", id2str(pack->info_id));
+            break;
+        }
+    }
+
+    return err;
+}
+
+
diff --git a/mbtk/mbtk_ril/src/mbtk_sms.c b/mbtk/mbtk_ril/src/mbtk_sms.c
new file mode 100755
index 0000000..5235a18
--- /dev/null
+++ b/mbtk/mbtk_ril/src/mbtk_sms.c
@@ -0,0 +1,1212 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_type.h"
+#include "mbtk_info.h"
+#include "atchannel.h"
+#include "at_tok.h"
+#include "mbtk_utils.h"
+#include "info_data.h"
+
+void pack_rsp_send(int fd, int info_id, const void* data, int data_len);
+
+/*
+AT+CMGF?
++CMGF: 0
+
+OK
+
+*/
+static int req_cmgf_get(int *state, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+CMGF?", "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    printf("req_cmgf_get() ---line:%s\n", line);
+    char* ptr = strstr(line, "+CMGF: ");
+    printf("req_cmgf_get() ---ptr:%s\n",ptr);
+    if(ptr)
+    {
+        *state = atoi(ptr + strlen("+CMGF: "));
+    }
+    else
+    {
+        err = -1;
+    }
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CMGF=0"
+or
+AT+CMGF=1"
+
+OK
+*/
+static int req_cmgf_set(int state, int *cme_err)
+{
+    printf("req_cmgf_set()-------------start\n");
+    printf("state:%d\n",state);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+    if(state)
+    {
+        strcpy(cmd, "AT+CMGF=1");
+    }
+    else
+    {
+        strcpy(cmd, "AT+CMGF=0");
+    }
+
+    printf("req_cmgf_set()----cmd:%s\n", cmd);
+    int err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0) {
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*set AT+CNMI=1,2*/
+static int req_cnmi_set(int *cme_err)
+{
+    printf("req_cnmi_set()-------------start3\n");
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+
+	strcpy(cmd, "AT+CNMI=1,2");
+
+    printf("req_cnmi_set()----cmd:%s\n", cmd);
+    int err = at_send_command(cmd, &response);
+
+    if (err < 0 || response->success == 0) {
+		printf("err:%d, response->success:%d \n", err, response->success);
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    err = 0;
+exit:
+    at_response_free(response);
+    printf("exit,err:%d\n", err);
+    return err;
+}
+
+/*
+AT+CPMS?
+
++CPMS: "SM",15,50,"SM",15,50,"SM",15,50
+
+OK
+
+*/
+static int req_cpms_get(char *reg, int *cme_err)
+{
+	printf("req_cpms_get------------start(3)\n");
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+CPMS?", "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+	ATLine* lines_ptr = response->p_intermediates;
+	char *line = NULL;
+	int len = 0;
+	while(lines_ptr)
+	{
+		line = lines_ptr->line;
+		if(line ==NULL)
+		{
+			printf("line is null----------------------\n");
+		}
+
+		printf("-----------line:%s, strlen:%d, len:%d----------\n", line, strlen(line), len);
+		memcpy(reg+len, line, strlen(line));
+        len += strlen(line);
+		lines_ptr = lines_ptr->p_next;
+	}
+
+	printf("cpms_get()------reg:%s\n", reg);
+
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+
+/*
+AT+CPMS=<mem1>[,<mem2>[,<mem3>]]
+AT+CPMS="ME","ME","ME"
+
++CPMS: 14,50,14,50,14,50
+
+OK
+
+*/
+static int req_cpms_set(const char *mem, char *reg, int len, int *cme_err)
+{
+    printf("req_cpms_set(2)----------------start\n");
+    printf("mem:%s\n", mem);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+    int err = 0;
+	char data[20] = {0};
+
+    if(mem != NULL)
+    {
+    	memcpy(data, mem, len);
+        sprintf(cmd, "AT+CPMS=%s", data);
+    }
+    else{
+        printf("mem is null\n");
+    }
+
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+
+	if(strlen(cmd) > 8)
+	{
+        err = at_send_command_multiline(cmd, "+CPMS:", &response);
+        if (err < 0 || response->success == 0){
+            *cme_err = at_get_cme_error(response);
+            goto exit;
+        }
+
+        char *line = response->p_intermediates->line;
+        printf("line:%s, len:%d\n", line, strlen(line));
+
+        memcpy(reg, line, strlen(line));
+
+        printf("cpms_reg:%s\n", reg);
+	}
+    err = 0;
+exit:
+    printf("goto exit do");
+    at_response_free(response);
+    return err;
+}
+
+/*
+if PDU mode (+CMGF=0):
+	AT+CMGS=<length><CR>
+PDU is given<ctrl-Z/ESC>
+if text mode (+CMGF=1):
+	AT+CMGS=<da>[,<toda>]<CR>
+text is entered<ctrl-Z/ESC>
+
+	AT+CMGS=15775690697,hello world
+
+
+*/
+static int req_cmgs_set(char *cmgs, char *reg, int len, int *cme_err)
+{
+    printf("req_cmgs_set()----------------start\n");
+    printf("cmgs:%s\n", cmgs);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char pnum[13] = {0};
+    char *ptr = cmgs;
+    int err = 0;
+	int data_len = 0;
+
+	char *src = strstr(cmgs, ",");
+	if(src != NULL)
+	{
+		memcpy(pnum, ptr,  src - ptr);
+		src++;
+		int data_len = 0;
+        data_len = len - (src - ptr);
+		memcpy(data, src, data_len);
+	}
+
+	sprintf(cmd, "AT+CMGS=%s", pnum);
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+	
+
+	if(strlen(cmd) > 0)
+	{
+		int err = at_send_command_sms(cmd, data, "+CMGS: ", &response);
+		printf("err:%d, response:%d\n", err, response->success);
+
+		if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+		char *line;
+		line = response->p_intermediates->line;
+		memcpy(reg, line, strlen(line));
+		printf("line:%s\n", line);
+
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+static int req_cmgw_set(char *cmgw,int len, int *cme_err)
+{
+    printf("req_cmgw_set()----------------start\n");
+    printf("cmgw:%s\n", cmgw);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char pnum[13] = {0};
+    char *ptr = cmgw;
+    int err = 0;
+
+	char *src = strstr(cmgw, ",");
+	if(src != NULL)
+	{
+		memcpy(pnum, ptr,  src - ptr);
+		src++;
+		int data_len = 0;
+        data_len = len - (src - ptr);
+		memcpy(data, src, data_len);
+	}
+
+	sprintf(cmd, "AT+CMGW=%s", pnum);
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+	
+	if(strlen(cmd) > 0)
+	{
+		int err = at_send_command_sms(cmd, data, "+CMGW: ", &response);
+		printf("err:%d, response:%d\n", err, response->success);
+
+		if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+		char *line;
+		line = response->p_intermediates->line;
+		printf("line:%s\n", line);
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CMGD=25
+OK
+
++MMSG: 1, 0
+*/
+static int req_cmgd_set(char *cmgd, int len, int *cme_err)
+{
+    printf("0req_cmgd_set()--------------start\n");
+    printf("cmgd:%s\n", cmgd);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char pnum[13] = {0};
+    char *ptr = cmgd;
+    int err = 0;
+
+	memcpy(data, cmgd, len );
+	sprintf(cmd, "AT+CMGD=%s", data);
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+	
+	if(strlen(cmd) > 0)
+	{
+		int err = at_send_command(cmd, &response);
+	    if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+
+//     Format problem caused the crash
+//       char *line;
+//		line = response->p_intermediates->line;
+//		printf("line:%s\n", line);
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CMGL="ALL"	
+
++CMGL: 1,"REC READ","10658678",,"22.11.14 10:41:44 GMT+8"
+
+56DB5DDD62
+
++CMGL: 2,"STO UNSENT","18927467953"
+hello world
+
+*/
+
+static int req_cmgl_set(const char *cmgl, char *reg, int len, int *cme_err)
+{
+    printf("req_cmgl_set(2)-----------------start\n");
+    printf("cmgl:%s\n", cmgl);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char index_data[256] = {0};
+	int s_index = 0, g_index = 0;
+	bool index_flag = false;
+	char *ptr_index = index_data;
+	char phone[50];
+	char number[5] = {0};
+    int err = 0;
+
+	memcpy(data, cmgl, len);
+
+	char *ptr1 = data;
+	char *ptr2 = strstr(data, ",");
+	if(ptr2 != NULL)
+	{
+		memcpy(number,ptr1, ptr2-ptr1 );
+		s_index = atoi(number);
+		if(s_index == 0)
+		{
+			index_flag = TRUE;
+			memcpy(ptr_index, "+CMGL:", strlen("+CMGL:"));
+		}
+        memset(number, 0, sizeof(number));
+		ptr2++;
+	}else{
+		printf("cmgl set data is error\n eg:index,data\n");
+		return -1;
+	}
+
+	sprintf(cmd, "AT+CMGL=%s", ptr2);
+	printf("cmd:%s\n", cmd);
+
+	ptr1 = NULL;
+	ptr2 = NULL;
+	
+	if(strlen(cmd) > 0)
+	{
+        err = at_send_command_multiline(cmd, "", &response);
+		if (err < 0 || response->success == 0 || !response->p_intermediates){
+			*cme_err = at_get_cme_error(response);
+            printf("at_send_command_multiline() is err-----------------\n");
+			goto exit;
+		}
+
+        ATLine* lines_ptr = response->p_intermediates;
+        char *line = NULL;
+        int reg_len = 0;
+		bool flag = false;
+        while(lines_ptr)
+        {
+            line = lines_ptr->line;
+            if(line ==NULL)
+            {
+                printf("line is null----------------------\n");
+            }
+
+            printf("-----line:%s\n", line);
+			if(!flag)
+			{
+				ptr1 = strstr(line, "+CMGL: ");
+				if(ptr1 != NULL)
+				{
+                    ptr1 += 7;
+                    ptr2 = strstr(line, ",");
+                    memcpy(number,ptr1, ptr2-ptr1 );
+                    printf("number:%s, ptr1:%s, ptr2:%s\n", number, ptr1, ptr2);
+                    g_index = atoi(number);
+                    if(index_flag)
+                    {
+                        sprintf(ptr_index+strlen(ptr_index), "%d,", g_index);
+                    }
+				}
+				//if( g_index == s_index)
+                if( g_index == s_index  && !index_flag)
+				{
+                    printf("g_index == s_index, g_index:%d,s_index:%d\n", g_index, s_index);
+					flag = true;
+				}
+			}
+			if(flag && reg_len <=1024)
+			{
+	            memcpy(reg+reg_len, line, strlen(line));
+	            printf("-----memcpy------reg:%s----------\n", reg);
+	            printf("len:%d\n", reg_len);
+	            reg_len += strlen(line);
+			}
+
+            lines_ptr = lines_ptr->p_next;
+        }
+	}
+
+	if(index_flag)
+	{
+		memset(reg, 0, sizeof(reg));
+		memcpy(reg, ptr_index, strlen(ptr_index) );
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    printf("req_cmgl_set()-----------------end\n");
+    return err;
+}
+
+/*
+at+csca?
++CSCA: "+8613800280500",145
+OK
+*/
+static int req_csca_get(char *req, int *cme_err)
+{
+    ATResponse *response = NULL;
+    char *tmp_ptr = NULL;
+    int err = at_send_command_singleline("AT+CSCA?", "", &response);
+
+    if (err < 0 || response->success == 0 || !response->p_intermediates){
+        *cme_err = at_get_cme_error(response);
+        goto exit;
+    }
+
+    char *line = response->p_intermediates->line;
+    printf("req_csca_get() ---line:%s\n", line);
+    char* ptr = strstr(line, "+CSCA: ");
+    printf("req_csca_get() ---ptr:%s\n",ptr);
+    if(ptr)
+    {
+        memcpy(req, line, strlen(line));
+        printf("err:%d, req:%s\n", err, req);
+        err = 0;
+    }
+    else
+    {
+        err = -1;
+    }
+    
+exit:
+    at_response_free(response);
+    return err;
+}
+
+static int req_csca_set(char *csca, int len, int *cme_err)
+{
+    printf("req_csca_set()--------------start\n");
+    printf("csca:%s\n", csca);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char pnum[13] = {0};
+    char *ptr = csca;
+    int err = 0;
+
+	memcpy(data, csca, len);
+	sprintf(cmd, "AT+CSCA=%s", data);
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+	
+	if(strlen(cmd) > 0)
+	{
+		int err = at_send_command(cmd, &response);
+	    if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+
+    //    char *line;
+	//	line = response->p_intermediates->line;
+	//	printf("line:%s\n", line);
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+static int req_csmp_set(char *csmp, int len, int *cme_err)
+{
+    printf("req_csmp_set()-------------------start\n");
+    printf("csmp:%s\n", csmp);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char pnum[13] = {0};
+    char *ptr = csmp;
+    int err = 0;
+
+	memcpy(data, csmp, len);
+	sprintf(cmd, "AT+CSMP=%s", data);
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+	
+	if(strlen(cmd) > 0)
+	{
+		int err = at_send_command(cmd, &response);
+	    if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+
+        char *line;
+		line = response->p_intermediates->line;
+		printf("line:%s\n", line);
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+static int req_cscb_set(char *cscb,int len, int *cme_err)
+{
+    printf("req_cscb_set()----------------start\n");
+    printf("cscb:%s\n", cscb);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[218] = {0};
+	char pnum[13] = {0};
+    char *ptr = cscb;
+    int err = 0;
+
+	memcpy(data, cscb, len);
+	sprintf(cmd, "AT+CSCB=%s", cscb);
+	printf("cmd:%s,data:%s---------\n", cmd,data);
+	
+	if(strlen(cmd) > 0)
+	{
+		int err = at_send_command(cmd, &response);
+	    if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+
+        char *line;
+		line = response->p_intermediates->line;
+		printf("line:%s\n", line);
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+/*
+AT+CMSS=13
++CMSS: 81
+OK
+*/
+static int req_cmss_set(const char *cmss, char *reg, int len, int *cme_err)
+{
+    printf("req_cmss_set()----------------start\n");
+    printf("cmss:%s\n", cmss);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+	char data[20] = {0};
+    int err = 0;
+
+    if(cmss != NULL)
+    {
+    	memcpy(data, cmss, len);
+        sprintf(cmd, "AT+CMSS=%s", data);
+    //    sprintf(cmd, "AT+CMSS=%d", 8);
+    }
+    else{
+        printf("mem is null\n");
+    }
+
+    printf("cmss.   cmd:%s\n", cmd);
+
+	if(strlen(cmd) > 8)
+	{
+        err = at_send_command_multiline(cmd, "+CMSS:", &response);
+		if (err < 0 || response->success == 0){
+			*cme_err = at_get_cme_error(response);
+			goto exit;
+		}
+		
+		char *line = response->p_intermediates->line;
+		printf("line:%s\n", line);
+		
+		char *tmp_str = NULL;
+		err = at_tok_nextstr(&line, &tmp_str); // phone_number
+		if (err < 0)
+		{
+			goto exit;
+		}
+		memcpy(reg, tmp_str, strlen(tmp_str));
+		printf("cmss_reg:%s\n", reg);
+        /*
+	    int err = at_send_command(cmd, &response);
+
+	    if (err < 0 || response->success == 0) {
+	        *cme_err = at_get_cme_error(response);
+	        goto exit;
+	    }
+
+        char *line;
+		line = response->p_intermediates->line;
+		printf("line:%s\n", line);
+        */
+	}
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+/*
+AT+CMGR=1
++CMGR: "REC READ","10658678",,"22.11.14 10:41:44 GMT+8"
+
+56DB5DDD624B673A62A5FF039003003400310034003500340035003F0073003D0037003800680061006C00450066
+
+OK
+*/
+static int req_cmgr_set(int index, char *reg, int *cme_err)
+{
+    printf("0req_cmgr_set()-------------------start\n");
+    printf("index:%d\n", index);
+    ATResponse *response = NULL;
+    char cmd[30] = {0};
+    int err = 0;
+    sprintf(cmd, "AT+CMGR=%d", index);
+
+    printf("req_cmgr_set()----cmd:%s\n", cmd);
+
+	if(strlen(cmd) > 0)
+	{
+        err = at_send_command_multiline(cmd, "", &response);
+		if (err < 0 || response->success == 0 || !response->p_intermediates){
+			*cme_err = at_get_cme_error(response);
+            printf("at_send_command_multiline() is err-----------------\n");
+			goto exit;
+		}
+
+        ATLine* lines_ptr = response->p_intermediates;
+        char *line = NULL;
+        int reg_len = 0;
+        while(lines_ptr)
+        {
+            line = lines_ptr->line;
+            if(line ==NULL)
+            {
+                printf("line is null----------------------\n");
+            }
+
+            if(reg_len > 0)
+			{
+				memcpy(reg+reg_len, "\r\n", strlen("\r\n"));
+				reg_len += strlen("\r\n");
+			}
+            memcpy(reg+reg_len, line, strlen(line));
+            printf("-----memcpy------reg:%s----------\n", reg);
+            printf("len:%d\n", reg_len);
+            reg_len += strlen(line);
+            lines_ptr = lines_ptr->p_next;
+        }
+	}
+
+    err = 0;
+exit:
+    at_response_free(response);
+    return err;
+}
+
+
+//void net_list_free(void *data);
+// Return MBTK_INFO_ERR_SUCCESS,will call pack_error_send() to send RSP.
+// Otherwise, do not call pack_error_send().
+mbtk_info_err_enum sms_pack_req_process(sock_client_info_t* cli_info, mbtk_info_pack_t* pack)
+{
+    mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+    int cme_err = MBTK_INFO_ERR_CME_NON;
+    switch(pack->info_id)
+    {
+        case MBTK_INFO_ID_SMS_STATE_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)
+            {
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set
+            {
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMGF_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                int state;
+                if(req_cmgf_get(&state, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Get SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGF_RSP, &state, sizeof(uint8));
+                }
+            }
+            else     // Set VoLTE state.
+            {
+                uint8 mode = *(pack->data);
+                if(pack->data_len != sizeof(uint8) || (mode != 0 && mode != 1))
+                {
+                    err = MBTK_INFO_ERR_REQ_PARAMETER;
+                    LOG("Set SMS CMGF parameter error.");
+                    break;
+                }
+
+                if(req_cmgf_set(mode, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGF_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CNMI_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // SET at+cnmi=1,2.
+            {
+                int state;
+                if(req_cnmi_set(&cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    printf("set req_cnmi_set() fail.\n");
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("set sms cnmi fail.");
+                }
+                else
+                {
+                    printf("req_cnmi_set success\n");
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CNMI_RSP, NULL, 0);
+                }
+            }
+			break;
+		}
+        case MBTK_INFO_ID_SMS_CPMS_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                char reg[100] = {0};
+                if(req_cpms_get(reg, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Get SMS CMGF fail.");
+                }
+                else
+                {
+                    printf("req_cpms_get_ success, reg:%s, len:%d ", reg, strlen(reg));
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CPMS_RSP, reg, strlen(reg));
+                }
+            }
+            else     // Set VoLTE state.
+            {
+                char *mem = (char*)(pack->data);
+				int len = pack->data_len;
+                char reg[100] = {0};
+                printf("mem:%s, len:%d", pack->data, pack->data_len);
+
+                if(req_cpms_set(mem, reg, len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    printf("cpms_set fail\n");
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    printf("cpms_set success, reg:%s\n", reg);
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CPMS_RSP, reg, strlen(reg));
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMGS_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *cmgs = (char*)pack->data;
+				int len = pack->data_len;
+				char reg[50] ={0};
+                printf("mbtk_sms,cmgs:%s,len:%d\n", cmgs, len);
+
+                if(req_cmgs_set(cmgs,reg,len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGS_RSP, reg, strlen(reg));
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMSS_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *cmss = (char*)pack->data;
+				int len = pack->data_len;
+                char reg[128] = {0};
+                printf("mbtk_sms,cmgs:%s, len:%d\n", cmss, len);
+
+                if(req_cmss_set(cmss,reg, len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    printf("req_cmss_set success, reg:%s", reg);
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMSS_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMGR_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+                uint8 index = *(pack->data);
+                char reg[1024] = {0};
+                if(pack->data_len != sizeof(uint8) )
+                {
+                    err = MBTK_INFO_ERR_REQ_PARAMETER;
+                    LOG("Set SMS CMGF parameter error.");
+                    break;
+                }
+
+                if(req_cmgr_set(index, reg, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    printf("1req_cmgr_set_success, reg:%s\n", reg);
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGR_RSP, reg, strlen(reg));
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMGW_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // +CMGW=<oa/da>[,<tooa/toda>[,<stat>]]<CR>
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set cmgw data.
+            {
+				char *cmgw = (char*)pack->data;
+				int len = pack->data_len;
+                printf("mbtk_sms,cmgw:%s,len:%d\n", cmgw, len);
+
+                if(req_cmgw_set(cmgw, len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGW_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMGD_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *cmgd = (char*)pack->data;
+				int len = pack->data_len;
+                printf("mbtk_sms,cmgs:%s,len:%d\n", cmgd, len);
+
+                if(req_cmgd_set(cmgd,len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGD_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CMGL_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *cmgl = (char*)pack->data;
+				int len = pack->data_len;
+                char reg[5*1024] = {0};
+                char reg1[1024+1] = {0};
+                printf("mbtk_sms,cmgs:%s, len:%d\n", cmgl, len);
+
+                if(req_cmgl_set(cmgl, reg, len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                 //   printf("1cmgl_set_success---------len:%d\n reg:%s\n",strlen(reg), reg);
+                    memcpy(reg1, reg, 1024);
+                    printf("0len:%d, reg1:%s\n", strlen(reg1), reg1);
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CMGL_RSP, reg1, strlen(reg1));
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CSCA_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                char csca[50]={0};
+                if(req_csca_get(csca, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Get SMS CSCA fail.");
+                    printf("get sms csca fail\n");
+                }
+                else
+                {
+                    printf("get sms csca suscess\n");
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CSCA_RSP, csca, strlen(csca));
+                }
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *csca = (char*)pack->data;
+				int len = pack->data_len;
+                printf("mbtk_sms,cmgs:%s,len:%d\n", csca, len);
+
+                if(req_csca_set(csca, len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CSCA_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CSMP_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *csmp = (char*)pack->data;
+				int len = pack->data_len;
+                printf("mbtk_sms,cmgs:%s,len:%d\n", csmp, len);
+
+                if(req_csmp_set(csmp,len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CSMP_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        case MBTK_INFO_ID_SMS_CSCB_REQ:
+        {
+            if(pack->data_len == 0 || pack->data == NULL)   // Get VoLTE state.
+            {
+                printf("pack->data_len:%d,,pack->data:%s\n",pack->data_len, pack->data);
+                err = MBTK_INFO_ERR_UNSUPPORTED;
+            }
+            else     // Set VoLTE state.
+            {
+				char *cscb = (char*)pack->data;
+				int len = pack->data_len;
+                printf("mbtk_sms,cmgs:%s, len:%d\n", cscb, len);
+
+                if(req_cscb_set(cscb,len, &cme_err) || cme_err != MBTK_INFO_ERR_CME_NON)
+                {
+                    if(cme_err != MBTK_INFO_ERR_CME_NON) {
+                        err = MBTK_INFO_ERR_CME + cme_err;
+                    } else {
+                        err = MBTK_INFO_ERR_UNKNOWN;
+                    }
+                    LOG("Set SMS CMGF fail.");
+                }
+                else
+                {
+                    pack_rsp_send(cli_info->fd, MBTK_INFO_ID_SMS_CSCB_RSP, NULL, 0);
+
+                    // Restart is required to take effect.
+                    LOG("Will reboot system...");
+                }
+
+            }
+            break;
+        }
+        default:
+        {
+            err = MBTK_INFO_ERR_REQ_UNKNOWN;
+            LOG("Unknown request : %s", id2str(pack->info_id));
+            break;
+        }
+    }
+
+    return err;
+}
diff --git a/mbtk/ql_lib/Makefile b/mbtk/ql_lib/Makefile
new file mode 100755
index 0000000..f802fef
--- /dev/null
+++ b/mbtk/ql_lib/Makefile
@@ -0,0 +1,41 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/ql_lib
+
+INC_DIR += -I$(BUILD_ROOT)/mbtk_lib/inc
+	
+LIB_DIR +=
+
+LIBS += -llog -lubus -lubox -lblobmsg_json -lrilutil -lmbtk_lib
+
+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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+dtarget := $(OUT_DIR)/lib/libql_lib.so
+
+all: $(dtarget)
+
+$(dtarget):
+	$(CC) $(CFLAGS) $(LOCAL_SRC_FILES) -o $@ $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
+
diff --git a/mbtk/ql_lib/src/ql_adc.c b/mbtk/ql_lib/src/ql_adc.c
new file mode 100755
index 0000000..812427e
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_atc.c b/mbtk/ql_lib/src/ql_atc.c
new file mode 100755
index 0000000..cd1cf49
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_audio.c b/mbtk/ql_lib/src/ql_audio.c
new file mode 100755
index 0000000..69f0361
--- /dev/null
+++ b/mbtk/ql_lib/src/ql_audio.c
@@ -0,0 +1,595 @@
+#include "ql/ql_audio.h"
+#include "mbtk_log.h"
+#include "mbtk_audio.h"
+
+static mbtk_audio_handle record_hdl = NULL;
+static _cb_onRecorder record_cb_fun = NULL;
+static int Samprate = 8000;
+
+/*****************************************************************
+* 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)
+{
+    return (int)mbtk_audio_open(MBTK_AUTIO_TYPE_OUT, 1, Samprate, cb_func);
+}
+
+/*========================================================================
+  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)
+{
+    return mbtk_audio_play_stream((void *)hdl, pData, length);
+}
+
+/*========================================================================
+  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)
+{
+    return mbtk_audio_play_file((void *)hdl, fd, offset);
+}
+
+//
+// Function:  Ql_AudPlayer_Pause
+//
+// Description:
+//   Pause playing.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+int  Ql_AudPlayer_Pause(int hdl)
+{
+    return mbtk_audio_pause((void *)hdl);
+}
+
+//
+// Function:  Ql_AudPlayer_Resume
+//
+// Description:
+//   Resume playing.
+// @param hdl:
+//   Handle received from Ql_AudPlayer_Open().
+int  Ql_AudPlayer_Resume(int hdl)
+{
+    return mbtk_audio_resume((void *)hdl);
+}
+
+//
+// Function:  Ql_AudPlayer_Stop
+//
+// Description:
+//   Stop playing audio
+// hdl:
+//   Handle received from Ql_AudPlayer_Open().
+void Ql_AudPlayer_Stop(int hdl)
+{
+    return mbtk_audio_stop((void *)hdl);
+}
+
+//
+// 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)
+{
+    mbtk_audio_close((void *)hdl);
+}
+
+
+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)
+{
+    record_hdl = mbtk_audio_open(MBTK_AUTIO_TYPE_IN, 1, 8000, NULL);
+    record_cb_fun = cb_fun;
+    return (int)record_hdl;
+}
+
+//
+// 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)
+{
+    return mbtk_audio_record(record_hdl, record_cb_fun, NULL);
+}
+
+//
+// Function:  Ql_AudRecorder_Pause
+//
+// Description:
+//   Pause recording
+int  Ql_AudRecorder_Pause(void)
+{
+    return 0;
+}
+
+//
+// Function:  Ql_AudRecorder_Resume
+//
+// Description:
+//   Resume recording
+int  Ql_AudRecorder_Resume(void)
+{
+    return 0;
+}
+
+//
+// Function:  Ql_AudRecorder_Stop
+//
+// Description:
+//   Stop recording
+void Ql_AudRecorder_Stop(void)
+{
+
+}
+
+//
+// Function:  Ql_AudRecorder_Close
+//
+// Description:
+//   Close recorder, and free the resource
+void Ql_AudRecorder_Close(void)
+{
+    mbtk_audio_close(record_hdl);
+    record_hdl = NULL;
+    record_cb_fun = NULL;
+}
+
+//
+// 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)
+{
+
+	printf("Volume is %d \n",value);
+	int volume =0;
+	int handler = 0;
+
+    if(value < -36 || value > 12)
+    {
+        volume = 0;
+    }
+    else
+    {
+        volume = value;
+    }
+
+    mbtk_audio_ubus_client_init(&handler, dtmf_cb1);
+	mbtk_audio_dsp_set(1, volume);
+
+	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)
+    {
+       Samprate = 16000;
+    }
+    else{
+        Samprate = 8000;
+    }
+
+    return 0;
+}
+
+int Ql_Mp3_To_Wav(const char *wavpath, char *mp3path)
+{
+//    return 0;
+    return mbtk_audio_mp3_to_wav(wavpath, mp3path);
+}
+
+int Ql_Mp3_To_Play(char *mp3path, int hdl,int sample_rate)
+{
+ //   return 0;
+    return mbtk_audio_mp3_to_play(mp3path, hdl, sample_rate);
+}
+
+//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/ql_lib/src/ql_call.c b/mbtk/ql_lib/src/ql_call.c
new file mode 100755
index 0000000..700f93d
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_cell_locator.c b/mbtk/ql_lib/src/ql_cell_locator.c
new file mode 100755
index 0000000..b36075d
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_common.c b/mbtk/ql_lib/src/ql_common.c
new file mode 100755
index 0000000..70d0ad3
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_data_call.c b/mbtk/ql_lib/src/ql_data_call.c
new file mode 100755
index 0000000..5f88b55
--- /dev/null
+++ b/mbtk/ql_lib/src/ql_data_call.c
@@ -0,0 +1,530 @@
+#include "ql/DSI_ConnectManager.h"
+#include "mbtk_info_api.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;
+
+void ql_wan_net_state_change_cb(const void* data, int data_len)
+{
+    uint8 *net_data = NULL;
+    net_data = (uint8 *)data;
+
+    if(ql_net_status_cb != NULL)
+    {
+        if(*net_data > 100 && *net_data < 200)
+        {
+            int cid;
+            cid = *net_data;
+            cid = cid - 100;
+            ql_apn_info[cid].active = FALSE;//close
+        }
+        else if(*net_data > 200)
+        {
+            int cid;
+            cid = *net_data;
+            cid = cid - 200;
+            ql_apn_info[cid].active = TRUE;//open
+        }
+        else
+        {
+            ql_net_status_cb(*net_data);
+
+            if(*net_data == 25 || *net_data == 26 || *net_data == 27)
+            {
+                ql_net_status_cb(CONNECT_CONSUCCESS);
+            }
+        }
+    }
+    else
+    {
+        //ql_netw_status_cb(-1);
+    }
+}
+
+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;
+    }
+}
+
+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;
+}
+
+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;
+    if(profile_idx < MBTK_APN_CID_MIN || profile_idx > MBTK_APN_CID_MAX)
+    {
+        LOGD("ql_wan_start_ex() cid out of range.");
+#if 0 //mbtk wyq for data_call add "if 0"
+        if(ql_net_ex_status_cb)
+            ql_net_ex_status_cb(profile_idx, ql_apn_info[profile_idx].ip_type ,PDP_ERROR_UNSPECIFIED, 0);
+#endif
+        return -1;
+    }
+
+#if 0 //mbtk wyq for data_call add "if 0"
+    //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)
+    {
+        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;
+    }
+
+    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:
+#endif
+    ret = mbtk_data_call_start(ql_info_handle, profile_idx, mbtk_interval_sec, op == 1 ? TRUE : FALSE, 0);
+    if(ret != 0)
+    {
+#if 0 //mbtk wyq for data_call add "if 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;
+        }
+#endif
+        LOGD("mbtk_data_call_start() fail.");
+    }
+    else
+    {
+        //ql_apn_info[8].cid=profile_idx;
+        //ql_netw_status_cb(CONNECT_CONSUCCESS);
+        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;
+    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, mbtk_interval_sec, 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/ql_lib/src/ql_dev_api.c b/mbtk/ql_lib/src/ql_dev_api.c
new file mode 100755
index 0000000..d473ab8
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_fota.c b/mbtk/ql_lib/src/ql_fota.c
new file mode 100755
index 0000000..5894272
--- /dev/null
+++ b/mbtk/ql_lib/src/ql_fota.c
@@ -0,0 +1,306 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include "ql/ql_fota.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+    #define fota_log(...)                    printf(__VA_ARGS__)
+#else
+    #define fota_log(...)
+#endif
+
+#define UNUSEDPARAM(param) (void)param;
+#define OTA_MAX_STRING_LEN	128
+
+static struct ubus_context    *fota_ubus_ctx = NULL;
+static uint32_t	 		      fota_request_id;
+static struct ubus_subscriber notification_event;
+static pthread_t              fota_status_pthread;
+static struct blob_buf b;
+static fota_callback fota_cb = NULL;
+
+enum {
+	ATTR_SMSGPS,
+	ATTR_SMSGPS_MAX,
+};
+
+static const struct blobmsg_policy ota_info_attr_policy[] = {
+	[ATTR_SMSGPS] ={.name = "notification",  .type = BLOBMSG_TYPE_STRING,},
+};
+
+/**
+ *  \brief strstr_n
+ *
+ *  find string return number
+ *
+ *  \param param
+ *  \return return type
+ */
+static int strstr_n(const char *s1, const char *s2)
+{
+    int n;
+    int strlen = 0;
+
+    if(*s2) {
+        while(*s1) {
+            for(n = 0; *(s1+n) == *(s2 + n); n++) {
+                if(!*(s2 + n + 1)) {
+                    strlen++;
+                    return strlen;
+                }
+            }
+            s1++;
+            strlen++;
+        }
+        return 0;
+    }
+    else
+        return 0;
+}
+
+static int otad_notify(struct ubus_context* ctx, struct ubus_object* obj,
+                       struct ubus_request_data* req, const char* method,
+                       struct blob_attr* msg)
+{
+    UNUSEDPARAM(ctx);
+    UNUSEDPARAM(obj);
+    UNUSEDPARAM(req);
+    UNUSEDPARAM(method);
+    // User can get downloading process information from here
+    int ret, len;
+    char progress[4] = {0};
+	char *notify_str;
+
+	struct blob_attr *tb[ATTR_SMSGPS_MAX];
+	ret = blobmsg_parse(ota_info_attr_policy, ARRAY_SIZE(ota_info_attr_policy), tb,
+						blob_data(msg), blob_len(msg));
+
+	if (ret || !tb[ATTR_SMSGPS]) {
+		printf("invalid SMS\n");
+		return -1;
+	}
+
+	notify_str = blobmsg_get_string(tb[ATTR_SMSGPS]);
+    len = strlen(notify_str);
+    fota_log("%s : %s\r\n", __FUNCTION__, notify_str);
+    if (strstr_n(notify_str, "start")) {
+        fota_cb(0, 0);
+    } else if (strstr_n(notify_str, "end[1]")) {
+        fota_cb(0, 100);
+        printf("download firmware success!\r\n");
+    } else if (strstr_n(notify_str, "end[0]")) {
+        fota_cb(1, 100);
+    }
+    ret = strstr_n(notify_str, "progress");
+    if (ret) {
+        memcpy(progress, &notify_str[ret + 8], len - ret - 9);
+        fota_cb(0, atoi(progress));
+    }
+    return 0;
+}
+
+static void otad_subscriber_remove_cb(struct ubus_context* ctx,
+                                      struct ubus_subscriber* obj, uint32_t id)
+{
+    UNUSEDPARAM(ctx);
+    UNUSEDPARAM(obj);
+    UNUSEDPARAM(id);
+    fota_log("%s,%d\n", __FUNCTION__, __LINE__);
+}
+
+
+/*******************************************************************************\
+*   Function:       main
+\*******************************************************************************/
+void* fota_main(void* argc)
+{
+    int ret, retries = 0;
+    UNUSEDPARAM(argc);
+
+    //register for ril indication
+    ret = ubus_register_subscriber(fota_ubus_ctx, &notification_event);
+    if (ret) {
+        fota_log("%s,%d\n", __FUNCTION__, __LINE__);
+        pthread_exit(NULL);
+    }
+    notification_event.cb = otad_notify;
+    notification_event.remove_cb = otad_subscriber_remove_cb;
+
+    ubus_subscribe(fota_ubus_ctx, &notification_event, fota_request_id);
+    uloop_run();
+    ubus_unsubscribe(fota_ubus_ctx, &notification_event, fota_request_id);
+    pthread_exit(NULL);
+
+    return NULL;
+}
+
+int ql_fota_init(fota_callback cb)
+{
+    int id;
+    int retries = 0;
+
+    /*create ubus loop to listen to RIL event*/
+    uloop_init();
+    fota_ubus_ctx = ubus_connect(NULL);
+    if (!fota_ubus_ctx) {
+        fota_log("%s,%d\n", __FUNCTION__, __LINE__);
+        uloop_done();
+        return 0;
+    }
+
+    ubus_add_uloop(fota_ubus_ctx);
+
+    do {
+        //register for ril request
+        retries = 0;
+        if (ubus_lookup_id(fota_ubus_ctx, "ota", &fota_request_id)) {
+            fota_log("%s,%d\n", __FUNCTION__, __LINE__);
+            sleep(1);
+        } else {
+            break;
+        }
+    } while (retries++ < 20);
+    if (retries >= 20) {
+        printf("%s,%d\n", __FUNCTION__, __LINE__);
+        goto fail1;
+    }
+    pthread_create(&fota_status_pthread, NULL, (void*)fota_main, NULL);
+    fota_cb = cb;
+fail1:
+    return 0;
+}
+
+static void sync_prog_cb(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+    char *str;
+    if (!msg)
+        return;
+
+    /*
+    在这里处理返回的消息。
+    本例子只是将返回的消息打印出来。
+    */
+    str = blobmsg_format_json_indent(msg, true, 0);
+    printf("%s\n", str);
+
+    if (strstr_n(str, "end[1]")) {
+        fota_cb(0, 100);
+        printf("download firmware success!\r\n");
+    } else if (strstr_n(str, "end[0]") || strstr_n(str, "failed")) {
+        fota_cb(1, 0);
+    }
+    free(str);
+}
+/*******************************************************************************
+* @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)
+{
+    static struct ubus_request req;
+    int _segment_size;
+    blob_buf_init(&b, 0);
+    blobmsg_add_string(&b, "url", fname);
+    blobmsg_add_u32(&b, "type", 2);
+    blobmsg_add_u32(&b, "sync", 1);
+    _segment_size = segment_size;
+    if (_segment_size > 1024) {
+        blobmsg_add_u32(&b, "segment_size", _segment_size);
+    }
+    // blobmsg_add_u32(&b, "segment_size", segment_size);
+    /* 调用"ota"对象的"download"方法 */
+    ubus_invoke(fota_ubus_ctx, fota_request_id,
+               "download", b.head, sync_prog_cb, NULL, 30 * 1000);
+
+    return 0;
+}
+
+
+/*******************************************************************************
+* @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)
+{
+    static struct ubus_request req;
+    int _segment_size;
+    blob_buf_init(&b, 0);
+    blobmsg_add_string(&b, "url", url);
+    blobmsg_add_string(&b, "username", "user name");
+    blobmsg_add_u32(&b, "type", 0);
+    blobmsg_add_u32(&b, "sync", 1);
+    _segment_size = segment_size;
+    if (_segment_size > 1024) {
+        blobmsg_add_u32(&b, "segment_size", _segment_size);
+    }
+    blobmsg_add_u32(&b, "sync", 1);
+    ubus_invoke_async(fota_ubus_ctx, fota_request_id, "download", b.head, &req);
+    ubus_complete_request_async(fota_ubus_ctx, &req);
+    return 0;
+}
+/*******************************************************************************
+* @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)
+{
+    int ret;
+
+    ret = pthread_cancel(fota_status_pthread);
+    fota_log("kill pthread : %d \n", ret);
+    pthread_join(fota_status_pthread, NULL);
+    do {
+        ret = pthread_kill(fota_status_pthread, 0);
+        fota_log("kill pthread: %d \n", ret);
+        if (ret == ESRCH) {
+            fota_log("The specified thread does not exist or has terminated\n");
+        } else if (ret == EINVAL) {
+            fota_log("Useless signal\n");
+        } else {
+            fota_log("The thread exists\n");
+        }
+        usleep(100000);
+    } while (0 == ret);
+
+
+    ubus_free(fota_ubus_ctx);
+    uloop_done();
+
+    fota_cb = NULL;
+
+    if (is_reboot) {
+        system("reboot");
+    }
+    return 0;
+}
diff --git a/mbtk/ql_lib/src/ql_gpio.c b/mbtk/ql_lib/src/ql_gpio.c
new file mode 100755
index 0000000..3b84532
--- /dev/null
+++ b/mbtk/ql_lib/src/ql_gpio.c
@@ -0,0 +1,484 @@
+#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 "ql/ql_gpio.h"
+
+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;
+}
+
+
+/*****************************************************************
+* 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
+                 )
+{
+    if(gpio_export(pin_name))
+    {
+        LOGE("gpio_export() fail.");
+        return RES_IO_ERROR;
+    }
+
+    if(gpio_direct_set(pin_name, dir == PINDIRECTION_IN ? "in" : "out"))
+    {
+        LOGE("gpio_direct_set() fail.");
+        return RES_IO_ERROR;
+    }
+
+    if(gpio_value_set(pin_name, 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)
+{
+    if(gpio_value_set(pin_name, 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)
+{
+    return gpio_value_get(pin_name);
+}
+
+/*****************************************************************
+* 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)
+{
+    if(gpio_direct_set(pin_name, 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];
+    if(gpio_direct_get(pin_name, buff, 10)) {
+        LOGE("gpio_direct_get() fail.");
+        return RES_IO_NOT_SUPPORT;
+    } else {
+        if(strcmp(buff, "in") == 0) {
+            return PINDIRECTION_IN;
+        } else if(strcmp(buff, "out") == 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)
+{
+    if(gpio_unexport(pin_name))
+    {
+        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/ql_lib/src/ql_i2c.c b/mbtk/ql_lib/src/ql_i2c.c
new file mode 100755
index 0000000..8b8c6a0
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_quec_nw.c b/mbtk/ql_lib/src/ql_quec_nw.c
new file mode 100755
index 0000000..9582913
--- /dev/null
+++ b/mbtk/ql_lib/src/ql_quec_nw.c
@@ -0,0 +1,911 @@
+#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;
+
+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);
+        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
+    {
+        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 = signal.rssi;
+        }
+        else if(signal.type == MBTK_RADIO_TECH_E_UTRAN)     //LTE
+        {
+            //pt_info->LTE_SignalStrength.cqi = signal.;
+            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 = signal.rssi;
+        }
+        else
+        {
+            return QL_NW_GENERIC_FAILURE;
+        }
+        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/ql_lib/src/ql_quec_sim.c b/mbtk/ql_lib/src/ql_quec_sim.c
new file mode 100755
index 0000000..edcef9a
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_sleep_wakelock.c b/mbtk/ql_lib/src/ql_sleep_wakelock.c
new file mode 100755
index 0000000..03f356c
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_sms.c b/mbtk/ql_lib/src/ql_sms.c
new file mode 100755
index 0000000..cbad623
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_spi.c b/mbtk/ql_lib/src/ql_spi.c
new file mode 100755
index 0000000..4fc5d9f
--- /dev/null
+++ b/mbtk/ql_lib/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/ql_lib/src/ql_uart.c b/mbtk/ql_lib/src/ql_uart.c
new file mode 100755
index 0000000..ee9ce4c
--- /dev/null
+++ b/mbtk/ql_lib/src/ql_uart.c
@@ -0,0 +1,418 @@
+#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]      = 1;   /* 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;
+    }
+    newtio.c_iflag = IGNPAR;
+    newtio.c_oflag = 0;
+    newtio.c_lflag = 0;
+
+    tcflush(fd, TCIFLUSH);
+
+    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/ql_lib/src/ql_voice.c b/mbtk/ql_lib/src/ql_voice.c
new file mode 100644
index 0000000..9df4053
--- /dev/null
+++ b/mbtk/ql_lib/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;
+}
+
diff --git a/mbtk/test/Makefile b/mbtk/test/Makefile
new file mode 100755
index 0000000..3a10f89
--- /dev/null
+++ b/mbtk/test/Makefile
@@ -0,0 +1,41 @@
+ROOT = $(shell pwd)/../..
+include ../Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/test
+
+INC_DIR += 
+	
+LIB_DIR +=
+
+LIBS += -lmbtk_lib -lql_lib -llynq_lib -lmbtk_mqtt_lib -lpolarssl -laudio-apu -lcutils -ltinyalsa -lacm
+
+CFLAGS += 
+
+DEFINE +=
+
+MY_FILES_PATH:=$(LOCAL_PATH)
+#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 += $(MY_SRC_LIST)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+
+BINS = $(patsubst %.c,%,$(LOCAL_SRC_FILES))
+
+all: $(BINS)
+
+$(BINS):
+	@echo "  BIN     $@"
+	$(CC) $(CFLAGS) -o $(OUT_DIR)/bin/$@ $@.c $(DEFINE) $(INC_DIR) $(LIB_DIR) $(LIBS)
+
+clean:
+	
\ No newline at end of file
diff --git a/mbtk/test/aiti_audio_test.c b/mbtk/test/aiti_audio_test.c
new file mode 100755
index 0000000..c9fa936
--- /dev/null
+++ b/mbtk/test/aiti_audio_test.c
@@ -0,0 +1,540 @@
+#include "mbtk_type.h"
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+// #include "ql_at.h"
+#include "ql/ql_audio.h"
+// #include "mopen_tts.h"
+
+#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
+
+#define MBTK_AUD_DEMO_WAV1 "/data/demo1.wav"
+
+
+int play_hdl = 0;
+static int record_fd = 0;
+
+
+int Ql_cb_playback(int hdl, int result)
+{
+    printf("%s: hdl=%d, result=%d\n\r", __func__, hdl, result);
+    if (result == AUD_PLAYER_FINISHED || result == AUD_PLAYER_NODATA)
+    {
+        printf("%s: play finished\n\r", __func__);
+    }
+    return 0;
+}
+
+void record_cb_func(int cb_result, char* databuf, unsigned int len)
+{
+    int rc;
+
+    if(NULL != databuf && len > 0 && record_fd > 0)
+    {
+        //for debug:save into file
+        rc = write(record_fd, databuf, len);
+        if (rc < 0) {
+            printf("%s: error writing to file!\n", __FUNCTION__);
+        } else if (rc < len) {
+            printf("%s: wrote less the buffer size!\n", __FUNCTION__);
+        }
+    }
+}
+
+
+int MBTK_wav_pcm16Le_check(int fd)
+{
+    struct wav_header hdr;
+
+    if (fd <= 0)
+        return -1;
+
+    if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+    {
+        printf("\n%s: cannot read header\n", __FUNCTION__);
+        return -1;
+    }
+
+        printf("hdr.riff_id:%X, hdr.riff_fmt:%X, hdr.fmt_id:%X", hdr.riff_id, hdr.riff_fmt, hdr.fmt_id);
+
+    if ((hdr.riff_id != ID_RIFF)
+            || (hdr.riff_fmt != ID_WAVE)
+            || (hdr.fmt_id != ID_FMT))
+    {
+        printf("\n%s: is not a riff/wave file\n", __FUNCTION__);
+        return -1;
+    }
+
+    if ((hdr.audio_format != FORMAT_PCM) || (hdr.fmt_sz != 16)) {
+        printf("\n%s: is not pcm format\n", __FUNCTION__);
+        return -1;
+    }
+
+    if (hdr.bits_per_sample != 16) {
+        printf("\n%s: is not 16bit per sample\n", __FUNCTION__);
+        return -1;
+    }
+
+    printf("audio_format: %d,num_channels: %d,sample_rate: %d,byte_rate: %d,bits_per_sample:  %d data_sz: %d\n",
+           hdr.audio_format, hdr.num_channels, hdr.sample_rate, hdr.byte_rate, hdr.bits_per_sample, hdr.data_sz);
+
+    return hdr.data_sz;
+}
+
+int MBTK_wav_pcm16Le_set(int fd)
+{
+    struct wav_header hdr;
+
+    if (fd <= 0)
+        return -1;
+
+    memset(&hdr, 0, sizeof(struct wav_header));
+
+    hdr.riff_id = ID_RIFF;
+    hdr.riff_fmt = ID_WAVE;
+    hdr.fmt_id = ID_FMT;
+    hdr.fmt_sz = 16;
+    hdr.audio_format = FORMAT_PCM;
+    hdr.num_channels = 1;
+    hdr.sample_rate = 8000;
+    hdr.bits_per_sample = 16;
+    hdr.byte_rate = (8000 * 1 * hdr.bits_per_sample) / 8;
+    hdr.block_align = (hdr.bits_per_sample * 1) / 8;
+    hdr.data_id = ID_DATA;
+    hdr.data_sz = 0;
+
+    hdr.riff_sz = hdr.data_sz + 44 - 8;
+    if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+unsigned char* handle_file1(char *audioFilePath)
+{
+    long filesize;
+    unsigned char *pcmBuf = NULL;
+    FILE *fp = NULL;
+    int size;
+
+    // 处理文件格式
+    fp = fopen(audioFilePath, "rb");
+    if (!fp) {
+        printf("%s:fopen failed",__func__);
+    }
+    
+    fseek(fp,0,SEEK_END);
+    filesize=ftell(fp);
+    printf("%s:filesize:%d\n", __func__, filesize);
+    fseek(fp,44,SEEK_SET);
+    pcmBuf =(unsigned char *)malloc(sizeof(char)*filesize);
+    memset(pcmBuf,0,sizeof(char)*filesize);
+//    fread(pcmBuf, filesize-44,1, fp);
+    fread(pcmBuf, 1, filesize-44, fp);
+    fclose(fp);
+
+    printf("strlen(pcmBuf):%d\n", strlen(pcmBuf));
+
+    return pcmBuf;
+}
+
+void *audio_thread(void *arg)
+{
+    printf("audio_thread(1)----------\n");
+    Ql_Playback_Samprate_Set(1);
+    int play_hdl = 0;
+    int fd = 0;
+    int ret;
+    int file_size =0;
+    int file_size1 =0;
+    unsigned char *pcmBuf = NULL;
+    unsigned char *pcmBuf1 = NULL;
+
+    play_hdl = Ql_AudPlayer_Open(NULL, Ql_cb_playback);
+    if(0 == play_hdl)
+    {
+        printf("Ql_AudPlayer_Open fail\n");
+    }
+
+    fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+    if (fd <= 0)
+    {
+        printf("Open fail\n");
+    }
+
+    int fd1 = open(MBTK_AUD_DEMO_WAV1, O_RDWR);
+    printf("fd1:%d\n", fd1);
+    if (fd1 <= 0)
+    {
+        printf("Open fail\n");
+    }
+
+    file_size = MBTK_wav_pcm16Le_check(fd);
+
+    file_size1 = MBTK_wav_pcm16Le_check(fd1);
+    printf("file_size:%d, file_size1:%d\n", file_size, file_size1);
+
+    pcmBuf = handle_file1(MBTK_AUD_DEMO_WAV);
+
+    pcmBuf1 = handle_file1(MBTK_AUD_DEMO_WAV1);
+    
+    if(file_size > 0  && file_size1 > 0 )
+    {
+        if(pcmBuf != NULL)
+        {
+            ret = Ql_AudPlayer_Play(play_hdl, pcmBuf, file_size);
+            printf("ret:%d\n", ret);
+        }
+
+        Ql_Rxgain_Set(3);
+        if(pcmBuf1 != NULL)
+        {
+            ret = Ql_AudPlayer_Play(play_hdl, pcmBuf1, file_size1);
+            printf("ret:%d\n", ret);
+        }
+
+    }
+
+    Ql_AudPlayer_Close(play_hdl);
+    close(fd);
+    close(fd1);
+    return 0;
+}
+
+
+void *audio_play_file_thread(void *arg)
+{
+    char operator[10];
+
+    int fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+    if (fd <= 0)
+        return 0;
+
+    int fd1 = open(MBTK_AUD_DEMO_WAV1, O_RDWR);
+    if (fd1 <= 0)
+        return 0;
+    
+    Ql_AudPlayer_PlayFrmFile(play_hdl, fd, 0);
+
+    Ql_Rxgain_Set(3);
+
+    Ql_AudPlayer_PlayFrmFile(play_hdl, fd1, 0);
+
+    close(fd);
+    close(fd1);
+
+    return 0;
+}
+
+
+int aplay_thread(char *audioFilePath)
+{
+    int res;
+    pthread_t play_thread;
+
+    res = pthread_create(&play_thread, NULL, audio_thread, audioFilePath);
+    if (res != 0) {
+        printf("%s:pthread_create failed",__func__);
+        return 0;
+    }
+
+    return 0;
+}
+
+
+int aplay_file_thread(int play_hdl)
+{
+    int res;
+    pthread_t play_thread;
+    int hdl = play_hdl;
+
+    res = pthread_create(&play_thread, NULL, audio_play_file_thread, &hdl);
+    if (res != 0) {
+        printf("%s:pthread_create failed",__func__);
+        return 0;
+    }
+
+    return 0;
+}
+
+
+
+void aplay(void)
+{
+    char operator[10];
+    char databuf[1024];
+    int opt = 0;
+    int fd = 0;
+    int size = 0;
+    int state;
+    int handler = 0;
+    int file_size = 0 ;
+
+    while(1)
+    {
+        printf("=========aplay========2\n"
+            "\t 0 Open PCM\n"
+            "\t 1 Play Stream\n"
+            "\t 2 Play file\n"
+            "\t 3 Close\n"
+            "\t 4 play stream thread\n"
+            "\t 5 pause\n"
+            "\t 6 repause\n"
+            "\t 7 play file thread\n"
+            "\t 8 play mp3\n"
+            "\t others exit\n\n"
+            "operator >> ");
+
+        fflush(stdin);
+        fgets(operator, sizeof(operator), stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+            case 0:
+                Ql_Playback_Samprate_Set(1);
+                play_hdl = Ql_AudPlayer_Open(NULL, Ql_cb_playback);
+                if(0 == play_hdl)
+                    printf("Ql_AudPlayer_Open fail\n");
+
+                printf("\nplay_hdl:%d\n", play_hdl);
+                break;
+            case 1:
+               if(0 == play_hdl)
+                    continue;
+
+                fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+                if (fd <= 0)
+                    continue;
+
+                file_size = MBTK_wav_pcm16Le_check(fd);
+                printf("file_size:%d\n", file_size);
+                if(file_size > 0 )
+                {
+                    unsigned char *pcmBuf = NULL;
+                    char *p1 = pcmBuf;
+                    pcmBuf = handle_file1(MBTK_AUD_DEMO_WAV);
+                    if(pcmBuf != NULL)
+                    {
+                        if(-1 == Ql_AudPlayer_Play(play_hdl, pcmBuf, file_size))
+                                printf("\n------\n");
+                    }
+
+                }
+
+//                Ql_Rxgain_Set(5);
+
+                close(fd);
+                break;
+            case 2:
+                if(0 == play_hdl)
+                    continue;
+
+                fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+                if (fd <= 0)
+                    continue;
+
+                if(1)
+                {
+                    Ql_AudPlayer_PlayFrmFile(play_hdl, fd, 44);
+                }
+                else
+                {
+                    printf("aplay file type error\n");
+                }
+                close(fd);
+                break;
+            case 3:
+                if(0 == play_hdl)
+                    continue;
+                Ql_AudPlayer_Close(play_hdl);
+                break;
+            case 4:
+                aplay_thread(MBTK_AUD_DEMO_WAV);
+                break;
+            case 5:
+                if(0 == play_hdl)
+                    continue;
+                Ql_AudPlayer_Pause(play_hdl);
+                break;
+            case 6:
+                if(0 == play_hdl)
+                    continue;
+                Ql_AudPlayer_Resume(play_hdl);
+                break;
+            case 7:
+                if(0 == play_hdl)
+                    continue;
+                aplay_file_thread(play_hdl);
+                break;
+            case 8:
+           //     Ql_Mp3_To_Wav("/data/demo.wav", "/data/mp3demo.mp3", play_hdl);
+                Ql_Mp3_To_Play("/data/mp3demo.mp3", play_hdl, 0);
+                break;
+            default:
+                return;
+        }
+
+        sleep(1);
+    }
+
+    printf("aplay exit\n");
+    return ;
+}
+void arec(void)
+{
+    int ret;
+    char operator[10];
+    int opt;
+    int hdl = 0;
+
+    while(1)
+    {
+        printf("=======arec======\n"
+            "\t 0 Open PCM\n"
+            "\t 1 Start Record\n"
+            "\t 2 Get state\n"
+            "\t 3 Pause\n"
+            "\t 4 Resume\n"
+            "\t 5 Stop\n"
+            "\t 6 Close\n"
+            "\t others exit\n\n"
+            "operator >> ");
+
+        fflush(stdin);
+        fgets(operator, sizeof(operator), stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+            case 0:
+                Ql_Playback_Samprate_Set(0);
+                hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
+                if (hdl == 0)
+                    return ;
+                break;
+            case 1:
+                if(0 == hdl)
+                {
+                    printf("audio is not initialized yet.\n");
+                    continue;
+                }
+
+                if(0 != record_fd)
+                {
+                    printf("audio It's already being recorded.\n");
+                    continue;
+                }
+                record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
+                if (record_fd <= 0)
+                    printf("file open error\n");
+
+                if(0 == MBTK_wav_pcm16Le_set(record_fd))
+                {
+                    ret = Ql_AudRecorder_StartRecord();
+                    if(0 != ret)
+                    {
+                        printf("audio record error: %d\n", ret);
+                        close(record_fd);
+                        record_fd = 0;
+                    }
+                }
+                else
+                {
+                    printf("arec set file header error\n");
+                    close(record_fd);
+                    record_fd = 0;
+                }
+                break;
+            case 2:
+                // printf("arec state : %d\n", state);
+                break;
+            case 3:
+                break;
+            case 4:
+                break;
+            case 5:
+                break;
+            case 6:
+                Ql_AudRecorder_Close();
+                if(record_fd > 0)
+                {
+                    close(record_fd);
+                    record_fd = 0;
+                }
+                break;
+            default:
+                return;
+        }
+
+        sleep(1);
+    }
+
+    printf("arec exit\n");
+    return ;
+}
+int main(void)
+{
+    char operator[10];
+    int opt;
+
+//    printf("Ql_Mp3_To_Wav()\n");
+//    mbtk_audio_mp3_to_wav("/data/demo.wav", "/data/mp3demo.mp3");
+ //   Ql_Mp3_To_Wav("/data/demo.wav", "/data/mp3demo.mp3");
+
+    while(1)
+    {
+        printf("=========audio main=========\n"
+            "\t0 exit\n"
+            "\t1 aplay\n"
+            "\t2 arec\n"
+            "\t3 set speaker Volume\n"
+            "\t4 get speaker Volume\n"
+            "\t5 set mic Volume\n"
+            "\t6 get mic Volume\n"
+            "\t7 tts\n"
+            "\t8 tone\n"
+            "operator: >> ");
+
+        fgets(operator, sizeof(operator), stdin);
+        fflush(stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+            case 0:
+                printf("main exit\n");
+                return 0;
+            case 1:
+                aplay();
+                break;
+            case 2:
+                arec();
+                break;
+            case 3:
+                mbtk_at_rec(NULL);
+                break;
+            case 4:
+                mbtk_at_play(NULL);
+                break;
+            case 5:
+                break;
+            case 6:
+                break;
+            case 7:
+                break;
+            case 8:
+                break;
+            default:
+                break;
+        }
+
+        sleep(1);
+    }
+
+    return 0;
+}
+
+
+
+
diff --git a/mbtk/test/at.c b/mbtk/test/at.c
new file mode 100755
index 0000000..c69ba82
--- /dev/null
+++ b/mbtk/test/at.c
@@ -0,0 +1,652 @@
+#include <termios.h>
+#include <pthread.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/select.h>
+
+#include "ql/ql_uart.h"
+#include "mbtk_type.h"
+
+//#define AT_TYPE_SOCKET
+#define MBTK_LOG
+
+#ifdef MBTK_LOG
+#include "mbtk_log.h"
+#else
+#define LOGE printf
+#define LOGD printf
+#define LOGV printf
+#define LOGI printf
+#endif
+
+#define DATABITS	CS8
+#define STOPBITS	0
+#define PARITYON        0
+#define PARITY          0
+
+typedef enum {
+    AT_MODE_SOCK_1 = 0,
+    AT_MODE_SOCK_2,
+    AT_MODE_DEV_1,
+    AT_MODE_DEV_2
+} at_mode_enum;
+
+static int epoll_fd = -1;
+static struct epoll_event epoll_events[20];
+static int at_fd = -1;
+static at_mode_enum at_mode = AT_MODE_SOCK_1;
+
+static char *at_rsp_complete_tag[] = {
+        "OK",
+        "ERROR",
+        "CONNECT",
+		"+CMS ERROR:",
+		"+CME ERROR:",
+		"NO ANSWER",
+		"NO DIALTONE",
+		NULL};
+
+//#ifdef AT_TYPE_SOCKET
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+//#endif
+
+static void at_epoll_change(int is_add,int fd)
+{
+    struct epoll_event ev;
+    memset(&ev,0x0,sizeof(struct epoll_event));
+    ev.data.fd = fd;
+    ev.events = EPOLLIN | EPOLLET;
+    if(is_add)
+    {
+        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,fd,&ev);
+    }
+    else
+    {
+        epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,&ev);
+    }
+}
+
+static int at_set_fd_noblock(int fd)
+{
+    // Set O_NONBLOCK
+    int flags = fcntl(fd, F_GETFL, 0);
+    if (flags < 0) {
+        LOGE("Get flags error:%s\n", strerror(errno));
+        return -1;
+    }
+    flags |= O_NONBLOCK;
+    if (fcntl(fd, F_SETFL, flags) < 0) {
+        LOGE("Set flags error:%s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+//#ifdef AT_TYPE_SOCKET
+int openSocket(const char* sockname)
+{
+	int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		LOGE("Error create socket: %s\n", strerror(errno));
+		return -1;
+	}
+	struct sockaddr_un addr;
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, sockname, sizeof(addr.sun_path));
+	while (TEMP_FAILURE_RETRY(connect(sock,(const struct sockaddr*)&addr, sizeof(addr))) != 0) {
+		LOGE("Error connect to socket %s: %s, try again", sockname, strerror(errno));
+		sleep(1);
+	}
+
+#if 0
+	int sk_flags = fcntl(sock, F_GETFL, 0);
+	fcntl(sock, F_SETFL, sk_flags | O_NONBLOCK);
+#endif
+
+	return sock;
+}
+
+//#else
+
+static int at_open(char *dev)
+{
+    // Init USB PC port.
+    struct termios ser_settings;
+    int fd = -1;
+
+usb_pc_init:
+    fd = open(dev,O_RDWR);
+    if(fd <= 0)
+    {
+        if(errno == ENODEV)
+        {
+            LOGD("Wait dev[%s] ready...",dev);
+            usleep(500000);
+            goto usb_pc_init;
+        }
+
+        LOGE("Cannot open USB PC port[%s] - [errno = %d]",dev,errno);
+        return -1;
+    }
+
+    tcgetattr(fd, &ser_settings);
+    cfmakeraw(&ser_settings);
+    //ser_settings.c_lflag |= (ECHO | ECHONL);
+    //ser_settings.c_lflag &= ~ECHOCTL;
+    tcsetattr(fd, TCSANOW, &ser_settings);
+
+#if 0
+    if(at_set_fd_noblock(at_fd))
+    {
+        LOGE("at_set_fd_noblock() fail.");
+        return -1;
+    }
+
+    at_epoll_change(1, at_fd);
+#endif
+
+    return fd;
+}
+//#endif
+
+static int adb_port_open(const char *dev, unsigned int baud)
+{
+	int fd;
+
+	while((fd = open(dev, O_RDWR)) < 0)
+	{
+		printf("%s: open %s failed\n", __func__, dev);
+		sleep(1);
+	}
+
+	/* set newtio */
+	struct termios newtio;
+	memset(&newtio, 0, sizeof(newtio));
+#if 0
+	(void)fcntl(fd, F_SETFL, 0);
+	newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
+	newtio.c_iflag = IGNPAR;
+	newtio.c_oflag = 0;
+	newtio.c_lflag = 0;    /* disable ECHO, ICANON, etc... */
+
+	newtio.c_cc[VERASE]   = 0x8;      /* del */
+	newtio.c_cc[VEOF]     = 4;      /* Ctrl-d */
+	newtio.c_cc[VMIN]     = 1;      /* blocking read until 1 character arrives */
+	newtio.c_cc[VEOL]     = 0xD;      /* '\0' */
+
+	tcflush(fd, TCIFLUSH);
+	tcsetattr(fd, TCSANOW, &newtio);
+#else
+	if (tcflush(fd, TCIOFLUSH) < 0) {
+		printf("Could not flush uart port\n");
+		return -1;
+	}
+
+    newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
+    newtio.c_cc[VMIN]	   = 1;   /* blocking read until 5 chars received */
+    newtio.c_cflag |= (CS8 | CLOCAL | CREAD);
+    newtio.c_iflag = IGNPAR;
+    newtio.c_oflag = 0;
+    newtio.c_lflag = 0;
+
+	int rate = baud;  // Default bitrate.
+	switch(rate)
+	{
+		case 300:
+			cfsetospeed(&newtio, B300);
+			cfsetispeed(&newtio, B300);
+			break;
+		case 600:
+			cfsetospeed(&newtio, B600);
+			cfsetispeed(&newtio, B600);
+			break;
+		case 1200:
+			cfsetospeed(&newtio, B1200);
+			cfsetispeed(&newtio, B1200);
+			break;
+		case 2400:
+			cfsetospeed(&newtio, B2400);
+			cfsetispeed(&newtio, B2400);
+			break;
+		case 4800:
+			cfsetospeed(&newtio, B4800);
+			cfsetispeed(&newtio, B4800);
+			break;
+		case 9600:
+			cfsetospeed(&newtio, B9600);
+			cfsetispeed(&newtio, B9600);
+			break;
+		case 19200:
+			cfsetospeed(&newtio, B19200);
+			cfsetispeed(&newtio, B19200);
+			break;
+		case 38400:
+			cfsetospeed(&newtio, B38400);
+			cfsetispeed(&newtio, B38400);
+			break;
+		case 57600:
+			cfsetospeed(&newtio, B57600);
+			cfsetispeed(&newtio, B57600);
+			break;
+		case 115200:
+			cfsetospeed(&newtio, B115200);
+			cfsetispeed(&newtio, B115200);
+			break;
+		case 230400:
+			cfsetospeed(&newtio, B230400);
+			cfsetispeed(&newtio, B230400);
+			break;
+		case 460800:
+			cfsetospeed(&newtio, B460800);
+			cfsetispeed(&newtio, B460800);
+			break;
+		case 921600:
+			cfsetospeed(&newtio, B921600);
+			cfsetispeed(&newtio, B921600);
+			break;
+		case 1500000:
+			cfsetospeed(&newtio, B1500000);
+			cfsetispeed(&newtio, B1500000);
+			break;
+		case 2000000:
+			cfsetospeed(&newtio, B2000000);
+			cfsetispeed(&newtio, B2000000);
+			break;
+		case 3000000:
+			cfsetospeed(&newtio, B3000000);
+			cfsetispeed(&newtio, B3000000);
+			break;
+		case 4000000:
+			cfsetospeed(&newtio, B4000000);
+			cfsetispeed(&newtio, B4000000);
+			break;
+		default:
+			cfsetospeed(&newtio, B115200);
+			cfsetispeed(&newtio, B115200);
+			break;
+	}
+
+	if (tcsetattr(fd, TCSANOW, &newtio) < 0) {
+		printf("Can't set port setting\n");
+		return -1;
+	}
+	/* Blocking behavior */
+	fcntl(fd, F_SETFL, 0);
+#endif
+
+    return fd;
+}
+
+
+static void signal_process(int signal_num) {
+    if(at_fd > 0) {
+        close(at_fd);
+    }
+#ifdef MBTK_LOG
+    LOGD("Exit by sig - %d\n", signal_num);
+#endif
+    exit(0);
+}
+
+static void* read_thread_run( void *arg)
+{
+    //UNUSED(arg);
+
+    char at_rsp[1024];
+    char *ptr;
+    int index;
+    int len;
+    while(at_fd > 0) {
+        memset(at_rsp, 0x0, 1024);
+        index = 0;
+        len = 0;
+        while(1) {
+            if((len = read(at_fd, at_rsp + index, 1024)) > 0) {
+                ptr = at_rsp;
+                while(*ptr == '\r' || *ptr == '\n')
+                {
+                    ptr++;
+                }
+                if(strlen(ptr) > 0 && ptr[strlen(ptr) - 1] == '\n') {
+                    printf("<%s\n", ptr);
+#ifdef MBTK_LOG
+                    LOGV("RSP:%s", ptr);
+#endif
+
+                    break;
+                } else {
+                    index += len;
+                }
+            } else {
+                LOGE("Read error:%d",errno);
+                return NULL;
+            }
+        }
+    }
+
+    LOGD("read_thread_run() exit.\n");
+    return NULL;
+}
+
+static int read_thread_start()
+{
+    pthread_t tid;
+    pthread_attr_t attr;
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    int ret = pthread_create(&tid, &attr, read_thread_run, &attr);
+    if (ret < 0)
+    {
+        LOGE("pthread_create\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int at_complete(char *rsp)
+{
+#if 0
+    char *ptr = at_rsp_complete_tag;
+    while(ptr) {
+        LOGD("ptr = %s", ptr);
+        if(strstr(rsp, ptr)) {
+            LOGD("%s , %s", rsp, ptr);
+            return 1;
+        }
+        ptr++;
+    }
+#else
+    int i = 0;
+    while(at_rsp_complete_tag[i]) {
+        LOGD("ptr = %s", at_rsp_complete_tag[i]);
+        if(strstr(rsp, at_rsp_complete_tag[i])) {
+            LOGD("%s , %s", rsp, at_rsp_complete_tag[i]);
+            return 1;
+        }
+        i++;
+    }
+
+#endif
+    return 0;
+}
+
+static void at_rsp_read()
+{
+    char at_rsp[1024];
+    int len = 0;
+    while(1) {
+        memset(at_rsp, 0x0, 1024);
+        if((len = read(at_fd, at_rsp, 1024)) > 0) {
+            printf("%s", at_rsp);
+            if(at_complete(at_rsp)) {
+                break;
+            }
+        } else {
+            printf("Read error:%d\n",errno);
+            break;
+        }
+    }
+}
+
+static void help()
+{
+    printf("at : Enter AT mode(Socket).\n");
+    printf("at <at_cmd>: Send AT command(Socket).\n");
+    printf("at <dev>: Enter AT mode(Device).\n");
+    printf("at <dev> echo: ´®¿ÚÊý¾Ý»ØÏÔ¡£\n");
+    printf("at <dev> <at_cmd>: Send AT command(Device).\n");
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (ÀàËÆ SIGINT £¬µ«Òª²úÉúcoreÎļþ)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            exit(0);
+        }
+        case SIGTERM:// ĬÈÏkill   (ͬ SIGKILL £¬µ« SIGKILL ²»¿É²¶»ñ)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (ͬ SIGSTOP £¬µ« SIGSTOP ²»¿É²¶»ñ)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // Èç¿ÕÖ¸Õë
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    //UNUSED(argc);
+    //UNUSED(argv);
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+#ifdef MBTK_LOG
+    mbtk_log_init("radio", "MBTK_AT");
+    LOGI("mbtk_at start.");
+#endif
+
+    signal(SIGKILL, signal_process);
+    signal(SIGINT, signal_process);
+    signal(SIGQUIT, signal_process);
+    signal(SIGTERM, signal_process);
+
+    char *at_cmd = NULL;
+    bool echo = FALSE;
+    if(argc == 1) {
+        at_mode = AT_MODE_SOCK_1;
+    } else if(argc == 2) {
+        if(!strncasecmp(argv[1], "at", 2)) {
+            at_mode = AT_MODE_SOCK_2;
+            at_cmd = argv[1];
+        } else if(!strncasecmp(argv[1], "/dev/", 5)) {
+            at_mode = AT_MODE_DEV_1;
+        } else {
+            help();
+            return -1;
+        }
+    } else if(argc == 3) {
+        if(!strncasecmp(argv[1], "/dev/", 5) && (!strncasecmp(argv[2], "at", 2) || !strncasecmp(argv[2], "echo", 4))) {
+            at_mode = AT_MODE_DEV_2;
+            if(!strncasecmp(argv[2], "at", 2)) {
+                at_cmd = argv[2];
+            } else {
+                echo = TRUE;
+            }
+        } else {
+            help();
+            return -1;
+        }
+    } else {
+        help();
+        return -1;
+    }
+#if 0
+#ifdef AT_TYPE_SOCKET
+    at_fd = openSocket("/tmp/atcmdmbtk");
+#else
+	at_fd = at_open(argv[1]);
+#endif
+    if(at_fd > 0) {
+#ifdef AT_TYPE_SOCKET
+        if(argc > 1) {
+            char *at_cmd = argv[1];
+#else
+	    if(argc > 2) {
+            char *at_cmd = argv[2];
+#endif
+#endif
+
+    if(at_mode == AT_MODE_SOCK_1 || at_mode == AT_MODE_SOCK_2) {
+        at_fd = openSocket("/tmp/atcmdmbtk");
+    } else {
+#if 0
+        at_fd = at_open(argv[1]);
+#else
+        if(echo) {
+            at_fd = adb_port_open(argv[1], 115200);
+        } else {
+            at_fd = at_open(argv[1]);
+        }
+#endif
+    }
+    if(at_fd > 0) {
+        if(at_cmd != NULL) {
+            char *ptr = at_cmd + strlen(at_cmd) - 1;
+            while(ptr >= at_cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+            // printf("AT:[%ld]%s\n", strlen(at_cmd), at_cmd);
+            if(!strncasecmp(at_cmd, "at", 2))
+            {
+                *(++ptr) = '\r';
+                *(++ptr) = '\n';
+                if(write(at_fd, at_cmd, strlen(at_cmd)) <= 0) {
+                    printf("Write error:%d\n", errno);
+                } else {
+                    // Read response.
+                    at_rsp_read();
+                }
+            } else {
+                printf("AT error!\n");
+            }
+        } else {
+            if(echo) {
+                char read_buff[1024];
+                char write_buff[1024];
+                int len;
+#if 0
+                fd_set fds;
+                int fdcount, nfds = 0;
+                while(1) {
+                    FD_SET(at_fd, &fds);
+        		    if(at_fd > nfds)
+        			    nfds = at_fd;
+
+                    fdcount = select(nfds + 1, &fds, NULL, NULL, NULL);
+        			if(fdcount < 0) /* error */
+        			{
+        				printf("select returned %d, errno %d, continue\r", fdcount, errno);
+        				sleep(1);
+        				continue;
+        			}
+
+        			if(FD_ISSET(at_fd, &fds))
+        			{
+                        FD_CLR(at_fd, &fds);
+                        memset(read_buff, 0x0, 1024);
+                        if((len = read(at_fd, read_buff, 1024)) > 0) {
+                            memset(write_buff, 0x0, 1024);
+                            printf("%s\n", read_buff);
+                            len = snprintf(write_buff, 1024, "%s\n", read_buff);
+                            write(at_fd, write_buff, len);
+                        } else {
+                            printf("Read error:%d\n",errno);
+                            return NULL;
+                        }
+                    }
+                }
+#else
+                printf("Waitting data!!!\n");
+                while(1) {
+                    memset(read_buff, 0x0, 1024);
+                    if((len = read(at_fd, read_buff, 1024)) > 0) {
+                        memset(write_buff, 0x0, 1024);
+                        printf("%s\n", read_buff);
+                        len = snprintf(write_buff, 1024, "%s\n", read_buff);
+                        write(at_fd, write_buff, len);
+                    } else {
+                        printf("Read error:%d\n",errno);
+                        return NULL;
+                    }
+                }
+#endif
+            } else {
+                setbuf(stdout, NULL);
+                read_thread_start();
+                char at_cmd[100];
+                //printf(">>");
+                while(1)
+                {
+                    memset(at_cmd, 0x0, 100);
+                    if(fgets(at_cmd, 100, stdin))
+                    {
+                        char *ptr = at_cmd + strlen(at_cmd) - 1;
+                        while(ptr >= at_cmd && (*ptr == '\r' || *ptr == '\n'))
+                        {
+                            *ptr-- = '\0';
+                        }
+                        // printf("AT:[%ld]%s\n", strlen(at_cmd), at_cmd);
+                        if(!strncasecmp(at_cmd, "at", 2))
+                        {
+                            *(++ptr) = '\r';
+                            *(++ptr) = '\n';
+                            if(write(at_fd, at_cmd, strlen(at_cmd)) <= 0) {
+                                LOGE("Write error:%d",errno);
+                                break;
+                            }
+                            printf(">%s",at_cmd);
+#ifdef MBTK_LOG
+                            LOGV("AT:%s",at_cmd);
+#endif
+                        } else if(!strcasecmp(at_cmd, "q")) {
+                            break;
+                        } else {
+                            printf("\n");
+                        }
+                    }
+                }
+            }
+        }
+
+        close(at_fd);
+
+#ifdef MBTK_LOG
+        LOGD("EXIT");
+#endif
+    }
+
+    return 0;
+}
diff --git a/mbtk/test/audio_test.c b/mbtk/test/audio_test.c
new file mode 100755
index 0000000..3391a84
--- /dev/null
+++ b/mbtk/test/audio_test.c
@@ -0,0 +1,336 @@
+#include "mbtk_type.h"
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+// #include "ql_at.h"
+#include "ql/ql_audio.h"
+// #include "mopen_tts.h"
+
+#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
+
+static int record_fd = 0;
+
+int Ql_cb_playback(int hdl, int result)
+{
+    printf("%s: hdl=%d, result=%d\n\r", __func__, hdl, result);
+    if (result == AUD_PLAYER_FINISHED || result == AUD_PLAYER_NODATA)
+    {
+        printf("%s: play finished\n\r", __func__);
+    }
+    return 0;
+}
+
+void record_cb_func(int cb_result, char* databuf, unsigned int len)
+{
+    int rc;
+
+    if(NULL != databuf && len > 0 && record_fd > 0)
+    {
+        //for debug:save into file
+        rc = write(record_fd, databuf, len);
+        if (rc < 0) {
+            printf("%s: error writing to file!\n", __FUNCTION__);
+        } else if (rc < len) {
+            printf("%s: wrote less the buffer size!\n", __FUNCTION__);
+        }
+    }
+}
+int MBTK_wav_pcm16Le_check(int fd)
+{
+    struct wav_header hdr;
+
+    if (fd <= 0)
+        return -1;
+
+    if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+    {
+        printf("\n%s: cannot read header\n", __FUNCTION__);
+        return -1;
+    }
+
+    if ((hdr.riff_id != ID_RIFF)
+            || (hdr.riff_fmt != ID_WAVE)
+            || (hdr.fmt_id != ID_FMT))
+    {
+        printf("\n%s: is not a riff/wave file\n", __FUNCTION__);
+        return -1;
+    }
+
+    if ((hdr.audio_format != FORMAT_PCM) || (hdr.fmt_sz != 16)) {
+        printf("\n%s: is not pcm format\n", __FUNCTION__);
+        return -1;
+    }
+
+    if (hdr.bits_per_sample != 16) {
+        printf("\n%s: is not 16bit per sample\n", __FUNCTION__);
+        return -1;
+    }
+
+    return 0;
+}
+
+int MBTK_wav_pcm16Le_set(int fd)
+{
+    struct wav_header hdr;
+
+    if (fd <= 0)
+        return -1;
+
+    memset(&hdr, 0, sizeof(struct wav_header));
+
+    hdr.riff_id = ID_RIFF;
+    hdr.riff_fmt = ID_WAVE;
+    hdr.fmt_id = ID_FMT;
+    hdr.fmt_sz = 16;
+    hdr.audio_format = FORMAT_PCM;
+    hdr.num_channels = 1;
+    hdr.sample_rate = 8000;
+    hdr.bits_per_sample = 16;
+    hdr.byte_rate = (8000 * 1 * hdr.bits_per_sample) / 8;
+    hdr.block_align = (hdr.bits_per_sample * 1) / 8;
+    hdr.data_id = ID_DATA;
+    hdr.data_sz = 0;
+
+    hdr.riff_sz = hdr.data_sz + 44 - 8;
+    if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+        return -1;
+    }
+
+    return 0;
+}
+void aplay(void)
+{
+    char operator[10];
+    char databuf[1024];
+    int opt = 0;
+    int fd = 0;
+    int size = 0;
+    int state;
+    int play_hdl = 0;
+
+    while(1)
+    {
+        printf("=========aplay========\n"
+            "\t 0 Open PCM\n"
+            "\t 1 Play Stream\n"
+            "\t 2 Play file\n"
+            "\t 3 Close\n"
+            "\t others exit\n\n"
+            "operator >> ");
+
+        fflush(stdin);
+        fgets(operator, sizeof(operator), stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+            case 0:
+                play_hdl = Ql_AudPlayer_Open(NULL, Ql_cb_playback);
+                if(0 == play_hdl)
+                    printf("Ql_AudPlayer_Open fail\n");
+                break;
+            case 1:
+               if(0 == play_hdl)
+                    continue;
+
+                fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+                if (fd <= 0)
+                    continue;
+
+                if(0 == MBTK_wav_pcm16Le_check(fd))
+                {
+                    memset(databuf, 0, sizeof(databuf));
+                    while(0 < (size = read(fd, databuf, sizeof(databuf))))
+                    {
+                        if(-1 == Ql_AudPlayer_Play(play_hdl, databuf, size))
+                            break;
+                    }
+                    printf("aplay Stream end \n");
+                }
+
+                close(fd);
+                break;
+            case 2:
+                if(0 == play_hdl)
+                    continue;
+
+                fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+                if (fd <= 0)
+                    continue;
+
+                if(0 == MBTK_wav_pcm16Le_check(fd))
+                {
+                    Ql_AudPlayer_PlayFrmFile(play_hdl, fd, 0);
+                }
+                else
+                {
+                    printf("aplay file type error\n");
+                }
+                close(fd);
+                break;
+            case 3:
+                if(0 == play_hdl)
+                    continue;
+                Ql_AudPlayer_Close(play_hdl);
+                break;
+            case 4:
+            //    aplay_thread(MBTK_AUD_DEMO_WAV);
+                Ql_Mp3_To_Play("/data/mp3demo.mp3", play_hdl, 0);
+                break;
+            default:
+                return;
+        }
+
+        sleep(1);
+    }
+
+    printf("aplay exit\n");
+    return ;
+}
+void arec(void)
+{
+    int ret;
+    char operator[10];
+    int opt;
+    int hdl = 0;
+
+    while(1)
+    {
+        printf("=======arec======\n"
+            "\t 0 Open PCM\n"
+            "\t 1 Start Record\n"
+            "\t 2 Get state\n"
+            "\t 3 Pause\n"
+            "\t 4 Resume\n"
+            "\t 5 Stop\n"
+            "\t 6 Close\n"
+            "\t others exit\n\n"
+            "operator >> ");
+
+        fflush(stdin);
+        fgets(operator, sizeof(operator), stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+            case 0:
+                hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
+                if (hdl == 0)
+                    return ;
+                break;
+            case 1:
+                if(0 == hdl)
+                {
+                    printf("audio is not initialized yet.\n");
+                    continue;
+                }
+
+                if(0 != record_fd)
+                {
+                    printf("audio It's already being recorded.\n");
+                    continue;
+                }
+                record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
+                if (record_fd <= 0)
+                    printf("file open error\n");
+
+                if(0 == MBTK_wav_pcm16Le_set(record_fd))
+                {
+                    ret = Ql_AudRecorder_StartRecord();
+                    if(0 != ret)
+                    {
+                        printf("audio record error: %d\n", ret);
+                        close(record_fd);
+                        record_fd = 0;
+                    }
+                }
+                else
+                {
+                    printf("arec set file header error\n");
+                    close(record_fd);
+                    record_fd = 0;
+                }
+                break;
+            case 2:
+                // printf("arec state : %d\n", state);
+                break;
+            case 3:
+                break;
+            case 4:
+                break;
+            case 5:
+                break;
+            case 6:
+                Ql_AudRecorder_Close();
+                if(record_fd > 0)
+                {
+                    close(record_fd);
+                    record_fd = 0;
+                }
+                break;
+            default:
+                return;
+        }
+
+        sleep(1);
+    }
+
+    printf("arec exit\n");
+    return ;
+}
+int main(void)
+{
+    char operator[10];
+    int opt;
+
+    while(1)
+    {
+        printf("=========audio main=========\n"
+            "\t0 exit\n"
+            "\t1 aplay\n"
+            "\t2 arec\n"
+            "\t3 set speaker Volume\n"
+            "\t4 get speaker Volume\n"
+            "\t5 set mic Volume\n"
+            "\t6 get mic Volume\n"
+            "\t7 tts\n"
+            "\t8 tone\n"
+            "operator: >> ");
+
+        fgets(operator, sizeof(operator), stdin);
+        fflush(stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+            case 0:
+                printf("main exit\n");
+                return 0;
+            case 1:
+                aplay();
+                break;
+            case 2:
+                arec();
+                break;
+            case 3:
+                mbtk_at_rec(NULL);
+                break;
+            case 4:
+                mbtk_at_play(NULL);
+                break;
+            case 5:
+                break;
+            case 6:
+                break;
+            case 7:
+                break;
+            case 8:
+                break;
+            default:
+                break;
+        }
+
+        sleep(1);
+    }
+
+    return 0;
+}
diff --git a/mbtk/test/framebuffer_demo.c b/mbtk/test/framebuffer_demo.c
new file mode 100755
index 0000000..281e9ab
--- /dev/null
+++ b/mbtk/test/framebuffer_demo.c
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <math.h>
+
+/**< \brief 根据实际情况修改,此处为unsigned short是565的屏,根据程序打印出的
+    bits_per_pixel的值可以判断出输出格式是565还是888 */
+// typedef unsigned int color_t;
+typedef unsigned short color_t;
+/**< \brief 定义每个像素点对应的位数,如果是565的屏则为16,如果是888的屏则为32 */
+// #define BITS_PER_PIXEL    32
+#define BITS_PER_PIXEL    16
+
+static struct fb_var_screeninfo __g_vinfo;    /* 显示信息 */
+color_t *__gp_frame;                    /* 虚拟屏幕首地址 */
+
+#pragma pack(2)
+typedef unsigned short WORD;
+typedef unsigned char BYTE;
+typedef unsigned int DWORD;
+typedef int LONG;
+
+typedef struct tagBITMAPFILEHEADER
+{
+    WORD bfType;        // 位图文件的类型,必须为BM
+    DWORD bfSize;       // 位图文件的大小,以字节为单位
+    WORD bfReserved1;   // 位图文件保留字,必须为0
+    WORD bfReserved2;   // 位图文件保留字,必须为0
+    DWORD bfOffBits;    // 位图数据的起始位置,以相对于位图
+                        // 文件头的偏移量表示,以字节为单位
+} BITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFOHEADER
+{
+    DWORD biSize; // 本结构所占用字节数
+    LONG biWidth; // 位图的宽度,以像素为单位
+    LONG biHeight; // 位图的高度,以像素为单位
+    WORD biPlanes; // 目标设备的级别,必须为1
+    WORD biBitCount;// 每个像素所需的位数,必须是1(双色),
+         // 4(16色),8(256色)或24(真彩色)之一
+    DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
+        // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
+    DWORD biSizeImage; // 位图的大小,以字节为单位
+    LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数
+    LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数
+    DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数
+    DWORD biClrImportant;// 位图显示过程中重要的颜色数
+} BITMAPINFOHEADER;
+#pragma pack(0)
+
+typedef WORD (*bmp_xx_to_16)(char *);
+
+//画点
+void draw_point(int x, int y, color_t color)
+{
+    color_t *p = __gp_frame;
+
+    p += __g_vinfo.xres * y + x;
+    *p = color;
+}
+
+WORD bmp_24_to_16(char *input)
+{
+    /* 如果使用的bmp图片的颜色深度是24位,适用于888的屏,但如果一定要在565的屏
+        上显示,则取红色的高5位,绿色的高6位和蓝色的高5位,拼成16位的数据
+        进行显示。这样做并不是最好的办法,更好的方法是将需要丢失的部分数
+        据进行进位或舍去。
+        */
+    WORD c;
+    char b, g, r;
+    r = *input >> 3;
+    input++;
+    g = *input >> 2;
+    input++;
+    b = *input >> 3;
+
+    c = (b << 11) | (g << 5) | r;
+
+    return c;
+}
+
+WORD bmp_16_to_16(char *input)
+{
+    WORD c;
+
+    c = *input;
+    input++;
+    c = (c << 8) | *input;
+    c = ((c >> 8) & 0x00ff) | ((c & 0x00ff) << 8);
+
+    return c;
+}
+
+//功能:在指定坐标显示指定BPM24位图
+//参数:(x , y)坐标
+//        pic:24位BMP图像
+void Show_BMP(int x , int y , const char *pic)
+{
+    int fd = 0;
+    color_t c;
+    BITMAPFILEHEADER filehead;
+    BITMAPINFOHEADER infohead;
+    int i,j;
+    unsigned char pixel_byte;
+    unsigned char *p = NULL , *p_data = NULL;
+    int width_error = 0;
+    short* t_data = NULL;
+    bmp_xx_to_16 transform_func = NULL;
+    int index = 0;
+
+    printf("%s: %s\n", __FUNCTION__, pic);
+    fd = open(pic , O_RDONLY);
+    if(fd == -1) {
+        printf("fail to open\n");
+        return;
+    }
+
+    read(fd , &filehead , sizeof(filehead));
+    read(fd , &infohead , sizeof(infohead));
+    printf("bfType: 0x%x, bfSize: %d, bfOffBits: 0x%x\n", filehead.bfType, filehead.bfSize, filehead.bfOffBits);
+
+    printf("biSize: %d, biWidth: %d, biHeight: %d\n", infohead.biSize, infohead.biWidth, infohead.biHeight);
+    printf("biPlanes: %d, biBitCount: %d, biCompression: %d\n", infohead.biPlanes, infohead.biBitCount, infohead.biCompression);
+    printf("biSizeImage: %d, biXPelsPerMeter: %d, biYPelsPerMeter: %d\n", infohead.biSizeImage, infohead.biXPelsPerMeter, infohead.biYPelsPerMeter);
+
+    width_error = (4 - infohead.biWidth * 3 % 4) % 4;
+    pixel_byte = infohead.biBitCount / 8;
+
+    if (16 == infohead.biBitCount) {
+        transform_func = bmp_16_to_16;
+    } else if (24 == infohead.biBitCount) {
+        transform_func = bmp_24_to_16;
+    } else {
+        printf("Not Suppurt %d bmp\n", infohead.biBitCount);
+        close(fd);
+        return;
+    }
+
+    t_data = malloc(__g_vinfo.xres_virtual * __g_vinfo.yres_virtual * __g_vinfo.bits_per_pixel / 8);
+
+    if(t_data == NULL) {
+        perror("fail to malloc");
+    }
+
+    p_data = malloc(infohead.biSizeImage);
+    if(p_data == NULL) {
+        perror("fail to malloc");
+    }
+
+    printf("biSizeImage:%d, width_error: %d\n", infohead.biSizeImage, width_error);
+    read(fd , p_data , infohead.biSizeImage);
+    p = p_data;
+
+    int ret;
+    char data[24] = {0};
+    int debug_fd = open("/data/debug_fb", O_RDWR|O_CREAT|O_TRUNC, 0644);
+    if (debug_fd < 0) {
+        printf("debug_fb open error\n");
+        return;
+    }
+    printf("height:%d, width:%d\n", infohead.biHeight, infohead.biWidth);
+    for(j = infohead.biHeight - 1; j >= 0; j--) {
+        for(i = 0; i < infohead.biWidth; i++) {
+            c = transform_func(p);
+            // c = *p;
+            p += pixel_byte;
+            // c = ((c >> 8) & 0x00ff) | ((c & 0x00ff) << 8);
+            t_data[__g_vinfo.xres * (y + j) + (x + i)] = c;
+            // draw_point(x + i, y + j, c);
+            index++;
+
+            sprintf(data, "index:%d, i:%d, j:%d\n", index, i, j);
+            ret = write(debug_fd, data, strlen(data));
+            if (ret < 0) {
+                printf("%s write error\n", __FUNCTION__);
+            }
+        }
+        p += width_error;
+    }
+    close(debug_fd);
+    printf("%s: %d\n", __FUNCTION__, infohead.biHeight * infohead.biWidth * __g_vinfo.bits_per_pixel / 8);
+    memcpy(__gp_frame, t_data,
+           infohead.biHeight * infohead.biWidth * __g_vinfo.bits_per_pixel / 8);
+    printf("%s: %d\n", __FUNCTION__, index);
+    free(p_data);
+    free(t_data);
+    close(fd);
+}
+
+/**
+ * \brief 填充整屏
+ */
+void full_screen (color_t color)
+{
+    int i;
+    color_t *p = __gp_frame;
+
+    for (i = 0; i < __g_vinfo.xres_virtual * __g_vinfo.yres_virtual; i++) {
+        *p++ = color;
+    }
+}
+
+/**
+ * \brief 清屏
+ */
+void clear()
+{
+    full_screen(0);
+}
+
+/* framebuffer初始化 */
+int framebuffer_init (void)
+{
+    int fd = 0;
+
+    fd = open("/dev/fb0", O_RDWR);
+    if (fd == -1) {
+        perror("fail to open /dev/fb0\n");
+        return -1;
+    }
+
+    /* 获取显示信息 */
+    ioctl(fd, FBIOGET_VSCREENINFO, &__g_vinfo);                     /* 获取显示信息 */
+    printf("bits_per_pixel = %d\n", __g_vinfo.bits_per_pixel);      /* 得到一个像素点对应的位数 */
+    printf("xres_virtual = %d\n", __g_vinfo.xres_virtual);            /* 打印虚拟屏幕列数 */
+    printf("yres_virtual = %d\n", __g_vinfo.yres_virtual);            /* 打印虚拟屏幕行数 */
+    printf("xres = %d\n", __g_vinfo.xres);                            /* 打印屏幕列数 */
+    printf("yres = %d\n", __g_vinfo.yres);                            /* 打印屏幕行数 */
+
+    int len = __g_vinfo.xres_virtual * __g_vinfo.yres_virtual * __g_vinfo.bits_per_pixel / 8;    /* 映射区大小 */
+
+    printf("fb size = %d\n", len);
+    __gp_frame = mmap(NULL,                             /* 映射区的开始地址,为NULL表示由系统决定映射区的起始地址 */
+                      len,
+                      PROT_WRITE | PROT_READ,            /* 内存保护标志(可读可写) */
+                      MAP_SHARED,                        /* 映射对象类型(与其他进程共享) */
+                      fd,                                /* 有效的文件描述符 */
+                      0);                                /* 被映射内容的偏移量 */
+    if (__gp_frame == NULL) {
+        perror("fail to mmap\n");
+        return -1;
+    }
+
+    return fd;
+}
+
+
+int main(int argc, const char *argv[])
+{
+    int fd;
+
+    if (argc < 2) {
+        printf("%s \" img \"", argv[0]);
+        exit(1);
+    }
+
+    fd = framebuffer_init();
+    if (fd < 0) {
+        printf("framebuffer_init error\n");
+        return 0;
+    }
+
+    printf("framebuffer_init Success.\n");
+    /* 清屏 */
+    clear();
+
+    printf("clear Success.\n");
+
+    // full_screen(0xF800);  // 显示红色
+
+    Show_BMP(0 , 0 , argv[1]);
+
+    close(fd);
+
+    return 0;
+}
diff --git a/mbtk/test/gnss_basic_demo.c b/mbtk/test/gnss_basic_demo.c
new file mode 100755
index 0000000..3d5b485
--- /dev/null
+++ b/mbtk/test/gnss_basic_demo.c
@@ -0,0 +1,514 @@
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <pthread.h>
+#include <errno.h>
+#include <time.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#define MBTK_GNSS_DEV  "/dev/ttyS2"
+
+#define MBTK_UART_RECV_BUFFER_SIZE 1024
+#define MBTK_UART_SEND_BUFFER_MAX 128
+#define GPS_DEV "/sys/devices/soc.0/d4000000.apb/mbtk-dev-op/gps_power"
+
+static int dev_fd = 0;
+static int inited = 0;
+static pthread_t  uart_pthread;
+
+static int mopen_open_gps(int state)
+{
+    int fd, ret;
+    char s[4] = "on";
+    fd = open(GPS_DEV, O_RDWR | O_TRUNC, 0644);
+    if (fd < 0) {
+        printf("[%s]  file [%s] open error\n", __FUNCTION__, GPS_DEV);
+        return -1;
+    }
+    if (0 == state) {
+        memcpy(s, "off", 3);
+    }
+    ret = write(fd, s, 4);
+    if (ret < 0) {
+        printf("%s: error writing to file!\n", __FUNCTION__);
+        close(fd);
+        return -2;
+    }
+
+    close(fd);
+    return 0;
+}
+
+void mopen_gnss_NonBlock(int fd, int cmd)
+{
+    int flags;
+
+    flags = fcntl(fd, F_GETFL, 0);
+    if (cmd) {
+        flags |= O_NONBLOCK;
+    } else {
+        flags &= ~O_NONBLOCK;
+    }
+
+    fcntl(fd, F_SETFL, flags);
+}
+
+int set_baudrate(int fd, int baudrate)
+{
+    struct termios options, oldtio;
+
+    if (fcntl(fd, F_SETFL, 0) < 0) {
+        printf("fcntl failed!\n");
+        return -1;
+    }
+
+    if (tcgetattr(fd, &oldtio) != 0) {
+        printf("setup serial error!\n");
+        return -1;
+    }
+
+    /* Get the current options for the port... */
+    tcgetattr(fd, &options);
+
+    /* Set the baud rates to baudrate... */
+    cfsetispeed(&options, baudrate);
+    cfsetospeed(&options, baudrate);
+    tcsetattr(fd, TCSANOW, &options);
+
+    if (0 != tcgetattr(fd, &options)) {
+        printf("get options error!\n");
+        return -1;
+    }
+
+    /*
+     * 8bit Data,no partity,1 stop bit...
+     */
+    options.c_cflag &= ~PARENB;//无奇偶校验
+    options.c_cflag &= ~CSTOPB;//停止位,1位
+    options.c_cflag &= ~CSIZE; //数据位的位掩码
+    options.c_cflag |= CS8;    //数据位,8位
+
+    cfmakeraw(&options);
+
+    /*
+     * Set the new options for the port...
+     */
+    if (tcsetattr(fd, TCSANOW, &options) != 0) {
+        printf("setup serial error!\n");
+        return -1 ;
+    }
+
+    return 0 ;
+}
+
+int mopen_gnss_open(char* dev, int baudrate)
+{
+    int ret;
+    int fd = 0;
+
+    fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
+    if (fd < 0) {
+        return -1;
+    }
+    printf("curent dev: %s, fd: %d \n", dev, fd);
+
+    if (baudrate) {
+        printf("set baudrate: %d \n", baudrate);
+        ret = set_baudrate(fd, baudrate);
+        if (-1 == ret) {
+            close(fd);
+            return -1;
+        }
+    } else {
+        set_baudrate(fd, B9600);
+    }
+
+    return fd;
+}
+
+static int mopen_gnss_read(int fd, char* buf, unsigned int buf_len)
+{
+    buf_len = (buf_len > MBTK_UART_RECV_BUFFER_SIZE ? MBTK_UART_RECV_BUFFER_SIZE : buf_len);
+    return read(fd, buf, buf_len);
+}
+
+int mopen_gnss_write(int fd, const char* buf, unsigned int buf_len)
+{
+    size_t size;
+    size_t size_to_wr;
+    ssize_t size_written;
+    if (MBTK_UART_SEND_BUFFER_MAX < buf_len) {
+        return -1;
+    }
+    for (size = 0; size < buf_len;) {
+        size_to_wr = buf_len - size;
+        if (size_to_wr > MBTK_UART_SEND_BUFFER_MAX) {
+            size_to_wr = MBTK_UART_SEND_BUFFER_MAX;
+        }
+
+        size_written = write(fd, &buf[size], size_to_wr);
+        if (size_written == -1) {
+            return -1;
+        }
+        printf("send cmd: %s", &buf[size]);
+        size += size_written;
+        if (size_written != size_to_wr) {
+            return size;
+        }
+    }
+    return size;
+}
+
+int mopen_gnss_close(int fd)
+{
+    return close(fd);
+}
+
+int mopen_send_cmd(int baud, char *cmd)
+{
+    int fd, __baud;
+    char buf[24] = {0};
+
+    printf("set baud: %d\n", baud);
+    if (115200 == baud)
+        __baud = B115200;
+    else
+        __baud = B9600;
+
+    fd = mopen_gnss_open(MBTK_GNSS_DEV, __baud);
+    if (fd < 0) {
+        printf("Open %s error!!\r\n", MBTK_GNSS_DEV);
+        return -1;
+    }
+
+    sprintf(buf, "$%s\r\n", cmd);
+    mopen_gnss_write(fd, buf, strlen(buf));
+    close(fd);
+
+    return 0;
+}
+
+static void gnss_uart_pthread(void* hdl)
+{
+    int ret = 0;
+    char buf[MBTK_UART_RECV_BUFFER_SIZE] = {0};
+
+    pthread_detach(pthread_self());
+
+    memset(buf, 0, sizeof(buf));
+    while (inited) {
+        ret = mopen_gnss_read(dev_fd, buf, MBTK_UART_RECV_BUFFER_SIZE);
+        if (ret > 0) {
+            printf("read: [%d] %s\n", ret, buf);
+            memset(buf, 0, sizeof(buf));
+        } else {
+            printf("read error\n");
+        }
+        usleep(100000);
+    }
+
+    pthread_exit(NULL);
+}
+
+int mopen_gnss_send_cmd(const char* cmd, int cmd_len)
+{
+    return  mopen_gnss_write(dev_fd, cmd, cmd_len);
+}
+
+/**
+ *  \brief mopen_gnss_dev_reset
+ *
+ *  Detailed description
+ *
+ *  \param
+ *         type: 0 软件复位
+ *               1 芯片级复位(看门狗)
+ *               2 板级复位
+ *               3 接收机停止
+ *         mode :
+ *         0 : 热启动
+ *         1 : 温启动
+ *         2 : 冷启动
+ *  \return return type
+ */
+int mopen_gnss_dev_reset(int type, int mode)
+{
+    int ret;
+    // h00 热启动
+    // h01 温启动
+    // h85 冷启动
+    char send_buf[36] = {0};
+
+    if (0 == mode || 1 == mode) {
+        snprintf(send_buf, sizeof(send_buf), "$RESET,%d,h0%d\r\n", type, mode);
+    } else if (2 == mode) {
+        snprintf(send_buf, sizeof(send_buf), "$RESET,%d,h85\r\n", type);
+    } else if (3 == mode) {
+        snprintf(send_buf, sizeof(send_buf), "$RESET,%d,hFF\r\n", type);
+    } else {
+        printf("%s reset mode invalid.\n", __func__);
+        return -2;
+    }
+    printf("%s : %s\n", __FUNCTION__, send_buf);
+    ret = mopen_gnss_send_cmd(send_buf, strlen(send_buf));
+    if (ret < 0) {
+        printf("%s %d FAIL.	ret:%d\n", __FUNCTION__, __LINE__, ret);
+        return -1;
+    }
+    // set_baudrate(handle->dev_fd, B9600);
+
+    return 0;
+}
+
+int mopen_gnss_get_device_info(void)
+{
+    int ret;
+    char* send_buf = "$PDTINFO\r\n";
+
+    ret = mopen_gnss_send_cmd(send_buf, strlen(send_buf));
+    if (ret < 0) {
+        printf("mopen_gnss_client_init FAIL.	ret:%d\n", ret);
+        return -1;
+    }
+
+    return 0;
+}
+/**
+ * @brief      mopen_gnss_set_system_config
+ *
+ * @details    设置卫星系统配置
+ *
+ * @param      mode
+ *             0 -> H01(1) –GPS L1+SBAS+QZSS
+ *             1 -> H10 – BDS B1
+ *             2 -> H101 2 – GPS+GLONASS+GALILEO+SBAS+QZSS
+ *             3 -> H11 3 – GPS+BDS+GALILEO+SBAS+QZSS
+ * @return     return type
+ */
+int mopen_gnss_set_system_config(int mode)
+{
+    int ret;
+    char send_buf[20] = "$CFGSYS,H10\r\n";
+    char* str_mode[4] = {"H01", "H10", "H101", "H11"};
+
+    if (mode > 3) {
+        printf("%s param invalid.\n", __func__);
+        return -2;
+    }
+    snprintf(send_buf, sizeof(send_buf), "$CFGSYS,%s\r\n", str_mode[mode]);
+    ret = mopen_gnss_send_cmd(send_buf, strlen(send_buf));
+    if (ret < 0) {
+        printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+        return -3;
+    }
+
+    return 0;
+}
+
+/**
+* @brief 使用popen调用终端并获取执行结果
+*
+* @param[in] cmd 命令内容
+* @param[out] result 保存结果的地址
+* @return 0或1 执行状态,成功或失败
+*/
+int exec_cmd(const char* cmd, char* result)
+{
+    FILE* pipe = popen(cmd, "r");
+    if (!pipe) {
+        return -1;
+    }
+
+    char buffer[256] = {0};
+    while (!feof(pipe)) {
+        if (fgets(buffer, 256, pipe)) {
+            strstr(buffer, "GA");
+            printf("%s", buffer);
+            memset(buffer, 0, sizeof(buffer));
+        }
+    }
+    pclose(pipe);
+    return 0;
+}
+
+/*
+  sync : 1
+ */
+int mopen_gnss_firmware_update(void)
+{
+    const char* cmd = "mbtk_gnss_update -d /dev/ttyS2 \
+                       -l /etc/mbtk/bootloader_r3.0.0_build6773_uartboot_115200.pkg \
+                       -f /etc/mbtk/UC6228CI-R3.4.0.0Build7258_mfg.pkg";
+
+    printf("Mopen Gnss Firmware Update -> \n");
+    int ret = exec_cmd(cmd, NULL);
+    if (0 == ret) {
+        printf("Gnss update result: %x\n", ret);
+    }
+
+    printf("%s %d: %d.\n", __FUNCTION__, __LINE__, ret);
+    return ret;
+}
+
+/**
+ * @brief      mopen_gnss_get_uart
+ *
+ * @details    get uart config info.
+ *             $CFGPRT,1,h0,9600,129,3*57
+ *
+ * @param      param
+ *
+ * @return     return type
+ */
+int mopen_gnss_get_uart(void)
+{
+    int ret;
+    char* send_buf = "$CFGPRT,1\r\n";
+    // char *send_buf = "$CFGPRT,2\r\n";
+
+    ret = mopen_gnss_send_cmd(send_buf, strlen(send_buf));
+    if (ret < 0) {
+        printf("mopen_gnss_client_init FAIL.	ret:%d\n", ret);
+        return -1;
+    }
+    return 0;
+}
+int mopen_gnss_client_init(int baudrate)
+{
+    int ret;
+
+    ret = mopen_open_gps(1);
+    if (ret) {
+        printf("GNSS open init error\n");
+        return -4;
+    }
+    sleep(1);
+
+    dev_fd = mopen_gnss_open(MBTK_GNSS_DEV, baudrate);
+
+    pthread_create(&uart_pthread, NULL, (void*)gnss_uart_pthread, NULL);
+    inited = 1;
+
+    return ret;
+}
+
+static int _kill_pthread(pthread_t pid, int kill)
+{
+    int ret;
+
+    if (kill) {
+        ret = pthread_cancel(pid);
+        pthread_join(pid, NULL);
+    }
+    do {
+        ret = pthread_kill(pid, 0);
+        if (ret == ESRCH) {
+            printf("The specified thread does not exist or has terminated\n");
+        } else if (ret == EINVAL) {
+            printf("Useless signal\n");
+        } else {
+            printf("The thread exists\n");
+        }
+        usleep(100000);
+    } while (0 == ret);
+
+    return 0;
+}
+
+int mopen_gnss_client_deinit(void)
+{
+    int ret;
+
+    mopen_gnss_close(dev_fd);
+    ret = mopen_open_gps(0);
+    if (ret) {
+        printf("GNSS close init error\n");
+        return -1;
+    }
+    inited = 0;
+    printf("kill thread uart.\n");
+    _kill_pthread(uart_pthread, 1);
+
+    return 0;
+}
+
+void user_help(void)
+{
+    printf("=========gnss main=========\n"
+           "\t0 exit\n"
+           "\t1 gnss init\n"
+           "\t2 gnss deinit\n"
+           "\t3 gnss reset\n"
+           "\t4 gnss update Firmware\n"
+           "\t5 gnss System config\n"
+           "\t6 gnss uart\n"
+           "\t7 gnss set uart 115200\n"
+           "please input operator: >> ");
+}
+
+int main(int argc, char* argv[])
+{
+    int ret;
+    int opt;
+
+    if (argc > 1) {
+        printf("%s, %s\n", argv[1], argv[2]);
+        opt = atoi(argv[1]);
+        printf("%s, %s\n", argv[1], argv[2]);
+        mopen_send_cmd(opt, argv[2]);
+        return 0;
+    }
+    while (1) {
+        user_help();
+        scanf("%d", &opt);
+        switch (opt) {
+        case 0:
+            printf("main exit\n");
+            return 0;
+        case 1:
+            ret = mopen_gnss_client_init(0);
+            if (ret < 0) {
+                printf("lynq_gnss_init FAIL.	ret:%d\n", ret);
+                return -1;
+            }
+            opt = 0;
+            break;
+        case 2: {
+            mopen_gnss_client_deinit();
+            break;
+        }
+        case 3: {
+            mopen_gnss_dev_reset(0, 0);
+            break;
+        }
+        case 4: {
+            mopen_gnss_firmware_update();
+            break;
+        }
+        case 5: {
+            mopen_gnss_set_system_config(2);
+            break;
+        }
+        case 6: {
+            mopen_gnss_get_device_info();
+            sleep(1);
+            mopen_gnss_get_uart();
+
+            break;
+        }
+        case 7: {
+            ret = mopen_gnss_client_init(115200);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    return 0;
+}
diff --git a/mbtk/test/gnss_update_demo.c b/mbtk/test/gnss_update_demo.c
new file mode 100755
index 0000000..d797f04
--- /dev/null
+++ b/mbtk/test/gnss_update_demo.c
@@ -0,0 +1,1283 @@
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sched.h>
+#include <limits.h>
+#include <linux/serial.h>
+
+#define RTM_FILE_NAME "rtm.bin"
+
+#define PARA_ERR                -1
+#define FILE_CHECK_ERR          -2
+#define ENTER_UPDATE_MODE_ERR   -3
+#define UPDATE_ERR              -4
+#define UART_DEV_ERR            -5
+
+#define XMODEM_SOH 0x01
+#define XMODEM_STX 0x02
+#define XMODEM_EOT 0x04
+#define XMODEM_ACK 0x06
+#define XMODEM_NAK 0x15
+#define XMODEM_CAN 0x18
+#define XMODEM_CRC_CHR	'C'
+#define XMODEM_CRC_SIZE 2		/* Crc_High Byte + Crc_Low Byte */
+#define XMODEM_FRAME_ID_SIZE 2 		/* Frame_Id + 255-Frame_Id */
+#define XMODEM_DATA_SIZE_SOH 128  	/* for Xmodem protocol */
+#define XMODEM_DATA_SIZE_STX 1024 	/* for 1K xmodem protocol */
+#define USE_1K_XMODEM 1  		/* 1 for use 1k_xmodem 0 for xmodem */
+#define	TIMEOUT_USEC	0
+#define	TIMEOUT_SEC		10
+
+#if (USE_1K_XMODEM)
+#define XMODEM_DATA_SIZE 	XMODEM_DATA_SIZE_STX
+#define XMODEM_HEAD		XMODEM_STX
+#else
+#define XMODEM_DATA_SIZE 	XMODEM_DATA_SIZE_SOH
+#define XMODEM_HEAD 		XMODEM_SOH
+#endif
+
+
+/******************************************************************************
+ * 时间处理相关的宏
+ *****************************************************************************/
+// 时间超时标志
+int timeout_sign = 1;
+// 获取当前时间
+#define GET_TIME()  { gettimeofday(&time_m, NULL); \
+	time_m.tv_sec += TIMEOUT_SEC;\
+}
+// 设置从循环中退出的时间
+#define SET_TIME_OUT(x)  { gettimeofday(&time_m, NULL); \
+	time_m.tv_sec += x;\
+}
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		printf("\ntimeout!!!\n\n");\
+		close(fd); \
+		return ret; \
+	} \
+}
+// 检测时间是否超时,超时则退出当前循环
+#define CHK_TIME_BREAK()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		timeout_sign = 1; 	\
+		printf("\ntimeout!!!\n\n");\
+		break; \
+	} \
+}
+// 检测延时是否到达,到达则退出当前循环
+#define DELAY_TIME_BREAK()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		timeout_sign = 1; 	\
+		break; \
+	} \
+}
+
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME1()  { gettimeofday(&time_n, NULL); \
+	if(time_n.tv_sec > time_m.tv_sec) { \
+		printf("\ntimeout!!!\n\n");\
+		if(datafile != NULL) \
+		fclose(datafile); \
+		return ret; \
+	} \
+}
+
+
+/******************************************************************************
+ * APData 相关定义、声明
+ *****************************************************************************/
+// APData 数据头部定义
+typedef struct {
+	unsigned int  ih_magic;		// Image Header Magic Number
+	unsigned int  ih_dcrc;		// Image Data CRC checksum
+	unsigned int  ih_time;		// Image Creation Timestamp
+	unsigned int  ih_size;		// Image Data Size
+	unsigned int  ih_compress;		// Image Header compress or not:0, not compress
+	unsigned int  pkg_flash_addr;	// flash memory offset for package
+	unsigned int  pkg_run_addr;		// Run time address for this package
+	unsigned int  ih_hcrc;		// Image Header CRC checksum
+} uc_image_header_t;
+
+// APData 数据头部长度
+#define HEADERLEN 32
+// APData 接收状态类型
+typedef enum ReceStat{
+	WAIT_FD = 1,
+	WAIT_FC,
+	WAIT_FB,
+	WAIT_FA,
+	RECE_HEADER,
+	RECE_DATA,
+} RecvStat_t;
+// APData 接收状态变量
+static RecvStat_t recvStat = WAIT_FD;
+// APData 接收状态变量
+static int isStartReceive = 0;
+// APData 开始接收
+void af_start_receive();
+// APData 停止接收,在数据接收完成或出错时调用
+void af_stop_receive();
+// 获取isStartReceive 变量值
+int af_is_start_receive();
+// APData 数据接收入口
+int af_add_char(char *file, unsigned char c);
+// 校验 APData 数据头
+int af_check_header(unsigned char *pbuf, unsigned int len);
+// 校验 APData 数据区
+int af_check_data(unsigned int * pbuf, unsigned int len);
+// 获取 APData 数据长度
+int af_get_data_len();
+// APData 数据接收缓存
+unsigned int recv_buf[1024 * 2];
+unsigned char *pbuf;
+int data_len;
+// 校验文件
+int check_file(char *fname);
+
+/******************************************************************************
+ * 与接收机串口通讯相关定义、声明
+ *****************************************************************************/
+// select功能使用变量
+static int use_select = 1;
+// 初始化串口资源
+int initial_serialPort(char * serial_device);
+// 设置串口波特率
+int set_baudrate(int fd, int baudrate);
+// 检测串口数据
+static int select_read(int fd, int timeout);
+// 读取串口数据
+ssize_t deal_read(int fd, void *buf, size_t count);
+// 向接收机发送串口数据
+static void gps_dev_send(int fd, char *msg);
+// 通过xmodem协议向接收机发送串口数据
+int xmodem_send(int fd, char *fname);
+
+/******************************************************************************
+ * apflash 功能函数
+ *****************************************************************************/
+// 检测接收机发送的'YC'信号,如果收到,则标志着接收机进入boot模式,并可以通过xmodem发送数据
+int check_YC(char newchar);
+// 获取 APData 数据, 应该在接收机定位且星历数据接收完整时获取
+int getAPData(int fd, char *file);
+// 向接收机发送 APData 数据,有效的APData数据可以让CI模块迅速定位
+int sendAPData(int fd, char *ap);
+// 校验 APData 数据文件
+int checkAPData(char *apFile);
+// 为接收机加载BootLoader,该流程执行时,需要根据终端提示,给接收机下电和上电,确保接收机进入boot模式
+int downloadBL(int fd, char *bl);
+// 为接收机加载Firmware,该流程必须在加载BootLoader之后进行
+int downloadFW(int fd, char *fw);
+
+void printGetapUsage(char *app)
+{
+	printf("\n%s getap -d receiverPort [-b baudrate] [-h] -a apfile \n", app);
+	printf("\tfunction: read APData from receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+}
+
+void printSendapUsage(char *app)
+{
+	printf("\n%s sendap -d receiverPort [-b baudrate] [-h] -a apfile\n", app);
+	printf("\tfunction: send APData to receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+}
+
+void printCheckapUsage(char *app)
+{
+	printf("\n%s checkap -a apfile [-h]\n", app);
+	printf("\tfunction: check APData\n");
+	printf("\tparas:\n");
+	printf("\t\tapfile: APData file\n");
+}
+
+void printDownloadblUsage(char *app)
+{
+	printf("\n%s downbl -d receiverPort [-b baudrate] -l bootloader [-h]\n", app);
+	printf("\tfunction: download bootloader to receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+	printf("\t\tbootloader: bootloader file\n");
+}
+
+void printDownloadfwUsage(char *app)
+{
+	printf("\n%s downfw -d receiverPort [-b baudrate] -f firmware [-h]\n", app);
+	printf("\tfunction: download firmware to receiver\n");
+	printf("\tparas:\n");
+	printf("\t\treceiverPort: Port that connected to receiver\n");
+	printf("\t\tbaudrate: baudrate of receiverPort\n");
+	printf("\t\tfirmware: firmware file\n");
+}
+
+void printUsage(char *app)
+{
+	printGetapUsage(app);
+	printSendapUsage(app);
+	printCheckapUsage(app);
+	printDownloadblUsage(app);
+	printDownloadfwUsage(app);
+}
+
+#define GPS_DEV "/sys/devices/soc.0/d4000000.apb/mbtk-dev-op/gps_power"
+
+static int mopen_open_gps(int state)
+{
+    int fd, ret;
+    char s[4] = "on";
+    fd = open(GPS_DEV, O_RDWR | O_TRUNC, 0644);
+    if(fd < 0) {
+        printf("[%s]  file [%s] open error\n", __FUNCTION__, GPS_DEV);
+        return -1;
+    }
+    if(0 == state)
+    {
+        memcpy(s, "off", 3);
+    }
+    ret = write(fd, s, 4);
+    if (ret < 0) {
+        printf("%s: error writing to file!\n", __FUNCTION__);
+        close(fd);
+        return -2;
+    }
+
+    close(fd);
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int c;
+	int ret = 0;
+	int fd = -1;
+	int paraMask = 0;
+	int baud = 115200;
+	char devPort[200] = {0};
+	char fw[200] = {0};
+	char bl[200] = {0};
+	char ap[200] = {0};
+	int func = 0; // 1:getap, 2:sendap, 3:downbl, 4:downfw, 5:checkap
+
+	// Verify arguments
+	if (argc < 2) {
+		printf("Usage:\n");
+		printUsage(argv[0]);
+		exit(1);
+	}
+
+	if(strcmp(argv[1], "getap") == 0) {
+		func = 1;
+		paraMask = 1;
+	} else if (strcmp(argv[1], "sendap") == 0) {
+		func = 2;
+		paraMask = 1;
+	} else if (strcmp(argv[1], "downbl") == 0) {
+		func = 3;
+		paraMask = 9;
+	} else if (strcmp(argv[1], "downfw") == 0) {
+		func = 4;
+		paraMask = 5;
+	} else if (strcmp(argv[1], "checkap") == 0) {
+		func = 5;
+		paraMask = 16;
+	} else {
+		printf("Usage:\n");
+		printUsage(argv[0]);
+		exit(1);
+	}
+
+	for(;;) {
+		opterr = 0;
+		c = getopt(argc, argv, "d:b:f:l:a:h");
+		if(c < 0)
+			break;
+		switch(c) {
+			case 'd':
+				snprintf(devPort, 200, "%s", optarg);
+				printf("receiver port: %s\n", devPort);
+				paraMask &= ~1;
+				break;
+			case 'b':
+				baud = atoi(optarg);
+				printf("baud rate: %d\n", baud);
+				break;
+			case 'f':
+				snprintf(fw, 200, "%s", optarg);
+				printf("firmware: %s\n", fw);
+				paraMask &= ~4;
+				break;
+			case 'l':
+				snprintf(bl, 200, "%s", optarg);
+				printf("bootloader: %s\n", bl);
+				paraMask &= ~8;
+				break;
+			case 'a':
+				snprintf(ap, 200, "%s", optarg);
+				printf("apdata file: %s\n", ap);
+				paraMask &= ~16;
+				break;
+			case 'h':
+			default:
+				printf("Usage:\n");
+				if (func == 1)
+					printGetapUsage(argv[0]);
+				else if (func == 2)
+					printSendapUsage(argv[0]);
+				else if (func == 3)
+					printDownloadblUsage(argv[0]);
+				else if (func == 4)
+					printDownloadfwUsage(argv[0]);
+				else if (func == 5)
+					printCheckapUsage(argv[0]);
+				else
+					printUsage(argv[0]);
+				exit(1);
+		}
+	}
+	if (paraMask) {
+		if (func == 1)
+			printGetapUsage(argv[0]);
+		else if (func == 2)
+			printSendapUsage(argv[0]);
+		else if (func == 3)
+			printDownloadblUsage(argv[0]);
+		else if (func == 4)
+			printDownloadfwUsage(argv[0]);
+		else if (func == 5)
+			printCheckapUsage(argv[0]);
+		else
+			printUsage(argv[0]);
+		exit(1);
+	}
+
+	// Open serial port
+	if (func != 5) {
+		if ((fd = initial_serialPort(devPort)) == -1)
+		{
+			printf("Can't open COM\n");
+			return UART_DEV_ERR;
+		}
+		if (baud == 115200) {
+			set_baudrate(fd, B115200);
+		} else if (baud == 921600) {
+			set_baudrate(fd, B921600);
+		} else if (baud == 1843200) {
+			set_baudrate(fd, B1500000);
+		} else {
+			printf("baudrate %d not supported\n", baud);
+			close(fd);
+			exit(1);
+		}
+	}
+
+	// execute function
+	switch(func) {
+		case 1:
+			ret = getAPData(fd, ap);
+			break;
+		case 2:
+			ret = sendAPData(fd, ap);
+			break;
+		case 3:
+			ret = downloadBL(fd, bl);
+			break;
+		case 4:
+			ret = downloadFW(fd, fw);
+			break;
+		case 5:
+			ret = checkAPData(ap);
+			break;
+		default:break;
+	}
+	close(fd);
+	return ret;
+
+}
+
+int getAPData(int fd, char *file)
+{
+	int rByte = 0;
+	char rbuf[4096];
+	int ret = 0, i;
+	struct timeval time_m, time_n;
+
+    if (NULL == file) {
+	    printf("Please input file!! \n");
+		return 1;
+    }
+	if (!fd)
+		return 1;
+	printf("Get apdata\n");
+	gps_dev_send(fd, "$ReqRecvFlash\r\n");
+	af_start_receive();
+	GET_TIME();
+	while(1) {
+		CHK_TIME();
+		if(select_read(fd,1) > 0)
+			usleep(50000);
+		else
+			continue;
+
+		rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+		if(rByte >= 1){
+			if(af_is_start_receive()) {
+				for(i = 0; i < rByte; i++)
+					af_add_char(file, rbuf[i]);
+			} else {
+				break;
+			}
+		}
+	}
+
+	checkAPData(file);
+	return 0;
+}
+
+int sendAPData(int fd, char *apFile)
+{
+	int rByte = 0;
+	char rbuf[4096];
+	int ret = 0;
+	struct timeval time_m, time_n;
+
+	if(access(apFile, F_OK) != -1)
+	{
+		// Download APData only if the file exits
+		printf("Download APData...\n");
+		if(xmodem_send(fd, apFile))
+		{
+			printf("xmodem error!\n");
+			close(fd);
+			return ENTER_UPDATE_MODE_ERR;
+		}
+		// Waiting for 'C'
+		GET_TIME();
+		while(1)
+		{
+			CHK_TIME();
+			if(select_read(fd,1) > 0)
+				usleep(500000);
+			else
+				continue;
+			rByte = deal_read(fd,&rbuf,sizeof(rbuf)-1);
+			rbuf[rByte] = 0;
+			if(rByte > 0)
+			{
+				if(rbuf[rByte - 1] == 'C')
+					break;
+			}
+		}
+		printf("download APData success\n");
+	}
+	else
+	{
+		printf("file err!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+int checkAPData(char *apFile)
+{
+	printf("Checking %s\n", apFile);
+	if(check_file(apFile))
+	{
+		printf("file error!\n");
+		return FILE_CHECK_ERR;
+
+	}
+	else
+	{
+		printf("pass\r\n");
+	}
+	return 0;
+}
+
+int downloadFW(int fd, char *fw)
+{
+    int ret;
+	struct timeval time_m, time_n;
+	char rbuf[512];
+
+    if(NULL == fw) {
+	    printf("Error: Can't find firmware.\n");
+        return -1;
+    }
+	printf("Download firmware...\n");
+	if(xmodem_send(fd, fw) < 0) {
+		printf("xmodem error! send firmware failed!\n");
+		close(fd);
+		return UPDATE_ERR;
+	}
+
+	printf("Download firmware success\n");
+	return 0;
+}
+
+int downloadBL(int fd, char *bl)
+{
+	int rByte = 0;
+	char rbuf[4096];
+	char name[128];
+	int ret = 0;
+	struct timeval time_m, time_n;
+
+    if(NULL == bl) {
+	    printf("Error: Can't find bootloader.\n");
+        return -1;
+    }
+	printf("------Please Powerdown the receiver!\n");
+    mopen_open_gps(0);
+	SET_TIME_OUT(3);
+	while(1) {
+		DELAY_TIME_BREAK(); //
+		if(select_read(fd,1) > 0)
+			usleep(50000);
+		else
+			continue;
+
+		rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+	}
+	int start = 0,finish = 0;
+
+	memset(name, 0, sizeof(name));
+	sprintf(name,"M!T");
+	printf("waiting for YC, timeout is %d s\n", TIMEOUT_SEC);
+	printf("-------Please Powerup the receiver!\n");
+    mopen_open_gps(1);
+	// Waiting for 'YC'
+	GET_TIME();
+	while(1) {
+		int finish = 0, i;
+		CHK_TIME_BREAK(); //
+		rByte = write( fd, name, strlen(name));
+		rByte = select_read(fd,1);
+		if(rByte <= 0)
+			continue;
+		rByte = deal_read(fd, rbuf, sizeof(rbuf) - 1);
+		rbuf[rByte] = 0;
+		for (i = 0 ; i < rByte; i++)
+		{
+			if (check_YC(rbuf[i])) {
+				printf("Receive 'YC'\n");
+				finish = 1;
+				break;
+			}
+		}
+		if (finish)
+			break;
+	}
+	//wait 'YC' timeout deal
+	if (timeout_sign == 1)
+	{
+		//wait NAK
+		GET_TIME();
+		while(1)
+		{
+			CHK_TIME();
+			if(select_read(fd,1) <= 0)
+				continue;
+
+			rByte = deal_read(fd, rbuf,sizeof(rbuf));
+			if (rbuf[rByte-1] == 'C')
+			{
+				printf("###read xmodem start character 'C'.\n");
+				break;
+			}
+		}
+	}
+	use_select = 1;
+	printf("download bootloader...\n");
+
+	// Transfer bootloader via xmodem protocal
+	// if(xmodem_send(fd, "./bootloader.bin")) {
+	if(xmodem_send(fd, bl)) {
+		printf("xmodem error!\n");
+		close(fd);
+		return ENTER_UPDATE_MODE_ERR;
+	}
+	printf("download bootloader success\n");
+	return 0;
+}
+
+int check_YC(char newchar)
+{
+	int static state = 0;
+	int ret = 0;
+	switch (state) {
+		case 0:
+			if (newchar == 'Y')
+				state = 1;
+			break;
+		case 1:
+			if (newchar == 'C') {
+				state = 1;
+				ret = 1;
+			}
+			break;
+		default:
+			state = 0;
+	}
+	return ret;
+}
+
+const unsigned short CRC16_Table[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+unsigned short crc16_ccitt(const unsigned char *buf, int len)
+{
+	register int counter;
+	register unsigned short crc = 0;
+	for (counter = 0; counter < len; counter++)
+		crc = (crc << 8) ^ CRC16_Table[((crc >> 8) ^ *(char *)buf++) & 0x00FF];
+	return crc;
+}
+
+
+unsigned int checksum32(unsigned int * pbuf, unsigned int len)
+{
+	unsigned int i, sumValue = 0;
+	len >>=2;
+
+	for(i=0;i<len;i++)
+	{
+		sumValue += *pbuf++;
+	}
+	return sumValue;
+}
+
+void af_start_receive()
+{
+	recvStat = WAIT_FD;
+	isStartReceive = 1;
+	return;
+}
+
+void af_stop_receive()
+{
+    int i;
+	printf("%s:%d\r\n", __FUNCTION__, __LINE__);
+	printf("%s:%d  recvStat = %d\r\n", __FUNCTION__, __LINE__, recvStat);
+	pbuf = (unsigned char *)recv_buf;
+	for(i = 0; i < 4636; i++){
+		if(i % 32 == 0)printf("\r\n");
+		printf("%02X ", pbuf[i]);
+	}
+	printf("\r\n");
+	isStartReceive = 0;
+	return;
+}
+
+int af_is_start_receive()
+{
+	return isStartReceive;
+}
+
+int af_check_header(unsigned char *pbuf, unsigned int len)
+{
+	unsigned int crc = crc16_ccitt(pbuf, len-4);
+
+	if(crc == *(unsigned int *)(pbuf + len - 4))
+		return 1;
+	else
+		return 0;
+}
+
+int af_check_data(unsigned int * pbuf, unsigned int len)
+{
+	unsigned int cs = checksum32(pbuf + 8, len);
+	if(cs == pbuf[1])
+		return 1;
+	else
+		return 0;
+}
+
+int af_get_data_len()
+{
+	int len = *(int *)(recv_buf+3);
+	return len;
+}
+
+int af_add_char(char *file, unsigned char c)
+{
+	int ret = 0;
+	switch(recvStat){
+		case WAIT_FD:
+			if(c == 0xfd){
+				pbuf = (unsigned char *)recv_buf;
+				pbuf[0] = c;
+				recvStat = WAIT_FC;
+				printf("------------received 0xfd\r\n");
+			}
+			break;
+		case WAIT_FC:
+			if(c == 0xfc){
+				pbuf[1] = c;
+				recvStat = WAIT_FB;
+				printf("------------received 0xfc\r\n");
+			}else{
+				af_stop_receive();
+			}
+			break;
+		case WAIT_FB:
+			if(c == 0xfb){
+				pbuf[2] = c;
+				recvStat = WAIT_FA;
+				printf("------------received 0xfb\r\n");
+			}else{
+				af_stop_receive();
+			}
+			break;
+		case WAIT_FA:
+			if(c == 0xfa){
+				pbuf[3] = c;
+				recvStat = RECE_HEADER;
+				pbuf += 4;
+				printf("------------received 0xfa\r\n");
+			}else{
+				af_stop_receive();
+			}
+			break;
+		case RECE_HEADER:
+			*pbuf = c;
+			pbuf++;
+			if((pbuf - (unsigned char *)recv_buf) == HEADERLEN){
+				if(af_check_header((unsigned char *)recv_buf, HEADERLEN)){
+					recvStat = RECE_DATA;
+					data_len = af_get_data_len();
+				}else{
+					af_stop_receive();
+				}
+			}
+			break;
+		case RECE_DATA:
+			*pbuf = c;
+			pbuf++;
+			if((pbuf - (unsigned char *)recv_buf) == data_len + HEADERLEN){
+				if(af_check_data(recv_buf, recv_buf[3])){
+					int fd = open(file, O_WRONLY|O_CREAT, S_IRWXU);
+					write(fd, recv_buf, pbuf - (unsigned char *)recv_buf);
+					printf("%s:%d rtm len = %ld\r\n", __FUNCTION__, __LINE__, pbuf-(unsigned char *)recv_buf);
+					close(fd);
+					printf("receive rtm\n");
+				}else{
+					printf("af_check_data false!");
+				}
+				af_stop_receive();
+			}
+			ret = 1;
+			break;
+		default:
+			printf("%s:recvStat = %d\r\n", __FUNCTION__, recvStat);
+			break;
+	}
+	return ret;
+}
+
+
+
+ssize_t deal_read(int fd, void *buf, size_t count)
+{
+	int ret = 0;
+
+	while (1)
+	{
+		ret = read(fd, buf, count);
+		if (ret == 0)
+		{
+			printf("read serial return 0, please check serial device.\n");
+			exit(UART_DEV_ERR);
+		}
+		if(ret < 0)
+		{
+			if ((errno == EAGAIN) || (errno == EINTR))
+			{
+				printf("read serial return -1, errno = %d, retry.\n", errno);
+				continue;
+			}
+			else
+			{
+				printf("read serial return -1, errno = %d, please check serial device.\n", errno);
+				exit(UART_DEV_ERR);
+			}
+		}
+		return ret;
+	}
+}
+
+unsigned short get_crc16 ( char *ptr, unsigned short count )
+{
+	unsigned short crc, i;
+
+	crc = 0;
+	while(count--)
+	{
+		crc = crc ^ (int) *ptr++ << 8;
+
+		for(i = 0; i < 8; i++)
+		{
+			if(crc & 0x8000)
+				crc = crc << 1 ^ 0x1021;
+			else
+				crc = crc << 1;
+		}
+	}
+
+	return (crc & 0xFFFF);
+}
+
+void dump_u(void *buf, int len)
+{
+	unsigned char *p = (unsigned char *)buf;
+	int i;
+
+	for(i = 0; i < len; i++) {
+		if(i % 16 == 0) printf("%04x:", i);
+		if(i % 16 == 8) printf(" -");
+		printf(" %02x", p[i]);
+		if(i % 16 == 15) printf("\n");
+	}
+	if(i % 16) printf("\n");
+}
+
+unsigned int get_file_size(const char * name)
+{
+	struct stat statbuff;
+	//unsigned int size, checksum;
+	if(stat(name, &statbuff) < 0)
+		return -1;
+	else
+		return statbuff.st_size;
+}
+
+
+int check_file(char * fname)
+{
+	FILE *fd;
+	uc_image_header_t header;
+	unsigned int buf[1024];
+	unsigned int fsize, checksum, i;
+	unsigned int len;
+	unsigned short crc;
+	size_t rByte;
+
+	if((fd=fopen(fname,"rb"))==NULL)
+	{
+		printf("\n can't open (%s) or not exist!(errno=%d:%s) \n", fname, errno, strerror(errno));
+		return -1;
+	}
+
+	fsize = get_file_size(fname);
+
+	printf("file size [%d]\n",fsize);
+
+	if(fsize == 0)
+		return -1;
+
+	while(fsize > sizeof(header)) {
+		rByte = fread((char *)&header, sizeof(char), sizeof(header), fd);
+
+		dump_u((char *)&header, sizeof(header));
+
+		crc = get_crc16 ( (char *) &header, sizeof(header)-4);
+		printf("crc16  [%08x]\n", crc);
+
+		if((header.ih_hcrc & 0xFFFF) != crc) {
+			fclose(fd);
+			return -1;
+		}
+
+		fsize -= sizeof(header);
+		fsize -= header.ih_size;
+		checksum = 0;
+		len = header.ih_size;
+		while(len > 0)
+		{
+			if(len >= 1024 )
+				rByte = 1024;
+			else
+				rByte = len;
+
+			memset(buf, 0, sizeof(buf));
+			rByte = fread((char *)buf, 1, rByte, fd);
+			for(i = 0; i < (rByte+3)/4; i++)
+				checksum += buf[i];
+
+			len -= rByte;
+		}
+		printf("checksum  [%08x]\n\n",checksum);
+
+		if( checksum != header.ih_dcrc) {
+			fclose(fd);
+			return -1;
+		}
+	}
+
+	fclose(fd);
+	return 0;
+}
+
+static int select_read(int fd, int timeout) //1ms
+{
+	fd_set set;
+	struct timeval t;
+	int ret;
+	int i = timeout;
+
+	if(use_select) {
+		do {
+			FD_ZERO(&set);
+			FD_SET(fd, &set);
+			t.tv_sec = 0;
+			t.tv_usec = 100;
+
+			ret = select(FD_SETSIZE, &set, NULL, NULL, &t );
+			if(ret == 0) continue;
+			if(ret < 0 && errno == EINTR)continue;
+			else return ret;
+		} while(i--);
+	} else {
+		struct timeval t0, t1;
+		long dt = 0;
+		int c;
+
+		gettimeofday(&t0, NULL);
+		do {
+			c = 0;
+			ret = ioctl(fd, FIONREAD, &c);
+			if(c > 0) { ret = c; break; }
+
+			gettimeofday(&t1, NULL);
+			dt = t1.tv_usec - t0.tv_usec;
+			dt += (t1.tv_sec-t0.tv_sec)*1000*1000;
+		} while(dt/1000 < timeout);
+	}
+
+	return ret;
+}
+
+int set_baudrate(int fd, int baudrate)
+{
+	struct termios options, oldtio;
+
+	if(fcntl(fd, F_SETFL, 0) < 0) {
+		printf("fcntl failed!\n");
+		return -1;
+	}
+
+	if(tcgetattr(fd, &oldtio) != 0) {
+		printf("setup serial error!\n");
+		return -1;
+	}
+
+	/* Get the current options for the port... */
+	tcgetattr(fd, &options);
+
+	/* Set the baud rates to baudrate... */
+	cfsetispeed(&options,baudrate);
+	cfsetospeed(&options,baudrate);
+	tcsetattr(fd, TCSANOW, &options);
+
+	if (0 != tcgetattr(fd, &options))
+	{
+		printf("get options error!\n");
+		return -1;
+	}
+
+	/*
+	 * 8bit Data,no partity,1 stop bit...
+	 */
+	options.c_cflag &= ~PARENB;//无奇偶校验
+	options.c_cflag &= ~CSTOPB;//停止位,1位
+	options.c_cflag &= ~CSIZE; //数据位的位掩码
+	options.c_cflag |= CS8;    //数据位,8位
+
+	cfmakeraw(&options);
+
+	/*
+	 * Set the new options for the port...
+	 */
+	if (tcsetattr(fd, TCSANOW, &options) != 0)
+	{
+		printf("setup serial error!\n");
+		return -1 ;
+	}
+
+	return 0 ;
+}
+
+int initial_serialPort(char * serial_device)
+{
+	int fd;
+	fd = open( serial_device , O_RDWR );
+	if ( fd == -1 )
+	{
+		/* open error! */
+		printf("Can't open serial port(%s)!(errno=%d:%s) \n", serial_device, errno, strerror(errno));
+		return -1;
+	}
+
+	set_baudrate(fd, B9600);
+
+	return fd ;
+}
+
+static void gps_dev_send(int fd, char *msg)
+{
+	int i, n, ret;
+
+	i = strlen(msg);
+
+	n = 0;
+
+	printf("function gps_dev_send: %s", msg);
+	do {
+
+		ret = write(fd, msg + n, i - n);
+
+		if (ret < 0 && errno == EINTR) {
+			continue;
+		}
+
+		n += ret;
+
+	} while (n < i);
+
+	// drain cmd
+	tcdrain(fd);
+
+	return;
+}
+
+int xmodem_send(int fd, char *fname)
+{
+	char packet_data[XMODEM_DATA_SIZE];
+	char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1];
+	int ret = -1;
+
+	FILE *datafile;
+	int complete,retry_num,pack_counter,read_number,write_number,i;
+	unsigned short crc_value;
+	unsigned char ack_id = 'C';
+	struct timeval time_m, time_n;
+
+	datafile = NULL;
+	pack_counter = 0;	// 包计数器清零
+	complete = 0;
+	retry_num = 0;
+
+	printf("[%s]\n",fname);
+	//只读方式打开一个准备发送的文件,如果不存在就报错,退出程序。
+	if((datafile=fopen(fname,"rb"))==NULL)
+	{
+		printf("\n can't open (%s) or not exist!(errno=%d:%s) \n", fname, errno, strerror(errno));
+		return -1;
+	}
+	else
+	{
+		printf("Ready to send the file:%s\n",fname);
+	}
+
+	printf("Waiting for signal C/NAK!\n");
+	GET_TIME();
+	while(1)
+	{
+		CHK_TIME1();
+		if(select_read(fd,1) > 0)
+			usleep(10000);
+		else
+			continue;
+
+		//read(fd,&ack_id,1);
+		deal_read(fd,&ack_id,1);
+		if(ack_id == 'C')
+			break;
+	}
+
+	printf("The signal NAK: %02x ok!!!\n",ack_id);//打印接收到的NAK信息
+
+	while(!complete)
+	{
+		switch(ack_id)
+		{
+			case XMODEM_CRC_CHR:	// 接收到字符'C'开始启动传输,并使用CRC校验
+				printf("begining to Send file %s...\n",fname);
+
+			case XMODEM_ACK:        //0x06
+				retry_num = 0;
+				pack_counter++;
+
+				read_number = fread(packet_data, sizeof(char), XMODEM_DATA_SIZE, datafile);
+				//从打开的datafile指向的文件中读取
+				//XMODEM_DATA_SIZE 个(char)数据,
+				//放到packet_data这个数组中
+				if(read_number > 0)//read_number为返回的读取实际字节数
+				{
+					//printf("test:read_number:%d\n", read_number);
+					if(read_number < XMODEM_DATA_SIZE_STX)
+					{
+						printf("Start filling the last frame!\n");
+						for(; read_number < XMODEM_DATA_SIZE; read_number++)
+							packet_data[read_number] = 0x1A;  // 不足128字节用0x1A填充
+						//printf("replenish data.\n");
+					}
+
+					frame_data[0] = XMODEM_HEAD;  // 帧开始字符
+					frame_data[1] = (char)pack_counter;  // 信息包序号
+					frame_data[2] = (char)(255 - frame_data[1]);  // 信息包序号的补码
+
+					for(i=0; i < XMODEM_DATA_SIZE; i++)  // 128字节的数据段
+						frame_data[i+3] = packet_data[i];//把收到的字符和信息头一起打包
+
+					crc_value = get_crc16(packet_data, XMODEM_DATA_SIZE); // 16位crc校验
+					frame_data[XMODEM_DATA_SIZE+3] = (unsigned char)(crc_value >> 8);// 高八位数据
+					frame_data[XMODEM_DATA_SIZE+4] = (unsigned char)(crc_value);     //低八位数据
+
+					/* 发送133字节数据 */
+					write_number = write( fd, frame_data, XMODEM_DATA_SIZE + 5);//向串口写一个包数据,即133字节数据
+					printf("."); //ADD: process
+					fflush(stdout);
+					//printf("waiting for next ACK... \n......\n");
+
+					GET_TIME();
+					while(1)
+					{
+						CHK_TIME1();
+						if(select_read(fd,1) > 0)
+							usleep(10000);
+						else
+							continue;
+
+						//read(fd,&ack_id,1);
+						deal_read(fd,&ack_id,1);
+						break;
+					}
+
+					if(ack_id == XMODEM_ACK) {
+						//printf("ACK Ok!!Ready sending next pack!\n");
+						;
+					}
+					else
+					{
+						printf("ACK Error!\n");
+						printf("0x%02X\n",ack_id);
+						//printf("pack_counter = %d\n", pack_counter);
+					}
+				}
+
+				else  // 文件发送完成
+				{
+					ack_id = XMODEM_EOT;
+					complete = 1;
+					printf("Complete ACK\n");
+
+					GET_TIME();
+					while(ack_id != XMODEM_ACK)
+					{
+						CHK_TIME1();
+						ack_id = XMODEM_EOT;
+						write_number = write(fd,&ack_id,1);
+						while((deal_read(fd, &ack_id, 1)) <= 0);
+					}
+					printf("Send file successful!!!\n");
+					fclose(datafile);
+					datafile = NULL;
+				}
+				break;
+
+			case XMODEM_NAK:
+				if( retry_num++ > 10)
+				{
+					printf("Retry too many times,Quit!\n");
+					complete = 1;
+				}
+				else //重试,发送
+				{
+					write_number = write(fd, frame_data, XMODEM_DATA_SIZE + 5);
+					printf("Retry for ACK,%d,%d...", pack_counter, write_number);
+
+					GET_TIME();
+					while(1)
+					{
+						CHK_TIME1();
+						if(select_read(fd,1) > 0)
+							usleep(100);
+						else
+							continue;
+
+						//read(fd,&ack_id,1);
+						deal_read(fd,&ack_id,1);
+						break;
+					}
+
+					if( ack_id == XMODEM_ACK )
+						printf("OK\n");
+					else
+						printf("Error!\n");
+				}
+				break;
+			default:
+				printf("Fatal Error! %d\n", ack_id);
+				complete = 1;
+				return -1;
+				break;
+		}
+	}
+
+	if( datafile != NULL )
+		fclose(datafile);
+
+	return 0;
+}
diff --git a/mbtk/test/iconv_demo.cc b/mbtk/test/iconv_demo.cc
new file mode 100755
index 0000000..de95454
--- /dev/null
+++ b/mbtk/test/iconv_demo.cc
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iconv.h>
+#include <errno.h>
+#include <stddef.h>
+
+struct outbuf
+{
+    struct outbuf *next;
+    char *outptr;
+    size_t outbytesleft;
+    char buf[256];
+};
+
+char *eazyiconv(const char *to, const char *from,
+                char *str, size_t str_blen, size_t str_elemsize, size_t out_tailzero_blen, size_t *out_size,
+                const char *replchr)
+{
+    char *retstr = NULL;
+    struct outbuf *outhead = NULL;
+    struct outbuf *outtail = NULL;
+    struct outbuf *outiter = NULL;
+    iconv_t cd = NULL;
+    char *inptr = str;
+    size_t inbytesleft = str_blen;
+    int retval = 0;
+    int err = 0;
+    size_t blocksize = 0;
+    size_t totalsize = 0;
+    char *retiter = NULL;
+    unsigned int chrval = 0;
+    iconv_t cdreplchr = NULL;
+    char replchrfmtbuf[256] = "";
+    char replchrbuf[256] = "";
+    char *replchrfmtptr = replchrfmtbuf;
+    size_t replchrfmtleft = sizeof replchrfmtbuf;
+    char *replchrptr = replchrbuf;
+    size_t replchrleft = sizeof replchrbuf;
+    int replchr_blen = 0;
+
+    cd = iconv_open(to, from);
+    if (cd == (iconv_t)-1)
+    {
+        goto noclean;
+    }
+
+    outhead = outtail = calloc(1, sizeof(struct outbuf));
+    if (outtail == NULL)
+    {
+        goto clean_cd;
+    }
+    outtail->next = NULL;
+    outtail->outptr = outtail->buf;
+    outtail->outbytesleft = sizeof outtail->buf;
+    memset(outtail->buf, 0, sizeof outtail->buf);
+
+    while (1)
+    {
+        retval = iconv(cd, &inptr, &inbytesleft, &outtail->outptr, &outtail->outbytesleft);
+        if (retval == -1)
+            err = errno;
+        else
+            err = 0;
+        switch (err)
+        {
+            case 0:
+                outiter = calloc(1, sizeof(struct outbuf));
+                if (outiter == NULL)
+                {
+                    goto clean_outbufs;
+                }
+                if (inptr == NULL) // succeeded cleanup iconv
+                {
+                    goto succeeded;
+                }
+                else // fully succeeded iconv
+                {
+                    inptr = NULL; // do cleanup iconv
+                    inbytesleft = 0;
+                }
+                break;
+            case EINVAL: // incomplete tail sequence
+            case EILSEQ: // invalid sequence
+                chrval = 0;
+                memcpy(&chrval, inptr, str_elemsize > sizeof chrval ? sizeof chrval : str_elemsize);
+                snprintf(replchrfmtbuf, sizeof replchrfmtbuf, replchr, chrval);
+                inptr += str_elemsize;
+                inbytesleft -= str_elemsize;
+
+                cdreplchr = iconv_open(to, "UTF-8");
+                if (cdreplchr == (iconv_t)-1)
+                {
+                    goto clean_outbufs;
+                }
+                replchrfmtptr = replchrfmtbuf;
+                replchrfmtleft = strlen(replchrfmtbuf);
+                replchrptr = replchrbuf;
+                replchrleft = sizeof replchrbuf;
+                iconv(cdreplchr, &replchrfmtptr, &replchrfmtleft, &replchrptr, &replchrleft);
+                iconv(cdreplchr, NULL, NULL, &replchrptr, &replchrleft);
+                iconv_close(cdreplchr);
+                replchr_blen = replchrptr - replchrbuf;
+
+                if (outtail->outbytesleft < replchr_blen)
+                {
+                    outiter = calloc(1, sizeof(struct outbuf));
+                    if (outiter == NULL)
+                    {
+                        goto clean_outbufs;
+                    }
+                    outtail->next = outiter;
+                    outtail = outiter;
+                    outtail->next = NULL;
+                    outtail->outptr = outtail->buf;
+                    outtail->outbytesleft = sizeof outtail->buf;
+                    memset(outtail->buf, 0, sizeof outtail->buf);
+                }
+                memcpy(outtail->outptr, replchrbuf, replchr_blen);
+                outtail->outptr += replchr_blen;
+                outtail->outbytesleft -= replchr_blen;
+                break;
+            case E2BIG: // no enough space
+                outiter = calloc(1, sizeof(struct outbuf));
+                if (outiter == NULL)
+                {
+                    goto clean_outbufs;
+                }
+                outtail->next = outiter;
+                outtail = outiter;
+                outtail->next = NULL;
+                outtail->outptr = outtail->buf;
+                outtail->outbytesleft = sizeof outtail->buf;
+                memset(outtail->buf, 0, sizeof outtail->buf);
+                break;
+            default:
+                break;
+        }
+    }
+
+succeeded:
+    totalsize = 0;
+    for (outiter = outhead; outiter != NULL; outiter = outiter->next)
+    {
+        blocksize = outiter->outptr - outiter->buf;
+        totalsize += blocksize;
+    }
+    retstr = calloc(totalsize + out_tailzero_blen, 1);
+    if (retstr == NULL)
+    {
+        goto clean_outbufs;
+    }
+    retiter = retstr;
+    for (outiter = outhead; outiter != NULL; outiter = outiter->next)
+    {
+        blocksize = outiter->outptr - outiter->buf;
+        memcpy(retiter, outiter->buf, blocksize);
+        retiter += blocksize;
+    }
+    memset(retiter, 0, out_tailzero_blen);
+    *out_size = totalsize;
+
+clean_outbufs:
+    while (outhead != NULL)
+    {
+        outiter = outhead;
+        outhead = outhead->next;
+        free(outiter);
+    }
+    outtail = NULL;
+clean_cd:
+    iconv_close(cd);
+noclean:
+    return retstr;
+}
+
+int main(int argc, char **argv)
+{
+    if (argc < 7)
+    {
+        printf("usage: eiconv_test from_charset from_elemsize to_charset to_elemsize from_file to_file (no utf-16/32)\n");
+        return 0;
+    }
+    FILE *from_file = fopen(argv[5], "rb");
+    fseek(from_file, 0, SEEK_END);
+    off_t fsize = ftell(from_file);
+    fseek(from_file, 0, SEEK_SET);
+    char *from_str = malloc(fsize + 1);
+    fread(from_str, 1, fsize, from_file);
+    fclose(from_file);
+
+    size_t out_size = 0;
+    char *to_str = eazyiconv(argv[3], argv[1],
+                             from_str, fsize, atoi(argv[2]), atoi(argv[4]), &out_size,
+                             "<0x%02X>");
+
+    FILE *to_file = fopen(argv[6], "wb");
+    fwrite(to_str, 1, out_size, to_file);
+    free(to_str);
+    fclose(to_file);
+    return 0;
+}
+
+
diff --git a/mbtk/test/key_ev_demo.c b/mbtk/test/key_ev_demo.c
new file mode 100755
index 0000000..190e4a6
--- /dev/null
+++ b/mbtk/test/key_ev_demo.c
@@ -0,0 +1,249 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <poll.h>
+#include <errno.h>
+#include <linux/input.h>
+#include <sys/stat.h>
+#include <sys/reboot.h>
+#include <sys/timerfd.h>
+#include <time.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+
+
+#define MAX_DEVICES 16
+#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
+#define POWER_KEY_LONG_PRESS_TIMEOUT 8000  // 8s
+#define POWER_KEY_PRESS_TIMEOUT 2000  // 2s
+
+static struct pollfd ev_fds[MAX_DEVICES];
+static unsigned ev_count = 0;
+
+
+static int ev_init(void)
+{
+    DIR *dir;
+    struct dirent *de;
+    int fd;
+
+    fd = open("/dev/rtc0", O_RDONLY);
+    if (fd < 0)
+    {
+        LOGW("open rtc0 error\n");
+    }
+    else
+    {
+        ev_fds[ev_count].fd = fd;
+        ev_fds[ev_count].events = POLLIN;
+        ev_count++;
+        LOGI("Monitor /dev/rtc0");
+    }
+
+    dir = opendir("/dev/input");
+    if (dir != NULL)
+    {
+        LOGI("dir = /dev/input");
+        while ((de = readdir(dir)) != NULL)
+        {
+            if (strncmp(de->d_name, "event", 5))
+                continue;
+            fd = openat(dirfd(dir), de->d_name, O_RDONLY);
+            if (fd < 0)
+                continue;
+
+            ev_fds[ev_count].fd = fd;
+            ev_fds[ev_count].events = POLLIN;
+            ioctl(fd, EVIOCSSUSPENDBLOCK, 1);
+            ev_count++;
+            if (ev_count == MAX_DEVICES)
+                break;
+
+            LOGI("Monitor /dev/input/%s", de->d_name);
+        }
+
+        closedir(dir);
+    }
+    else
+    {
+        LOGE("opendir() fail.[%d]",errno);
+        return -1;
+    }
+    return 0;
+}
+
+static void ev_exit(void)
+{
+    while (ev_count > 0)
+    {
+        close(ev_fds[--ev_count].fd);
+    }
+}
+
+/* wait: 0 dont wait; -1 wait forever; >0 wait ms */
+static int ev_get(struct input_event *ev, int wait_ms)
+{
+    int r;
+    unsigned n;
+    unsigned long alarm_data;
+
+//    if(wait_ms < 0)
+//    {
+//        LOGE("poll event return\n");
+//        return -1;
+//    }
+
+    LOGI("Waitting data...");
+    r = poll(ev_fds, ev_count, wait_ms);
+    LOGI("Get Data:result = %d",r);
+
+    if (r > 0)
+    {
+        for (n = 0; n < ev_count; n++)
+        {
+            if (ev_fds[n].revents & POLLIN)
+            {
+                if (n == 0)
+                {
+                    r = read(ev_fds[n].fd, &alarm_data, sizeof(alarm_data));
+                    LOGD("get form 0 is %ld", alarm_data);
+                    ev->type = EV_KEY;
+                    ev->code = KEY_BRL_DOT8;
+                    ev->value = 1;
+                    return 0;
+                }
+                else
+                {
+                    r = read(ev_fds[n].fd, ev, sizeof(*ev));
+                    if (r == sizeof(*ev))
+                        return 0;
+                }
+            }
+        }
+    }
+    return -1;
+}
+
+
+static void power_process(bool down, struct timeval *time)
+{
+    printf("POWER_KEY - %s,Time : %ld %ld \n", down ? "DOWN" : "UP", time->tv_sec, time->tv_usec);
+#if 0
+	static struct timeval down_time;
+    static bool key_down;
+    if(down)  // Down
+    {
+        key_down = true;
+        power_long_press_timeout = false;
+        down_time.tv_sec = time->tv_sec;
+        down_time.tv_usec = time->tv_usec;
+        signal(SIGALRM, power_key_timer_alrm);
+        struct itimerval val;
+        // Only time
+        val.it_interval.tv_sec  = 0;
+        val.it_interval.tv_usec = 0;
+        // Time
+        if(POWER_KEY_LONG_PRESS_TIMEOUT >= 1000)
+        {
+            val.it_value.tv_sec  = POWER_KEY_LONG_PRESS_TIMEOUT/1000;
+            val.it_value.tv_usec = POWER_KEY_LONG_PRESS_TIMEOUT%1000;
+        }
+        else
+        {
+            val.it_value.tv_sec  = 0;
+            val.it_value.tv_usec = POWER_KEY_LONG_PRESS_TIMEOUT;
+        }
+        if (setitimer(ITIMER_REAL, &val, NULL) == -1)
+        {
+            LOGE("setitimer fail.[%d]",errno);
+            return;
+        }
+    }
+    else     // UP
+    {
+        if(key_down)
+        {
+            // ms
+            long time_used = (time->tv_sec - down_time.tv_sec) * 1000 + (time->tv_usec - down_time.tv_usec) / 1000;
+            LOGI("Down time[%ld,%ld], Up time[%ld,%ld], time_used = %ld ms",down_time.tv_sec,down_time.tv_usec,
+                 time->tv_sec,time->tv_usec,time_used);
+
+            if(!power_long_press_timeout)
+            {
+                // Cancel alarm
+                struct itimerval value;
+                value.it_value.tv_sec = 0;
+                value.it_value.tv_usec = 0;
+                value.it_interval = value.it_value;
+                setitimer(ITIMER_REAL, &value, NULL);
+
+                if(time_used <= POWER_KEY_PRESS_TIMEOUT)
+                {
+                    screen_state_change(false);
+                }
+                else
+                {
+                    LOGI("Press timeout.");
+                }
+            }
+            else
+            {
+                LOGI("Long Press timeout.");
+            }
+        }
+        else
+        {
+            LOGI("UP key for screen on.");
+        }
+
+        key_down = false;
+    }
+#endif
+}
+
+
+int main(int argc, char *argv[])
+{
+	mbtk_log_init(NULL, "MBTK_KEY");
+    // Open dev
+    ev_init();
+
+    int ret = 0;
+    struct input_event ev;
+    while(1)
+    {
+        ret = ev_get(&ev, -1);
+        if(ret)
+        {
+            LOGW("ev_get() fail.");
+            continue;
+        }
+
+        LOGI("ev:time[%ld,%ld],type:%d,code:%d,value:%d",ev.time.tv_sec,ev.time.tv_usec,
+             ev.type,ev.code,ev.value);
+        if(ev.type != EV_KEY)
+        {
+            LOGW("event type error.[%d]",ev.type);
+            continue;
+        }
+
+        switch(ev.code)
+        {
+            case KEY_POWER:   // Power key
+            {
+                power_process(ev.value, &(ev.time));
+                break;
+            }
+            default:
+            {
+                LOGD("Unknown KEY[%d]",ev.code);
+                break;
+            }
+        }
+    }
+    return 0;
+}
diff --git a/mbtk/test/lynq_gnss_test.c b/mbtk/test/lynq_gnss_test.c
new file mode 100755
index 0000000..9ba5185
--- /dev/null
+++ b/mbtk/test/lynq_gnss_test.c
@@ -0,0 +1,179 @@
+/**
+ *   \file gnss_test.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  Sniper <e190@163.com>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-26
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include "mbtk_type.h"
+#include "lynq/lynq_gnss.h"
+//#include "mbtk_gnss.h"
+
+void gnss_handler_cb
+(
+    uint32 h_loc,
+    int    e_msg_id,
+    void   *pv_data,
+    void   *context_ptr
+) {
+    printf("e_msg_id=%d\n", e_msg_id);
+    switch(e_msg_id)
+    {
+        case E_LYNQ_LOC_MSG_ID_STATUS_INFO:
+            break;
+        case E_LYNQ_LOC_MSG_ID_LOCATION_INFO:
+            break;
+        case E_LYNQ_LOC_MSG_ID_SV_INFO:
+            break;
+        case E_LYNQ_LOC_MSG_ID_NMEA_INFO:
+        {
+            LYNQ_LOC_NMEA_INFO_T  *pt_nmea = (LYNQ_LOC_NMEA_INFO_T *)pv_data;
+
+            printf("NMEA info: timestamp=%lld, length=%d, nmea=%s\n",
+                    pt_nmea->timestamp, pt_nmea->length, pt_nmea->nmea);
+            break;
+        }
+        case E_LYNQ_LOC_MSG_ID_CAPABILITIES_INFO:
+            break;
+        case E_LYNQ_LOC_MSG_ID_AGPS_STATUS:
+            break;
+        case E_LYNQ_LOC_MSG_ID_NI_NOTIFICATION:
+            break;
+        case E_LYNQ_LOC_MSG_ID_XTRA_REPORT_SERVER:
+            break;
+    }
+}
+#if 1
+int main(int argc, char *argv[])
+{
+    int ret;
+
+    ret = lynq_gnss_enable_glonass();
+    if(ret < 0) {
+        printf("lynq_gnss_init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+
+    ret = lynq_gnss_init();
+    if(ret < 0) {
+        printf("lynq_gnss_init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+
+    lynq_gnss_callback_reg(gnss_handler_cb);
+
+    ret = lynq_gnss_agps_dataconnopen();
+    if(ret < 0) {
+        printf("lynq_gnss_agps_dataconnopen FAIL. ret:%d\n", ret);
+        return -1;
+    }
+
+    ret = lynq_gnss_start();
+    if(ret < 0) {
+        printf("lynq_gnss_start FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    sleep(10);
+    ret = lynq_gnss_stop();
+    if(ret < 0) {
+        printf("lynq_gnss_stop FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    ret = lynq_gnss_deinit();
+    if(ret < 0) {
+        printf("lynq_gnss_deinit FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    return 0;
+}
+
+#else
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    int opt;
+    char dev_file[12] = {0};
+
+    while(1)
+    {
+        printf("=========gnss main=========\n"
+            "\t0 exit\n"
+            "\t1 gnss init\n"
+            "\t2 gnss add callback function\n"
+            "\t3 gnss start\n"
+            "\t4 gnss stop\n"
+            "\t5 gnss deinit\n"
+            "\t6 agps down\n"
+            "please input operator: >> ");
+        scanf("%d", &opt);
+        switch (opt)
+        {
+        case 0:
+            printf("main exit\n");
+            return 0;
+        case 1:
+            ret = lynq_gnss_init();
+            if(ret < 0)
+            {
+                printf("lynq_gnss_init FAIL.	ret:%d\n",ret);
+                return -1;
+            }
+            opt = 0;
+            break;
+        case 2:
+        {
+
+            lynq_gnss_callback_reg(gnss_handler_cb);
+            break;
+        }
+        case 3:
+        {
+            lynq_gnss_start();
+            break;
+        }
+        case 4:
+        {
+            lynq_gnss_stop();
+            break;
+        }
+        case 5:
+        {
+            lynq_gnss_deinit();
+            break;
+        }
+        case 6:
+        {
+            ret = lynq_gnss_agps_dataconnopen();
+            if(ret < 0)
+            {
+                printf("lynq_gnss_agps_dataconnopen FAIL. ret:%d\n", ret);
+                return -1;
+            }
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+    return 0;
+}
+#endif
diff --git a/mbtk/test/lynq_sms_test.c b/mbtk/test/lynq_sms_test.c
new file mode 100755
index 0000000..e16893d
--- /dev/null
+++ b/mbtk/test/lynq_sms_test.c
@@ -0,0 +1,126 @@
+/**
+ *   \file dtmf_test.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  jinLuo
+ *   \Version: 1.0.0
+ *   \Date: 2022-12-1
+ */
+
+/******************************************************************************\
+ *   Include files
+\******************************************************************************/
+#include <pthread.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <stdlib.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "lynq/lynq_sms_api.h"
+
+
+int main(int argc, char *argv[])
+{
+    char operator[20];
+    int opt;
+    int ret, uToken; 
+	char serNum[50] = {0};
+
+    while(1)
+    {
+        printf("=========audio main=========\n"
+            "\t0 exit\n"
+            "\t1 sms init\n"
+            "\t2 send sms\n"
+            "\t3 wait receive new sms\n"
+            "\t4 delete sms(int index);\n"
+            "\t5 list sms\n"
+            "\t6 query sms storage status\n"
+            "\t7 query service number\n"
+            "\t8 set service number\n"
+            "\t9 deinit sms\n"
+            "operator: >> ");
+        fgets(operator, sizeof(operator), stdin);
+        fflush(stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+        case 0:
+            printf("main exit\n");
+            return 0;
+        case 1:
+            lynq_init_sms(uToken);
+            break;
+        case 2:
+			printf("please input volume (0~1): \n");
+            fgets(operator, sizeof(operator), stdin);
+            fflush(stdin);
+            opt = atoi(operator);
+			if(opt)
+			{
+				lynq_send_sms("15775590631", 1, "nihaoma,wohenhao"); //text mode
+			}
+			else{
+				lynq_send_sms("29", 0, "0891683108200805F011000D91685177550996F70008A80E4F60597D5417FF1F62115F88597D");  //pud mode
+			}
+            break;
+        case 3:
+            lynq_wait_receive_new_sms(&uToken);
+            break;
+		case 4:
+            printf("please input volume (0~100): \n");
+            fgets(operator, sizeof(operator), stdin);
+            fflush(stdin);
+            opt = atoi(operator);
+			lynq_delete_sms(opt);
+            break;
+		case 5:
+			printf("please input index (0~50): \n");
+            fgets(operator, sizeof(operator), stdin);
+            fflush(stdin);
+            opt = atoi(operator);
+            lynq_list_sms(1, opt, "ALL" ); 
+				//opt : 0 ; Query all stored SMS messages
+				//opt : > 0 ; Gets the content of the SMS message starting from the index number 
+			break;
+		case 6:
+            lynq_query_sms_storage_status();
+			break;
+        case 7:
+            ret = lynq_get_smsc_address(serNum);
+            if(!ret)
+                printf("get_smsc:%s\n", serNum);
+            break;
+        case 8:
+            printf("please input service num: \n");
+            fgets(operator, sizeof(operator), stdin);
+            fflush(stdin);
+            ret= lynq_set_smsc_address(operator);
+            break;
+        case 9:
+            lynq_deinit_sms();
+            break;
+        default:
+            break;
+        }
+    }
+
+    return 0;
+}
diff --git a/mbtk/test/mbtk_adc_test.c b/mbtk/test/mbtk_adc_test.c
new file mode 100755
index 0000000..2d1b689
--- /dev/null
+++ b/mbtk/test/mbtk_adc_test.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+#include "mbtk_adc.h"
+
+int main(int argc, char *argv[])
+{
+    int adc = mbtk_adc_get(MBTK_ADC0);
+    if(adc > 0) {
+        printf("ADC0 = %d\n", adc);
+    } else {
+        printf("Get ADC0 fail.\n");
+    }
+
+    adc = mbtk_adc_get(MBTK_ADC1);
+    if(adc > 0) {
+        printf("ADC1 = %d\n", adc);
+    } else {
+        printf("Get ADC1 fail.\n");
+    }
+    return 0;
+}
+
diff --git a/mbtk/test/mbtk_at_test.c b/mbtk/test/mbtk_at_test.c
new file mode 100755
index 0000000..a6cb361
--- /dev/null
+++ b/mbtk/test/mbtk_at_test.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+
+#include "mbtk_at.h"
+
+#define LOGE printf
+#define LOGI printf
+
+int main(int argc, char *argv[])
+{
+    if(argc != 2) {
+        LOGE("./at_test at_cmd\n");
+        return -1;
+    }
+
+    if(mbtk_at_init()) {
+        LOGE("mbtk_at_init() fail.\n");
+        return -1;
+    }
+
+    char at_rsp[2048];
+    if(!mbtk_at_send(argv[1], at_rsp, 2048)) {
+        LOGI("%s", at_rsp);
+    } else {
+        LOGE("mbtk_at_send() fail.\n");
+    }
+
+    if(mbtk_at_deinit()) {
+        LOGE("mbtk_at_deinit() fail.\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/mbtk/test/mbtk_coap_test.c b/mbtk/test/mbtk_coap_test.c
new file mode 100755
index 0000000..4159a34
--- /dev/null
+++ b/mbtk/test/mbtk_coap_test.c
@@ -0,0 +1,53 @@
+#include <string.h>
+#include "mbtk_type.h"
+#include "ql/ql_vcall.h"
+#include "mbtk_coap.h"
+#include "mbtk_coap_api.h"
+
+int coap_get_method(void);
+
+int coap_post_method(void);
+
+
+int main(int argc, char *argv[])
+{
+    char operator[10];
+    int opt;
+    int    ret     = -1;
+
+	printf("coap_demo star\r\n");
+	coap_get_method();
+
+	sleep(20);
+	coap_post_method();
+
+    return 0;
+}
+
+
+int coap_get_method(void)
+{
+	int ret = -1;
+	ret = mbtk_coap_ecoapnew_exec_cmd("134.102.218.18",5683,0,0);    //server ip, port
+	mbtk_coap_ecoapmsgid_exec_cmd(1);								//set message id
+	mbtk_coap_ecoaptype_exec_cmd(0);								//set message type
+	mbtk_coap_ecoapcode_exec_cmd(1);								//set Get request method
+	mbtk_coap_ecoapopt_exec_cmd("b474657374",10);					//set option
+
+	mbtk_coap_ecoapsend_exec_cmd(1, 0, NULL);						//request Get
+	return 0;
+}
+
+
+int coap_post_method(void)
+{
+	int ret = -1;
+	ret = mbtk_coap_ecoapnew_exec_cmd("134.102.218.18",5683,0,0);     //server ip, port
+	mbtk_coap_ecoapmsgid_exec_cmd(3);            					//set message id
+	mbtk_coap_ecoaptype_exec_cmd(0);             					//set message type
+	mbtk_coap_ecoapcode_exec_cmd(2);			 					//set Post request method
+	mbtk_coap_ecoapopt_exec_cmd("b474657374",10);					//set option
+
+	mbtk_coap_ecoapsend_exec_cmd(3, 7, "1111111");  				//request post
+	return 0;
+}
diff --git a/mbtk/test/mbtk_dtmf_test.c b/mbtk/test/mbtk_dtmf_test.c
new file mode 100755
index 0000000..a21464e
--- /dev/null
+++ b/mbtk/test/mbtk_dtmf_test.c
@@ -0,0 +1,94 @@
+/**
+ *   \file dtmf_test.c
+ *   \brief A Documented file.
+ *
+ *  Detailed description
+ *   \Author:  js.wang <js.wang@mobiletek.cn>
+ *   \Version: 1.0.0
+ *   \Date: 2022-03-31
+ */
+
+/******************************************************************************\
+ *   Include files
+\******************************************************************************/
+#include <pthread.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <stdlib.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "mbtk_audio.h"
+
+void dtmf_cb(char dtmf)
+{
+    printf("%s:%c\n", __FUNCTION__, dtmf);
+}
+
+void audio_volume_cb(int volume)
+{
+    printf("%s:%d\n", __FUNCTION__, volume);
+}
+
+int main(int argc, char *argv[])
+{
+    char operator[10];
+    int opt;
+    mbtk_audio_client_handle_type dtmf_handle;
+
+
+    while(1)
+    {
+        printf("=========audio main=========\n"
+            "\t0 exit\n"
+            "\t1 audio init\n"
+            "\t2 audio get volume\n"
+            "\t3 audio set volume\n"
+            "\t4 audio deinit\n"
+            "operator: >> ");
+        fgets(operator, sizeof(operator), stdin);
+        fflush(stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+        case 0:
+            printf("main exit\n");
+            return 0;
+        case 1:
+            mbtk_audio_ubus_client_init(&dtmf_handle, dtmf_cb);
+            break;
+        case 2:
+            mbtk_audio_ubus_volume_get(audio_volume_cb);
+            break;
+        case 3:
+            printf("please input volume (0~100): \n");
+            fgets(operator, sizeof(operator), stdin);
+            fflush(stdin);
+            opt = atoi(operator);
+            mbtk_audio_ubus_volume_set(opt);
+            break;
+        case 4:
+            mbtk_audio_ubus_client_deinit(dtmf_handle);
+            break;
+        default:
+            break;
+        }
+    }
+
+    return 0;
+}
diff --git a/mbtk/test/mbtk_ftp_test.c b/mbtk/test/mbtk_ftp_test.c
new file mode 100755
index 0000000..481108d
--- /dev/null
+++ b/mbtk/test/mbtk_ftp_test.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "mbtk_type.h"
+#include "mbtk_ftp.h"
+#include "mbtk_log.h"
+#include "mbtk_str.h"
+
+static int ftp_cmd_process(mbtk_ftp_handle handle, const char *cmd)
+{
+    if(!strncasecmp(cmd, "download", 8)) {
+        // Download file: /data
+        uint32 len_count = 0;
+        uint32 len;
+        int download_time = 0;
+
+        uint32 file_size = mbtk_ftp_file_size(handle, "/Luo/Luo_up.txt");
+        if(file_size > 0)
+        {
+            printf("Will download file:/data[%d]\n", file_size);
+            // Start download
+            len = mbtk_ftp_download_start(handle, "/Luo/Luo_up.txt", "/tmp/ftp_data", NULL);
+            if(len > 0)
+            {
+                len_count += len;
+                download_time++;
+                printf("Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+                while (len_count < file_size
+                       && download_time <= 10 // Try 10 times.
+                       && (len = mbtk_ftp_download_continue(handle)) > 0)
+                {
+                    len_count += len;
+                    download_time++;
+                    printf("Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+                }
+
+                printf("Download complete - [%d / %d].\n",len_count, file_size);
+            }
+            else
+            {
+                printf("FTP download fail[%d / %d].\n",len_count, file_size);
+                return -1;
+            }
+        }else {
+            printf("File error.\n");
+            return -1;
+        }
+    }
+    else if(!strncasecmp(cmd, "upload", 6)) {
+        int len = 0;
+        len = mbtk_ftp_upload_start(handle, "/Luo/up_ftp3.txt", "/tmp/ftp_data", 0);
+        if( len != 0)
+        {
+            printf("FTP update fail\n");
+            return -1;
+        }
+        else
+        {
+            printf("FTP update success\n");
+        }
+    }
+    else if(!strncasecmp(cmd, "pwd", 3)) {
+        char path[50] = {0};
+        mbtk_ftp_error_enum err = mbtk_ftp_pwd(handle, path);
+        if(FTP_ERR_SUCCESS != err) {
+            printf("mbtk_ftp_pwd() fail:%d\n", err);
+            return -1;
+        }
+
+        printf("PWD : %s\n", path);
+    } else if(!strncasecmp(cmd, "cd ", 3)) {
+        char path[50] = {0};
+        memcpy(path, cmd + 3, strlen(cmd) - 3);
+        mbtk_ftp_error_enum err = mbtk_ftp_cd(handle, path);
+        if(FTP_ERR_SUCCESS != err) {
+            printf("mbtk_ftp_cd() fail:%d\n", err);
+            return -1;
+        }
+
+        printf("cd %s\n", path);
+    } else if(!strncasecmp(cmd, "ls", 2)) {
+        mbtk_ftp_file_info_s list_head;
+        mbtk_ftp_error_enum err = mbtk_ftp_dir_ls(handle, &list_head);
+        if(FTP_ERR_SUCCESS != err) {
+            printf("mbtk_ftp_dir_ls() fail:%d\n", err);
+            return -1;
+        }
+
+        mbtk_ftp_file_info_s *f_ptr = list_head.next;
+        while(f_ptr && !str_empty(f_ptr->name)) {
+            printf("%s, %s, %d\n", f_ptr->name, f_ptr->is_file ? "F" : "D", f_ptr->size);
+            f_ptr = f_ptr->next;
+        }
+    } else {
+        printf("Unknow CMD.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    mbtk_ftp_handle handle = mbtk_ftp_init("58.246.1.50", 6521, FTP_AUTH_TYPE_NON, false, false);
+    if(handle < 0) {
+        printf("mbtk_ftp_init() fail.\n");
+        return -1;
+    }
+
+    mbtk_ftp_error_enum err = mbtk_ftp_login(handle, " FTP_TST", "FTPTST_0320");
+    if(err != FTP_ERR_SUCCESS) {
+        printf("mbtk_ftp_login() fail:%d\n", err);
+        goto ftp_exit;
+    }
+
+    printf("Login success.\nCMD:");
+
+    char cmd[50];
+    while(1) {
+        memset(cmd, 0, 50);
+        gets(cmd);
+        if(!strcasecmp(cmd, "q")) {
+            break;
+        } else {
+            ftp_cmd_process(handle, cmd);
+        }
+
+        printf("CMD:");
+    }
+
+    printf("FTP test success.\n");
+ftp_quit:
+    mbtk_ftp_quit(handle);
+ftp_exit:
+    mbtk_ftp_deinit(handle);
+    printf("FTP test complete.\n");
+    return 0;
+
+}
+
diff --git a/mbtk/test/mbtk_http_test.c b/mbtk/test/mbtk_http_test.c
new file mode 100755
index 0000000..edfd81d
--- /dev/null
+++ b/mbtk/test/mbtk_http_test.c
@@ -0,0 +1,74 @@
+#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"
+
+
+static void http_data_cb_func(
+    int session_id, mbtk_http_data_type_enum type,
+    void *data,int data_len)
+{
+    if(type == MBTK_HTTP_DATA_HEADER) {
+        printf("Header(%d):%s\n",data_len,(char*)data);
+    } else if(type == MBTK_HTTP_DATA_CONTENT) {
+        printf("Data(%d):%s\n",data_len,(char*)data);
+    } else {
+        LOGI(">>>>>Complete<<<<<\n");
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    if(argc != 2) {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    LOGI("MBTK HTTP Version 1.1");
+
+    int http_handle = mbtk_http_handle_get(TRUE, http_data_cb_func);
+    if(http_handle < 0)
+    {
+        LOGE("mbtk_http_handle_get() fail.");
+        return -1;
+    }
+
+    int http_session = mbtk_http_session_create(http_handle,HTTP_OPTION_GET,HTTP_VERSION_1_1);
+    if(http_handle < 0)
+    {
+        LOGE("mbtk_http_session_create() fail.");
+        return -1;
+    }
+
+    if(mbtk_http_session_url_set(http_handle, http_session, argv[1])) {
+        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);
+
+
+    if(mbtk_http_session_start(http_handle, http_session)) {
+        LOGE("mbtk_http_session_start() fail.\n");
+        return -1;
+    }
+
+
+    if(mbtk_http_handle_free(http_handle))
+    {
+        LOGE("mbtk_http_handle_free() fail.");
+        return -1;
+    }
+
+    LOGI("MBTK_HTTP exit.");
+    return 0;
+
+}
diff --git a/mbtk/test/mbtk_info_test.c b/mbtk/test/mbtk_info_test.c
new file mode 100755
index 0000000..73a7050
--- /dev/null
+++ b/mbtk/test/mbtk_info_test.c
@@ -0,0 +1,1281 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_info_api.h"
+#include "lynq/lynq_sms_api.h"
+
+//#include "lynq_net_api.h"
+
+static mbtk_info_handle_t* info_handle = NULL;
+
+void net_state_change_cb(const void* data, int data_len)
+{
+
+}
+
+void call_state_change_cb(const void* data, int data_len)
+{
+    mbtk_call_info_t *reg = (mbtk_call_info_t *)data;
+    switch (reg->call_wait)
+    {
+        case MBTK_CLCC:
+            printf("\r\nRING : %d, %d, %d, %d, %d, %s, %d\r\n", reg->dir1, reg->dir, reg->state, reg->mode, reg->mpty, reg->phone_number, reg->type);
+            break;
+        case MBTK_DISCONNECTED:
+            printf("\r\nRING : call dis connected!\r\n");
+            break;
+        case MBTK_CPAS:
+            printf("\r\nCALL : Call state = %d\r\n", reg->pas);
+            /*
+                MBTK_CALL_RADY,                 //MT allows commands from TA/TE
+                MBTK_CALL_UNAVAILABLE,          //MT does not allow commands from TA/TE
+                MBTK_CALL_UNKNOWN,              //MT is not guaranteed to respond to instructions
+                MBTK_CALL_RINGING,              //MT is ready for commands from TA/TE, but the ringer is active
+                MBTK_CALL_PROGRESS,             //MT is ready for commands from TA/TE, but a call is in progress
+                MBTK_CALL_ASLEEP,               //MT is unable to process commands from TA/TE because it is in a low functionality state
+                MBTK_CALL_ACTIVE,
+            */
+           switch (reg->pas)
+           {
+                case MBTK_CALL_RADY:
+                    printf("CALL: call READY\r\n");
+                    break;
+                case MBTK_CALL_UNAVAILABLE:
+                    printf("CALL: call unavaliable\r\n");
+                    break;
+                case MBTK_CALL_UNKNOWN:
+                    printf("CALL: call unknown\r\n");
+                    break;
+                case MBTK_CALL_RINGING:
+                    printf("CALL: call ringing\r\n");
+                    break;
+                case MBTK_CALL_PROGRESS:
+                    printf("CALL: call progress\r\n");
+                    break;
+                case MBTK_CALL_ASLEEP:
+                    printf("CALL: call asleep\r\n");
+                    break;
+                case MBTK_CALL_ACTIVE:
+                    printf("CALL: call active\r\n");
+                    break;
+                default:
+                    printf("\r\n");
+                    break;
+           }
+            break;
+        default:
+            printf("\r\nRING : None call_wait = %d\r\n", reg->call_wait);
+            break;
+    }
+    /*
+    if(reg->call_wait == )         //CLCC
+    {
+        printf("\r\nRING : %d, %d, %d, %d, %d, %s, %d\r\n", reg->dir1, reg->dir, reg->state, reg->mode, reg->mpty, reg->phone_number, reg->type);
+    }
+    else if(reg->call_wait == 2)    //Disconnected
+    {
+        printf("\r\nRING : call dis connected!\r\n");
+    }
+    else
+    {
+        printf("\r\nRING : None\r\n");
+    }
+    */
+}
+
+void 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));
+
+}
+
+void radio_state_change_cb(const void* data, int data_len)
+{
+    uint8 *ptr = (uint8*)data;
+    printf("Radio state : %d\n", *ptr);
+}
+
+void sim_state_change_cb(const void* data, int data_len)
+{
+    uint8 *ptr = (uint8*)data;
+    printf("SIM state : %d\n", *ptr);
+}
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+static void test2(int is_ipv6, char *ip)
+{
+    char ipaddr[20] = {0};
+	if(is_ipv6) {
+        struct in6_addr sin_addr;
+        if(inet_pton(AF_INET6, ip, &sin_addr) < 0) {
+            printf("inet_pton() fail.\n");
+        } else {
+		    log_hex("IPv6", &sin_addr, sizeof(struct in6_addr));
+        }
+	} else {
+	    struct in_addr sin_addr;
+        if(inet_pton(AF_INET, ip, &sin_addr) < 0) {
+            printf("inet_pton() fail.\n");
+        } else {
+		    log_hex("IPv4", &sin_addr, sizeof(struct in_addr));
+        }
+	}
+}
+
+
+static void help()
+{
+    printf("version: Get version.\n");
+    printf("imei: Get IMEI.\n");
+    printf("sn: Get SN.\n");
+    printf("meid: Get MEID.\n");
+    printf("volte: Get VoLTE state.\n");
+    printf("volte 0: Close VoLTE.\n");
+    printf("volte 1: Open VoLTE.\n");
+    printf("radio: Get radio state.\n");
+    printf("radio 0: Close radio.\n");
+    printf("radio 1: Open radio.\n");
+    printf("sim: Get sim state.\n");
+    printf("avail_net: Get available network.\n");
+    printf("imsi: Get IMSI.\n");
+    printf("iccid: Get ICCID.\n");
+    printf("pn: Get Phone Number.\n");
+    printf("sel_mode: Get network select mode.\n");
+    printf("sel_mode <sel_mode> <net_type> <plmn>: Set network select mode.\n");
+    printf("band: Get current bands.\n");
+    printf("band support: Get support bands.\n");
+    printf("band <net_pref> <gsm_band> <umts_band> <tdlte_band> <fddlte_band>: Set current bands.\n");
+    printf("signal: Get network signal.\n");
+    printf("reg: Get network registe information.\n");
+    printf("cell: Get current cell information.\n");
+    printf("shutdown <0,1,2>: reboot/poweroff/halt system.\n");
+    printf("power_sim <0,1>: Power off/on sim.\n");
+    printf("temp <0,1>: Get SOC/RF temperature.\n");
+    printf("time <0,1,2> YYYY-MM-DD HH:MM:SS : Set system time as CELL/NTP/User.\n");
+    printf("apn : Get current apns.\n");
+    printf("apn <cid> <1/2/3/4> <apn> : Set apn.\n");
+    printf("data_call <0/1/2> <cid> <timeout>: Stop/Start/State data call.\n");
+    printf("call: Call the phone number.\n");
+    printf("answer: Answer the phone call.\n");
+    printf("hangup: Hang up all phone call. No id.\n");
+    printf("hangup 0: Hang up waiting or background phone call.\n");
+    printf("hangup 1: Hang up a phone call.\n");
+    printf("hangup 2: Hang up a phone call.\n");
+    printf("hangup 3: Hangup foreground resume background call.\n");
+    printf("waitin: Returns the list of current calls.\n");
+    printf("mute: Get mute state.\n");
+    printf("mute 0: Close mute.\n");
+    printf("mute 1: Open mute.\n");
+    printf("dtmf : Set dtmf character[0, 1, 2, ..., A, B, C, D, *, #], duration [300-600].\n   Such as: dtmf 0 300\n");
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            mbtk_info_handle_free(&info_handle);
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (类似 SIGINT ,但要产生core文件)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            mbtk_info_handle_free(&info_handle);
+            exit(0);
+        }
+        case SIGTERM:// 默认kill   (同 SIGKILL ,但 SIGKILL 不可捕获)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            mbtk_info_handle_free(&info_handle);
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (同 SIGSTOP ,但 SIGSTOP 不可捕获)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // 如空指针
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+    mbtk_log_init(NULL,"INFO_CLI");
+
+    //test2(0, "192.168.1.198");
+    //test2(1, "2409:8162:140:cd3c:1:2:1494:72ba");
+    //test2(1, "254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239");
+    //test2(1, "2400:3200::1");
+
+    info_handle = mbtk_info_handle_get();
+    if(!info_handle)
+    {
+        return -1;
+    }
+
+    mbtk_net_state_change_cb_reg(info_handle, net_state_change_cb);
+    mbtk_call_state_change_cb_reg(info_handle, call_state_change_cb);
+    mbtk_sms_state_change_cb_reg(info_handle, sms_state_change_cb);
+    mbtk_radio_state_change_cb_reg(info_handle, radio_state_change_cb);
+    mbtk_sim_state_change_cb_reg(info_handle, sim_state_change_cb);
+
+    printf(">>>>>>>>>>>>>>>>>>>>>>>>Enter cmd:\n");
+    char cmd[100];
+    while(1)
+    {
+        memset(cmd, 0, 100);
+        int err;
+        if(fgets(cmd, 100, stdin))
+        {
+            char *ptr = cmd + strlen(cmd) - 1;
+            while(ptr >= cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+            if(!strncasecmp(cmd, "version", 7))
+            {
+                char version[50] = {0};
+                err = mbtk_version_get(info_handle, version);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Version : %s\n", version);
+                }
+            } else if(!strncasecmp(cmd, "imei", 4)){
+                char imei[50] = {0};
+                err = mbtk_imei_get(info_handle, imei);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("IMEI : %s\n", imei);
+                }
+            } else if(!strncasecmp(cmd, "sn", 2)){
+                char sn[50] = {0};
+                err = mbtk_sn_get(info_handle, sn);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("SN : %s\n", sn);
+                }
+            } else if(!strncasecmp(cmd, "meid", 4)){
+                char meid[50] = {0};
+                err = mbtk_meid_get(info_handle, meid);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("MEID : %s\n", meid);
+                }
+            } else if(!strncasecmp(cmd, "volte", 5)){ // "volte" or "volte 0" or "volte 1"
+                int volte;
+                if(!strcasecmp(cmd, "volte")) { // Get
+                    err = mbtk_volte_state_get(info_handle, &volte);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE : %d\n", volte);
+                    }
+                } else { // Set
+                    if(!strcasecmp(cmd, "volte 1")) { // Open VoLTE
+                        volte = 1;
+                    } else { // Close VoLTE
+                        volte = 0;
+                    }
+                    err = mbtk_volte_state_set(info_handle, volte);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "radio", 5)){ // "radio" or "radio 0" or "radio 1"
+                int radio;
+                if(!strcasecmp(cmd, "radio")) { // Get
+                    err = mbtk_radio_state_get(info_handle, &radio);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Radio : %d\n", radio);
+                    }
+                } else { // Set
+                    if(!strcasecmp(cmd, "radio 1")) { // Open radio
+                        radio = 1;
+                    } else { // Close radio
+                        radio = 0;
+                    }
+                    err = mbtk_radio_state_set(info_handle, radio);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Radio set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "sim", 3)){
+                mbtk_sim_state_enum sim;
+                err = mbtk_sim_state_get(info_handle, &sim);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Sim : %d\n", sim);
+                }
+            } else if(!strncasecmp(cmd, "imsi", 4)){
+                char imsi[50] = {0};
+                err = mbtk_imsi_get(info_handle, imsi);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("IMSI : %s\n", imsi);
+                }
+            } else if(!strncasecmp(cmd, "iccid", 5)){
+                char iccid[50] = {0};
+                err = mbtk_iccid_get(info_handle, iccid);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("ICCID : %s\n", iccid);
+                }
+            } else if(!strncasecmp(cmd, "pn", 2)){
+                char phone_number[50] = {0};
+                err = mbtk_phone_number_get(info_handle, phone_number);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Phone Number : %s\n", phone_number);
+                }
+            } else if(!strncasecmp(cmd, "avail_net", 9)){
+                list_node_t* net_list = NULL;
+                err = mbtk_available_net_get(info_handle, &net_list);
+                if(err || net_list == NULL) {
+                    printf("Error : %d\n", err);
+                } else {
+                    mbtk_net_info_t* net = NULL;
+                    list_first(net_list);
+                    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);
+                    }
+                }
+                list_free(net_list);
+            } else if(!strncasecmp(cmd, "cell", 4)){
+                char *ptr = strstr(cmd, ",");	 //CPMS,ME,ME,ME
+				if(ptr == NULL)
+				{
+                    printf("ptr == NULL\n");
+                    list_node_t* cell_list = NULL;
+                    int type;
+                    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:
+                                    printf("GSM : lac=%d, ci=%d, arfcn=%d, bsic=%d\n", cell->value1, cell->value2, cell->value3, cell->value4);
+                                    break;
+                                case 1:
+                                    printf("UMTS : lac=%d, ci=%d, arfcn=%d\n", cell->value1, cell->value2, cell->value3);
+                                    break;
+                                case 2:
+                                    printf("LTE : tac=%d, PCI=%d, dlEuarfcn=%d, ulEuarfcn=%d, band=%d\n", cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+                                    break;
+                                default:
+                                    break;
+                            }
+                        }
+                        while ((cell = (mbtk_cell_info_t*) list_next(cell_list)))
+                        {
+                            switch(type)
+                            {
+                                case 0:
+                                    printf("CELL : %d, %d, %d, %d, %d", cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+                                    break;
+                                case 1:
+                                    printf("CELL : lac=%d, ci=%d, arfcn=%d\n", cell->value1, cell->value2, cell->value3);
+                                    break;
+                                case 2:
+                                    printf("CELL : phyCellId=%d, euArfcn=%d, rsrp=%d, rsrq=%d\n", cell->value1, cell->value2, cell->value3, cell->value4);
+                                    break;
+                                default:
+                                    break;
+                            }
+                        }
+                    }
+                    list_free(cell_list);
+                }
+                else{
+                    char *ptr = strstr(cmd, ",");	 //cell,2,3,,40936,430
+					char mem[50]={0};
+					char resp[1024] = {0};
+					if(ptr != NULL)
+					{
+						ptr++;
+						memset(mem, 0, sizeof(mem));
+						memcpy(mem, ptr, strlen(ptr));
+						printf("cell:%s\n", mem);
+					}
+					printf("cell_mem: %s \n", mem);
+
+					memset(resp, 0, sizeof(resp));
+					err = mbtk_cell_set(info_handle, mem, resp);
+					if(err) {
+						printf("Error : %d\n", err);
+					} else {
+						printf("cell set . resp:%s\n", resp);
+					}
+
+                }
+            } else if(!strncasecmp(cmd, "sel_mode", 8)){ // "sel_mode" or "sel_mode 1 7 46000"
+                mbtk_net_info_t net;
+                memset(&net, 0, sizeof(mbtk_net_info_t));
+                if(!strcasecmp(cmd, "sel_mode")) { // Get
+                    err = mbtk_net_sel_mode_get(info_handle, &net);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Net : %d, %d, %d, %d\n", net.net_sel_mode, net.net_type, net.net_state, net.plmn);
+                    }
+                } else { // Set
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net.net_sel_mode = (uint8)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net.net_type = (uint8)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net.plmn = (uint32)atoi(ptr);
+
+                    err = mbtk_net_sel_mode_set(info_handle, &net);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Net select mode set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "band", 4)){ // "band" or "band support" or "band 0 79 147 482 524503"
+                mbtk_band_info_t band;
+                if(!strcasecmp(cmd, "band")) { // Get
+                    err = mbtk_current_band_get(info_handle, &band);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Band : %d, %d, %d, %d, %d\n", band.net_pref, band.gsm_band, band.umts_band, band.tdlte_band, band.fddlte_band);
+                    }
+                } else if(!strcasecmp(cmd, "band support")) { // Get
+                    err = mbtk_support_band_get(info_handle, &band);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Band : %d, %d, %d, %d, %d\n", band.net_pref, band.gsm_band, band.umts_band, band.tdlte_band, band.fddlte_band);
+                    }
+                } else { // "band 0 79 147 482 524503"
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    band.net_pref = (uint8)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    band.gsm_band = (uint16)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    band.umts_band = (uint16)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    band.tdlte_band = (uint32)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    band.fddlte_band = (uint32)atoi(ptr);
+
+                    err = mbtk_current_band_set(info_handle, &band);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Band set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "signal", 6)){
+                mbtk_signal_info_t signal;
+                err = mbtk_net_signal_get(info_handle, &signal);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Signal : %d, %d, %d, %d, %d, %d, %d, %d\n", signal.type, signal.rssi, signal.rxlev, signal.ber,
+                        signal.rscp, signal.ecno, signal.rsrq, signal.rsrp);
+                }
+            } else if(!strncasecmp(cmd, "reg", 3)){
+                mbtk_net_reg_info_t reg;
+                err = mbtk_net_reg_get(info_handle, &reg);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("REG : call_state=%d, data_state=%d, ims_state=%d, net_type=%d, %04x, %08x\n", reg.call_state, reg.data_state, reg.ims_state, reg.type, reg.lac, reg.ci);
+                }
+            } else if(!strncasecmp(cmd, "call", 4)){
+                char phone_number[12];
+                char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                memset(phone_number,0,strlen(phone_number));
+                memcpy(phone_number,ptr,strlen(ptr));
+                printf("phone number is: %s\n",phone_number);
+                err = mbtk_call_start(info_handle, phone_number);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Call success.\n");
+                }
+            } else if(!strncasecmp(cmd, "answer", 6)){
+                err = mbtk_call_answer(info_handle);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Call success.\n");
+                }
+            } else if(!strncasecmp(cmd, "hangup", 6)){
+                int phone_id;
+                if(!strcasecmp(cmd, "hangup")) { // hang up all
+                    err = mbtk_call_hang(info_handle);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Call hang up all.\n");
+                    }
+                } else if(!strcasecmp(cmd, "hangup 0")) {
+                    err = mbtk_waiting_or_background_call_hang(info_handle);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Call hang up waiting or background.\n");
+                    }
+                } else if(!strcasecmp(cmd, "hangup 3")) {
+                    err = mbtk_foreground_resume_background_call_hang(info_handle);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Call hang up foreground resume background.\n");
+                    }
+                } else {
+                    if(!strcasecmp(cmd, "hangup 1")) { // hang up a call
+                        phone_id = 1;
+                    } else if(!strcasecmp(cmd, "hangup 2")) {
+                        phone_id = 2;
+                    } else {
+                        printf("Error : Invalid input\n");
+                    }
+                    err = mbtk_a_call_hang(info_handle, phone_id);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("A Call hang up.\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "waitin", 6)){
+                mbtk_call_info_t reg;
+                err = mbtk_call_reg_get(info_handle, &reg);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    if(reg.call_wait == 0) {
+                        printf("No call ring\n");
+                    }
+                    else {
+                        printf("RING : %d, %d, %d, %d, %d, %s, %d\n", reg.dir1, reg.dir, reg.state, reg.mode, reg.mpty, reg.phone_number, reg.type);
+                    }
+                }
+            } else if(!strncasecmp(cmd, "mute", 4)){ // "mute" or "mute 0" or "mute 1"
+                int mute;
+                if(!strcasecmp(cmd, "mute")) { // Get
+                    err = mbtk_mute_state_get(info_handle, &mute);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("mute : %d\n", mute);
+                    }
+                } else { // Set
+                    if(!strcasecmp(cmd, "mute 1")) { // on mute
+                        mute = 1;
+                    } else { // off mute
+                        mute = 0;
+                    }
+                    err = mbtk_mute_state_set(info_handle, mute);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("mute set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "DTMF", 4)){ // valid character: (0, 1, ..., 9, A, B, C, D, *, #)
+
+                mbtk_call_dtmf_info_t reg;
+
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                reg.character = *ptr;
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                reg.duration = (uint32)atoi(ptr);
+                printf("DTMF character is: %c,%d\n",reg.character, reg.duration);
+                err = mbtk_dtmf_send(info_handle, &reg);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("DTMF success.\n");
+                }
+            } else if(!strncasecmp(cmd, "shutdown", 8)){
+                if(!strcasecmp(cmd, "shutdown 0")) {
+                    err = mbtk_system_reboot(0);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else if(!strcasecmp(cmd, "shutdown 1")) {
+                    err = mbtk_system_reboot(1);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else if(!strcasecmp(cmd, "shutdown 2")) {
+                    err = mbtk_system_reboot(2);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else {
+                    printf("Error.");
+                }
+            } else if(!strncasecmp(cmd, "power_sim", 9)){
+                if(!strcasecmp(cmd, "power_sim 0")) {
+                    err = mbtk_sim_power_set(0);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else if(!strcasecmp(cmd, "power_sim 1")) {
+                    err = mbtk_sim_power_set(1);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else {
+                    printf("Error.");
+                }
+            } else if(!strncasecmp(cmd, "temp", 4)){
+                int temp;
+                if(!strcasecmp(cmd, "temp 0")) {
+                    err = mbtk_temp_get(info_handle, 0, &temp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("SOC : %d\n", temp);
+                    }
+                } else if(!strcasecmp(cmd, "temp 1")) {
+                    err = mbtk_temp_get(info_handle, 1, &temp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("RF : %d\n", temp);
+                    }
+                } else {
+                    printf("Error.");
+                }
+            } else if(!strncasecmp(cmd, "time", 4)){
+                if(!strcasecmp(cmd, "time 0")) {
+                    err = mbtk_time_set(info_handle, 0, NULL);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else if(!strcasecmp(cmd, "time 1")) {
+                    err = mbtk_time_set(info_handle, 1, NULL);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else if(!strncasecmp(cmd, "time 2 ", 7)) {
+                    err = mbtk_time_set(info_handle, 2, cmd + 7);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Success.\n");
+                    }
+                } else { // Get time type.
+                    int time_type;
+                    err = mbtk_time_get(info_handle, &time_type);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Time type:%d.\n", time_type);
+                    }
+                }
+            } else if(!strncasecmp(cmd, "apn", 3)){
+                if(!strcasecmp(cmd, "apn")) { // Get apn
+                #define APN_MAX 10
+                    mbtk_apn_info_t apns[APN_MAX];
+                    int apn_num = APN_MAX;
+                    err = mbtk_apn_get(info_handle, &apn_num, apns);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("APN Num:%d\n", apn_num);
+                        int i = 0;
+                        while(i < apn_num) {
+                            printf("APN : %d, %s, %s\n", apns[i].cid, apn2str(apns[i].ip_type), apns[i].apn);
+                            i++;
+                        }
+                    }
+                } else { // apn <cid> <0/1/2/3> <apn>
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    int cid = atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    mbtk_ip_type_enum ip_type = (mbtk_ip_type_enum)atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    char *apn  = ptr;
+
+                    err = mbtk_apn_set(info_handle, cid, ip_type, apn, NULL, NULL, NULL);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("APN set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "data_call", 9)){ // data_call <0/1/2> <cid> <timeout>
+                // data_call <0/1/2> <cid> <timeout>
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                mbtk_data_call_type_enum type = (mbtk_data_call_type_enum)atoi(ptr);
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int cid = atoi(ptr);
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int timeout = atoi(ptr);
+
+                if(type == MBTK_DATA_CALL_START) {
+                    err = mbtk_data_call_start(info_handle, cid, 0, FALSE, timeout);
+                } else if(type == MBTK_DATA_CALL_STOP) {
+                    err = mbtk_data_call_stop(info_handle, cid, timeout);
+                } else {
+                    mbtk_ipv4_info_t ipv4;
+                    mbtk_ipv6_info_t ipv6;
+                    err = mbtk_data_call_state_get(info_handle, cid, &ipv4, &ipv6);
+                    if(!err) {
+                        if(ipv4.valid) {
+                            // log_hex("IPv4", &ipv4, sizeof(mbtk_ipv4_info_t));
+                            char ip_tmp[20];
+
+                            memset(ip_tmp, 0, 20);
+                            if(inet_ntop(AF_INET, &(ipv4.IPAddr), ip_tmp, 20) == NULL) {
+                                printf("IP error.\n");
+                            } else {
+                                printf("IP : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 20);
+                            if(inet_ntop(AF_INET, &(ipv4.PrimaryDNS), ip_tmp, 20) == NULL) {
+                                printf("PrimaryDNS error.\n");
+                            } else {
+                                printf("PrimaryDNS : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 20);
+                            if(inet_ntop(AF_INET, &(ipv4.SecondaryDNS), ip_tmp, 20) == NULL) {
+                                printf("SecondaryDNS error.\n");
+                            } else {
+                                printf("SecondaryDNS : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 20);
+                            if(inet_ntop(AF_INET, &(ipv4.GateWay), ip_tmp, 20) == NULL) {
+                                printf("GateWay error.\n");
+                            } else {
+                                printf("GateWay : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 20);
+                            if(inet_ntop(AF_INET, &(ipv4.NetMask), ip_tmp, 20) == NULL) {
+                                printf("NetMask error.\n");
+                            } else {
+                                printf("NetMask : %s\n", ip_tmp);
+                            }
+                        }
+
+                        if(ipv6.valid) {
+                            // log_hex("IPv6", &ipv6, sizeof(mbtk_ipv6_info_t));
+                            char ip_tmp[50];
+
+                            memset(ip_tmp, 0, 50);
+                            if(ipv6_2_str(&(ipv6.IPV6Addr), ip_tmp)) {
+                                printf("IP error.\n");
+                            } else {
+                                printf("IP : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 50);
+                            if(ipv6_2_str(&(ipv6.PrimaryDNS), ip_tmp)) {
+                                printf("PrimaryDNS error.\n");
+                            } else {
+                                printf("PrimaryDNS : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 50);
+                            if(ipv6_2_str(&(ipv6.SecondaryDNS), ip_tmp)) {
+                                printf("SecondaryDNS error.\n");
+                            } else {
+                                printf("SecondaryDNS : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 50);
+                            if(ipv6_2_str(&(ipv6.GateWay), ip_tmp)) {
+                                printf("GateWay error.\n");
+                            } else {
+                                printf("GateWay : %s\n", ip_tmp);
+                            }
+
+                            memset(ip_tmp, 0, 50);
+                            if(ipv6_2_str(&(ipv6.NetMask), ip_tmp)) {
+                                printf("NetMask error.\n");
+                            } else {
+                                printf("NetMask : %s\n", ip_tmp);
+                            }
+                        }
+                    }
+                }
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("DATA_CALL success\n");
+                }
+            }else if(!strncasecmp(cmd, "cmgf", 4)){ // set mode 0: pud, 1:text
+                int mode;
+                if(!strcasecmp(cmd, "cmgf")) { // Get
+                    err = mbtk_sms_cmgf_get(info_handle, &mode);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE : %d\n", mode);
+                    }
+                } else { // Set
+                    if(!strcasecmp(cmd, "cmgf 1")) { // cmgf 1
+                        mode = 1;
+                    } else { //
+                        mode = 0;
+                    }
+                    printf("mode:%d\n", mode);
+                    sleep(2);
+                   err = mbtk_sms_cmgf_set(info_handle, mode);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE set success\n");
+                    }
+                }
+            }else if(!strncasecmp(cmd, "cpms", 4)){ // //CPMS=ME, ME, ME
+				char mem[100] = {0};
+                char resp[100] = {0};
+                if(!strcasecmp(cmd, "cpms")) { // Get
+                    err = mbtk_sms_cpms_get(info_handle, &mem);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("cpms : %s\n", mem);
+                    }
+                } else { // Set
+
+					char *ptr = strstr(cmd, ",");    //CPMS,ME,ME,ME
+                    if(ptr != NULL)
+				    {
+				    	ptr++;
+                        memset(mem, 0, sizeof(mem));
+				        memcpy(mem, ptr, strlen(ptr));
+						printf("cpms:%s\n", mem);
+				    }
+                    printf("cpms 0\n");
+
+                    memset(resp, 0, sizeof(resp));
+                    err = mbtk_sms_cpms_set(info_handle, mem, resp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("cpms set success. resp:%s\n", resp);
+                    }
+                }
+            }else if(!strncasecmp(cmd, "cmgs", 4)){ //   AT+CMGS="10086", CMGS TEST
+                char cmgs[1024] = {0};
+                char resp[50] = {0};
+                if(!strcasecmp(cmd, "cmgs")) { // Get
+                    int mode;
+                //    err = mbtk_sms_cmgs_get(info_handle, &mode);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE : %d\n", mode);
+                    }
+                } else { // Set
+
+							/*
+							*AT+CMGS="10086", CMGS TEST	                  // Send a SMS
+							> CMGS TEST
+							+CMGS: 17
+							OK
+							*/
+
+                    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);
+                    } else {
+                        printf("cmgs set success . resp:%s\n", resp);
+                    }
+                }
+            }else if(!strncasecmp(cmd, "cmss", 4)){ // +CMSS=<index>[,<da>[,<toda>]]
+                char cmss[20] = {0};
+                char resp[20] = {0};
+                if(!strcasecmp(cmd, "cmgs")) { // Get
+                    printf("cmss : OK\n");
+
+                } else {
+                    char *ptr = strstr(cmd, "cmss,");    //CMSS=<index>
+                    if(ptr != NULL)
+				    {
+                        ptr = strstr(cmd, ",");
+				    	ptr++;
+                        memset(cmss, 0, sizeof(cmss));
+				        memcpy(cmss, ptr, strlen(ptr));
+						printf("1cmss:%s\n", cmss);
+				    }
+
+
+                    err = mbtk_sms_cmss_set(info_handle, cmss, resp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("cmss set success. resp:%s\n", resp);
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "cmgr", 4)){ // +CMGR=<index
+                int index = 0;
+                char resp[1024] = {0};
+                if(!strcasecmp(cmd, "cmgr")) { // Get
+                    printf("cmgr : OK\n");
+
+                } else {
+                    char *ptr = strstr(cmd, "cmgr,");    //+CMGR <index>
+                    if(ptr != NULL)
+				    {
+                        ptr = strstr(cmd, ",");
+                        ptr++;
+				    	index = atoi(ptr);
+				    }
+                    printf("1index:%d\n", index);
+
+                    memset(resp, 0, sizeof(resp));
+                    err = mbtk_sms_cmgr_set(info_handle, index, resp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("cmgr set success. rep:%s\n", resp);
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "cmgw", 4)){ // +CMGW=<oa/da>[,<tooa/toda>[,<stat>]]<CR>
+                                                    //+CMGW=<length>[,<stat>]<CR>PDU is given<ctrl-Z/ESC>
+                char cmgw[128] = {0};
+                char resp[50] = {0};
+                if(!strcasecmp(cmd, "cmgw")) { // Get
+                    printf("cmgw : OK\n");
+
+                } else {
+                    char *ptr = strstr(cmd, "cmgw,");    //+CMGW, <oa/da>, data
+                    if(ptr != NULL)
+				    {
+                        ptr = strstr(cmd, ",");
+				    	ptr++;
+                        memset(cmgw, 0, sizeof(cmgw));
+				        memcpy(cmgw, ptr, strlen(ptr));
+						printf("cmgw:%s\n", cmgw);
+				    }
+
+                    memset(resp, 0, sizeof(resp));
+                    err = mbtk_sms_cmgw_set(info_handle, cmgw, resp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("cmgw set success. resp:%s\n", resp);
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "cmgd", 4)){ // +CMGD=<index>[,<delflag>
+                                                    //
+                char cmgd[128] = {0};
+                if(!strcasecmp(cmd, "cmgd")) { // Get
+                    printf("cmgd : OK\n");
+
+                } else {
+                    char *ptr = strstr(cmd, ",");    //+CMGD=<index>[,<delflag>
+                    if(ptr != NULL)
+				    {
+				    	ptr++;
+                        memset(cmgd, 0, sizeof(cmgd));
+				        memcpy(cmgd, ptr, strlen(ptr));
+						printf("1cmgd:%s\n", cmgd);
+				    }
+
+
+                    err = mbtk_sms_cmgd_set(info_handle, cmgd);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE set success\n");
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "cmgl", 4)){ // AT+CMGL[=<stat>]
+                                                    //
+                char cmgl[128] = {0};
+                char resp[5*1024] ={0};
+                if(!strcasecmp(cmd, "cmgl")) { // Get
+                    printf("cmgl : OK\n");
+
+                } else {
+                    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("Error : %d\n", err);
+                    } else {
+                      //  printf("cmgl set success, reg:%s\n",resp);
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "csca", 4)){ // AT+CSCA=<number> [,<type>]
+                                                    //
+                char csca[128] = {0};
+                if(!strcasecmp(cmd, "csca")) { // Get
+                    err = mbtk_sms_csca_get(info_handle, csca);
+                    if(err) {
+                        printf("mbtk_sms_csca_get Error : %d\n", err);
+                    } else {
+                        printf("mbtk_sms_csca_get success\n");
+                    }
+
+                } else {
+                    char *ptr = strstr(cmd, ",");  //  AT+CSCA=<number> [,<type>]
+                    if(ptr != NULL)
+				    {
+				    	ptr++;
+                        memset(csca, 0, sizeof(csca));
+				        memcpy(csca, ptr, strlen(ptr));
+						printf("csca:%s\n", csca);
+				    }
+
+                    err = mbtk_sms_csca_set(info_handle, csca);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE set success\n");
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "csmp", 4)){ // AT+CSMP=[<fo>[,<vp>[,<pid>[,<dcs>]]]]
+                                                    //
+                char csmp[128] = {0};
+                if(!strcasecmp(cmd, "csmp")) { // Get
+                    printf("cmgl : OK\n");
+
+                } else {
+                    char *ptr = strstr(cmd, ",");  //  AT+CSMP=[<fo>[,<vp>[,<pid>[,<dcs>]]]]
+                    if(ptr != NULL)
+				    {
+				    	ptr++;
+                        memset(csmp, 0, sizeof(csmp));
+				        memcpy(csmp, ptr, strlen(ptr));
+						printf("csmp:%s\n", csmp);
+				    }
+
+                    err = mbtk_sms_csmp_set(info_handle, csmp);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE set success\n");
+                    }
+                }
+            }
+            else if(!strncasecmp(cmd, "cscb", 4)){ // AT+CSCB=<[<mode>[,<mids>[,<dcss>]]]>
+                                                    //
+                char cscb[128] = {0};
+                if(!strcasecmp(cmd, "cscb")) { // Get
+                    printf("cmgl : OK\n");
+
+                } else {
+                    char *ptr = strstr(cmd, ",");  //  AT+CSCB=<[<mode>[,<mids>[,<dcss>]]]>
+                    if(ptr != NULL)
+				    {
+				    	ptr++;
+                        memset(cscb, 0, sizeof(cscb));
+				        memcpy(cscb, ptr, strlen(ptr));
+						printf("cscb:%s\n", cscb);
+				    }
+
+                    err = mbtk_sms_cscb_set(info_handle, cscb);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("VoLTE set success\n");
+                    }
+                }
+            }
+            else if(!strcasecmp(cmd, "h") || !strcasecmp(cmd, "help")) {
+                help();
+            } else if(!strcasecmp(cmd, "q")) {
+                mbtk_info_handle_free(&info_handle);
+                break;
+            } else {
+                printf("\n");
+            }
+        }
+    }
+
+    LOG("Client exec complete.");
+#if 1
+    while(1)
+    {
+        sleep(1000 * 365 * 24 * 60 * 60);
+    }
+#else
+    sleep(1);
+#endif
+    return 0;
+}
diff --git a/mbtk/test/mbtk_mqtt_aliyun_test.c b/mbtk/test/mbtk_mqtt_aliyun_test.c
new file mode 100755
index 0000000..923b123
--- /dev/null
+++ b/mbtk/test/mbtk_mqtt_aliyun_test.c
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include "mbtk_mqtt.h"
+#include "pthread.h"
+#include "string.h"
+#include "unistd.h"
+#include "sys/stat.h"
+#include "sys/types.h"
+#include "sys/socket.h"
+#include "netinet/in.h"
+#include "arpa/inet.h"
+#include "fcntl.h"
+#include "mbtk_sock2.h"
+/*
+typedef struct {
+    char clientId[255];
+    char deviceToken[255];
+} regnwl_info_t;
+*/
+
+int aliyun_xiyinyimi_connect(mbtk_mqtt_device_session_t *device, regnwl_info_t *regn);
+
+struct opts_struct opts = {
+    (char *)"iot-dev", 0, (char *)"\n", QOS0, "admin", "password", (char *)"localhost", 1883, 0
+};//初始化结构体
+
+iot_device_info_t gateway = {
+    .iotstatus = IOT_STATUS_LOGIN,
+    .model = {"2022"},
+    .company = {"/my"}
+};//初始化主题
+
+static Cloud_MQTT_t *miot_mqtt;
+
+void set_mqtt_t(Cloud_MQTT_t *piot_mqtt)
+{
+    miot_mqtt = piot_mqtt;
+}
+Cloud_MQTT_t * get_mqtt_t()
+{
+    return miot_mqtt;
+}
+
+void mqtt_data_rx_cb(void *pbuf, int len) 
+{
+
+    printf("data = %s\n", (unsigned char *)pbuf);	//打印接收到的数据
+}
+
+
+void MQTTMessageArrived_Cb(MessageData* md)
+{
+    MQTTMessage *message = md->message; 
+
+    Cloud_MQTT_t *piot_mqtt = get_mqtt_t();
+
+    if (NULL != piot_mqtt->DataArrived_Cb) {
+        piot_mqtt->DataArrived_Cb((void *)message->payload, message->payloadlen);//异步消息体
+    }
+}
+
+
+void *mqtt_thread(void *arg)
+{
+    while (gateway.iotstatus != IOT_STATUS_DROP){
+        printf("gateway.iotstatus is %d\n",gateway.iotstatus);
+        iot_yield(arg,&gateway);									//维持服务器稳定,断开重连
+    }
+    printf("gateway.iotstatus is IOT_STATUS_DROP");
+//    mqtt_device_disconnect(arg);
+    pthread_exit(NULL);
+    return NULL;
+}
+
+
+
+//int mbtk_aliyun_mqtt_register_init(mbtk_mqtt_device_session_t *mbtk_mqtt_device )
+int main(int argc, char *argv[])
+{
+
+    printf("aliyun mqtt start2\n");
+    int ret, len; 
+    char will_msg[256] = {"hello world"};						//初始化遗嘱数据
+    static int i = 0;
+
+    mbtk_mqtt_device_session_t mbtk_mqtt_device = {0};
+    memcpy(mbtk_mqtt_device.device_name, argv[1] , strlen(argv[1]));
+    memcpy(mbtk_mqtt_device.product_key, "a14Vv4QUPeP" , strlen("a14Vv4QUPeP"));
+    memcpy(mbtk_mqtt_device.product_secret, "GiBigxEaluyAPnD4" , strlen( "GiBigxEaluyAPnD4"));
+    mbtk_mqtt_device.host = 0;
+    mbtk_mqtt_device.port = 1883;
+
+
+    Cloud_MQTT_t *Iot_mqtt;
+    Iot_mqtt = (Cloud_MQTT_t *)malloc(sizeof(Cloud_MQTT_t));
+    memset(Iot_mqtt,0x0,sizeof(Cloud_MQTT_t));
+
+    //一型一密免预注册mqtt
+    mbtk_aliyun_mqtt_one_type_one_secret_unregin_set_info_init(Iot_mqtt, &mbtk_mqtt_device,60*1000,4,mqtt_data_rx_cb);
+
+    mqtt_will_msg_set(Iot_mqtt, will_msg, strlen(will_msg));	//设置遗嘱
+    set_mqtt_t(Iot_mqtt);   
+    ret = mbtk_aliyun_mqtt_one_type_one_secret_unregin_device_connect(Iot_mqtt);						//初始化并连接mqtt服务器
+
+    printf("connect success\n");
+    int rc = mbtk_MQTTSubscribe(&Iot_mqtt->Client, Iot_mqtt->sub_topic, opts.qos, MQTTMessageArrived_Cb);
+    if (rc) {
+        printf("mqtt subscribe fail \n");
+        char clientId[255] = {0};
+        char deviceToken[255] = {0};
+        if(! mbtk_aliyun_mqtt_one_type_one_secret_unregin_get_regin_info(clientId, deviceToken) )
+        {
+            regnwl_info_t regn_info = {0};
+            memcpy(regn_info.clientId,clientId , strlen(clientId));
+            memcpy(regn_info.deviceToken, deviceToken , strlen(deviceToken));
+            printf("example\n");
+            printf("%s\n, %s\n", clientId, deviceToken);
+            aliyun_xiyinyimi_connect(&mbtk_mqtt_device, &regn_info);
+        }
+    }
+
+    return 0;
+}
+
+int aliyun_xiyinyimi_connect(mbtk_mqtt_device_session_t *device, regnwl_info_t *regn)
+{
+
+    int ret, len; 
+    char will_msg[256] = {"hello world"};						//初始化遗嘱数据
+    static int retry_count = 0;
+    pthread_t thread_ID;      //定义线程id
+    static int i = 0;
+
+    Cloud_MQTT_t *Iot_mqtt;
+    Iot_mqtt = (Cloud_MQTT_t *)malloc(sizeof(Cloud_MQTT_t));
+    memset(Iot_mqtt,0x0,sizeof(Cloud_MQTT_t));
+    
+
+    iot_aliyun_mqtt_one_type_one_secret_unregin_connect_init(Iot_mqtt,device, regn->clientId, regn->deviceToken, 30,3,"aaa","aaa",mqtt_data_rx_cb);	
+
+//    iot_mqtt_init(Iot_mqtt,host,port, client, user, pass,30,3,"aaa","aaa",mqtt_data_rx_cb);	
+
+    mqtt_will_msg_set(Iot_mqtt, will_msg, strlen(will_msg));	//设置遗嘱
+
+    set_mqtt_t(Iot_mqtt);    
+    ret = mqtt_device_connect(Iot_mqtt);						//初始化并连接mqtt服务器
+    
+
+    while (ret < 0 && retry_count <= 5) {
+        printf("ret = %d\r\n", ret);
+        retry_count ++ ;
+        printf("retry_count = %d\n",retry_count);
+        sleep(3);
+        ret = mqtt_device_connect(Iot_mqtt);
+    }
+    if(ret < 0 && retry_count > 5)
+    {
+        printf("reconnect times more than 5 exit\n");
+        return NULL;
+    }
+    retry_count = 0;
+
+    printf("connect success\n");
+    int rc = mbtk_MQTTSubscribe(&Iot_mqtt->Client, Iot_mqtt->sub_topic, opts.qos, MQTTMessageArrived_Cb);
+    if (rc) {
+        printf("mqtt subscribe fail \n");
+        ret = -105;
+        return 0;
+    }
+    gateway.iotstatus = IOT_STATUS_CONNECT;
+    
+    pthread_create(&thread_ID, NULL, &mqtt_thread, (void *)Iot_mqtt);	//创建一个线程执行mqtt客户端
+    pthread_detach(thread_ID);	//设置线程结束收尸
+
+    while (1)
+    {
+        mbtk_MQTTPublish("my yes", 6, 0,&Iot_mqtt->Client,Iot_mqtt->pub_topic,2,0);//循环发布"my yes"
+        sleep(3);						//睡眠3s
+        i++;
+        if (i > 5)
+        {
+            mbtk_MQTTUnsubscribe(&Iot_mqtt->Client,Iot_mqtt->sub_topic);
+            break;
+        }
+    }
+    return 0;
+}
+
+
+
+
diff --git a/mbtk/test/mbtk_mqtt_test.c b/mbtk/test/mbtk_mqtt_test.c
new file mode 100755
index 0000000..5d99258
--- /dev/null
+++ b/mbtk/test/mbtk_mqtt_test.c
@@ -0,0 +1,127 @@
+#include <stdio.h>
+#include "mbtk_mqtt.h"
+#include "pthread.h"
+#include "string.h"
+#include "unistd.h"
+#include "sys/stat.h"
+#include "sys/types.h"
+#include "sys/socket.h"
+#include "netinet/in.h"
+#include "arpa/inet.h"
+#include "fcntl.h"
+#include "mbtk_sock2.h"
+
+
+struct opts_struct opts = {
+    (char *)"iot-dev", 0, (char *)"\n", QOS0, "admin", "password", (char *)"localhost", 1883, 0
+};//初始化结构体
+
+iot_device_info_t gateway = {
+    .iotstatus = IOT_STATUS_LOGIN,
+    .model = {"2022"},
+    .company = {"/my"}
+};//初始化主题
+
+static Cloud_MQTT_t *miot_mqtt;
+
+void set_mqtt_t(Cloud_MQTT_t *piot_mqtt)
+{
+    miot_mqtt = piot_mqtt;
+}
+Cloud_MQTT_t * get_mqtt_t()
+{
+    return miot_mqtt;
+}
+
+void mqtt_data_rx_cb(void *pbuf, int len)
+{
+
+    printf("data = %s\n", (unsigned char *)pbuf);	//打印接收到的数据
+}
+
+
+void MQTTMessageArrived_Cb(MessageData* md)
+{
+    MQTTMessage *message = md->message;
+
+    Cloud_MQTT_t *piot_mqtt = get_mqtt_t();
+
+    if (NULL != piot_mqtt->DataArrived_Cb) {
+        piot_mqtt->DataArrived_Cb((void *)message->payload, message->payloadlen);//异步消息体
+    }
+}
+
+void *mqtt_thread(void *arg)
+{
+    while (gateway.iotstatus != IOT_STATUS_DROP){
+        printf("gateway.iotstatus is %d\n",gateway.iotstatus);
+        iot_yield(arg,&gateway);									//维持服务器稳定,断开重连
+    }
+    printf("gateway.iotstatus is IOT_STATUS_DROP");
+//    mqtt_device_disconnect(arg);
+    pthread_exit(NULL);
+    return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+    if(argc >6 || argc < 4)
+    {
+        printf("input error.\n example:./mqtt_test 192.168.1.1 8080 clientid username password\n");
+        return 0;
+    }
+    int ret, len;
+    char will_msg[256] = {"hello world"};						//初始化遗嘱数据
+    static int retry_count = 0;
+    pthread_t thread_ID;      //定义线程id
+    static int i = 0;
+
+    Cloud_MQTT_t *Iot_mqtt;
+    Iot_mqtt = (Cloud_MQTT_t *)malloc(sizeof(Cloud_MQTT_t));
+    memset(Iot_mqtt,0x0,sizeof(Cloud_MQTT_t));
+
+    iot_mqtt_init(Iot_mqtt,argv[1],atoi(argv[2]),argv[3],argv[4],argv[5],30,3,"aaa","aaa",mqtt_data_rx_cb);									//初始化
+    mqtt_will_msg_set(Iot_mqtt, will_msg, strlen(will_msg));	//设置遗嘱
+    set_mqtt_t(Iot_mqtt);
+    ret = mqtt_device_connect(Iot_mqtt);						//初始化并连接mqtt服务器
+
+
+    while (ret < 0 && retry_count <= 5) {
+        printf("ret = %d\r\n", ret);
+        retry_count ++ ;
+        printf("retry_count = %d\n",retry_count);
+        sleep(3);
+        ret = mqtt_device_connect(Iot_mqtt);
+    }
+    if(ret < 0 && retry_count > 5)
+    {
+        printf("reconnect times more than 5 exit\n");
+        return NULL;
+    }
+    retry_count = 0;
+
+    printf("connect success\n");
+    int rc = mbtk_MQTTSubscribe(&Iot_mqtt->Client, Iot_mqtt->sub_topic, opts.qos, MQTTMessageArrived_Cb);
+    if (rc) {
+        printf("mqtt subscribe fail \n");
+        ret = -105;
+        return 0;
+    }
+    gateway.iotstatus = IOT_STATUS_CONNECT;
+
+    pthread_create(&thread_ID, NULL, &mqtt_thread, (void *)Iot_mqtt);	//创建一个线程执行mqtt客户端
+    pthread_detach(thread_ID);	//设置线程结束收尸
+
+    while (1)
+    {
+        mbtk_MQTTPublish("my yes", 6, 0,&Iot_mqtt->Client,Iot_mqtt->pub_topic,2,0);//循环发布"my yes"
+        sleep(3);						//睡眠3s
+        i++;
+        if (i > 5)
+        {
+            mbtk_MQTTUnsubscribe(&Iot_mqtt->Client,Iot_mqtt->sub_topic);
+            break;
+        }
+    }
+    return 0;
+}
diff --git a/mbtk/test/mbtk_net_control_test.c b/mbtk/test/mbtk_net_control_test.c
new file mode 100755
index 0000000..89e7a7f
--- /dev/null
+++ b/mbtk/test/mbtk_net_control_test.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define LOG_TAG "mbtk_net"
+#include "mbtk_type.h"
+#include "mbtk_net_control.h"
+#include "mbtk_log.h"
+
+
+int main(int argc, char *argv[])
+{
+    if(argc != 2) {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    LOGI("net_control start.");
+
+    if(!strcmp(argv[1], "on")) {
+        if(mbtk_net_enable(TRUE)) {
+            printf("Open Net fail.\n");
+        } else {
+            printf("Open Net success.\n");
+        }
+    } else if(!strcmp(argv[1], "off")) {
+        if(mbtk_net_enable(FALSE)) {
+            printf("Close Net fail.\n");
+        } else {
+            printf("Close Net success.\n");
+        }
+    } else if(!strcmp(argv[1], "get")) {
+        mbtk_net_state_t state = mbtk_net_state_get();
+        printf("Net State : %d\n", state);
+    } else {
+        printf("Unknown arg : %s\n", argv[1]);
+    }
+
+
+    LOGI("net_control exit.");
+    return 0;
+
+}
+
+
diff --git a/mbtk/test/polarssl_demo.c b/mbtk/test/polarssl_demo.c
new file mode 100755
index 0000000..d43b4d8
--- /dev/null
+++ b/mbtk/test/polarssl_demo.c
@@ -0,0 +1,479 @@
+#include <stdio.h>
+#include "mbtk_log.h"
+#include "ql/ql_mcm_sim.h"
+#include <sys/socket.h>
+#include <polarssl/net.h>
+#include <polarssl/ssl.h>
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#include <polarssl/certs.h>
+#include <polarssl/x509.h>
+#include <polarssl/error.h>
+#include <polarssl/debug.h>
+#include <polarssl/config.h>
+
+#define DFL_SERVER_NAME         "asr"
+#define DFL_SERVER_ADDR         NULL
+#define DFL_SERVER_PORT         4433
+#define DFL_REQUEST_PAGE        "/"
+#define DFL_REQUEST_SIZE        -1
+#define DFL_DEBUG_LEVEL         0
+#define DFL_NBIO                0
+#define DFL_CA_FILE             "/ca.crt"
+#define DFL_CA_PATH             "/ca.crt"
+#define DFL_CRT_FILE            "/client.crt"
+#define DFL_KEY_FILE            "/client.key"
+#define DFL_PSK                 ""
+#define DFL_PSK_IDENTITY        "Client_identity"
+#define DFL_FORCE_CIPHER        0
+#define DFL_RENEGOTIATION       SSL_RENEGOTIATION_DISABLED
+#define DFL_ALLOW_LEGACY        SSL_LEGACY_NO_RENEGOTIATION
+#define DFL_RENEGOTIATE         0
+#define DFL_EXCHANGES           1
+#define DFL_MIN_VERSION         SSL_MINOR_VERSION_3
+#define DFL_MAX_VERSION         SSL_MINOR_VERSION_3
+#define DFL_AUTH_MODE           SSL_VERIFY_REQUIRED
+#define DFL_MFL_CODE            SSL_MAX_FRAG_LEN_NONE
+#define DFL_TRUNC_HMAC          0
+#define DFL_RECONNECT           0
+#define DFL_RECO_DELAY          0
+#define DFL_TICKETS             SSL_SESSION_TICKETS_ENABLED
+#define DFL_ALPN_STRING         NULL
+
+#define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: "
+#define GET_REQUEST_END "\r\n\r\n"
+
+#define  CA_CERT \
+"-----BEGIN CERTIFICATE-----\r\n" \
+"MIIDKjCCAhICCQCOewfZiRCiNjANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJD\r\n" \
+"TjEQMA4GA1UECBMHU2lDaHVhbjEVMBMGA1UEChMMTU9CSUxFVEVLLkNBMQswCQYD\r\n" \
+"VQQLEwJJVDESMBAGA1UEAxMJTU9CSUxFVEVLMB4XDTE4MDkxODA4MDUzMloXDTMz\r\n" \
+"MDkxOTA4MDUzMlowVzELMAkGA1UEBhMCQ04xEDAOBgNVBAgTB1NpQ2h1YW4xFTAT\r\n" \
+"BgNVBAoTDE1PQklMRVRFSy5DQTELMAkGA1UECxMCSVQxEjAQBgNVBAMTCU1PQklM\r\n" \
+"RVRFSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOkdYJF1h1xjKbY0\r\n" \
+"ipbl88G653PiCh8ZMjmIUYeiDKC8+0wtXZtHvQIl6AncOzBy9XHVOctbKn34exC8\r\n" \
+"SEotMuo2T49vs9VtE8GYu2pOrf3m42NpLRnYAxfm9qw53CMHx+Jn7Oa9fnxa8haA\r\n" \
+"pRc2BTVadWGoS8EEwoZFk0eNb7Z2Gc7U0c+GhISI4oVTTocGvGgMzkvduu5JJbbc\r\n" \
+"BOcNFrii9sRO9vtOYQtqOEg01Uum2Dwp/o2bDLXNJEqAIh4WACiM4iPmmlRHWT2y\r\n" \
+"NjQ3vcbEdrFwbHRtO46+Vw54HnSyCoFb3uCHMNMvXObZ/8AU9E3Cgat4j0sgEeB0\r\n" \
+"hqA4MiMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAtEAjf0CjsLgG9ROdmp1qXYft\r\n" \
+"+ndIT5l82KRK57ZQsfdFbnJOvALeF/ICKU0M2TXgJNiGOA5RxDi00YYdMbOIPwVZ\r\n" \
+"JH4b87J/LYdLAGf+Q+kVI6gWH3hPm4Jzfzq/40KVrf3mpa54yWz6ZYtwfxBjrMgr\r\n" \
+"IVe0O5SIJ99lsddgzgUkqYN2vWJW2zZ50xuXOAyo+pOnjzX0wuOcaBT3JCHWJRAb\r\n" \
+"VhJCf9JbswDgnddJerqFtB8pnpAOdGokLCOoM06q3s3P9mhGX+72HXdX7G8CSAuG\r\n" \
+"PVCGf6RaF0/G4B9R1c3du3lZRlQWfx2pxyU0LS86iFQFWqzqcWEXIcULVdcErQ==\r\n" \
+"-----END CERTIFICATE-----\r\n"
+
+const char ca1_cert[]= CA_CERT;
+
+
+struct options
+{
+    const char *server_name;    /* hostname of the server (client only)     */
+    const char *server_addr;    /* address of the server (client only)      */
+    int server_port;            /* port on which the ssl service runs       */
+    int debug_level;            /* level of debugging                       */
+    int nbio;                   /* should I/O be blocking?                  */
+    const char *request_page;   /* page on server to request                */
+    int request_size;           /* pad request with header to requested size */
+    const char *ca_file;        /* the file with the CA certificate(s)      */
+    const char *ca_path;        /* the path with the CA certificate(s) reside */
+    const char *crt_file;       /* the file with the client certificate     */
+    const char *key_file;       /* the file with the client key             */
+    const char *psk;            /* the pre-shared key                       */
+    const char *psk_identity;   /* the pre-shared key identity              */
+    int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
+    int renegotiation;          /* enable / disable renegotiation           */
+    int allow_legacy;           /* allow legacy renegotiation               */
+    int renegotiate;            /* attempt renegotiation?                   */
+    int renego_delay;           /* delay before enforcing renegotiation     */
+    int exchanges;              /* number of data exchanges                 */
+    int min_version;            /* minimum protocol version accepted        */
+    int max_version;            /* maximum protocol version accepted        */
+    int auth_mode;              /* verify mode for connection               */
+    unsigned char mfl_code;     /* code for maximum fragment length         */
+    int trunc_hmac;             /* negotiate truncated hmac or not          */
+    int reconnect;              /* attempt to resume session                */
+    int reco_delay;             /* delay in seconds before resuming session */
+    int tickets;                /* enable / disable session tickets         */
+    const char *alpn_string;    /* ALPN supported protocols                 */
+} opt;
+
+
+static sim_client_handle_type cli_handle;
+int server_fd = -1;
+
+static void my_debug( void *ctx, int level, const char *str )
+{
+    ((void) level);
+
+    fprintf( (FILE *) ctx, "%s", str );
+    fflush(  (FILE *) ctx  );
+}
+
+
+static int ssl_client_init()
+{
+    int ret = 0, len, tail_len, i, written, frags;
+    unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
+    const char *pers = "ssl_client";
+
+    entropy_context entropy;
+    ctr_drbg_context ctr_drbg;
+    ssl_context ssl;
+    ssl_session saved_session;
+    x509_crt cacert;
+    x509_crt clicert;
+    pk_context pkey;
+
+    memset( &ssl, 0, sizeof( ssl_context ) );
+    memset( &saved_session, 0, sizeof( ssl_session ) );
+    x509_crt_init( &cacert );
+    x509_crt_init( &clicert );
+    pk_init( &pkey );
+
+    fflush( stdout );
+
+     /*
+     * 0. Initialize the RNG and the session data
+     */
+
+    entropy_init( &entropy );
+    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        printf( " failed\n  ! ctr_drbg_init returned -0x%x\n", -ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+     /*
+     * 1.1. Load the trusted CA
+     */
+    //ret = x509_crt_parse(&cacert,ca1_cert,strlen(ca1_cert));
+    ret = x509_crt_parse_file( &cacert, opt.ca_path );
+    if( ret < 0 )
+    {
+        printf( " failed\n  !  ca x509_crt_parse returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+    printf( " ok\n" );
+
+     /*
+     * 1.2. Load own certificate and private key
+     *
+     * (can be skipped if client authentication is not required)
+     */
+
+    ret = x509_crt_parse_file( &clicert, opt.crt_file );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  crt x509_crt_parse returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    ret = pk_parse_keyfile( &pkey, opt.key_file, NULL);
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  key x509_crt_parse returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+     /*
+     * 2. Setup stuff
+     */
+    printf( "  . Setting up the SSL/TLS structure..." );
+    fflush( stdout );
+
+    if( ( ret = ssl_init( &ssl ) ) != 0 )
+    {
+        printf( " failed\n  ! ssl_init returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
+    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+    ssl_set_authmode( &ssl, opt.auth_mode );
+
+    ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
+    ssl_set_dbg( &ssl, my_debug, stdout );
+
+    ssl_set_bio( &ssl, net_recv, &server_fd, net_send, &server_fd );
+
+    ssl_set_renegotiation( &ssl, opt.renegotiation );
+    ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
+
+    ssl_set_ca_chain( &ssl, &cacert, NULL, NULL );
+
+    if( ( ret = ssl_set_own_cert( &ssl, &clicert, &pkey ) ) != 0 )
+        {
+            printf( " failed\n  ! ssl_set_own_cert returned %d\n\n", ret );
+            goto exit;
+        }
+    if( opt.min_version != -1 )
+        ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+    if( opt.max_version != -1 )
+        ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+    printf( " ok\n" );
+    /*
+     * 3. Handshake
+     */
+    printf( "  . Performing the SSL/TLS handshake..." );
+    fflush( stdout );
+
+    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
+    {
+        if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
+        {
+            printf( " failed\n  ! ssl_handshake returned -0x%x\n", -ret );
+            if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
+                printf(
+                    "    Unable to verify the server's certificate. "
+                        "Either it is invalid,\n"
+                    "    or you didn't set ca_file or ca_path "
+                        "to an appropriate value.\n"
+                    "    Alternatively, you may want to use "
+                        "auth_mode=optional for testing purposes.\n" );
+            printf( "\n" );
+            goto exit;
+        }
+    }
+
+    printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
+            ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
+
+    /*
+     * 4. Verify the server certificate
+     */
+    printf( "  . Verifying peer X.509 certificate..." );
+
+    if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
+    {
+        printf( " failed\n" );
+
+        if( ( ret & BADCERT_EXPIRED ) != 0 )
+            printf( "  ! server certificate has expired\n" );
+
+        if( ( ret & BADCERT_REVOKED ) != 0 )
+            printf( "  ! server certificate has been revoked\n" );
+
+        if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
+            printf( "  ! CN mismatch (expected CN=%s)\n", opt.server_name );
+
+        if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
+            printf( "  ! self-signed or not signed by a trusted CA\n" );
+
+        printf( "\n" );
+    }
+    else
+        printf( " ok\n" );
+
+    if( ssl_get_peer_cert( &ssl ) != NULL )
+    {
+        printf( "  . Peer certificate information    ...\n" );
+        x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
+                       ssl_get_peer_cert( &ssl ) );
+        printf( "%s\n", buf );
+    }
+    /*
+     * 5. Write the GET request
+     */
+    printf( "  > Write to server:" );
+    fflush( stdout );
+
+    len = snprintf( (char *) buf, sizeof(buf) - 1, GET_REQUEST,
+                    opt.request_page );
+    tail_len = strlen( GET_REQUEST_END );
+
+    /* Add padding to GET request to reach opt.request_size in length */
+    if( opt.request_size != DFL_REQUEST_SIZE &&
+        len + tail_len < opt.request_size )
+    {
+        memset( buf + len, 'A', opt.request_size - len - tail_len );
+        len += opt.request_size - len - tail_len;
+    }
+
+    strncpy( (char *) buf + len, GET_REQUEST_END, sizeof(buf) - len - 1 );
+    len += tail_len;
+
+    /* Truncate if request size is smaller than the "natural" size */
+    if( opt.request_size != DFL_REQUEST_SIZE &&
+        len > opt.request_size )
+    {
+        len = opt.request_size;
+
+        /* Still end with \r\n unless that's really not possible */
+        if( len >= 2 ) buf[len - 2] = '\r';
+        if( len >= 1 ) buf[len - 1] = '\n';
+    }
+
+    for( written = 0, frags = 0; written < len; written += ret, frags++ )
+    {
+        while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 )
+        {
+            if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
+            {
+                printf( " failed\n  ! ssl_write returned -0x%x\n\n", -ret );
+                goto exit;
+            }
+        }
+    }
+
+    buf[written] = '\0';
+    printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
+
+    /*
+     * 6. Read the HTTP response
+     */
+    printf( "  < Read from server:" );
+    fflush( stdout );
+
+    do
+    {
+        len = sizeof( buf ) - 1;
+        memset( buf, 0, sizeof( buf ) );
+        ret = ssl_read( &ssl, buf, len );
+
+        if( ret == POLARSSL_ERR_NET_WANT_READ ||
+            ret == POLARSSL_ERR_NET_WANT_WRITE )
+            continue;
+
+        if( ret <= 0 )
+        {
+            switch( ret )
+            {
+                case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
+                    printf( " connection was closed gracefully\n" );
+                    ret = 0;
+                    goto close_notify;
+
+                case 0:
+                case POLARSSL_ERR_NET_CONN_RESET:
+                    printf( " connection was reset by peer\n" );
+                    ret = 0;
+                    goto exit;
+
+                default:
+                    printf( " ssl_read returned -0x%x\n", -ret );
+                    goto exit;
+            }
+        }
+
+        len = ret;
+        buf[len] = '\0';
+        printf( " %d bytes read\n\n%s", len, (char *) buf );
+
+        /* End of message should be detected according to the syntax of the
+         * application protocol (eg HTTP), just use a dummy test here. */
+        if( ret > 0 && buf[len-1] == '\n' )
+        {
+            ret = 0;
+            break;
+        }
+    }
+    while( 1 );
+
+    /*
+     * 7. Done, cleanly close the connection
+     */
+close_notify:
+        printf( "  . Closing the connection..." );
+
+        while( ( ret = ssl_close_notify( &ssl ) ) < 0 )
+        {
+            if( ret == POLARSSL_ERR_NET_CONN_RESET )
+            {
+                printf( " ok (already closed by peer)\n" );
+                ret = 0;
+                goto exit;
+            }
+
+            if( ret != POLARSSL_ERR_NET_WANT_READ &&
+                ret != POLARSSL_ERR_NET_WANT_WRITE )
+            {
+                printf( " failed\n  ! ssl_close_notify returned %d\n\n", ret );
+                goto exit;
+            }
+        }
+
+        printf( " ok\n" );
+exit:
+    if( server_fd )
+        net_close( server_fd );
+
+    x509_crt_free( &clicert );
+    x509_crt_free( &cacert );
+    pk_free( &pkey );
+    ssl_session_free( &saved_session );
+    ssl_free( &ssl );
+    ctr_drbg_free( &ctr_drbg );
+    entropy_free( &entropy );
+
+    printf( " ok end\n" );
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    printf("Start!\n");
+
+    opt.server_name         = DFL_SERVER_NAME;
+    opt.server_addr         = DFL_SERVER_ADDR;
+    opt.server_port         = DFL_SERVER_PORT;
+    opt.debug_level         = DFL_DEBUG_LEVEL;
+    opt.nbio                = DFL_NBIO;
+    opt.request_page        = DFL_REQUEST_PAGE;
+    opt.request_size        = DFL_REQUEST_SIZE;
+    opt.ca_file             = DFL_CA_FILE;
+    opt.ca_path             = DFL_CA_PATH;
+    opt.crt_file            = DFL_CRT_FILE;
+    opt.key_file            = DFL_KEY_FILE;
+    opt.psk                 = DFL_PSK;
+    opt.psk_identity        = DFL_PSK_IDENTITY;
+    opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
+    opt.renegotiation       = DFL_RENEGOTIATION;
+    opt.allow_legacy        = DFL_ALLOW_LEGACY;
+    opt.renegotiate         = DFL_RENEGOTIATE;
+    opt.exchanges           = DFL_EXCHANGES;
+    opt.min_version         = DFL_MIN_VERSION;
+    opt.max_version         = DFL_MAX_VERSION;
+    opt.auth_mode           = DFL_AUTH_MODE;
+    opt.mfl_code            = DFL_MFL_CODE;
+    opt.trunc_hmac          = DFL_TRUNC_HMAC;
+    opt.reconnect           = DFL_RECONNECT;
+    opt.reco_delay          = DFL_RECO_DELAY;
+    opt.tickets             = DFL_TICKETS;
+    opt.alpn_string         = DFL_ALPN_STRING;
+
+
+    if(argc < 3)
+    {
+        printf("input error \n example: mbtk_test ip prot\n");
+        return -1;
+    }
+    opt.server_addr = argv[1];
+    opt.server_port = atoi(argv[2]);
+
+    int ret = -1;
+    if( ( ret = net_connect( &server_fd, opt.server_addr,
+                                         opt.server_port ) ) != 0 )
+    {
+        printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
+        return -1;
+    }
+
+    ret = net_set_nonblock( server_fd );
+    if( ret != 0 )
+    {
+        printf( " failed\n  ! net_set_(non)block() returned -0x%x\n\n", -ret );
+        return -1;
+    }
+    printf( " ok\n" );
+    ret = ssl_client_init();
+    printf("ret is %d\n",ret);
+    printf("End!\n");
+    return 0;
+}
diff --git a/mbtk/test/ql_DSI_ConnectManager_test.c b/mbtk/test/ql_DSI_ConnectManager_test.c
new file mode 100755
index 0000000..ae7edcc
--- /dev/null
+++ b/mbtk/test/ql_DSI_ConnectManager_test.c
@@ -0,0 +1,364 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "ql/DSI_ConnectManager.h"
+#include "mbtk_log.h"
+
+static void help()
+{
+    printf("apn_get <cid> : Get current apns.\n");
+    printf("apn <cid> <0/1/2> <apn> [<user> <pass> <auth>] : Set apn (IPV4V6/IPV4/IPV6).\n");
+    printf("data_call <0/1/2> <cid> <timeout>: Stop/Start/State data call.\n");
+    printf("data_call_ex <0/1/2> <cid> <timeout>: Stop/Start/State data call.\n");
+}
+
+static int proc_exit()
+{
+    int err = ql_wan_release();
+    if(err)
+    {
+        printf("ql_wan_release fail.");
+        return -1;
+    }
+    return 0;
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (类似 SIGINT ,但要产生core文件)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTERM:// 默认kill   (同 SIGKILL ,但 SIGKILL 不可捕获)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (同 SIGSTOP ,但 SIGSTOP 不可捕获)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // 如空指针
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+static void data_call_status_cb(int status)
+{
+    printf("DATA_CALL_STATE:%d\n", status);
+}
+
+static void data_call_ex_status_cb(int cid,int iptype,int status,int cause)
+{
+    printf("DATA_CALL_EX_STATE:%d, %d, %d, %d\n", cid, iptype, status, cause);
+}
+
+int main(int argc, char *argv[])
+{
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+    mbtk_log_init(NULL,"MBTK_QL_TEST");
+
+    //test2(0, "192.168.1.198");
+    //test2(1, "2409:8162:140:cd3c:1:2:1494:72ba");
+    //test2(1, "254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239");
+    //test2(1, "2400:3200::1");
+
+    int err = ql_wan_init();
+    if(err)
+    {
+        printf("ql_wan_init fail.");
+        return -1;
+    }
+
+    printf(">>>>>>>>>>>>>>>>>>>>>>>>Enter cmd:\n");
+    char cmd[100];
+    while(1)
+    {
+        memset(cmd, 0, 100);
+        if(fgets(cmd, 100, stdin))
+        {
+            char *ptr = cmd + strlen(cmd) - 1;
+            while(ptr >= cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+
+            if(!strncasecmp(cmd, "apn", 3)){
+                if(!strncasecmp(cmd, "apn_get", 7)) { // Get apn
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    int cid = atoi(ptr);
+                    int ip_type = -1;
+                    char apn[128] = {0};
+                    char userName[128] = {0};
+                    char password[128] = {0};
+                    int auth = -1;
+                    err = ql_wan_getapn(cid, &ip_type, apn, 128, userName, 128, password, 128, &auth);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("APN : %d, %d, %s, %s, %s, %d\n", cid, ip_type, apn, userName, password, auth);
+                    }
+                } else { // apn <cid> <0/1/2> <apn> [<user> <pass> <auth>]
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    int cid = atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    int ip_type = atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    char apn[128] = {0};
+                    memcpy(apn, ptr, strlen(ptr));
+                    char *tmp = apn;
+                    while(*tmp) {
+                        if(*tmp == ' ') {
+                            *tmp = '\0';
+                            break;
+                        }
+                        tmp++;
+                    }
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL) {
+                        err = ql_wan_setapn(cid, ip_type, apn, NULL, NULL, QL_DSI_AUTH_PREF_NULL);
+                    } else {
+                        while(*ptr != '\0' && *ptr == ' ')
+                            ptr++;
+                        char user[128] = {0};
+                        memcpy(user, ptr, strlen(ptr));
+                        tmp = user;
+                        while(*tmp) {
+                            if(*tmp == ' ') {
+                                *tmp = '\0';
+                                break;
+                            }
+                            tmp++;
+                        }
+
+                        ptr = strstr(ptr, " ");
+                        if(ptr == NULL)
+                            continue;
+                        while(*ptr != '\0' && *ptr == ' ')
+                            ptr++;
+                        char pass[128] = {0};
+                        memcpy(pass, ptr, strlen(ptr));
+                        tmp = pass;
+                        while(*tmp) {
+                            if(*tmp == ' ') {
+                                *tmp = '\0';
+                                break;
+                            }
+                            tmp++;
+                        }
+
+                        ptr = strstr(ptr, " ");
+                        if(ptr == NULL)
+                            continue;
+                        while(*ptr != '\0' && *ptr == ' ')
+                            ptr++;
+                        QL_DSI_AUTH_PREF_T auth  = (QL_DSI_AUTH_PREF_T)atoi(ptr);
+
+                        err = ql_wan_setapn(cid, ip_type, apn, user, pass, auth);
+                    }
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("APN set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "data_call_ex", 12)){ // data_call_ex <0/1/2> <cid> <timeout>
+                // data_call <0/1/2> <cid> <timeout>
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int type = atoi(ptr);
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int cid = atoi(ptr);
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int timeout = atoi(ptr);
+
+                switch (type)
+                {
+                    case 0:
+                        err = ql_wan_stop(cid);
+                        break;
+                    case 1:
+                        err = ql_wan_start_ex(cid, 1, data_call_ex_status_cb);
+                        break;
+                    case 2: {
+                        ql_data_call_info info;
+                        err = ql_get_data_call_info(cid, &info);
+                        if(!err) {
+                            printf("cid : %d, ip_type : %d\n", info.profile_idx, info.ip_type);
+                            if(info.v4.state) {
+                                printf("%s: %s, %s, %s\n", info.v4.addr.name, info.v4.addr.ip, info.v4.addr.pri_dns, info.v4.addr.sec_dns);
+                            } else {
+                                printf("IPV4 not available.\n");
+                            }
+
+                            if(info.v6.state) {
+                                printf("%s: %s, %s, %s\n", info.v6.addr.name, info.v6.addr.ip, info.v6.addr.pri_dns, info.v6.addr.sec_dns);
+                            } else {
+                                printf("IPV6 not available.\n");
+                            }
+                        }
+                        break;
+                    }
+                    default:
+                        printf("Type error:%d\n", type);
+                        break;
+                }
+
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("DATA_CALL success\n");
+                }
+            } else if(!strncasecmp(cmd, "data_call", 9)){ // data_call <0/1/2> <cid> <timeout>
+                // data_call <0/1/2> <cid> <timeout>
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int type = atoi(ptr);
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int cid = atoi(ptr);
+
+                ptr = strstr(ptr, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                int timeout = atoi(ptr);
+
+                switch (type)
+                {
+                    case 0:
+                        err = ql_wan_stop(cid);
+                        break;
+                    case 1:
+                        err = ql_wan_start(cid, 1, data_call_status_cb);
+                        break;
+                    case 2: {
+                        ql_data_call_info info;
+                        err = ql_get_data_call_info(cid, &info);
+                        if(!err) {
+                            printf("cid : %d, ip_type : %d\n", info.profile_idx, info.ip_type);
+                            if(info.v4.state) {
+                                printf("%s: %s, %s, %s\n", info.v4.addr.name, info.v4.addr.ip, info.v4.addr.pri_dns, info.v4.addr.sec_dns);
+                            } else {
+                                printf("IPV4 not available.\n");
+                            }
+
+                            if(info.v6.state) {
+                                printf("%s: %s, %s, %s\n", info.v6.addr.name, info.v6.addr.ip, info.v6.addr.pri_dns, info.v6.addr.sec_dns);
+                            } else {
+                                printf("IPV6 not available.\n");
+                            }
+                        }
+                        break;
+                    }
+                    default:
+                        printf("Type error:%d\n", type);
+                        break;
+                }
+
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("DATA_CALL success\n");
+                }
+            }
+            else if(!strcasecmp(cmd, "h") || !strcasecmp(cmd, "help")) {
+                help();
+            } else if(!strcasecmp(cmd, "q")) {
+                break;
+            } else {
+                printf("\n");
+            }
+        }
+    }
+
+    proc_exit();
+
+    LOGI("Client exec complete.");
+#if 1
+    while(1)
+    {
+        sleep(1000 * 365 * 24 * 60 * 60);
+    }
+#else
+    sleep(1);
+#endif
+    return 0;
+}
+
diff --git a/mbtk/test/ql_adc_test.c b/mbtk/test/ql_adc_test.c
new file mode 100755
index 0000000..6eb83f6
--- /dev/null
+++ b/mbtk/test/ql_adc_test.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+#include "ql/ql_adc.h"
+
+int main(int argc, char *argv[])
+{
+    int adc = ql_adc_show(ADC0);
+    if(adc > 0) {
+        printf("ADC0 = %d\n", adc);
+    } else {
+        printf("Get ADC0 fail.\n");
+    }
+
+    adc = ql_adc_show(ADC1);
+    if(adc > 0) {
+        printf("ADC1 = %d\n", adc);
+    } else {
+        printf("Get ADC1 fail.\n");
+    }
+    return 0;
+}
+
diff --git a/mbtk/test/ql_call_test.c b/mbtk/test/ql_call_test.c
new file mode 100755
index 0000000..3d41fed
--- /dev/null
+++ b/mbtk/test/ql_call_test.c
@@ -0,0 +1,283 @@
+#include "mbtk_type.h"
+#include "ql/ql_at.h"
+#include "ql/ql_vcall.h"
+#include "ql/ql_mcm_call.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}
+};
+
+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;
+    }
+}
+
+#if 0
+int main(int argc, char *argv[])
+{
+    int    cmdIdx  = 0;
+    int    ret     = E_QL_OK;
+    char   phoneNum[32] = {0};
+    voice_client_handle_type    h_voice     = 0;
+    int                         voice_call_id = 0;
+
+    printf("QL_Voice_Call_Client_Init .....\n");
+    ret = QL_Voice_Call_Client_Init(&h_voice);
+    if(ret < 0)
+    {
+        printf("QL_Voice_Call_Client_Init FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    printf("QL_Voice_Call_Client_Init ret = %d, with h_voice=%d\n", ret, h_voice);
+
+    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);
+        return -1;
+    }
+    printf("QL_Voice_Call_AddCommonStateHandler ret = %d\n", ret);
+
+    print_help();
+
+    while(1)
+    {
+        printf("please input cmd index(-1 exit): ");
+        scanf("%d", &cmdIdx);
+        if(cmdIdx == -1)
+        {
+            break;
+        }
+
+        switch(cmdIdx)
+        {
+        case 0://"print_help"
+        {
+            print_help();
+            break;
+        }
+       	case 1://"QL_Voice_Call_Ecall"
+        {
+            char    PhoneNum[32]                  = {0};
+            printf("please input dest phone number: \n");
+            scanf("%s", PhoneNum);
+
+			char    msd[140+1]                  = {0};
+            printf("please input msd content: \n");
+            scanf("%s", msd);
+
+            E_QL_MCM_ECALL_VARIANT_T ecall_mode;
+            printf("please input ecall mode(1:test 2:emergency): \n");
+            scanf("%d", &ecall_mode);
+            QL_Voice_Call_Start(h_voice, E_QL_VCALL_EXTERNAL_SLOT_1, PhoneNum, NULL);
+            // ret = QL_Voice_Call_Ecall(h_voice, E_QL_VCALL_EXTERNAL_SLOT_1, PhoneNum,
+            //                           ecall_mode, &voice_call_id);
+			printf(" voice_call_id = %d\n", voice_call_id);
+            printf(" ret = %d\n", ret);
+            break;
+        }
+        case 2://QL_Voice_Call_Ecall_HangUp
+        {
+            ret = QL_Voice_Call_Ecall_HangUp(h_voice);
+            printf(" ret = %d\n", ret);
+            break;
+        }
+
+       default:
+            print_help();
+            break;
+        }
+    }
+
+    ret = QL_Voice_Call_RemoveCommonStateHandler(h_voice);
+    if(ret < 0)
+    {
+        printf("QL_Voice_Call_RemoveCommonStateHandler.	ret:%d\n",ret);
+        return -1;
+    }
+    printf("QL_Voice_Call_RemoveCommonStateHandler ret = %d\n", ret);
+
+    ret = QL_Voice_Call_Client_Deinit(h_voice);
+    if(ret < 0)
+    {
+        printf("QL_Voice_Call_Client_Deinit FAIL.	ret:%d\n",ret);
+        return -1;
+    }
+    printf("QL_Voice_Call_Client_Deinit ret = %d, with h_voice=%d\n", ret, h_voice);
+
+    return 0;
+}
+#else
+
+int main(int argc, char *argv[])
+{
+    char operator[10];
+    int opt;
+    int    ret     = E_QL_OK;
+    char   phoneNum[32] = {0};
+    voice_client_handle_type    h_voice     = 0;
+
+    while(1)
+    {
+        printf("=========call main=========\n"
+            "\t0 exit\n"
+            "\t1 call init\n"
+            "\t2 call register handle\n"
+            "\t3 call start\n"
+            "\t4 call end\n"
+            "\t5 call answer\n"
+            "\t6 call set auto answer\n"
+            "\t7 call hold\n"
+            "\t8 call unhold\n"
+            "\t9 call deinit\n"
+            "operator: >> ");
+
+        fgets(operator, sizeof(operator), stdin);
+        fflush(stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+        case 0:
+            printf("main exit\n");
+            return 0;
+        case 1:
+            ret = QL_Voice_Call_Client_Init(&h_voice);
+            if(ret < 0)
+            {
+                printf("QL_Voice_Call_Client_Init FAIL.	ret:%d\n",ret);
+                return -1;
+            }
+            printf("QL_Voice_Call_Client_Init ret = %d, with h_voice=%d\n", ret, h_voice);
+
+            break;
+        case 2:
+            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);
+                return -1;
+            }
+            break;
+        case 3:
+            QL_Voice_Call_Start(h_voice, 0, "15982066434", NULL);
+            break;
+        case 4:
+            QL_Voice_Call_End(h_voice, 0);
+            break;
+        case 5:
+            QL_Voice_Call_Answer(h_voice, 0);
+            break;
+        case 6:
+            QL_Voice_Call_SetAutoAnswer(h_voice, E_QL_MCM_VOICE_AUTO_ANSWER_ENABLE, 6000);
+            break;
+        case 7:
+            QL_Voice_Call_Hold(h_voice);
+            break;
+        case 8:
+            QL_Voice_Call_UnHold(h_voice);
+            break;
+        case 9:
+            QL_Voice_Call_Client_Deinit(h_voice);
+            break;
+        case 10:
+            // QL_Voice_Call_UnHold;
+            break;
+        default:
+            break;
+        }
+
+        sleep(1);
+    }
+
+    return 0;
+}
+#endif
diff --git a/mbtk/test/ql_dev_test.c b/mbtk/test/ql_dev_test.c
new file mode 100755
index 0000000..105f460
--- /dev/null
+++ b/mbtk/test/ql_dev_test.c
@@ -0,0 +1,201 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "ql/ql_dev.h"
+#include "mbtk_log.h"
+
+static void help()
+{
+    printf("version: Get version.\n");
+    printf("imei: Get IMEI.\n");
+    printf("sn: Get SN.\n");
+    printf("model: Get Model.\n");
+    printf("cfun: Get radio state.\n");
+    printf("cfun <state> <rest>: Set radio state.\n");
+}
+
+static int proc_exit()
+{
+    QL_DEV_ERROR_CODE err = ql_dev_release();
+    if(QL_DEV_SUCCESS != err)
+    {
+        printf("ql_dev_release fail.");
+        return -1;
+    }
+    return 0;
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (类似 SIGINT ,但要产生core文件)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTERM:// 默认kill   (同 SIGKILL ,但 SIGKILL 不可捕获)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (同 SIGSTOP ,但 SIGSTOP 不可捕获)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // 如空指针
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+    mbtk_log_init(NULL,"MBTK_QL_TEST");
+
+    //test2(0, "192.168.1.198");
+    //test2(1, "2409:8162:140:cd3c:1:2:1494:72ba");
+    //test2(1, "254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239");
+    //test2(1, "2400:3200::1");
+
+    QL_DEV_ERROR_CODE err = ql_dev_init();
+    if(QL_DEV_SUCCESS != err)
+    {
+        printf("ql_dev_init fail.");
+        return -1;
+    }
+
+    printf(">>>>>>>>>>>>>>>>>>>>>>>>Enter cmd:\n");
+    char cmd[100];
+    while(1)
+    {
+        memset(cmd, 0, 100);
+        if(fgets(cmd, 100, stdin))
+        {
+            char *ptr = cmd + strlen(cmd) - 1;
+            while(ptr >= cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+
+            if(!strncasecmp(cmd, "version", 7))
+            {
+                char version[50] = {0};
+                err = ql_dev_get_firmware_version(version);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Version : %s\n", version);
+                }
+            } else if(!strncasecmp(cmd, "imei", 4)){
+                char imei[50] = {0};
+                err = ql_dev_get_imei(imei);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("IMEI : %s\n", imei);
+                }
+            } else if(!strncasecmp(cmd, "sn", 2)){
+                char sn[50] = {0};
+                err = ql_dev_get_sn(sn);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("SN : %s\n", sn);
+                }
+            } else if(!strncasecmp(cmd, "model", 5)){
+                char model[50] = {0};
+                err = ql_dev_get_model(model);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Model : %s\n", model);
+                }
+            } else if(!strncasecmp(cmd, "cfun", 4)){
+                int cfun;
+                if(!strcasecmp(cmd, "cfun")) { // Get
+                    err = ql_dev_get_modem_fun(&cfun);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Cfun : %d\n", cfun);
+                    }
+                } else { // Set
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    cfun = atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    int rst = atoi(ptr);
+                    err = ql_dev_set_modem_fun((QL_DEV_MODEM_FUNCTION)cfun, rst);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("cfun set success\n");
+                    }
+                }
+            }
+            else if(!strcasecmp(cmd, "h") || !strcasecmp(cmd, "help")) {
+                help();
+            } else if(!strcasecmp(cmd, "q")) {
+                break;
+            } else {
+                printf("\n");
+            }
+        }
+    }
+
+    proc_exit();
+
+    LOGI("Client exec complete.");
+#if 1
+    while(1)
+    {
+        sleep(1000 * 365 * 24 * 60 * 60);
+    }
+#else
+    sleep(1);
+#endif
+    return 0;
+}
+
diff --git a/mbtk/test/ql_gpio_test.c b/mbtk/test/ql_gpio_test.c
new file mode 100755
index 0000000..c2b2754
--- /dev/null
+++ b/mbtk/test/ql_gpio_test.c
@@ -0,0 +1,44 @@
+#include "ql/ql_gpio.h"
+#include "mbtk_log.h"
+
+int main(int argc, char *argv[])
+{
+    mbtk_log_init("radio", "MBTK_GPIO");
+
+    if(argc != 2) {
+        printf("./gpio_test <gpio>\n");
+        return -1;
+    }
+
+    int tmp_gpio = atoi(argv[1]);
+    if(tmp_gpio <= 0) {
+        printf("GPIO error : %d\n", tmp_gpio);
+        return -1;
+    }
+
+    Enum_PinName gpio = (Enum_PinName)tmp_gpio;
+    if(Ql_GPIO_Init(gpio, PINDIRECTION_OUT, PINLEVEL_LOW, PINPULLSEL_DISABLE)) {
+        printf("Ql_GPIO_Init() fail.\n");
+        return -1;
+    }
+
+    printf("GPIO : %d, dir : %s, level : %d\n", gpio, Ql_GPIO_GetDirection(gpio) == PINDIRECTION_IN ? "in" : "out",
+        Ql_GPIO_GetLevel(gpio));
+
+    if(Ql_GPIO_SetLevel(gpio, PINLEVEL_HIGH)) {
+        printf("Ql_GPIO_SetLevel() fail.\n");
+        return -1;
+    }
+
+    printf("GPIO : %d, dir : %s, level : %d\n", gpio, Ql_GPIO_GetDirection(gpio) == PINDIRECTION_IN ? "in" : "out",
+        Ql_GPIO_GetLevel(gpio));
+
+    if(Ql_GPIO_Uninit(gpio)) {
+        printf("Ql_GPIO_Uninit() fail.\n");
+        return -1;
+    }
+
+    printf("Success!!!\n");
+    return 0;
+}
+
diff --git a/mbtk/test/ql_i2c_test.c b/mbtk/test/ql_i2c_test.c
new file mode 100755
index 0000000..04aed4d
--- /dev/null
+++ b/mbtk/test/ql_i2c_test.c
@@ -0,0 +1,31 @@
+#include "ql/ql_i2c.h"
+
+
+int main(int argc, char *argv[])
+{
+	int fd = -1;
+    if(argc != 2) {
+        printf("./i2c_test <dev>\n");
+        return -1;
+    }
+    char send_data[64] = {0};
+	send_data[0] = 0x55;
+	send_data[1] = 0x00;
+	send_data[2] = 0x84;
+    fd= Ql_I2C_Init(argv[1]);
+    if(fd <= 0) {
+        printf("Ql_I2C_Init() fail.\n");
+        return -1;
+    }
+
+	if(Ql_I2C_Write(fd, 0x12, 0x10,send_data, 3) < 0) {
+        printf("Ql_I2C_Write() fail.\n");
+        return -1;
+	}
+
+    Ql_I2C_Deinit(fd);
+
+    printf("Success!!!\n");
+
+    return 0;
+}
diff --git a/mbtk/test/ql_nw_test.c b/mbtk/test/ql_nw_test.c
new file mode 100755
index 0000000..81acb5c
--- /dev/null
+++ b/mbtk/test/ql_nw_test.c
@@ -0,0 +1,334 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "ql/ql_nw.h"
+#include "mbtk_log.h"
+
+static void help()
+{
+    printf("net_pref : Get net prefferred.\n");
+    printf("net_pref <net_pref> <roaming> : Set net prefferred.\n");
+    printf("net_time : Get network time.\n");
+    printf("operator : Get current operator information.\n");
+    printf("net_avail : Get available networks.\n");
+    printf("reg : Get current reg info.\n");
+    printf("sel_mode: Get network select mode.\n");
+    printf("sel_mode <sel_mode> <net_type> <plmn>: Set network select mode.\n");
+    printf("signal : Get current signal.\n");
+    printf("cell : Get cell info.\n");
+    printf("volte : Get VOLTE state.\n");
+    printf("csq_signal : Get current csq signal.\n");
+}
+
+static int proc_exit()
+{
+    QL_NW_ERROR_CODE err = ql_nw_release();
+    if(QL_NW_SUCCESS != err)
+    {
+        printf("ql_nw_release fail.");
+        return -1;
+    }
+    return 0;
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (类似 SIGINT ,但要产生core文件)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTERM:// 默认kill   (同 SIGKILL ,但 SIGKILL 不可捕获)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (同 SIGSTOP ,但 SIGSTOP 不可捕获)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // 如空指针
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+    mbtk_log_init(NULL,"MBTK_QL_TEST");
+
+    //test2(0, "192.168.1.198");
+    //test2(1, "2409:8162:140:cd3c:1:2:1494:72ba");
+    //test2(1, "254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239");
+    //test2(1, "2400:3200::1");
+
+    QL_NW_ERROR_CODE err = ql_nw_init();
+    if(QL_NW_SUCCESS != err)
+    {
+        printf("ql_nw_init fail.");
+        return -1;
+    }
+
+    printf(">>>>>>>>>>>>>>>>>>>>>>>>Enter cmd:\n");
+    char cmd[100];
+    while(1)
+    {
+        memset(cmd, 0, 100);
+        if(fgets(cmd, 100, stdin))
+        {
+            char *ptr = cmd + strlen(cmd) - 1;
+            while(ptr >= cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+
+            if(!strncasecmp(cmd, "net_pref", 8)){
+                QL_NW_CONFIG_INFO_T net_pref;
+                if(!strcasecmp(cmd, "net_pref")) { // Get
+                    err = ql_nw_get_config(&net_pref);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("net_pref : %d, roaming : %d\n", net_pref.preferred_nw_mode, net_pref.roaming_pref);
+                    }
+                } else { // Set
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net_pref.preferred_nw_mode = atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net_pref.roaming_pref = atoi(ptr);
+
+                    err = ql_nw_set_config(&net_pref);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("net_pref set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "net_time", 8)){
+                QL_NW_NITZ_TIME_INFO_T time;
+                err = ql_nw_get_nitz_time_info(&time);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Time : %s, %ld, %d\n", time.nitz_time, time.abs_time, time.leap_sec);
+                }
+            } else if(!strncasecmp(cmd, "operator", 8)){
+                QL_NW_OPERATOR_INFO_T operator;
+                err = ql_nw_get_operator_name(&operator);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Operator : %s, %s, %s, %s\n", operator.long_eons, operator.short_eons, operator.mcc, operator.mnc);
+                }
+            } else if(!strncasecmp(cmd, "net_avail", 9)){
+                QL_NW_SCAN_RESULT_LIST_INFO_T nets;
+                err = ql_nw_perform_scan(&nets);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    if(nets.entry_len > 0) {
+                        int i = 0;
+                        for(; i < nets.entry_len; i++) {
+                            printf("Net %d: %d, %d, %s, %s, %s, %s\n", i+1, nets.entry[i].status, nets.entry[i].act,
+                                nets.entry[i].operator_name.long_eons, nets.entry[i].operator_name.short_eons,
+                                nets.entry[i].operator_name.mcc, nets.entry[i].operator_name.mnc);
+                        }
+                    }
+                }
+            } else if(!strncasecmp(cmd, "reg", 3)){
+                QL_NW_REG_STATUS_INFO_T reg;
+                err = ql_nw_get_reg_status(&reg);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Data Reg:%d, %d, %x, %x\n", reg.data_reg.state, reg.data_reg.rat, reg.data_reg.lac, reg.data_reg.cid);
+                    printf("Voice Reg:%d, %d, %x, %x\n", reg.voice_reg.state, reg.voice_reg.rat, reg.voice_reg.lac, reg.voice_reg.cid);
+                }
+            } else if(!strncasecmp(cmd, "sel_mode", 8)){ // "sel_mode" or "sel_mode 460 00 7"
+                QL_NW_SELECTION_INFO_T net;
+                memset(&net, 0, sizeof(QL_NW_SELECTION_INFO_T));
+                if(!strcasecmp(cmd, "sel_mode")) { // Get
+                    err = ql_nw_get_selection(&net);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Net : %d, %s, %s, %d\n", net.nw_selection_mode , net.mcc , net.mnc , net.act);
+                    }
+                } else { // Set
+                    char *ptr = strstr(cmd, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net.nw_selection_mode = atoi(ptr);
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    //net.mcc = (uint8)atoi(ptr);
+                    memcpy(net.mcc, ptr, 4);
+                    int i = 0;
+                    while(i < 4) {
+                        if(net.mcc[i] == ' ') {
+                            net.mcc[i] = '\0';
+                            break;
+                        }
+                        i++;
+                    }
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    //net.mnc = (uint32)atoi(ptr);
+                    memcpy(net.mnc, ptr, 4);
+                    i = 0;
+                    while(i < 4) {
+                        if(net.mnc[i] == ' ') {
+                            net.mnc[i] = '\0';
+                            break;
+                        }
+                        i++;
+                    }
+
+                    ptr = strstr(ptr, " ");
+                    if(ptr == NULL)
+                        continue;
+                    while(*ptr != '\0' && *ptr == ' ')
+                        ptr++;
+                    net.act = (QL_NW_ACCESS_TECHNOLOGY)atoi(ptr);
+
+                    err = ql_nw_set_selection(&net);
+                    if(err) {
+                        printf("Error : %d\n", err);
+                    } else {
+                        printf("Net select mode set success\n");
+                    }
+                }
+            } else if(!strncasecmp(cmd, "signal", 6)){
+                QL_NW_SIGNAL_STRENGTH_INFO_T sig;
+                err = ql_nw_get_signal_strength(&sig);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Signal GSM:%d, %d, %d, %d\n", sig.GW_SignalStrength.rscp, sig.GW_SignalStrength.bitErrorRate, sig.GW_SignalStrength.rscp, sig.GW_SignalStrength.ecio);
+                    printf("Signal LTE:%d, %d, %d, %d, %d\n", sig.LTE_SignalStrength.rssi , sig.LTE_SignalStrength.rsrp, sig.LTE_SignalStrength.rsrq, sig.LTE_SignalStrength.rssnr, sig.LTE_SignalStrength.cqi);
+                }
+            } else if(!strncasecmp(cmd, "cell", 4)){
+                QL_NW_CELL_INFO_T cell;
+                err = ql_nw_get_cell_info(&cell);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    int i = 0;
+                    if(cell.gsm_info_valid) {
+                        while(i < cell.gsm_info_num) {
+                            printf("GSM cell %d: %d, %x, %d, %d, %x, %d, %d\n", i + 1, cell.gsm_info[i].flag, cell.gsm_info[i].cid, cell.gsm_info[i].mcc, cell.gsm_info[i].mnc, cell.gsm_info[i].lac, cell.gsm_info[i].arfcn, cell.gsm_info[i].bsic);
+                            i++;
+                        }
+                    }
+
+                    if(cell.umts_info_valid) {
+                        i = 0;
+                        while(i < cell.umts_info_num) {
+                            printf("UMTS cell %d: %d, %x, %x, %d, %d, %x, %d, %d\n", i + 1, cell.umts_info[i].flag , cell.umts_info[i].cid, cell.umts_info[i].lcid, cell.umts_info[i].mcc, cell.umts_info[i].mnc, cell.umts_info[i].lac, cell.umts_info[i].uarfcn, cell.umts_info[i].psc);
+                            i++;
+                        }
+                    }
+
+                    if(cell.lte_info_valid) {
+                        i = 0;
+                        while(i < cell.lte_info_num) {
+                            printf("LTE cell %d: %d, %x, %d, %d, %x, %d, %d\n", i + 1, cell.lte_info[i].flag, cell.lte_info[i].cid, cell.lte_info[i].mcc, cell.lte_info[i].mnc, cell.lte_info[i].tac, cell.lte_info[i].pci, cell.lte_info[i].earfcn);
+                            i++;
+                        }
+                    }
+                }
+            } else if(!strncasecmp(cmd, "volte", 5)){
+                VOLTE_STATE state;
+                err = ql_nw_get_volte_state(&state);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("VOLTE state : %d\n", state.reg_state);
+                }
+            } else if(!strncasecmp(cmd, "csq_signal", 10)){
+                QL_NW_CSQ_SIGNAL_STRENGTH_INFO_T signal;
+                err = ql_nw_csq_get_signal_strength(&signal);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("+CSQ : %d, %d\n", signal.rssi, signal.bitErrorRate);
+                }
+            }
+            else if(!strcasecmp(cmd, "h") || !strcasecmp(cmd, "help")) {
+                help();
+            } else if(!strcasecmp(cmd, "q")) {
+                break;
+            } else {
+                printf("\n");
+            }
+        }
+    }
+
+    proc_exit();
+
+    LOGI("Client exec complete.");
+#if 1
+    while(1)
+    {
+        sleep(1000 * 365 * 24 * 60 * 60);
+    }
+#else
+    sleep(1);
+#endif
+    return 0;
+}
+
diff --git a/mbtk/test/ql_sim_test.c b/mbtk/test/ql_sim_test.c
new file mode 100755
index 0000000..f907ab3
--- /dev/null
+++ b/mbtk/test/ql_sim_test.c
@@ -0,0 +1,274 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "ql/ql_sim.h"
+#include "mbtk_log.h"
+
+static void help()
+{
+    printf("imsi : Get IMSI.\n");
+    printf("iccid : Get ICCID.\n");
+    printf("pn : Get phone number.\n");
+    printf("pin_en <pin> : Enable pin.\n");
+    printf("pin_dis <pin> : Disable pin.\n");
+    printf("pin_ch <old_pin> <new_pin> : Change pin.\n");
+    printf("pin_verify <pin> : Verify pin.\n");
+    printf("puk_unlock <puk> <new_pin> : Unlock using PUK.\n");
+    printf("sim : Get sim state.\n");
+}
+
+static int proc_exit()
+{
+    QL_SIM_ERROR_CODE err = ql_sim_release();
+    if(QL_SIM_SUCCESS != err)
+    {
+        printf("ql_sim_release fail.");
+        return -1;
+    }
+    return 0;
+}
+
+static void sig_process(int sig)
+{
+    LOGI("I got signal %d\n", sig);
+    switch(sig)
+    {
+        case SIGINT: // Ctrl + C
+        {
+            LOGI("Exit by SIGINT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGQUIT: // Ctrl + \ (类似 SIGINT ,但要产生core文件)
+        {
+            LOGI("Exit by SIGQUIT.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTERM:// 默认kill   (同 SIGKILL ,但 SIGKILL 不可捕获)
+        {
+            LOGI("Exit by SIGTERM.\n");
+            proc_exit();
+            exit(0);
+        }
+        case SIGTSTP:// Ctrl + Z (同 SIGSTOP ,但 SIGSTOP 不可捕获)
+        {
+            LOGI("Exit by SIGTSTP.\n");
+            exit(0);
+        }
+        case SIGSEGV: // 如空指针
+        {
+            LOGI("Exit by SIGSEGV.\n");
+            exit(0);
+        }
+        default:
+        {
+            LOGI("Unknown sig:%d\n",sig);
+            break;
+        }
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    signal(SIGINT, sig_process);
+    signal(SIGQUIT, sig_process);
+    signal(SIGTERM, sig_process);
+    //signal(SIGTSTP, sig_process);
+    //signal(SIGSEGV, sig_process);
+
+    mbtk_log_init(NULL,"MBTK_QL_TEST");
+
+    //test2(0, "192.168.1.198");
+    //test2(1, "2409:8162:140:cd3c:1:2:1494:72ba");
+    //test2(1, "254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239");
+    //test2(1, "2400:3200::1");
+
+    QL_SIM_ERROR_CODE err = ql_sim_init();
+    if(QL_SIM_SUCCESS != err)
+    {
+        printf("ql_sim_init fail.");
+        return -1;
+    }
+
+    printf(">>>>>>>>>>>>>>>>>>>>>>>>Enter cmd:\n");
+    char cmd[100];
+    while(1)
+    {
+        memset(cmd, 0, 100);
+        if(fgets(cmd, 100, stdin))
+        {
+            char *ptr = cmd + strlen(cmd) - 1;
+            while(ptr >= cmd && (*ptr == '\r' || *ptr == '\n'))
+            {
+                *ptr-- = '\0';
+            }
+
+            if(!strncasecmp(cmd, "imsi", 4)){
+                char imsi[30];
+                err = ql_sim_get_imsi(imsi, 30);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("IMSI : %s\n", imsi);
+                }
+            }else if(!strncasecmp(cmd, "iccid", 5)){
+                char iccid[30];
+                err = ql_sim_get_iccid(iccid, 30);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("ICCID : %s\n", iccid);
+                }
+            }else if(!strncasecmp(cmd, "pn", 2)){
+                char phonenumber[30];
+                err = ql_sim_get_phonenumber(phonenumber, 30);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("PhoneNumber : %s\n", phonenumber);
+                }
+            }else if(!strncasecmp(cmd, "pin_en", 6)){ // pin_en <pin>
+                QL_SIM_VERIFY_PIN_INFO pin = {0};
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                memcpy(pin.pin_value, ptr, strlen(ptr));
+
+                err = ql_sim_enable_pin(&pin);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Enable PIN(%s) success.\n", pin.pin_value);
+                }
+            }else if(!strncasecmp(cmd, "pin_dis", 7)){ // pin_dis <pin>
+                QL_SIM_VERIFY_PIN_INFO pin = {0};
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                memcpy(pin.pin_value, ptr, strlen(ptr));
+
+                err = ql_sim_disable_pin(&pin);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Disable PIN(%s) success.\n", pin.pin_value);
+                }
+            }else if(!strncasecmp(cmd, "pin_ch", 6)){ // pin_ch <old_pin> <new_pin>
+                QL_SIM_CHANGE_PIN_INFO pin = {0};
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+
+                char *tmp = pin.old_pin_value;
+                while(*ptr != '\0' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
+                    *tmp++ = *ptr++;
+                }
+                *tmp = '\0';
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+
+                tmp = pin.new_pin_value;
+                while(*ptr != '\0' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
+                    *tmp++ = *ptr++;
+                }
+                *tmp = '\0';
+
+                err = ql_sim_change_pin(&pin);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Change PIN(%s -> %s) success.\n", pin.old_pin_value, pin.new_pin_value);
+                }
+            }else if(!strncasecmp(cmd, "pin_verify", 10)){ // pin_verify <pin>
+                QL_SIM_VERIFY_PIN_INFO pin = {0};
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+                memcpy(pin.pin_value, ptr, strlen(ptr));
+
+                err = ql_sim_verify_pin(&pin);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Verify PIN(%s) success.\n", pin.pin_value);
+                }
+            }else if(!strncasecmp(cmd, "puk_unlock", 10)){ // puk_unlock <puk> <new_pin>
+                QL_SIM_UNBLOCK_PIN_INFO pin = {0};
+                char *ptr = strstr(cmd, " ");
+                if(ptr == NULL)
+                    continue;
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+
+                char *tmp = pin.puk_value;
+                while(*ptr != '\0' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
+                    *tmp++ = *ptr++;
+                }
+                *tmp = '\0';
+                while(*ptr != '\0' && *ptr == ' ')
+                    ptr++;
+
+                tmp = pin.new_pin_value;
+                while(*ptr != '\0' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
+                    *tmp++ = *ptr++;
+                }
+                *tmp = '\0';
+
+                err = ql_sim_unblock_pin(&pin);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("PUI unlock(PUK:%s   PIN:%s) success.\n", pin.puk_value, pin.new_pin_value);
+                }
+            }else if(!strncasecmp(cmd, "sim", 3)){
+                QL_SIM_CARD_STATUS_INFO sim;
+                err = ql_sim_get_card_status(&sim);
+                if(err) {
+                    printf("Error : %d\n", err);
+                } else {
+                    printf("Sim type:%d, state:%d, PIN:%d,%d,%d,%d\n", sim.card_type, sim.card_state, sim.card_pin_info.pin1_num_retries, sim.card_pin_info.pin2_num_retries, sim.card_pin_info.puk1_num_retries, sim.card_pin_info.puk2_num_retries);
+                }
+            }
+            else if(!strcasecmp(cmd, "h") || !strcasecmp(cmd, "help")) {
+                help();
+            } else if(!strcasecmp(cmd, "q")) {
+                break;
+            } else {
+                printf("\n");
+            }
+        }
+    }
+
+    proc_exit();
+
+    LOGI("Client exec complete.");
+#if 1
+    while(1)
+    {
+        sleep(1000 * 365 * 24 * 60 * 60);
+    }
+#else
+    sleep(1);
+#endif
+    return 0;
+}
+
diff --git a/mbtk/test/ql_sms_test.c b/mbtk/test/ql_sms_test.c
new file mode 100755
index 0000000..2d07d80
--- /dev/null
+++ b/mbtk/test/ql_sms_test.c
@@ -0,0 +1,120 @@
+/**

+ *   \file dtmf_test.c

+ *   \brief A Documented file.

+ *

+ *  Detailed description

+ *   \Author:  jinLuo

+ *   \Version: 1.0.0

+ *   \Date: 2022-12-1

+ */

+

+/******************************************************************************\

+ *   Include files

+\******************************************************************************/

+#include <pthread.h>

+#include <time.h>

+#include <sys/ioctl.h>

+#include <fcntl.h>

+#include <unistd.h>

+#include <sys/types.h>

+#include <sys/stat.h>

+#include <fcntl.h>

+#include <string.h>

+#include <stdio.h>

+#include <signal.h>

+#include <unistd.h>

+#include <fcntl.h>

+#include <errno.h>

+#include <string.h>

+#include <stdlib.h>

+#include <poll.h>

+#include <stdlib.h>

+

+#include <sys/ioctl.h>

+#include <sys/types.h>

+#include <sys/stat.h>

+#include "ql/ql_sms.h"

+

+

+int main(int argc, char *argv[])

+{

+    char operator[10];

+    char serNum[50] = {0};

+    char phonenumter[20] ={0};

+    int opt;

+    int ret, uToken; 

+

+    while(1)

+    {

+        printf("=========audio main=========\n"

+            "\t0 exit\n"

+            "\t1 sms init\n"

+            "\t2 send sms\n"

+            "\t3 wait receive new sms\n"

+            "\t4 delete sms(int index);\n"

+            "\t5 list sms\n"

+            "\t6 query sms storage status\n"

+            "\t7 query service number\n"

+            "\t8 set service number\n"

+            "\t9 deinit sms\n"

+            "operator: >> ");

+        fgets(operator, sizeof(operator), stdin);

+        fflush(stdin);

+        opt = atoi(operator);

+        switch (opt)

+        {

+        case 0:

+            printf("main exit\n");

+            return 0;

+        case 1:

+            ql_sms_init();

+            break;

+        case 2:

+            ql_sms_send_text_msg("+8615775690697", "hello world", 1);

+            break;

+        case 3:

+            ql_sms_add_event_handler(NULL, NULL);

+            break;

+		case 4:

+            ql_sms_send_pdu_msg("+8615775690697","你好",1);

+            break;

+       //     printf("please input volume (0~100): \n");

+       //     fgets(operator, sizeof(operator), stdin);

+       //     fflush(stdin);

+       //     opt = atoi(operator);

+		//	lynq_delete_sms(opt);

+            break;

+		case 5:

+			printf("please input index (0~50): \n");

+            fgets(operator, sizeof(operator), stdin);

+            fflush(stdin);

+            opt = atoi(operator);

+       //     lynq_list_sms(1, opt, "ALL" );

+			break;

+		case 6:

+        //    lynq_query_sms_storage_status();

+			break;

+        case 7:

+            ret = ql_sms_get_sms_center_address(serNum);

+            if(!ret)

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

+            break;

+        case 8:

+        //    printf("please input service num: \n");

+        //    fgets(phonenumter, sizeof(phonenumter), stdin);

+        //    fflush(stdin);

+        //    memcpy(phonenumter, "+8613800280500", "+8613800280500");

+            

+        //    ret= ql_sms_set_sms_center_address(phonenumter);

+            ret= ql_sms_set_sms_center_address("+8613800280500");

+            break;

+        case 9:

+            ql_sms_release();

+            break;

+        default:

+            break;

+        }

+    }

+

+    return 0;

+}

diff --git a/mbtk/test/ql_spi_test.c b/mbtk/test/ql_spi_test.c
new file mode 100755
index 0000000..dff5208
--- /dev/null
+++ b/mbtk/test/ql_spi_test.c
@@ -0,0 +1,92 @@
+#include "ql/ql_spi.h"
+
+
+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");
+
+#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;
+#endif
+    int fd = -1;
+	/* spi 初始化程序 */
+	if((fd = Ql_SPI_Init("/dev/spidev1.0", SPIMODE3, 8, S_13M)) <= 0)
+	{
+        printf("Ql_SPI_Init() fail.\n");
+        return -1;
+	}
+
+	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 发送数据 */
+	if(Ql_SPI_Write_Read(fd, send_data,read_data, 8)) {
+        printf("Ql_SPI_Write_Read() fail.\n");
+        return -1;
+	}
+
+#if 0
+	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 读取数据 */
+	if(Ql_SPI_Write_Read(fd, send_data,read_data, 16)) {
+        printf("Ql_SPI_Write_Read() fail.\n");
+        return -1;
+	}
+
+	printf("read data:");
+	for (j = 0; j < 20; j++)
+	{
+		printf("%#x, ", read_data[j]);
+	}
+#endif
+
+    if(Ql_SPI_DeInit(fd)) {
+        printf("Ql_SPI_DeInit() fail.\n");
+        return -1;
+    }
+
+    printf("success!!!\n");
+    return 0;
+}
diff --git a/mbtk/test/ql_uart_test.c b/mbtk/test/ql_uart_test.c
new file mode 100755
index 0000000..3936ef6
--- /dev/null
+++ b/mbtk/test/ql_uart_test.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <errno.h>
+
+#include "ql/ql_uart.h"
+
+
+int main(int argc, char *argv[])
+{
+    if(argc != 3) {
+        printf("./uart_test <dev> <baudrate>\n");
+        return -1;
+    }
+
+    int fd = Ql_UART_Open(argv[1], (Enum_BaudRate)atoi(argv[2]), FC_NONE);
+    if(fd < 0) {
+        printf("Ql_UART_Open() fail.\n");
+        return -1;
+    }
+
+    ST_UARTDCB dcb;
+    memset(&dcb, 0x0, sizeof(ST_UARTDCB));
+    dcb.databit = DB_CS8;
+    dcb.parity = PB_NONE;
+    dcb.flowctrl = FC_NONE;
+
+    if(Ql_UART_SetDCB(fd, &dcb)) {
+        printf("Ql_UART_SetDCB() fail.\n");
+        return -1;
+    }
+
+    char buff[1024];
+    int len;
+    while(1) {
+        memset(buff, 0x0 ,1024);
+        len = Ql_UART_Read(fd, buff, 1024);
+        if(len > 0) {
+            if(memcmp(buff, "exit", 4) == 0) {
+                Ql_UART_Write(fd, "exit\r\n", 6);
+                break;
+            } else {
+                printf("<%s\n", buff);
+
+                Ql_UART_Write(fd, "OK\r\n", 4);
+            }
+        } else {
+            printf("Ql_UART_Read() fail:%d, errno = %d\n", len, errno);
+        }
+    }
+    Ql_UART_Close(fd);
+
+    printf("exit!!!\n");
+
+    return 0;
+}
+
+
diff --git a/mbtk/test/ql_voice_test.c b/mbtk/test/ql_voice_test.c
new file mode 100755
index 0000000..43af279
--- /dev/null
+++ b/mbtk/test/ql_voice_test.c
@@ -0,0 +1,91 @@
+#include "mbtk_type.h"
+//#include "ql/ql_vcall.h"
+//#include "ql/ql_mcm_call.h"
+#include "ql/ql_voice.h"
+
+
+
+
+int main(int argc, char *argv[])
+{
+    char operator[10] = {0};
+    int opt;
+    int    ret     = 0;
+    char   phoneNum[32] = {0};
+    int    h_voice     = 0;
+
+    while(1)
+    {
+        printf("=========call main=========\n"
+            "\t0 exit\n"
+            "\t1 call init\n"
+            "\t2 call register handle\n"
+            "\t3 call start\n"
+            "\t4 call end\n"
+            "\t5 call answer\n"
+            "\t6 call set auto answer\n"
+            "\t7 call hold\n"
+            "\t8 call unhold\n"
+            "\t9 call deinit\n"
+            "operator: >> ");
+
+        fgets(operator, sizeof(operator), stdin);
+        fflush(stdin);
+        opt = atoi(operator);
+        switch (opt)
+        {
+        case 0:
+            printf("main exit\n");
+            return 0;
+        case 1:
+            ret = ql_voice_call_init();
+            if(ret < 0)
+            {
+                printf("ql_voice_call_init FAIL.	ret:%d\n",ret);
+                return -1;
+            }
+            printf("ql_voice_call_init ret = %d, with h_voice=%d\n", ret, h_voice);
+
+            break;
+        case 2:
+            ret = ql_voice_call_event_register(NULL, NULL);
+            if(ret < 0)
+            {
+                printf("ql_voice_call_event_register FAIL.		ret:%d\n",ret);
+                return -1;
+            }
+            break;
+        case 3:
+            ql_voice_call_start("15775690697");
+            break;
+        case 4:
+            ql_voice_call_end();
+            break;
+        case 5:
+            ql_voice_call_answer();
+            break;
+        case 6:
+            ql_voice_auto_answer(6000);
+            break;
+        case 7:
+            ql_voice_call_hold();
+            break;
+        case 8:
+            ql_voice_call_unhold();
+            break;
+        case 9:
+            ql_voice_call_release();
+            break;
+        case 10:
+            // QL_Voice_Call_UnHold;
+            break;
+        default:
+            break;
+        }
+
+        sleep(1);
+    }
+
+    return 0;
+}
+
diff --git a/mbtk/test/touch_ev_demo.c b/mbtk/test/touch_ev_demo.c
new file mode 100755
index 0000000..b7ae90d
--- /dev/null
+++ b/mbtk/test/touch_ev_demo.c
@@ -0,0 +1,374 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <linux/input.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <dirent.h>
+#include <stdbool.h>
+
+#ifndef TRUE
+#define TRUE   1   /* Boolean true value. */
+#endif
+
+#ifndef true
+#define true   1   /* Boolean true value. */
+#endif
+
+#ifndef FALSE
+#define FALSE  0   /* Boolean false value. */
+#endif
+
+#ifndef false
+#define false  0   /* Boolean false value. */
+#endif
+
+
+#ifndef NULL
+#define NULL  0
+#endif
+
+
+#ifndef null
+#define null  0
+#endif
+
+#define LOGI printf
+#define LOGE printf
+
+/**
+ * Compiler-digit : 16
+ * char : 1     (%c)
+ * char* : 2
+ * short int : 2
+ * int : 2      (%d)
+ * unsigned int : 2  (%u)
+ * float : 4    (%f)
+ * double : 8   (%f)
+ * long : 4
+ * unsigned long : 4
+ * long long : 8
+ * unsigned long long : 8
+ *
+ *
+ * Compiler-digit : 32
+ * char : 1
+ * char* : 4
+ * short int : 2
+ * int : 4
+ * unsigned int : 4
+ * float : 4
+ * double : 8
+ * long : 4
+ * unsigned long : 4
+ * long long : 8
+ * unsigned long long : 8
+ *
+ *
+ * Compiler-digit : 64
+ * char : 1
+ * char* : 8
+ * short int : 2
+ * int : 4
+ * unsigned int : 4
+ * float : 4
+ * double : 8
+ * long : 8
+ * unsigned long : 8
+ * long long : 8
+ * unsigned long long : 8
+ */
+typedef unsigned char boolean; /* Boolean value type. */
+// typedef unsigned char bool; /* Boolean value type. */
+typedef unsigned long long uint64; /* Unsigned 64 bit value */
+typedef unsigned long long uint64_t; /* Unsigned 64 bit value */
+typedef unsigned int uint32; /* Unsigned 32 bit value */
+typedef unsigned int uint32_t; /* Unsigned 32 bit value */
+typedef unsigned short uint16; /* Unsigned 16 bit value */
+typedef unsigned short uint16_t;
+typedef unsigned char uint8; /* Unsigned 8  bit value */
+typedef unsigned char uint8_t;
+typedef signed long long int64; /* Signed 64 bit value */
+typedef signed long long sint64; /* Signed 64 bit value */
+typedef signed int int32; /* Signed 32 bit value */
+typedef signed int sint32; /* Signed 32 bit value */
+typedef signed short int16; /* Signed 16 bit value */
+typedef signed short sint16; /* Signed 16 bit value */
+typedef signed char int8; /* Signed 8  bit value */
+typedef signed char sint8; /* Signed 8  bit value */
+typedef unsigned char byte; /* byte type */
+
+//#include "mbtk_type.h"
+//#include "mbtk_log.h"
+
+typedef int (*ev_callback)(int fd, uint32_t epevents, void *data);
+
+typedef enum {
+    ACTION_DOWN,
+    ACTION_MOVE,
+    ACTION_UP,
+    ACTION_CANCEL
+} touch_event_action_enum;
+
+typedef struct {
+    touch_event_action_enum action;
+    int x;
+    int y;
+} touch_event;
+
+static int move_x;
+static touch_event event_pre;
+static bool action_down_get = false;
+static bool action_touched = false;
+
+#define MAX_DEVICES 16
+#define MAX_MISC_FDS 16
+
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+
+#define test_bit(bit, array) \
+    ((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG)))
+
+struct fd_info {
+    ev_callback cb;
+    void *data;
+};
+
+static struct pollfd ev_fds[MAX_DEVICES + MAX_MISC_FDS];
+static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
+
+static unsigned ev_count = 0;
+static unsigned ev_dev_count = 0;
+static unsigned ev_misc_count = 0;
+
+int ev_get_input(int fd, short revents, struct input_event *ev);
+bool event_process(struct input_event ev);
+
+int ev_cb(int fd, uint32_t epevents, void *data)
+{
+    struct input_event ev;
+
+    int retval = ev_get_input(fd, epevents, &ev);
+    if(retval < 0) return -1;
+
+    if(!event_process(ev)) return 0;
+
+    return 0;
+}
+
+int ev_init(void *data)
+{
+    DIR *dir;
+    struct dirent *de;
+    int fd;
+
+    dir = opendir("/dev/input");
+    if(dir != 0) {
+        while((de = readdir(dir))) {
+            unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
+
+//            fprintf(stderr,"/dev/input/%s\n", de->d_name);
+            if(strncmp(de->d_name,"event",5)) continue;
+            fd = openat(dirfd(dir), de->d_name, O_RDONLY);
+            if(fd < 0) continue;
+
+            /* read the evbits of the input device */
+            if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
+                close(fd);
+                continue;
+            }
+
+            /* TODO: add ability to specify event masks. For now, just assume
+             * that only EV_KEY and EV_REL event types are ever needed. */
+            if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
+                close(fd);
+                continue;
+            }
+
+            ev_fds[ev_count].fd = fd;
+            ev_fds[ev_count].events = POLLIN;
+            ev_fdinfo[ev_count].cb = ev_cb;
+            ev_fdinfo[ev_count].data = data;
+            ev_count++;
+            ev_dev_count++;
+            if(ev_dev_count == MAX_DEVICES) break;
+        }
+    }
+
+    return 0;
+}
+
+void ev_exit(void)
+{
+    while (ev_count > 0) {
+        close(ev_fds[--ev_count].fd);
+    }
+    ev_misc_count = 0;
+    ev_dev_count = 0;
+}
+
+int ev_wait(int timeout)
+{
+    int r;
+
+    r = poll(ev_fds, ev_count, timeout);
+    if (r <= 0)
+        return -1;
+    return 0;
+}
+
+void ev_dispatch(void)
+{
+    unsigned n;
+    int ret;
+
+    for (n = 0; n < ev_count; n++) {
+        ev_callback cb = ev_fdinfo[n].cb;
+        if (cb && (ev_fds[n].revents & ev_fds[n].events))
+            cb(ev_fds[n].fd, ev_fds[n].revents, ev_fdinfo[n].data);
+    }
+}
+
+int ev_get_input(int fd, short revents, struct input_event *ev)
+{
+    int r;
+
+    if (revents & POLLIN) {
+        r = read(fd, ev, sizeof(*ev));
+        if (r == sizeof(*ev))
+            return 0;
+    }
+    return -1;
+}
+
+bool event_process(struct input_event ev)
+{
+    LOGI("Event:%d,%d,%d\n", ev.type, ev.code, ev.value);
+
+//    if(ev.type != EV_KEY){
+//        return false;
+//    }
+
+    bool is_touch = true;
+    // Touch Down/Up
+    if(ev.type == EV_KEY && ev.code == BTN_TOUCH) {
+        if(!!ev.value) { // Down
+            action_down_get = true;
+            action_touched = true;
+        }
+        else // UP
+        {
+            action_down_get = false;
+            action_touched = false;
+        }
+    } else if(ev.type == EV_ABS) { // Touch move
+        if(!action_touched) // No down
+            return false;
+    } else if(ev.type != EV_KEY) {
+        return false;
+    } else {
+        is_touch = false;
+    }
+
+    if (!is_touch && ev.value < 2){ // 2 is long press events
+        int down = !!ev.value;
+        if (down){
+            LOGI("LongPress : DOWN.");
+            //if(!l->onKeyDown(ev.type, ev.code)) return false;
+        }else{
+            //if(!l->onKeyUp(ev.type, ev.code)) return false;
+            LOGI("LongPress : UP.");
+        }
+    } else if (is_touch) {
+        touch_event m_event;
+        if(ev.type == EV_ABS) { // Move
+            if(ev.code == KEY_SLASH) { // X
+                move_x = ev.value;
+            } else if(ev.code == KEY_RIGHTSHIFT) { // Y
+                if(action_down_get)
+                {
+                    m_event.action = ACTION_DOWN;
+                    action_down_get = false;
+                } else {
+                    m_event.action = ACTION_MOVE;
+                }
+                m_event.x = move_x;
+                m_event.y = ev.value;
+
+                if(event_pre.x != m_event.x
+                    || event_pre.y != m_event.y)
+                {
+                    event_pre.x = m_event.x;
+                    event_pre.y = m_event.y;
+                #ifdef MBTK_TP_RESIZE_SUPPORT
+                    point_resize(getScreenWidth(),
+                        getScreenHeight(),
+                        mStatusBar->isVisibility() ? mStatusBar->getHeight() : 0,
+                        &m_event);
+                #endif
+                    LOGI("Window onTouchEvent action:%d (%d,%d) -> (%d,%d)",
+                        m_event.action, event_pre.x, event_pre.y, m_event.x, m_event.y);
+
+                }
+            } else {
+                // Do nothing
+            }
+        } else if(!action_down_get){ // UP
+            m_event.action = ACTION_UP;
+            m_event.x = event_pre.x;
+            m_event.y = event_pre.y;
+
+        #ifdef MBTK_TP_RESIZE_SUPPORT
+            point_resize(getScreenWidth(),
+                getScreenHeight(),
+                mStatusBar->isVisibility() ? mStatusBar->getHeight() : 0,
+                &m_event);
+        #endif
+
+            LOGI("Window onTouchEvent action:%d (%d,%d) -> (%d,%d)",
+                m_event.action, event_pre.x, event_pre.y, m_event.x, m_event.y);
+
+        } else {
+            // Do nothing
+        }
+    } else {
+        // Do nothing
+    }
+
+    //invalidate();
+
+    return true;
+}
+
+int main(int argc, char *argv[])
+{
+    mbtk_log_init(NULL, "MBTK_EVENT");
+
+    if(ev_init(NULL)) {
+        LOGE("ev_init() fail.");
+        return -1;
+    }
+
+    LOGI("event getting...");
+    while(1) {
+        if(!ev_wait(-1))
+            ev_dispatch();
+    }
+
+    LOGI("exit!!!");
+    return 0;
+}