Change mbtk_source_v2

Change-Id: I0699762ab517b43060aad43fec0d87c2bfc1445d
diff --git a/mbtk/libmbtk_lib/common/ds_ASBuffer.cpp b/mbtk/libmbtk_lib/common/ds_ASBuffer.cpp
new file mode 100755
index 0000000..dc06fc1
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/ds_ASString.cpp b/mbtk/libmbtk_lib/common/ds_ASString.cpp
new file mode 100755
index 0000000..eaa1b82
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_adc.c b/mbtk/libmbtk_lib/common/mbtk_adc.c
new file mode 100755
index 0000000..55cce7c
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_adc.c
@@ -0,0 +1,102 @@
+/**
+ *   \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"
+
+int mbtk_adc_close(const char* adc_dev)
+{
+    int ret = 0;
+    int fd = 0;
+    char adc = '3';
+    //system("echo 3 > /sys/kernel/debug/adc");
+    if(adc_dev != NULL && !access(adc_dev, R_OK))
+    {
+        //LOGI("DEV:%s", ADC_DEVICE_803);
+        fd = open(adc_dev, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    }
+    else
+    {
+        LOGE("No found ADC devices.");
+        return -1;
+    }
+
+    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;
+    }
+    close(fd);
+    return 0;
+}
+
+int mbtk_adc_get(const char* adc_dev, 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' : (channle == MBTK_ADC1 ? '1' : '2'));
+
+
+    if(adc_dev != NULL && !access(adc_dev, R_OK))
+    {
+        LOGI("[adc] DEV:%s", adc_dev);
+        fd = open(adc_dev, O_RDWR|O_CREAT|O_TRUNC, 0644);
+    }
+    else
+    {
+        LOGE("No found ADC devices : %s", adc_dev ? adc_dev : "NULL");
+        return -1;
+    }
+
+    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/libmbtk_lib/common/mbtk_alarm.c b/mbtk/libmbtk_lib/common/mbtk_alarm.c
new file mode 100755
index 0000000..d62a7e7
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_alarm.c
@@ -0,0 +1,41 @@
+#include "mbtk_alarm.h"
+
+/*===========================================================================
+FUNCTION mbtk_wakealarm_set()
+
+DESCRIPTION:
+  Set sleep wake alarm.
+
+PARAMETERS:
+  time_sec [IN]: Sleep wake-up time in second.
+
+RETURN VALUE:
+  int : Return 0 if success, other for failures.
+
+===========================================================================*/
+int mbtk_wakealarm_set(unsigned long time_sec);
+{
+
+    return 0;
+}
+
+/*===========================================================================
+FUNCTION mbtk_poweralarm_set()
+
+DESCRIPTION:
+  Set shutdown alarm clock.
+
+PARAMETERS:
+  time_sec [IN]: Shutdown wake-up time in second.
+
+RETURN VALUE:
+  int : Return 0 if success, other for failures.
+
+===========================================================================*/
+int mbtk_poweralarm_set(unsigned long time_sec)
+{
+
+    return 0;
+}
+
+
diff --git a/mbtk/libmbtk_lib/common/mbtk_at.c b/mbtk/libmbtk_lib/common/mbtk_at.c
new file mode 100755
index 0000000..8721a52
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_bs_position.c b/mbtk/libmbtk_lib/common/mbtk_bs_position.c
new file mode 100755
index 0000000..0119ae5
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_debug.c b/mbtk/libmbtk_lib/common/mbtk_debug.c
new file mode 100755
index 0000000..e9280c9
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_debug.c
@@ -0,0 +1,382 @@
+/*
+*    mbtk_debug.c
+*
+*    Generate application exception information.
+*
+*/
+/******************************************************************************
+
+                          EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2024/6/5     LiuBin      Initial version
+
+******************************************************************************/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <ucontext.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdarg.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+
+/* 纯C环境下,不定义宏NO_CPP_DEMANGLE */
+#if (!defined(__cplusplus)) && (!defined(NO_CPP_DEMANGLE))
+#define NO_CPP_DEMANGLE
+#endif
+
+#ifndef NO_CPP_DEMANGLE
+#include <cxxabi.h>
+#ifdef __cplusplus
+using __cxxabiv1::__cxa_demangle;
+#endif
+#endif
+
+#if (defined __x86_64__)
+#define REGFORMAT   "%016lx"
+#elif (defined __i386__)
+#define REGFORMAT   "%08x"
+#elif (defined __arm__)
+#define REGFORMAT   "%lx"
+#endif
+
+#define MBTK_PROC_DUMP_DIR           "persist.mbtk.dump_dir"
+#define MBTK_PROC_DUMP_FILE_DEF      "/etc/mbtk/mbtk_dump.log"
+
+
+static char proc_name[100];
+static char proc_dump_name[100];
+static int proc_dump_fd = -1;
+
+#ifdef HAS_ULSLIB
+#include <uls/logger.h>
+#define sigsegv_outp(x) sigsegv_outp(, gx)
+#else
+//#define sigsegv_outp(x, ...)    fprintf(stderr, x"\n", ##__VA_ARGS__)
+void sigsegv_outp(const char* format, ...)
+{
+    if(proc_dump_fd > 0) {
+        char buf[1024] = {0};
+        va_list ap;
+        int length = 0;
+
+        va_start(ap, format);
+        length = vsnprintf(buf, sizeof(buf), format, ap);
+        if (length < 0 || 0 == length) {
+            return;
+        }
+
+        char *tmp = buf + length - 1;
+        while(tmp >= buf && (*tmp == '\r' || *tmp == '\n')) {
+            *tmp-- = '\0';
+        }
+        tmp++;
+        *tmp = '\n';
+
+        write(proc_dump_fd, buf, strlen(buf));
+
+        va_end(ap);
+    }
+}
+#endif
+
+static void print_reg(ucontext_t *uc)
+{
+#if (defined __x86_64__) || (defined __i386__)
+    int i;
+    for (i = 0; i < NGREG; i++)
+    {
+        sigsegv_outp("reg[%02d]: 0x"REGFORMAT, i, uc->uc_mcontext.gregs[i]);
+    }
+#elif (defined __arm__)
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 0, uc->uc_mcontext.arm_r0);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 1, uc->uc_mcontext.arm_r1);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 2, uc->uc_mcontext.arm_r2);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 3, uc->uc_mcontext.arm_r3);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 4, uc->uc_mcontext.arm_r4);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 5, uc->uc_mcontext.arm_r5);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 6, uc->uc_mcontext.arm_r6);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 7, uc->uc_mcontext.arm_r7);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 8, uc->uc_mcontext.arm_r8);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 9, uc->uc_mcontext.arm_r9);
+    sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 10, uc->uc_mcontext.arm_r10);
+    sigsegv_outp("FP		= 0x"REGFORMAT, uc->uc_mcontext.arm_fp);
+    sigsegv_outp("IP		= 0x"REGFORMAT, uc->uc_mcontext.arm_ip);
+    sigsegv_outp("SP		= 0x"REGFORMAT, uc->uc_mcontext.arm_sp);
+    sigsegv_outp("LR		= 0x"REGFORMAT, uc->uc_mcontext.arm_lr);
+    sigsegv_outp("PC		= 0x"REGFORMAT, uc->uc_mcontext.arm_pc);
+    sigsegv_outp("CPSR		= 0x"REGFORMAT, uc->uc_mcontext.arm_cpsr);
+    sigsegv_outp("Fault Address	= 0x"REGFORMAT, uc->uc_mcontext.fault_address);
+    sigsegv_outp("Trap no		= 0x"REGFORMAT, uc->uc_mcontext.trap_no);
+    sigsegv_outp("Err Code	= 0x"REGFORMAT, uc->uc_mcontext.error_code);
+    sigsegv_outp("Old Mask	= 0x"REGFORMAT, uc->uc_mcontext.oldmask);
+#endif
+}
+
+static void print_call_link(ucontext_t *uc)
+{
+    int i = 0;
+    void **frame_pointer = (void **)NULL;
+    void *return_address = NULL;
+    Dl_info dl_info = { 0 };
+
+#if (defined __i386__)
+    frame_pointer = (void **)uc->uc_mcontext.gregs[REG_EBP];
+    return_address = (void *)uc->uc_mcontext.gregs[REG_EIP];
+#elif (defined __x86_64__)
+    frame_pointer = (void **)uc->uc_mcontext.gregs[REG_RBP];
+    return_address = (void *)uc->uc_mcontext.gregs[REG_RIP];
+#elif (defined __arm__)
+    /* sigcontext_t on ARM:
+            unsigned long trap_no;
+            unsigned long error_code;
+            unsigned long oldmask;
+            unsigned long arm_r0;
+            ...
+            unsigned long arm_r10;
+            unsigned long arm_fp;
+            unsigned long arm_ip;
+            unsigned long arm_sp;
+            unsigned long arm_lr;
+            unsigned long arm_pc;
+            unsigned long arm_cpsr;
+            unsigned long fault_address;
+    */
+    frame_pointer = (void **)uc->uc_mcontext.arm_fp;
+    return_address = (void *)uc->uc_mcontext.arm_pc;
+#endif
+
+    sigsegv_outp("\nStack trace:");
+    while (frame_pointer && return_address)
+    {
+        if (!dladdr(return_address, &dl_info))  break;
+        const char *sname = dl_info.dli_sname;
+#ifndef NO_CPP_DEMANGLE
+        int status;
+        char *tmp = __cxa_demangle(sname, NULL, 0, &status);
+        if (status == 0 && tmp)
+        {
+            sname = tmp;
+        }
+#endif
+        /* No: return address <sym-name + offset> (filename) */
+        sigsegv_outp("%02d: %p <%s + %lu> (%s)", ++i, return_address, sname,
+                     (unsigned long)return_address - (unsigned long)dl_info.dli_saddr,
+                     dl_info.dli_fname);
+#ifndef NO_CPP_DEMANGLE
+        if (tmp)    free(tmp);
+#endif
+        if (dl_info.dli_sname && !strcmp(dl_info.dli_sname, "main"))
+        {
+            break;
+        }
+
+#if (defined __x86_64__) || (defined __i386__)
+        return_address = frame_pointer[1];
+        frame_pointer = frame_pointer[0];
+#elif (defined __arm__)
+        return_address = frame_pointer[-1];
+        frame_pointer = (void **)frame_pointer[-3];
+#endif
+    }
+    sigsegv_outp("Stack trace end.");
+}
+
+static void proc_maps_print() {
+    char file[64] = {0x00};
+    sprintf(file,"/proc/%d/maps", getpid());
+    FILE *fptr = fopen(file, "r");
+    char line[1024];
+    if(fptr)
+    {
+        memset(line, 0, sizeof(line));
+        while(fgets(line, sizeof(line), fptr)) {
+            // printf("Line : %s", line);
+            if(strstr(line, "libmbtk_") || strstr(line, "liblynq_") || strstr(line, "libql_")) {
+                sigsegv_outp("%s", line);
+            }
+            memset(line, 0, sizeof(line));
+        }
+
+        fclose(fptr);
+    }
+}
+
+static void sigsegv_handler(int signo, siginfo_t *info, void *context)
+{
+    printf("sigsegv_handler - %d\n", signo);
+    if (context)
+    {
+        struct timeval log_time;
+        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", (int)(log_time.tv_usec / 1000));
+        sigsegv_outp("----------------------------%s----------------------------", tmp);
+
+        proc_maps_print();
+
+        ucontext_t *uc = (ucontext_t *)context;
+        char proc[100] = {0};
+        int fd = open("/proc/self/cmdline", O_RDONLY);
+        if(fd > 0)
+        {
+            if(read(fd, proc, sizeof(proc)) > 0) {
+                sigsegv_outp("Segmentation Fault:%s", proc);
+            } else {
+                sigsegv_outp("Segmentation Fault:%s", "Unknown");
+            }
+            close(fd);
+        } else {
+            sigsegv_outp("Segmentation Fault:%s", "Unknown");
+        }
+
+        sigsegv_outp("info.si_signo = %d", signo);
+        sigsegv_outp("info.si_errno = %d", info->si_errno);
+        sigsegv_outp("info.si_code  = %d (%s)", info->si_code,
+                     (info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR");
+        sigsegv_outp("info.si_addr  = 0x%x(%p)\n", info->si_addr, info->si_addr);
+
+        print_reg(uc);
+        print_call_link(uc);
+
+        signal(signo, SIG_DFL);
+        raise(signo);
+
+        printf("Segmentation Fault, refer to the log file:%s\n", proc_dump_name);
+    }
+
+    exit(0);
+}
+
+#if 1
+#define BACKTRACE_SIZE 32
+void sigsegv_handler_with_thread(int signo) {
+    struct timeval log_time;
+    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", (int)(log_time.tv_usec / 1000));
+    sigsegv_outp("----------------------------%s----------------------------", tmp);
+
+    proc_maps_print();
+
+    char proc[100] = {0};
+    int fd = open("/proc/self/cmdline", O_RDONLY);
+    if(fd > 0)
+    {
+        if(read(fd, proc, sizeof(proc)) > 0) {
+            sigsegv_outp("Segmentation Fault:%s", proc);
+        } else {
+            sigsegv_outp("Segmentation Fault:%s", "Unknown");
+        }
+        close(fd);
+    } else {
+        sigsegv_outp("Segmentation Fault:%s", "Unknown");
+    }
+
+    sigsegv_outp("info.si_signo = %d", signo);
+
+    int j, nptrs;
+    void *buffer[BACKTRACE_SIZE];
+    char **strings;
+    nptrs = backtrace(buffer, BACKTRACE_SIZE);
+    //printf("backtrace() returned %d addresses\n", nptrs);
+    strings = backtrace_symbols(buffer, nptrs);
+    if(strings == NULL){
+        //perror("backtrace_symbols");
+        exit(EXIT_FAILURE);
+    }
+
+    sigsegv_outp("\nStack trace:");
+    if(nptrs > 0) {
+        for (j = 0; j < nptrs; j++) {
+            sigsegv_outp("%02d: %s", j, strings[j]);
+        }
+    }
+    free(strings);
+    sigsegv_outp("Stack trace end.");
+
+    signal(signo, SIG_DFL);
+    raise(signo);
+
+    printf("Segmentation Fault, refer to the log file:%s\n", proc_dump_name);
+    exit(0);
+}
+#endif
+
+#define SETSIG(sa, sig, fun, flags)     \
+        do {                            \
+            sa.sa_sigaction = fun;      \
+            sa.sa_flags = flags;        \
+            sigemptyset(&sa.sa_mask);   \
+            sigaction(sig, &sa, NULL);  \
+        } while(0)
+
+
+// arm-openwrt-linux-addr2line -e out/bin/mbtk_gnssd 0x12ca8
+void mbtk_debug_open(const char *log_file, bool thread_support)
+{
+    struct sigaction sa;
+
+#if 1
+    if(thread_support) {
+        SETSIG(sa, SIGSEGV, sigsegv_handler_with_thread, 0);
+        SETSIG(sa, SIGABRT, sigsegv_handler_with_thread, 0);
+    } else {
+        SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO);
+        SETSIG(sa, SIGABRT, sigsegv_handler, SA_SIGINFO);
+    }
+#else
+    SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO);
+#endif
+
+    memset(proc_name, 0, sizeof(proc_name));
+    memset(proc_dump_name, 0, sizeof(proc_dump_name));
+    int fd = open("/proc/self/cmdline", O_RDONLY);
+    if(fd > 0)
+    {
+        if(read(fd, proc_name, sizeof(proc_name)) <= 0) {
+            LOGE("Get PROC name fail.");
+        }
+        close(fd);
+    }
+
+    // Redirect stderr to log_file.
+    if(log_file) {
+        memcpy(proc_dump_name, log_file, strlen(log_file));
+    } else {
+        property_get(MBTK_PROC_DUMP_DIR, proc_dump_name, "");
+        if(strlen(proc_dump_name) > 0) {
+            snprintf(proc_dump_name + strlen(proc_dump_name),sizeof(proc_dump_name) - strlen(proc_dump_name), "/%s", proc_name);
+        } else {
+            memcpy(proc_dump_name, MBTK_PROC_DUMP_FILE_DEF, strlen(MBTK_PROC_DUMP_FILE_DEF));
+        }
+    }
+
+#if 0
+    if(freopen(proc_dump_name, "a", stderr) == NULL) {
+        LOGE("reopen stderr to %s fail.[%d]", proc_dump_name, errno);
+    }
+#else
+    proc_dump_fd = open(proc_dump_name, O_WRONLY | O_CREAT | O_APPEND, 0666);
+    if(proc_dump_fd < 0) {
+        LOGE("Open(%s) fail:%d.", proc_dump_name, errno);
+    }
+#endif
+}
+
diff --git a/mbtk/libmbtk_lib/common/mbtk_device_info.c b/mbtk/libmbtk_lib/common/mbtk_device_info.c
new file mode 100755
index 0000000..31d9523
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_device_info.c
@@ -0,0 +1,262 @@
+/*
+*    mbtk_device_info.c
+*
+*    MBTK device partition information utils.
+*
+*/
+/******************************************************************************
+
+                          EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2024/2/27     LiuBin      Initial version
+
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "mbtk_type.h"
+#include "mbtk_device.h"
+#include "mbtk_log.h"
+#include "mbtk_str.h"
+#include "mbtk_mtd.h"
+
+/*
+* MBTK_DEVICE_INFO_ITEM_BASIC - mbtk_device_info_basic_t
+* MBTK_DEVICE_INFO_ITEM_FOTA - mbtk_device_info_fota_t
+* MBTK_DEVICE_INFO_ITEM_MODEM - mbtk_device_info_modem_t
+* MBTK_DEVICE_INFO_ITEM_LOG - mbtk_device_info_log_t
+*/
+int mbtk_dev_info_read(mbtk_device_info_item_enum item_type, void *item_ptr, int item_size)
+{
+    int fd, len, i;
+    mbtk_device_info_header_t info_header;
+    memset(&info_header, 0, sizeof(mbtk_device_info_header_t));
+
+    switch(item_type) {
+        case MBTK_DEVICE_INFO_ITEM_BASIC:
+        {
+            if(item_ptr == NULL || item_size != sizeof(mbtk_device_info_basic_t)) {
+                LOGE("ARG error:item-%d, item_size-%d", item_type, item_size);
+                return -1;
+            }
+            break;
+        }
+        case MBTK_DEVICE_INFO_ITEM_FOTA:
+        {
+            if(item_ptr == NULL || item_size != sizeof(mbtk_device_info_fota_t)) {
+                LOGE("ARG error:item-%d, item_size-%d", item_type, item_size);
+                return -1;
+            }
+            break;
+        }
+        case MBTK_DEVICE_INFO_ITEM_MODEM:
+        {
+            if(item_ptr == NULL || item_size != sizeof(mbtk_device_info_modem_t)) {
+                LOGE("ARG error:item-%d, item_size-%d", item_type, item_size);
+                return -1;
+            }
+            break;
+        }
+        case MBTK_DEVICE_INFO_ITEM_LOG:
+        {
+            if(item_ptr == NULL || item_size != sizeof(mbtk_device_info_log_t)) {
+                LOGE("ARG error:item-%d, item_size-%d", item_type, item_size);
+                return -1;
+            }
+            break;
+        }
+        default:
+        {
+            LOGE("Item type[%d] error.", item_type);
+            return -1;
+        }
+    }
+
+    mbtk_partition_info_t *partition_info = mbtk_partition_get();
+    if(partition_info == NULL) {
+        LOGE("mbtk_partition_get() fail.");
+        return -1;
+    }
+
+    i = 0;
+    char dev[32] = {0};
+    while(i < MBTK_PARTITION_NUM_MAX) {
+        if(partition_info[i].used && strcmp(partition_info[i].name, MBTK_DEVICE_INFO_PARTITION_NAME) == 0) {
+            snprintf(dev, 32, "/dev/%s", partition_info[i].dev);
+            LOGD("%s -> %s", partition_info[i].name, dev);
+            break;
+        }
+        i++;
+    }
+    if(strlen(dev) == 0) {
+        LOGE("DEV is null.");
+        return -1;
+    }
+
+    fd = open(dev, O_RDONLY);
+    if (fd < 0) {
+        LOGE("Fatal error: can't open device_info %s\n", dev);
+        return -1;
+    }
+
+    len = read(fd, &info_header, sizeof(mbtk_device_info_header_t));
+    if (len != sizeof(mbtk_device_info_header_t)) {
+        LOGE("Fatal error: read %d bytes(expect %d)\n", len, sizeof(mbtk_device_info_header_t));
+        close(fd);
+        goto fail;
+    }
+
+    if(info_header.tag != MBTK_DEVICE_INFO_PARTITION_TAG) {
+        LOGE("TAG error : %08x", info_header.tag);
+        goto fail;
+    }
+
+    if(info_header.version != MBTK_DEVICE_INFO_CURR_VERSION) {
+        LOGE("Version error : %d", info_header.version);
+        goto fail;
+    }
+
+    LOGD("Item count:%d", info_header.item_count);
+
+    if(info_header.item_header[item_type].addr == 0) {
+        LOGE("No found item : %d", item_type);
+        goto fail;
+    }
+
+    lseek(fd, info_header.item_header[item_type].addr, SEEK_SET);
+    if (read(fd, item_ptr, item_size) != item_size) {
+        LOGE("Read fail:%d", errno);
+        goto fail;
+    }
+
+    close(fd);
+    return 0;
+
+fail:
+    close(fd);
+    return -1;
+}
+
+int mbtk_dev_info_write(mbtk_device_info_item_enum item_type, void *item_ptr, int item_size)
+{
+    if(item_ptr == NULL) {
+        LOGE("ARG error.");
+        return -1;
+    }
+
+    switch(item_type) {
+        case MBTK_DEVICE_INFO_ITEM_BASIC:
+        {
+            if(item_size != sizeof(mbtk_device_info_basic_t)) {
+                LOGE("item_size != sizeof(mbtk_device_info_basic_t)\n\r");
+                return -1;
+            }
+            break;
+        }
+        case MBTK_DEVICE_INFO_ITEM_FOTA:
+        {
+            if(item_size != sizeof(mbtk_device_info_fota_t)) {
+                LOGE("item_size != sizeof(mbtk_device_info_fota_t)\n\r");
+                return -1;
+            }
+            break;
+        }
+        case MBTK_DEVICE_INFO_ITEM_MODEM:
+        {
+            if(item_size != sizeof(mbtk_device_info_modem_t)) {
+                LOGE("item_size != sizeof(mbtk_device_info_modem_t)\n\r");
+                return -1;
+            }
+            break;
+        }
+        case MBTK_DEVICE_INFO_ITEM_LOG:
+        {
+            if(item_size != sizeof(mbtk_device_info_log_t)) {
+                LOGE("item_size != sizeof(mbtk_device_info_log_t)\n\r");
+                return -1;
+            }
+            break;
+        }
+        default:
+        {
+            LOGE("Item type[%d] error.\n\r", item_type);
+            return -1;
+        }
+    }
+
+    mbtk_partition_info_t info;
+    memset(&info, 0x0, sizeof(mbtk_partition_info_t));
+    if(mbtk_partition_get_by_name("device_info", &info)) {
+        LOGE("mbtk_partition_get_by_name() fail.");
+        return -1;
+    }
+
+    LOGD("device_info name : %s, dev : %s, addr : %08x, size : %08x, erase_size : %08x", info.name,
+        info.dev, info.partition_start, info.partition_size, info.erase_size);
+
+    if(info.erase_size <= 0 || info.partition_size <= 0) {
+        LOGE("partition info error.");
+        return -1;
+    }
+
+    int fd = open(info.dev, O_RDWR);
+    if (fd < 0) {
+        LOGE("Fatal error: can't open device_info %s\n", info.dev);
+        return -1;
+    }
+
+    char *mtd_buff = (char*)malloc(info.erase_size);
+    if(mtd_buff == NULL) {
+        LOGE("malloc() failed\n");
+		return -1;
+    }
+    memset(mtd_buff, 0xFF, info.erase_size);
+    int len = read(fd, mtd_buff, info.erase_size);
+    if (len != info.erase_size) {
+        LOGE("Fatal error: read %d[%d] bytes(expect %d)\n", len, errno, info.erase_size);
+        goto fail;
+    }
+
+    struct erase_info_user mtdEraseInfo;
+	if (lseek(fd, 0, SEEK_SET) < 0)
+	{
+		LOGE("seek failed\n");
+		return -1;
+	}
+
+	mtdEraseInfo.length = info.partition_size;
+	mtdEraseInfo.start = 0;
+	ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+	ioctl(fd, MEMERASE, &mtdEraseInfo);
+
+    mbtk_device_info_header_t *info_header = (mbtk_device_info_header_t*)mtd_buff;
+    memcpy(mtd_buff + info_header->item_header[item_type].addr, item_ptr, item_size);
+
+    lseek(fd, 0, SEEK_SET);
+    if (write(fd, mtd_buff, info.erase_size) != info.erase_size) {
+        LOGE("Write fail:%d", errno);
+        goto fail;
+    }
+
+    if(mtd_buff) {
+        free(mtd_buff);
+    }
+
+    close(fd);
+    return 0;
+
+fail:
+    close(fd);
+    return -1;
+}
+
+
diff --git a/mbtk/libmbtk_lib/common/mbtk_file.c b/mbtk/libmbtk_lib/common/mbtk_file.c
new file mode 100755
index 0000000..44f3954
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_gpio.c b/mbtk/libmbtk_lib/common/mbtk_gpio.c
new file mode 100755
index 0000000..0116f60
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_gpio.c
@@ -0,0 +1,212 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+#include "mbtk_gpio.h"
+
+
+static int gpio_export(int gpio)
+{
+    int fd = -1;
+    char buffer[50];
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+    if(access(buffer , F_OK) == 0)
+    {
+        LOGD("%d has export.", gpio);
+        return 0;
+    }
+
+    fd = open("/sys/class/gpio/export", O_WRONLY);
+    if(fd < 0)
+    {
+        LOGE("Open gpio export file fail.");
+        return -1;
+    }
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer , "%d", gpio);
+    if(write(fd, buffer, strlen(buffer)) <= 0)
+    {
+        LOGE("Gpio[%d] export fail.", gpio);
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    return 0;
+}
+
+static int gpio_unexport(int gpio)
+{
+    int fd = -1;
+    char buffer[50];
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+    if(access(buffer , F_OK))
+    {
+        LOGD("%d not export.", gpio);
+        return 0;
+    }
+
+    fd = open("/sys/class/gpio/unexport", O_WRONLY);
+    if(fd < 0)
+    {
+        LOGE("Open gpio unexport file fail.");
+        return -1;
+    }
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer , "%d", gpio);
+    if(write(fd, buffer, strlen(buffer)) <= 0)
+    {
+        LOGE("Gpio[%d] unexport fail.", gpio);
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    return 0;
+}
+
+mbtk_gpio_direct_t mbtk_gpio_direct_get(int gpio)
+{
+    char buffer[50];
+    int fd = -1;
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer, "/sys/class/gpio/gpio%d/direction", gpio);
+    fd = open(buffer, O_RDONLY);
+    if(fd < 0)
+    {
+        LOGE("Open gpio[%d] direct fail.", gpio);
+        return MBTK_GPIO_DIRECT_UNKNOWN;
+    }
+
+    memset(buffer, 0x0, sizeof(buffer));
+    if(read(fd, buffer, sizeof(buffer)) <= 0)
+    {
+        LOGE("Get gpio[%d] direct fail.", gpio);
+        close(fd);
+        return MBTK_GPIO_DIRECT_UNKNOWN;
+    }
+    close(fd);
+
+    if(strcmp(buffer, "out") == 0) {
+        return MBTK_GPIO_DIRECT_OUT;
+    } else if(strcmp(buffer, "in") == 0) {
+        return MBTK_GPIO_DIRECT_IN;
+    } else {
+        LOGE("direct : %s", buffer);
+        return MBTK_GPIO_DIRECT_UNKNOWN;
+    }
+}
+
+int mbtk_gpio_direct_set(int gpio, mbtk_gpio_direct_t dir)
+{
+    char buffer[50];
+    int fd = -1;
+    int ret = 0;
+
+    if(gpio_export(gpio)) {
+        return -1;
+    }
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer, "/sys/class/gpio/gpio%d/direction", gpio);
+    fd = open(buffer, O_WRONLY);
+    if(fd < 0)
+    {
+        LOGE("Open gpio[%d] direct fail.", gpio);
+        return -1;
+    }
+
+    if(MBTK_GPIO_DIRECT_OUT == dir) {
+        if(write(fd, "out", 3) != 3) {
+            ret = -1;
+            LOGE("Write out fail:%d", errno);
+        }
+    } else if(MBTK_GPIO_DIRECT_IN == dir) {
+        if(write(fd, "in", 2) != 2) {
+            ret = -1;
+            LOGE("Write in fail:%d", errno);
+        }
+    } else {
+        LOGE("Unknown direct : %d", dir);
+        ret = -1;
+    }
+
+    close(fd);
+    return ret;
+}
+
+int mbtk_gpio_value_get(int gpio)
+{
+    char buffer[50];
+    int fd =-1;
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer, "/sys/class/gpio/gpio%d/value", gpio);
+    fd = open(buffer, O_RDONLY);
+    if(fd == -1)
+    {
+        LOGE("Open gpio[%d] fail.", gpio);
+        return -1;
+    }
+
+    if(read(fd, buffer, sizeof(buffer)) <= 0)
+    {
+        LOGE("Get gpio[%d] value fail", gpio);
+        close(fd);
+        return -1;
+    }
+
+    close(fd);
+    return atoi(buffer);
+}
+
+int mbtk_gpio_value_set(int gpio, mbtk_gpio_direct_t dir, int value)
+{
+    char buffer[50];
+    int fd = -1;
+    int ret =-1;
+
+    if(gpio_export(gpio)) {
+        return -1;
+    }
+
+    if(mbtk_gpio_direct_set(gpio, dir)) {
+        return -1;
+    }
+
+    memset(buffer, 0, sizeof(buffer));
+    sprintf(buffer, "/sys/class/gpio/gpio%d/value", gpio);
+    fd = open(buffer, O_WRONLY);
+    if(fd == -1)
+    {
+        LOGE("Open gpio[%d] value fail.", gpio);
+        return -1;
+    }
+    if(value == 0) {
+        ret = write(fd, "0", 1);
+    } else {
+        ret = write(fd, "1", 1);
+    }
+
+    close(fd);
+    if(ret != 1)
+    {
+        LOGE("Set gpio[%d] value fail.", gpio);
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
diff --git a/mbtk/libmbtk_lib/common/mbtk_list.c b/mbtk/libmbtk_lib/common/mbtk_list.c
new file mode 100755
index 0000000..d31cedf
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_log.c b/mbtk/libmbtk_lib/common/mbtk_log.c
new file mode 100755
index 0000000..11ec8fd
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_log.c
@@ -0,0 +1,203 @@
+#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 <unistd.h>
+#include <include/logd.h>
+#include <ctype.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "mbtk_str.h"
+
+typedef enum {
+    LOG_ID_MAIN = 0,
+    LOG_ID_RADIO = 1,
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+    LOG_ID_KMSG = 4,
+    LOG_ID_MAX
+} log_id_t;
+
+#define LOG_VERBOSE 8
+
+static int tlog_fd = -1;
+// Default for radio log.
+static int syslog_radio_enable = 2;
+static FILE* logfile = NULL;
+static int signal_fd = -1;
+
+static bool log_level_printed = FALSE;
+
+/**
+ * @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;
+    }
+
+    if (1 == syslog_radio_enable) {
+        syslog(level, "%s", buf);
+    } else if (2 == syslog_radio_enable) {
+        __android_log_printf(LOG_ID_RADIO, level, "%s", buf);
+
+        if(!log_level_printed) {
+            __android_log_printf(LOG_ID_RADIO, LOG_ERR_LEVEL, "sloglevel = %d", get_service_log_level());
+            log_level_printed = TRUE;
+        }
+    } 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/libmbtk_lib/common/mbtk_map.c b/mbtk/libmbtk_lib/common/mbtk_map.c
new file mode 100755
index 0000000..061a538
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_mtd.c b/mbtk/libmbtk_lib/common/mbtk_mtd.c
new file mode 100755
index 0000000..b17b27f
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_mtd.c
@@ -0,0 +1,163 @@
+/*
+*    mbtk_mtd.c
+*
+*    MBTK mtd partition utils API.
+*
+*/
+/******************************************************************************
+
+                          EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2024/2/26     LiuBin      Initial version
+
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "mbtk_mtd.h"
+#include "mbtk_log.h"
+#include "mbtk_str.h"
+
+static mbtk_partition_info_t partition_list[MBTK_PARTITION_NUM_MAX];
+static bool partition_inited = FALSE;
+
+mbtk_partition_info_t* mbtk_partition_get()
+{
+    if(partition_inited) {
+        return partition_list;
+    }
+
+    memset(partition_list, 0x0, sizeof(partition_list));
+    FILE *fp = fopen("/proc/mtd", "r");
+    if(fp == NULL) {
+        LOGE("fopen(/proc/mtd) fail:%d", errno);
+        return NULL;
+    }
+
+    char buff[64];
+    int index = 0;
+    char size_str[16];
+    char name[32];
+    char erase_size_str[16];
+    char name_temp[32];
+    memset(buff, 0x0, 64);
+    memset(name_temp, 0x0, 32);
+    while(fgets(buff, 64, fp)) {
+        if(str_startwith(buff, "mtd")) {
+            memset(size_str, 0x0, 16);
+            memset(erase_size_str, 0x0, sizeof(erase_size_str));
+            memset(name, 0x0, 32);
+            if(4 == sscanf(buff, "%s %s %s %s", partition_list[index].dev, size_str, erase_size_str, name)) {
+                if(name[0] == '\"' && name[strlen(name) - 1] == '\"') {
+                    memcpy(partition_list[index].name, name + 1, strlen(name) - 2); // No copy ""
+                } else {
+                    LOGE("partition(%s) name error.", buff);
+                    return NULL;
+                }
+
+                if(partition_list[index].dev[strlen(partition_list[index].dev) - 1] == ':') {
+                    partition_list[index].dev[strlen(partition_list[index].dev) - 1] = '\0';
+                }
+
+                partition_list[index].partition_size = (uint32)strtoul(size_str, NULL, 16);
+                partition_list[index].erase_size = (uint32)strtoul(erase_size_str, NULL, 16);
+                // XXX-sdtim or XXX-mount
+                ssize_t index_sdtim = str_indexof(partition_list[index].name, "-sdtim");
+                ssize_t index_mount = str_indexof(partition_list[index].name, "-mount");
+                if(index_sdtim > 0 || index_mount > 0) {
+                    if(index_sdtim > 0) {
+                        memcpy(name_temp, partition_list[index].name, index_sdtim);
+                    } else {
+                        memcpy(name_temp, partition_list[index].name, index_mount);
+                    }
+                    if(index > 0) {
+                        partition_list[index].partition_start = partition_list[index - 1].partition_start + partition_list[index - 1].partition_size;
+                    }
+                } else {
+                    if(strlen(name_temp) > 0) {
+                        memset(name_temp, 0x0, 32);
+                        if(index > 0) {
+                            partition_list[index].partition_start = partition_list[index - 2].partition_start;
+                        }
+                    } else {
+                        if(index > 0) {
+                            partition_list[index].partition_start = partition_list[index - 1].partition_start + partition_list[index - 1].partition_size;
+                        }
+                    }
+                }
+                partition_list[index].used = TRUE;
+            } else {
+                LOGE("sscanf(%s) fail:%d", buff, errno);
+                return NULL;
+            }
+            index++;
+        }
+        memset(buff, 0x0, 64);
+    }
+    fclose(fp);
+
+    int i = 0;
+    while(i < MBTK_PARTITION_NUM_MAX) {
+        if(partition_list[i].used) {
+            LOGD("%s(%s) : %08x %08x", partition_list[i].name, partition_list[i].dev,
+                partition_list[i].partition_start, partition_list[i].partition_size);
+        }
+        i++;
+    }
+
+    partition_inited = TRUE;
+    return partition_list;
+}
+
+int mbtk_partition_get_by_name(char *partition_name, mbtk_partition_info_t *info)
+{
+    FILE *fp = fopen("/proc/mtd", "r");
+    if(fp == NULL) {
+        LOGE("fopen(/proc/mtd) fail:%d", errno);
+        return -1;
+    }
+
+    char buff[64];
+    char size_str[16];
+    char erase_size_str[16];
+    char name[32];
+    memset(buff, 0x0, sizeof(buff));
+    while(fgets(buff, sizeof(buff), fp)) {
+        if(strstr(buff, partition_name)) {
+            memset(size_str, 0x0, sizeof(size_str));
+            memset(erase_size_str, 0x0, sizeof(erase_size_str));
+            memset(name, 0x0, sizeof(name));
+            memcpy(info->dev, "/dev/", 5);
+            if(4 == sscanf(buff, "%s %s %s %s", info->dev + 5, size_str, erase_size_str, name)) {
+                if(name[0] == '\"' && name[strlen(name) - 1] == '\"') {
+                    memcpy(info->name, name + 1, strlen(name) - 2); // No copy ""
+                } else {
+                    LOGE("partition(%s) name error.", buff);
+                    return -1;
+                }
+
+                if(info->dev[strlen(info->dev) - 1] == ':') {
+                    info->dev[strlen(info->dev) - 1] = '\0';
+                }
+
+                info->partition_size = (uint32)strtoul(size_str, NULL, 16);
+                info->erase_size = (uint32)strtoul(erase_size_str, NULL, 16);
+                //info->partition_start += info->partition_size;
+                break;
+            } else {
+                LOGE("sscanf(%s) fail:%d", buff, errno);
+                return -1;
+            }
+        }
+        memset(buff, 0x0, sizeof(buff));
+    }
+    fclose(fp);
+
+    return 0;
+}
+
+
diff --git a/mbtk/libmbtk_lib/common/mbtk_ntp.c b/mbtk/libmbtk_lib/common/mbtk_ntp.c
new file mode 100755
index 0000000..5b23e37
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_ntp.c
@@ -0,0 +1,299 @@
+/*
+* 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 <sys/time.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];
+    socklen_t data_len = addr->ai_addrlen;
+    int packet_len, 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))
+    {
+        printf("NTP client success!\n");
+        LOGI("NTP client success!\n");
+    }
+    else
+    {
+        printf("NTP client fail!\n");
+        LOGE("NTP client fail!\n");
+        close(sockfd);
+        return 0;
+    }
+
+    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/libmbtk_lib/common/mbtk_queue.c b/mbtk/libmbtk_lib/common/mbtk_queue.c
new file mode 100755
index 0000000..8abc4d1
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_str.c b/mbtk/libmbtk_lib/common/mbtk_str.c
new file mode 100755
index 0000000..ff2db9e
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_task.c b/mbtk/libmbtk_lib/common/mbtk_task.c
new file mode 100755
index 0000000..935369a
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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/libmbtk_lib/common/mbtk_utf.c b/mbtk/libmbtk_lib/common/mbtk_utf.c
new file mode 100755
index 0000000..771186d
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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 int 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;
+        int 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/libmbtk_lib/common/mbtk_utils.c b/mbtk/libmbtk_lib/common/mbtk_utils.c
new file mode 100755
index 0000000..fe4d716
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_utils.c
@@ -0,0 +1,569 @@
+#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 <stdlib.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/types.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;
+    }
+}
+
+int app_already_running(const char *pid_file)
+{
+    int fd;
+    char buff[16];
+
+    fd = open(pid_file, O_RDWR | O_CREAT, 0644);
+    if(fd < 0) {
+        LOGE("Open %s fail:%d", pid_file, errno);
+        exit(1);
+    }
+
+    if(flock(fd, LOCK_EX | LOCK_NB)) {
+        if(EWOULDBLOCK == errno) {
+            LOGE("%s is running.", pid_file);
+            exit(1);
+        } else {
+            close(fd);
+            return 1;
+        }
+    }
+
+    ftruncate(fd, 0);
+    sprintf(buff, "%ld", (long)getpid());
+    write(fd, buff, strlen(buff) + 1);
+    return 0;
+}
+
diff --git a/mbtk/libmbtk_lib/common/mbtk_version.c b/mbtk/libmbtk_lib/common/mbtk_version.c
new file mode 100755
index 0000000..a144c93
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_version.c
@@ -0,0 +1,130 @@
+/*
+*    mbtk_version.c
+*
+*    mbtk_source compilation informations.
+*
+*/
+/******************************************************************************
+
+                          EDIT HISTORY FOR FILE
+
+  WHEN        WHO       WHAT,WHERE,WHY
+--------    --------    -------------------------------------------------------
+2024/6/7     LiuBin      Initial version
+
+******************************************************************************/
+#include "mbtk_version.h"
+#include "mbtk_log.h"
+
+#define STR_GET(str) (#str)
+
+static mbtk_build_def_info_t def_infos[MBTK_BUILD_DEF_NUM];
+static bool inited = FALSE;
+
+static void def_item_set(mbtk_build_define_enum def_id, char *name, char *value)
+{
+    switch(def_id)
+    {
+        case MBTK_BUILD_DEF_AF_SUPPORT:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_AF_SUPPORT));
+#ifdef MBTK_AF_SUPPORT
+            strcpy(value, "Y");
+#else
+            strcpy(value, "N");
+#endif
+            break;
+        }
+        case MBTK_BUILD_DEF_YX_SUPPORT:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_YX_SUPPORT));
+#ifdef MBTK_YX_SUPPORT
+            strcpy(value, "Y");
+#else
+            strcpy(value, "N");
+#endif
+            break;
+        }
+        case MBTK_BUILD_DEF_SG_SUPPORT:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_SG_SUPPORT));
+#ifdef MBTK_SG_SUPPORT
+            strcpy(value, "Y");
+#else
+            strcpy(value, "N");
+#endif
+            break;
+        }
+        case MBTK_BUILD_DEF_MBTK_ALL_CID_SUPPORT:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_MBTK_ALL_CID_SUPPORT));
+#ifdef MBTK_ALL_CID_SUPPORT
+            strcpy(value, "Y");
+#else
+            strcpy(value, "N");
+#endif
+            break;
+        }
+        case MBTK_BUILD_DEF_MBTK_GNSS_MODE:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_MBTK_GNSS_MODE));
+#if defined(MBTK_GNSS_6228)
+            strcpy(value, "6228");
+#elif defined(MBTK_GNSS_5311)
+            strcpy(value, "5311");
+#else
+            strcpy(value, "Unknown");
+#endif
+            break;
+        }
+        case MBTK_BUILD_DEF_MBTK_DUMP_SUPPORT:
+        {
+            strcpy(name, STR_GET(MBTK_BUILD_DEF_MBTK_DUMP_SUPPORT));
+#ifdef MBTK_DUMP_SUPPORT
+            strcpy(value, "Y");
+#else
+            strcpy(value, "N");
+#endif
+            break;
+        }
+        default:
+        {
+            strcpy(name, "Unknown");
+            strcpy(value, "Unknown");
+            break;
+        }
+    }
+}
+
+static void def_info_reset()
+{
+    if(!inited) {
+        int index = 0;
+        while(index < MBTK_BUILD_DEF_NUM) {
+            memset(&(def_infos[index]), 0, sizeof(mbtk_build_def_info_t));
+            def_item_set(index, def_infos[index].name, def_infos[index].value);
+            index++;
+        }
+        inited = TRUE;
+    }
+}
+
+void mbtk_build_def_get(char *buff, int buff_len)
+{
+    if(buff && buff_len > 0) {
+        def_info_reset();
+
+        int len = 0;
+        int index = 0;
+        while(index < MBTK_BUILD_DEF_NUM) {
+            len += snprintf(buff + len, buff_len - len, "%s:%s\n", def_infos[index].name, def_infos[index].value);
+            index++;
+        }
+    }
+}
+
+void mbtk_lib_info_print()
+{
+    MBTK_SOURCE_INFO_PRINT("mbtk_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/common/ringbuffer.c b/mbtk/libmbtk_lib/common/ringbuffer.c
new file mode 100755
index 0000000..d5225cc
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/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;
+}