Parcourir la source

first version for llsync

supperthomas il y a 3 ans
Parent
commit
e5a7da1faa
37 fichiers modifiés avec 6567 ajouts et 0 suppressions
  1. 53 0
      SConscript
  2. 612 0
      date_template/ble_qiot_template.c
  3. 253 0
      date_template/ble_qiot_template.h
  4. 183 0
      date_template/nrf52832.json
  5. 239 0
      hal/nimble/ble_qiot_ble_device.c
  6. 27 0
      hal/nimble/ble_qiot_ble_device.h
  7. 109 0
      hal/nimble/ble_qiot_config.h
  8. 36 0
      hal/nimble/flash_storage.c
  9. 46 0
      hal/nimble/flash_storage.h
  10. 259 0
      hal/nimble/mcu_service.c
  11. 18 0
      hal/nimble/mcu_service.h
  12. 285 0
      qcloud_iot_explorer_ble/inc/ble_qiot_export.h
  13. 254 0
      qcloud_iot_explorer_ble/inc/ble_qiot_import.h
  14. 346 0
      qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_data.c
  15. 391 0
      qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_device.c
  16. 269 0
      qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_event.c
  17. 491 0
      qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_ota.c
  18. 634 0
      qcloud_iot_explorer_ble/src/core/ble_qiot_service.c
  19. 45 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_common.h
  20. 31 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_crc.h
  21. 32 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_hmac.h
  22. 44 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_data.h
  23. 173 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_device.h
  24. 56 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_event.h
  25. 124 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_ota.h
  26. 103 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_log.h
  27. 94 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_md5.h
  28. 93 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_param_check.h
  29. 97 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_service.h
  30. 93 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_sha1.h
  31. 36 0
      qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_utils_base64.h
  32. 180 0
      qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_base64.c
  33. 69 0
      qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_crc.c
  34. 83 0
      qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_hmac.c
  35. 83 0
      qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_log.c
  36. 299 0
      qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_md5.c
  37. 327 0
      qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_sha1.c

+ 53 - 0
SConscript

@@ -0,0 +1,53 @@
+from building import *
+import rtconfig
+
+cwd = GetCurrentDir()
+path = [cwd]
+src = []
+
+path += [
+    cwd + '/date_template',
+    cwd + '/qcloud_iot_explorer_ble/inc',
+    cwd + '/qcloud_iot_explorer_ble/src/internal_inc']
+
+src += Split('''
+    qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_base64.c
+    qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_crc.c
+    qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_hmac.c
+    qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_log.c
+    qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_md5.c
+    qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_sha1.c
+    ''')
+
+src += Split('''
+    date_template/ble_qiot_template.c
+    ''')
+
+src += Split('''
+    qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_data.c
+    qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_device.c
+    qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_event.c
+    qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_ota.c
+    qcloud_iot_explorer_ble/src/core/ble_qiot_service.c
+    ''')
+
+
+path += [
+    cwd + '/hal/nimble']
+    
+    
+src += Split('''
+    hal/nimble/ble_qiot_ble_device.c
+    hal/nimble/flash_storage.c    
+    hal/nimble/mcu_service.c   
+    ''')
+
+
+LOCAL_CCFLAGS = ''
+
+if rtconfig.CROSS_TOOL == 'keil':
+    LOCAL_CCFLAGS += ' --gnu '
+    
+group = DefineGroup('llsync', src, depend = ['PKG_USING_NIMBLE'], CPPPATH = path, LOCAL_CCFLAGS = LOCAL_CCFLAGS)
+
+Return('group')

+ 612 - 0
date_template/ble_qiot_template.c

@@ -0,0 +1,612 @@
+/*
+* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+* Licensed under the MIT License (the "License"); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://opensource.org/licenses/MIT
+* Unless required by applicable law or agreed to in writing, software distributed under the License is
+* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+* either express or implied. See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_template.h"
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_ble_device.h"
+
+static uint8_t sg_test_power_switch = false;
+
+static int ble_property_power_switch_set(const char *data, uint16_t len)
+{
+    ble_qiot_log_d("set property power_switch %d", *(uint8_t *)data);
+    property_power_switch(data, len);
+    sg_test_power_switch = data[0];
+
+    return 0;
+}
+
+static int ble_property_power_switch_get(char *data, uint16_t buf_len)
+{
+    ble_qiot_log_d("get property power_switch %d", sg_test_power_switch);
+    data[0] = sg_test_power_switch;
+
+    return sizeof(uint8_t);
+}
+
+static uint16_t sg_test_color = 0;
+
+static int ble_property_color_set(const char *data, uint16_t len)
+{
+    uint16_t color_value = 0;
+
+    memcpy(&color_value, data, sizeof(uint16_t));
+    color_value = NTOHS(color_value);
+    ble_qiot_log_d("set property color %d", color_value);
+    sg_test_color = color_value;
+
+    return 0;
+}
+
+static int ble_property_color_get(char *data, uint16_t buf_len)
+{
+    uint16_t color_value = 0;
+
+    ble_qiot_log_d("get property color %d", color_value);
+    color_value = HTONS(sg_test_color);
+    memcpy(data, &color_value, sizeof(uint16_t));
+
+    return sizeof(uint16_t);
+}
+
+static int sg_test_brightness = 0;
+
+static int ble_property_brightness_set(const char *data, uint16_t len)
+{
+    int brightness_value = 0;
+
+    memcpy(&brightness_value, data, sizeof(int));
+    brightness_value = NTOHL(brightness_value);
+
+    if ((brightness_value < BLE_QIOT_PROPERTY_BRIGHTNESS_MIN) ||
+        (brightness_value > BLE_QIOT_PROPERTY_BRIGHTNESS_MAX)) {
+        ble_qiot_log_e("invalid brightness value %d", brightness_value);
+        return -1;
+    }
+
+    ble_qiot_log_d("set property brightness %d", brightness_value);
+    sg_test_brightness = brightness_value;
+
+    return 0;
+}
+
+static int ble_property_brightness_get(char *data, uint16_t buf_len)
+{
+    int brightness_value = 0;
+
+    ble_qiot_log_d("get property brightness %d", sg_test_brightness);
+    brightness_value = HTONL(sg_test_brightness);
+    memcpy(data, &brightness_value, sizeof(int));
+
+    return sizeof(uint32_t);
+}
+
+static char sg_test_name[100 + 1] = "default name";
+
+static int ble_property_name_set(const char *data, uint16_t len)
+{
+    ble_qiot_log_d("set property name %.*s", len, data);
+    if (len > sizeof(sg_test_name) - 1) {
+        ble_qiot_log_d("too long name");
+        return -1;
+    }
+    memset(sg_test_name, 0, sizeof(sg_test_name));
+    memcpy(sg_test_name, data, len);
+
+    return 0;
+}
+
+static int ble_property_name_get(char *data, uint16_t buf_len)
+{
+    int i = 0;
+
+    ble_qiot_log_d("get property name %s", sg_test_name);
+    if (0 == strncmp("default name", sg_test_name, sizeof("default name") - 1)) {
+        for (i = 0; i < 26 * 3; i++) {
+            data[i] = 'a' + (i % 26);
+        }
+        return i;
+    } else {
+        memcpy(data, sg_test_name, strlen(sg_test_name));
+        return strlen(sg_test_name);
+    }
+}
+
+static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
+    {ble_property_power_switch_set, ble_property_power_switch_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_BOOL},
+    {ble_property_color_set, ble_property_color_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_ENUM},
+    {ble_property_brightness_set, ble_property_brightness_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_INT},
+    {ble_property_name_set, ble_property_name_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_STRING},
+};
+
+static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
+{
+    switch (type) {
+        case BLE_QIOT_DATA_TYPE_BOOL:
+            return left_size >= sizeof(uint8_t);
+        case BLE_QIOT_DATA_TYPE_INT:
+        case BLE_QIOT_DATA_TYPE_FLOAT:
+        case BLE_QIOT_DATA_TYPE_TIME:
+            return left_size >= sizeof(uint32_t);
+        case BLE_QIOT_DATA_TYPE_ENUM:
+            return left_size >= sizeof(uint16_t);
+        default:
+            // string length is unknow, default true
+            return true;
+    }
+}
+
+static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
+{
+    switch (type) {
+        case BLE_QIOT_DATA_TYPE_BOOL:
+            return ret_val <= sizeof(uint8_t);
+        case BLE_QIOT_DATA_TYPE_INT:
+        case BLE_QIOT_DATA_TYPE_FLOAT:
+        case BLE_QIOT_DATA_TYPE_TIME:
+            return ret_val <= sizeof(uint32_t);
+        case BLE_QIOT_DATA_TYPE_ENUM:
+            return ret_val <= sizeof(uint16_t);
+        default:
+            // string length is unknow, default true
+            return ret_val <= buf_len;
+    }
+}
+
+uint8_t ble_get_property_type_by_id(uint8_t id)
+{
+    if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
+        ble_qiot_log_e("invalid property id %d", id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+    return sg_ble_property_array[id].type;
+}
+
+int ble_user_property_set_data(const e_ble_tlv *tlv)
+{
+    POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
+    if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
+        ble_qiot_log_e("invalid property id %d", tlv->id);
+        return BLE_QIOT_RS_ERR;
+    }
+
+    if (NULL != sg_ble_property_array[tlv->id].set_cb) {
+        if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
+            ble_qiot_log_e("set property id %d failed", tlv->id);
+            return BLE_QIOT_RS_ERR;
+        } else {
+            return BLE_QIOT_RS_OK;
+        }
+    }
+    ble_qiot_log_e("invalid set callback, id %d", tlv->id);
+
+    return BLE_QIOT_RS_ERR;
+}
+
+int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
+{
+    int ret_len = 0;
+
+    POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
+    if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
+        ble_qiot_log_e("invalid property id %d", id);
+        return -1;
+    }
+
+    if (NULL != sg_ble_property_array[id].get_cb) {
+        if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
+            ble_qiot_log_e("not enough space get property id %d data", id);
+            return -1;
+        }
+        ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
+        if (ret_len < 0) {
+            ble_qiot_log_e("get property id %d data failed", id);
+            return -1;
+        } else {
+            if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)) {
+                return ret_len;
+            } else {
+                ble_qiot_log_e("property id %d length invalid, type %d", id, sg_ble_property_array[id].type);
+                return -1;
+            }
+        }
+    }
+    ble_qiot_log_e("invalid callback, property id %d", id);
+
+    return 0;
+}
+
+int ble_user_property_report_reply_handle(uint8_t result)
+{
+    ble_qiot_log_d("report reply result %d", result);
+    if (0 == result) {
+        report_reply_blink();
+    }
+
+    return BLE_QIOT_RS_OK;
+}
+
+int ble_user_property_struct_handle(const char *in_buf, uint16_t buf_len, ble_property_t struct_arr[], uint8_t arr_size)
+{
+    uint16_t              parse_len = 0;
+    uint16_t              ret_len   = 0;
+    e_ble_tlv             tlv;
+
+    while (parse_len < buf_len) {
+        memset(&tlv, 0, sizeof(e_ble_tlv));
+        ret_len = ble_lldata_parse_tlv(in_buf + parse_len, buf_len - parse_len, &tlv);
+        parse_len += ret_len;
+        if (parse_len > buf_len) {
+            ble_qiot_log_e("parse struct failed");
+            return parse_len;
+        }
+
+        if (tlv.id >= arr_size){
+            ble_qiot_log_e("invalid array index %d", tlv.id);
+            return parse_len;
+        }
+        if (NULL == struct_arr[tlv.id].set_cb){
+            ble_qiot_log_e("invalid member id %d", tlv.id);
+            return parse_len;
+        }
+        if (BLE_QIOT_RS_OK != struct_arr[tlv.id].set_cb(tlv.val, tlv.len)) {
+            ble_qiot_log_e("user handle property error, member id %d, type %d, len %d", tlv.id, tlv.type, tlv.len);
+            return parse_len;
+        }
+    }
+
+    return 0;
+}
+
+int ble_user_property_struct_get_data(char *in_buf, uint16_t buf_len, ble_property_t struct_arr[], uint8_t arr_size)
+{
+    uint8_t  property_id                       = 0;
+    uint8_t  property_type                     = 0;
+    int      property_len                      = 0;
+    char     *data_buf                         = in_buf;
+    uint16_t data_len                          = 0;
+    uint16_t string_len                        = 0;
+
+    for (property_id = 0; property_id < arr_size; property_id++) {
+        property_type = struct_arr[property_id].type;
+        if (property_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+            ble_qiot_log_e("member id %d type %d invalid", property_id, property_type);
+            return BLE_QIOT_RS_ERR;
+        }
+        data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(property_type, property_id);
+        if (BLE_QIOT_DATA_TYPE_STRING == property_type) {
+            // reserved 2 bytes for string length
+            property_len = struct_arr[property_id].get_cb((char *)data_buf + data_len + 2, buf_len - data_len - 2);
+        } else {
+            property_len = struct_arr[property_id].get_cb((char *)data_buf + data_len, buf_len - data_len);
+        }
+        if (property_len < 0) {
+            ble_qiot_log_e("too long data, member id %d, data length %d", property_id, data_len);
+            return BLE_QIOT_RS_ERR;
+        } else if (property_len == 0) {
+            // no data to post
+            data_len--;
+            data_buf[data_len] = '0';
+            ble_qiot_log_d("member id %d no data to post", property_id);
+        } else {
+            if (BLE_QIOT_DATA_TYPE_STRING == property_type) {
+                string_len = HTONS(property_len);
+                memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
+                data_len += sizeof(uint16_t);
+            }
+            data_len += property_len;
+        }
+    }
+
+    return data_len;
+}
+
+static int ble_event_get_status_report_status(char *buf, uint16_t buf_len)
+{
+    buf[0] = 1;
+
+    return 1;
+}
+
+static int ble_event_get_status_report_message(char *buf, uint16_t buf_len)
+{
+    int i = 0;
+
+    for (i = 0; i < 26 * 3; i++) {
+        buf[i] = 'a' + (i % 26);
+    }
+
+    return i;
+}
+
+static ble_event_param sg_ble_event_status_report_array[BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_BUTT] = {
+    {ble_event_get_status_report_status, BLE_QIOT_DATA_TYPE_BOOL},
+    {ble_event_get_status_report_message, BLE_QIOT_DATA_TYPE_STRING},
+};
+
+static int ble_event_get_low_voltage_voltage(char *data, uint16_t buf_len)
+{
+    float tmp = 1.0;
+
+    memcpy(data, &tmp, sizeof(float));
+
+    return sizeof(float);
+}
+
+static ble_event_param sg_ble_event_low_voltage_array[BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_BUTT] = {
+    {ble_event_get_low_voltage_voltage, BLE_QIOT_DATA_TYPE_FLOAT},
+};
+
+static int ble_event_get_hardware_fault_name(char *data, uint16_t buf_len)
+{
+    memcpy(data, "hardware_fault", sizeof("hardware_fault") - 1);
+
+    return sizeof("hardware_fault") - 1;
+}
+
+static int ble_event_get_hardware_fault_error_code(char *data, uint16_t buf_len)
+{
+    int error_code = HTONL(1024);
+
+    memcpy(data, &error_code, sizeof(int));
+
+    return sizeof(int);
+}
+
+static ble_event_param sg_ble_event_hardware_fault_array[BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_BUTT] = {
+    {ble_event_get_hardware_fault_name, BLE_QIOT_DATA_TYPE_STRING},
+    {ble_event_get_hardware_fault_error_code, BLE_QIOT_DATA_TYPE_INT},
+};
+
+static ble_event_t sg_ble_event_array[BLE_QIOT_EVENT_ID_BUTT] = {
+    {sg_ble_event_status_report_array, sizeof(sg_ble_event_status_report_array) / sizeof(ble_event_param)},
+    {sg_ble_event_low_voltage_array, sizeof(sg_ble_event_low_voltage_array) / sizeof(ble_event_param)},
+    {sg_ble_event_hardware_fault_array, sizeof(sg_ble_event_hardware_fault_array) / sizeof(ble_event_param)},
+};
+
+int ble_event_get_id_array_size(uint8_t event_id)
+{
+    if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
+        ble_qiot_log_e("invalid event id %d", event_id);
+        return -1;
+    }
+
+    return sg_ble_event_array[event_id].array_size;
+}
+
+uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id)
+{
+    if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
+        ble_qiot_log_e("invalid event id %d", event_id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+    if (param_id >= sg_ble_event_array[event_id].array_size) {
+        ble_qiot_log_e("invalid param id %d", param_id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+
+    return sg_ble_event_array[event_id].event_array[param_id].type;
+}
+
+int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len)
+{
+    int ret_len = 0;
+
+    if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
+        ble_qiot_log_e("invalid event id %d", event_id);
+        return -1;
+    }
+    if (param_id >= sg_ble_event_array[event_id].array_size) {
+        ble_qiot_log_e("invalid param id %d", param_id);
+        return -1;
+    }
+    if (NULL == sg_ble_event_array[event_id].event_array[param_id].get_cb) {
+        ble_qiot_log_e("invalid callback, event id %d, param id %d", event_id, param_id);
+        return 0;
+    }
+
+    if (!ble_check_space_enough_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len)) {
+        ble_qiot_log_e("not enough space get data, event id %d, param id %d", event_id, param_id);
+        return -1;
+    }
+    ret_len = sg_ble_event_array[event_id].event_array[param_id].get_cb(out_buf, buf_len);
+    if (ret_len < 0) {
+        ble_qiot_log_e("get event data failed, event id %d, param id %d", event_id, param_id);
+        return -1;
+    } else {
+        if (ble_check_ret_value_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len, ret_len)) {
+            return ret_len;
+        } else {
+            ble_qiot_log_e("evnet data length invalid, event id %d, param id %d, type %d", event_id, param_id,
+                           sg_ble_event_array[event_id].event_array[param_id].type);
+            return -1;
+        }
+    }
+}
+
+int ble_user_event_reply_handle(uint8_t event_id, uint8_t result)
+{
+    ble_qiot_log_d("event id %d, reply result %d", event_id, result);
+
+    return BLE_QIOT_RS_OK;
+}
+
+static int ble_action_handle_loop_input_cb(e_ble_tlv *input_param_array, uint8_t input_array_size,
+                                           uint8_t *output_id_array)
+{
+    int result = 0;
+
+    if (NULL == input_param_array || NULL == output_id_array) {
+        ble_qiot_log_e("invalid param");
+        return -1;
+    }
+
+    report_reply_blink();
+    for (int i = 0; i < input_array_size; i++) {
+        ble_qiot_log_d("id %d", input_param_array[i].id);
+    }
+
+    memcpy(&result, input_param_array[0].val, sizeof(int));
+    result = NTOHL(result);
+    ble_qiot_log_d("id %d, val %d", input_param_array[0].id, result);
+    action_led_blink(result);
+
+    output_id_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT] = true;
+
+    return 0;
+}
+
+static int ble_action_handle_loop_output_cb(uint8_t output_id, char *buf, uint16_t buf_len)
+{
+    int data_len = 0;
+    int i        = 0;
+
+    switch (output_id) {
+        case BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT:
+            for (i = 0; i < 26 * 3; i++) {
+                buf[i] = 'a' + (i % 26);
+            }
+            data_len = i;
+            break;
+        default:
+            break;
+    }
+    return data_len;
+}
+
+static uint8_t sg_ble_action_loop_input_type_array[BLE_QIOT_ACTION_LOOP_INPUT_ID_BUTT] = {
+    BLE_QIOT_DATA_TYPE_INT,
+};
+
+static uint8_t sg_ble_action_loop_output_type_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_BUTT] = {
+    BLE_QIOT_DATA_TYPE_STRING,
+};
+
+static ble_action_t sg_ble_action_array[BLE_QIOT_ACTION_ID_BUTT] = {
+    {ble_action_handle_loop_input_cb, ble_action_handle_loop_output_cb, sg_ble_action_loop_input_type_array,
+     sg_ble_action_loop_output_type_array, sizeof(sg_ble_action_loop_input_type_array) / sizeof(uint8_t),
+     sizeof(sg_ble_action_loop_output_type_array) / sizeof(uint8_t)},
+};
+
+uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id)
+{
+    if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
+        ble_qiot_log_e("invalid action id %d", action_id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+    if (input_id >= sg_ble_event_array[action_id].array_size) {
+        ble_qiot_log_e("invalid input id %d", input_id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+
+    return sg_ble_action_array[action_id].input_type_array[input_id];
+}
+
+uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id)
+{
+    if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
+        ble_qiot_log_e("invalid action id %d", action_id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+    if (output_id >= sg_ble_event_array[action_id].array_size) {
+        ble_qiot_log_e("invalid output id %d", output_id);
+        return BLE_QIOT_DATA_TYPE_BUTT;
+    }
+
+    return sg_ble_action_array[action_id].output_type_array[output_id];
+}
+
+int ble_action_get_input_id_size(uint8_t action_id)
+{
+    if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
+        ble_qiot_log_e("invalid action id %d", action_id);
+        return -1;
+    }
+
+    return sg_ble_action_array[action_id].input_id_size;
+}
+
+int ble_action_get_output_id_size(uint8_t action_id)
+{
+    if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
+        ble_qiot_log_e("invalid action id %d", action_id);
+        return -1;
+    }
+
+    return sg_ble_action_array[action_id].output_id_size;
+}
+
+int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
+                                       uint8_t *output_id_array)
+{
+    if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
+        ble_qiot_log_e("invalid action id %d", action_id);
+        return -1;
+    }
+
+    if (NULL != sg_ble_action_array[action_id].input_cb) {
+        if (0 != sg_ble_action_array[action_id].input_cb(input_param_array, input_array_size, output_id_array)) {
+            ble_qiot_log_e("input handle error");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len)
+{
+    int ret_len = 0;
+
+    if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
+        ble_qiot_log_e("invalid action id %d", action_id);
+        return -1;
+    }
+    if (NULL == sg_ble_action_array[action_id].output_cb) {
+        ble_qiot_log_e("invalid callback, action id %d", action_id);
+        return 0;
+    }
+
+    if (!ble_check_space_enough_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len)) {
+        ble_qiot_log_e("not enough space get data, action id %d, output id %d", action_id, output_id);
+        return -1;
+    }
+
+    ret_len = sg_ble_action_array[action_id].output_cb(output_id, buf, buf_len);
+    if (ret_len < 0) {
+        ble_qiot_log_e("get action data failed, action id %d, output id %d", action_id, output_id);
+        return -1;
+    } else {
+        if (ble_check_ret_value_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len,
+                                        ret_len)) {
+            return ret_len;
+        } else {
+            ble_qiot_log_e("action data length invalid, action id %d, output id %d", action_id, output_id);
+            return -1;
+        }
+    }
+}
+
+
+#ifdef __cplusplus
+}
+#endif

+ 253 - 0
date_template/ble_qiot_template.h

@@ -0,0 +1,253 @@
+/*
+* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+* Licensed under the MIT License (the "License"); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://opensource.org/licenses/MIT
+* Unless required by applicable law or agreed to in writing, software distributed under the License is
+* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+* either express or implied. See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#ifndef BLE_QIOT_TEMPLATE_H_
+#define BLE_QIOT_TEMPLATE_H_
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+// data type in template, corresponding to type in json file
+enum {
+    BLE_QIOT_DATA_TYPE_BOOL = 0,
+    BLE_QIOT_DATA_TYPE_INT,
+    BLE_QIOT_DATA_TYPE_STRING,
+    BLE_QIOT_DATA_TYPE_FLOAT,
+    BLE_QIOT_DATA_TYPE_ENUM,
+    BLE_QIOT_DATA_TYPE_TIME,
+    BLE_QIOT_DATA_TYPE_STRUCT,
+    BLE_QIOT_DATA_TYPE_BUTT,
+};
+
+// message type, reference data template
+enum {
+    BLE_QIOT_PROPERTY_AUTH_RW = 0,
+    BLE_QIOT_PROPERTY_AUTH_READ,
+    BLE_QIOT_PROPERTY_AUTH_BUTT,
+};
+
+// define message flow direction
+enum {
+    BLE_QIOT_EFFECT_REQUEST = 0,
+    BLE_QIOT_EFFECT_REPLY,
+    BLE_QIOT_EFFECT_BUTT,
+};
+#define	BLE_QIOT_PACKAGE_MSG_HEAD(_TYPE, _REPLY, _ID)	(((_TYPE) << 6) | (((_REPLY) == BLE_QIOT_EFFECT_REPLY) << 5) | ((_ID) & 0X1F))
+#define	BLE_QIOT_PACKAGE_TLV_HEAD(_TYPE, _ID)   	(((_TYPE) << 5) | ((_ID) & 0X1F))
+
+
+// define tlv struct
+typedef struct{
+    uint8_t type;
+    uint8_t id;
+    uint16_t len;
+    char *val;
+}e_ble_tlv;
+#define	BLE_QIOT_INCLUDE_PROPERTY
+
+// define property id
+enum {
+    BLE_QIOT_PROPERTY_ID_POWER_SWITCH = 0,
+    BLE_QIOT_PROPERTY_ID_COLOR,
+    BLE_QIOT_PROPERTY_ID_BRIGHTNESS,
+    BLE_QIOT_PROPERTY_ID_NAME,
+    BLE_QIOT_PROPERTY_ID_BUTT,
+};
+
+// define property color enum
+enum {
+    BLE_QIOT_PROPERTY_COLOR_RED = 0,
+    BLE_QIOT_PROPERTY_COLOR_GREEN = 1,
+    BLE_QIOT_PROPERTY_COLOR_BLUE = 2,
+    BLE_QIOT_PROPERTY_COLOR_BUTT = 3,
+};
+
+// define brightness attributes
+#define	BLE_QIOT_PROPERTY_BRIGHTNESS_STEP       	(1)
+#define	BLE_QIOT_PROPERTY_BRIGHTNESS_MIN        	(0)
+#define	BLE_QIOT_PROPERTY_BRIGHTNESS_MAX        	(100)
+#define	BLE_QIOT_PROPERTY_BRIGHTNESS_START      	(1)
+
+// define name length limit
+#define	BLE_QIOT_PROPERTY_NAME_LEN_MIN          	(0)
+#define	BLE_QIOT_PROPERTY_NAME_LEN_MAX          	(640)
+
+// define property set handle return 0 if success, other is error
+// sdk call the function that inform the server data to the device
+typedef int (*property_set_cb)(const char *data, uint16_t len);
+
+// define property get handle. return the data length obtained, -1 is error, 0 is no data
+// sdk call the function fetch user data and send to the server, the data should wrapped by user adn skd just transmit
+typedef int (*property_get_cb)(char *buf, uint16_t buf_len);
+
+// each property have a struct ble_property_t, make up a array named sg_ble_property_array
+typedef struct{
+    property_set_cb set_cb;	//set callback
+    property_get_cb get_cb;	//get callback
+    uint8_t authority;	//property authority
+    uint8_t type;	//data type
+}ble_property_t;
+#define	BLE_QIOT_INCLUDE_EVENT
+
+// define event id
+enum {
+    BLE_QIOT_EVENT_ID_STATUS_REPORT = 0,
+    BLE_QIOT_EVENT_ID_LOW_VOLTAGE,
+    BLE_QIOT_EVENT_ID_HARDWARE_FAULT,
+    BLE_QIOT_EVENT_ID_BUTT,
+};
+
+// define param id for event status_report
+enum {
+    BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_STATUS = 0,
+    BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_MESSAGE,
+    BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_BUTT,
+};
+
+// define range for param message
+#define	BLE_QIOT_EVENT_STATUS_REPORT_MESSAGE_LEN_MIN	(0)
+#define	BLE_QIOT_EVENT_STATUS_REPORT_MESSAGE_LEN_MAX	(64)
+
+// define param id for event low_voltage
+enum {
+    BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_VOLTAGE = 0,
+    BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_BUTT,
+};
+
+// define param voltage attributes
+#define	BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_STEP 	(1)
+#define	BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_MIN  	(0.0)
+#define	BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_MAX  	(24.0)
+#define	BLE_QIOT_EVENT_LOW_VOLTAGE_VOLTAGE_START	(1)
+
+// define param id for event hardware_fault
+enum {
+    BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_NAME = 0,
+    BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_ERROR_CODE,
+    BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_BUTT,
+};
+
+// define range for param name
+#define	BLE_QIOT_EVENT_HARDWARE_FAULT_NAME_LEN_MIN	(0)
+#define	BLE_QIOT_EVENT_HARDWARE_FAULT_NAME_LEN_MAX	(64)
+
+// define param error_code attributes
+#define	BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_STEP	(1)
+#define	BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_MIN	(0)
+#define	BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_MAX	(2000)
+#define	BLE_QIOT_EVENT_HARDWARE_FAULT_ERROR_CODE_START	(1)
+
+// define event get handle. return the data length obtained, -1 is error, 0 is no data
+// sdk call the function fetch user data and send to the server, the data should wrapped by user adn skd just transmit
+typedef int (*event_get_cb)(char *buf, uint16_t buf_len);
+
+// each param have a struct ble_event_param, make up a array for the event
+typedef struct{
+    event_get_cb get_cb;	//get param data callback
+    uint8_t type;	//param type
+}ble_event_param;
+
+// a array named sg_ble_event_array is composed by all the event array
+typedef struct{
+    ble_event_param *event_array;	//array of params data
+    uint8_t array_size;	//array size
+}ble_event_t;
+#define	BLE_QIOT_INCLUDE_ACTION
+
+// define action id
+enum {
+    BLE_QIOT_ACTION_ID_LOOP = 0,
+    BLE_QIOT_ACTION_ID_BUTT,
+};
+
+// define input id for action loop
+enum {
+    BLE_QIOT_ACTION_LOOP_INPUT_ID_INTERVAL = 0,
+    BLE_QIOT_ACTION_LOOP_INPUT_ID_BUTT,
+};
+
+// define output id for action loop
+enum {
+    BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT = 0,
+    BLE_QIOT_ACTION_LOOP_OUTPUT_ID_BUTT,
+};
+#define	BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_MIN 	(0)
+#define	BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_MAX 	(100)
+#define	BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_START	(0)
+#define	BLE_QIOT_ACTION_INPUT_LOOP_INTERVAL_STEP	(1)
+
+// define output id result attributes
+#define	BLE_QIOT_ACTION_OUTPUT_LOOP_RESULT_LEN_MIN	(0)
+#define	BLE_QIOT_ACTION_OUTPUT_LOOP_RESULT_LEN_MAX	(320)
+
+// define max input id and output id in all of input id and output id above
+#define	BLE_QIOT_ACTION_INPUT_ID_BUTT           	1
+#define	BLE_QIOT_ACTION_OUTPUT_ID_BUTT          	1
+
+// define action input handle, return 0 is success, other is error.
+// input_param_array carry the data from server, include input id, data length ,data val
+// input_array_size means how many input id
+// output_id_array filling with output id numbers that need obtained, sdk will traverse it and call the action_output_handle to obtained data
+typedef int (*action_input_handle)(e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array);
+
+// define action output handle, return length of the data, 0 is no data, -1 is error
+// output_id means which id data should be obtained
+typedef int (*action_output_handle)(uint8_t output_id, char *buf, uint16_t buf_len);
+
+// each action have a struct ble_action_t, make up a array named sg_ble_action_array
+typedef struct{
+    action_input_handle input_cb;	//handle input data
+    action_output_handle output_cb;	// get output data in the callback
+    uint8_t *input_type_array;	//type array for input id
+    uint8_t *output_type_array;	//type array for output id
+    uint8_t input_id_size;	//numbers of input id
+    uint8_t output_id_size;	//numbers of output id
+}ble_action_t;
+// property module
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+uint8_t ble_get_property_type_by_id(uint8_t id);
+
+int ble_user_property_set_data(const e_ble_tlv *tlv);
+int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len);
+int ble_user_property_report_reply_handle(uint8_t result);
+int ble_lldata_parse_tlv(const char *buf, int buf_len, e_ble_tlv *tlv);
+int ble_user_property_struct_handle(const char *in_buf, uint16_t buf_len, ble_property_t *struct_arr, uint8_t arr_size);
+int ble_user_property_struct_get_data(char *in_buf, uint16_t buf_len, ble_property_t *struct_arr, uint8_t arr_size);
+#endif
+
+// event module
+#ifdef BLE_QIOT_INCLUDE_EVENT
+int     ble_event_get_id_array_size(uint8_t event_id);
+uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id);
+int     ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len);
+int     ble_user_event_reply_handle(uint8_t event_id, uint8_t result);
+#endif
+
+// action module
+#ifdef BLE_QIOT_INCLUDE_ACTION
+uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id);
+uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id);
+int     ble_action_get_input_id_size(uint8_t action_id);
+int     ble_action_get_output_id_size(uint8_t action_id);
+int     ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
+                                           uint8_t *output_id_array);
+int     ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif //BLE_QIOT_TEMPLATE_H_

+ 183 - 0
date_template/nrf52832.json

@@ -0,0 +1,183 @@
+{
+  "version": "1.0",
+  "profile": {
+    "ProductId": "DHZX03IQAZ",
+    "CategoryId": "3"
+  },
+  "properties": [
+    {
+      "id": "power_switch",
+      "name": "电灯开关",
+      "desc": "控制电灯开灭",
+      "required": true,
+      "mode": "rw",
+      "define": {
+        "type": "bool",
+        "mapping": {
+          "0": "关",
+          "1": "开"
+        }
+      }
+    },
+    {
+      "id": "color",
+      "name": "颜色",
+      "desc": "灯光颜色",
+      "mode": "rw",
+      "define": {
+        "type": "enum",
+        "mapping": {
+          "0": "Red",
+          "1": "Green",
+          "2": "Blue"
+        }
+      }
+    },
+    {
+      "id": "brightness",
+      "name": "亮度",
+      "desc": "灯光亮度",
+      "mode": "rw",
+      "define": {
+        "type": "int",
+        "unit": "%",
+        "step": "1",
+        "min": "0",
+        "max": "100",
+        "start": "1"
+      }
+    },
+    {
+      "id": "name",
+      "name": "灯位置名称",
+      "desc": "灯位置名称:书房、客厅等",
+      "mode": "rw",
+      "define": {
+        "type": "string",
+        "min": "0",
+        "max": "640"
+      },
+      "required": false
+    }
+  ],
+  "events": [
+    {
+      "id": "status_report",
+      "name": "DeviceStatus",
+      "desc": "Report the device status",
+      "type": "info",
+      "required": false,
+      "params": [
+        {
+          "id": "status",
+          "name": "running_state",
+          "desc": "Report current device running state",
+          "define": {
+            "type": "bool",
+            "mapping": {
+              "0": "normal",
+              "1": "fault"
+            }
+          }
+        },
+        {
+          "id": "message",
+          "name": "Message",
+          "desc": "Some extra message",
+          "define": {
+            "type": "string",
+            "min": "0",
+            "max": "64"
+          }
+        }
+      ]
+    },
+    {
+      "id": "low_voltage",
+      "name": "LowVoltage",
+      "desc": "Alert for device voltage is low",
+      "type": "alert",
+      "required": false,
+      "params": [
+        {
+          "id": "voltage",
+          "name": "Voltage",
+          "desc": "Current voltage",
+          "define": {
+            "type": "float",
+            "unit": "V",
+            "step": "1",
+            "min": "0.0",
+            "max": "24.0",
+            "start": "1"
+          }
+        }
+      ]
+    },
+    {
+      "id": "hardware_fault",
+      "name": "Hardware_fault",
+      "desc": "Report hardware fault",
+      "type": "fault",
+      "required": false,
+      "params": [
+        {
+          "id": "name",
+          "name": "Name",
+          "desc": "Name like: memory,tf card, censors ...",
+          "define": {
+            "type": "string",
+            "min": "0",
+            "max": "64"
+          }
+        },
+        {
+          "id": "error_code",
+          "name": "Error_Code",
+          "desc": "Error code for fault",
+          "define": {
+            "type": "int",
+            "unit": "",
+            "step": "1",
+            "min": "0",
+            "max": "2000",
+            "start": "1"
+          }
+        }
+      ]
+    }
+  ],
+  "actions": [
+    {
+      "id": "loop",
+      "name": "loop",
+      "desc": "",
+      "input": [
+        {
+          "id": "interval",
+          "name": "interval",
+          "define": {
+            "type": "int",
+            "min": "0",
+            "max": "100",
+            "start": "0",
+            "step": "1",
+            "unit": ""
+          }
+        }
+      ],
+      "output": [
+        {
+          "id": "result",
+          "name": "result",
+          "define": {
+            "type": "string",
+            "min": "0",
+            "max": "320"
+          }
+        }
+      ],
+      "required": false
+    }
+  ]
+}

+ 239 - 0
hal/nimble/ble_qiot_ble_device.c

@@ -0,0 +1,239 @@
+/*
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-01-29     supperthomas first version
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_import.h"
+
+#include "flash_storage.h"
+#ifdef PKG_USING_NIMBLE
+#include "host/ble_gap.h"
+#endif
+
+// divece info which defined in explorer platform
+#define PRODUCT_ID  "05SAS7U5N4"
+#define DEVICE_NAME "ble"
+#define SECRET_KEY  "/Fyy1W2oD6Bup4lojNsKFw=="
+
+static uint8_t m_adv_handle = NULL; /**< Advertising handle used to identify an advertising set. */
+static uint8_t m_enc_advdata[31]; /**< Buffer for storing an encoded advertising set. */
+static uint8_t m_enc_scan_response_data[31]; /**< Buffer for storing an encoded scan data. */
+
+int ble_get_product_id(char *product_id)
+{
+    memcpy(product_id, PRODUCT_ID, strlen(PRODUCT_ID));
+    return 0;
+}
+
+int ble_get_device_name(char *device_name)
+{
+    memcpy(device_name, DEVICE_NAME, strlen(DEVICE_NAME));
+
+    return strlen(DEVICE_NAME);
+}
+
+int ble_get_psk(char *psk)
+{
+    memcpy(psk, SECRET_KEY, strlen(SECRET_KEY));
+
+    return 0;
+}
+
+int ble_get_mac(char *mac)
+{
+    uint8_t addr_le[6];
+    int rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr_le, NULL);
+    mac[0] = addr_le[5];
+    mac[1] = addr_le[4];
+    mac[2] = addr_le[3];
+    mac[3] = addr_le[2];
+    mac[4] = addr_le[1];
+    mac[5] = addr_le[0];
+    return 0;
+}
+
+int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
+{
+    return fstorage_write(flash_addr, write_len, write_buf);
+}
+
+int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
+{
+    return fstorage_read(flash_addr, read_len, read_buf);
+}
+
+
+
+ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
+{
+    MODLOG_DFLT(INFO, "===%s==%d=====\r\n", __func__, __LINE__);
+    return 0;
+}
+
+
+ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period)
+{
+    MODLOG_DFLT(INFO, "===%s==%d=====\r\n", __func__, __LINE__);
+    return 0;
+}
+
+ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id)
+{
+    MODLOG_DFLT(INFO, "===%s==%d=====\r\n", __func__, __LINE__);
+    return 0;
+}
+
+ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id)
+{
+    MODLOG_DFLT(INFO, "===%s==%d=====\r\n", __func__, __LINE__);
+    // do nothing
+    return BLE_QIOT_RS_OK;
+}
+
+
+
+//================================================
+
+ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
+{
+    struct ble_gap_adv_params adv_params;
+    struct ble_hs_adv_fields fields;
+    int rc;
+
+
+    /*
+     *  Set the advertisement data included in our advertisements:
+     *     o Flags (indicates advertisement type and other general info)
+     *     o Advertising tx power
+     *     o Device name
+     */
+    memset(&fields, 0, sizeof(fields));
+
+    ble_uuid16_t   uuids;
+    uuids.value                       = IOT_BLE_UUID_SERVICE;
+    uuids.u.type = BLE_UUID_TYPE_16;
+    fields.uuids16 = &uuids;
+    fields.num_uuids16 = 1;
+    fields.uuids16_is_complete = 1;
+
+    rc = ble_gap_adv_rsp_set_fields(&fields);
+    if (rc != 0)
+    {
+        MODLOG_DFLT(INFO, "error setting advertisement data; rc=%d\n", rc);
+        //    return;
+    }
+    memset(&fields, 0, sizeof(fields));
+
+    /*
+     * Advertise two flags:
+     *      o Discoverability in forthcoming advertisement (general)
+     *      o BLE-only (BR/EDR unsupported)
+     */
+    fields.flags = BLE_HS_ADV_F_DISC_GEN |
+                   BLE_HS_ADV_F_BREDR_UNSUP;
+
+    fields.name = (uint8_t *)DEVICE_NAME;
+    fields.name_len = strlen(DEVICE_NAME);
+    fields.name_is_complete = 1;
+
+    for (int i = 0; i < adv->manufacturer_info.adv_data_len; i++)
+    {
+        adv->manufacturer_info.adv_data[adv->manufacturer_info.adv_data_len - i + 1] =  adv->manufacturer_info.adv_data[adv->manufacturer_info.adv_data_len - i - 1];
+    }
+    adv->manufacturer_info.adv_data[0] = adv->manufacturer_info.company_identifier & 0xff;
+    adv->manufacturer_info.adv_data[1] = (uint8_t)(adv->manufacturer_info.company_identifier >> 8) & 0xff;
+    fields.mfg_data = adv->manufacturer_info.adv_data;
+    fields.mfg_data_len = adv->manufacturer_info.adv_data_len + 2;
+
+
+    rc = ble_gap_adv_set_fields(&fields);
+    if (rc != 0)
+    {
+        MODLOG_DFLT(INFO, "error setting advertisement data; rc=%d\n", rc);
+        //    return;
+    }
+
+    /* Begin advertising */
+    memset(&adv_params, 0, sizeof(adv_params));
+    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
+    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+    extern uint8_t blehr_addr_type;
+    extern int blehr_gap_event(struct ble_gap_event * event, void *arg);
+    rc = ble_gap_adv_start(blehr_addr_type, NULL, BLE_HS_FOREVER,
+                           &adv_params, blehr_gap_event, NULL);
+    if (rc != 0)
+    {
+        MODLOG_DFLT(INFO, "error enabling advertisement; rc=%d\n", rc);
+        //return;
+    }
+
+    return 0;
+}
+
+ble_qiot_ret_status_t ble_advertising_stop(void)
+{
+    ble_gap_adv_stop();
+    MODLOG_DFLT(INFO, "===%s==%d=====\r\n", __func__, __LINE__);
+    return BLE_QIOT_RS_OK;
+}
+extern uint16_t notify_conn_handle;
+ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
+{
+
+    MODLOG_DFLT(INFO, "===%s==%d==len:%x==notify_conn_handle:%x=\r\n", __func__, __LINE__, len, notify_conn_handle);
+    struct os_mbuf *om;
+    om = ble_hs_mbuf_from_flat(buf, len);
+
+    ble_gattc_notify_custom(notify_conn_handle, 7, om);
+
+    return BLE_QIOT_RS_OK;
+}
+
+// should return ATT_MTU - 3
+uint16_t ble_get_user_data_mtu_size(void)
+{
+    uint16_t mtu = ble_att_mtu(notify_conn_handle);
+    MODLOG_DFLT(INFO, "===%s==%d=mtu:%x====\r\n", __func__, __LINE__,mtu);
+    return mtu;
+}
+
+void property_power_switch(const char *data, uint16_t len)
+{
+    MODLOG_DFLT(INFO, "===%s==%d==len:%x=data:%x==\r\n", __func__, __LINE__, len, data[0]);
+
+#define DK_BOARD_LED_2  18
+
+#ifdef __RTTHREAD__
+    rt_pin_write(DK_BOARD_LED_2, data[0]);
+#endif
+    return;
+}
+
+void action_led_blink(int ms)
+{
+    MODLOG_DFLT(INFO, "===%s==%d====\n", __func__, __LINE__);
+}
+
+void report_reply_blink(void)
+{
+    MODLOG_DFLT(INFO, "===%s==%d====\n", __func__, __LINE__);
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 27 - 0
hal/nimble/ble_qiot_ble_device.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_DEVICE_H
+#define QCLOUD_BLE_QIOT_DEVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void property_power_switch(const char *data, uint16_t len);
+void report_reply_blink(void);
+void action_led_blink(int ms);
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // QCLOUD_BLE_QIOT_DEVICE_H

+ 109 - 0
hal/nimble/ble_qiot_config.h

@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_CONFIG_H
+#define QCLOUD_BLE_QIOT_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+
+
+#define BLE_QIOT_SDK_VERSION "1.5.0"  // llsync sdk version
+#define BLE_QIOT_SDK_DEBUG   0        // sdk debug switch
+
+// the device broadcast is controlled by the user, but we provide a mechanism to help the device save more power.
+// if you want broadcast is triggered by something like press a button instead of all the time, and the broadcast
+// stopped automatically in a few minutes if the device is not bind, define BLE_QIOT_BUTTON_BROADCAST is 1 and
+// BLE_QIOT_BIND_TIMEOUT is the period that broadcast stopped.
+// if the device in the bound state, broadcast dose not stop automatically.
+#define BLE_QIOT_BUTTON_BROADCAST 0
+#if BLE_QIOT_BUTTON_BROADCAST
+    #define BLE_QIOT_BIND_TIMEOUT (2 * 60 * 1000)  // unit: ms
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+// some data like integer need to be transmitted in a certain byte order, defined it according to your device
+#define __ORDER_LITTLE_ENDIAN__ 1234
+#define __ORDER_BIG_ENDIAN__    4321
+#define __BYTE_ORDER__          __ORDER_LITTLE_ENDIAN__
+
+// the following definition will affect the stack that LLSync used,the minimum value tested is
+// 2048(BLE_QIOT_EVENT_MAX_SIZE is 128, BLE_QIOT_EVENT_BUF_SIZE is 23 ) the max length that llsync event data, depends
+// on the length of user data reported to Tencent Lianlian at a time
+#define BLE_QIOT_EVENT_MAX_SIZE (128)
+// the minimum between BLE_QIOT_EVENT_MAX_SIZE and mtu
+#define BLE_QIOT_EVENT_BUF_SIZE (23)
+
+#ifdef __RTTHREAD__
+#include "rtthread.h"
+#endif
+#ifdef BSP_USING_SOFTDEVICE
+#include "nrf_log.h"
+#include "nrf_log_ctrl.h"
+#include "nrf_log_default_backends.h"
+#endif
+
+
+// in some BLE stack ble_qiot_log_hex() maybe not work, user can use there own hexdump function
+#define BLE_QIOT_USER_DEFINE_HEXDUMP 1
+
+#if BLE_QIOT_USER_DEFINE_HEXDUMP
+#define ble_qiot_log_hex(level, hex_name, data, data_len)                          \
+    do {                                                                           \
+    } while (0)
+#endif  // BLE_QIOT_USER_DEFINE_HEXDUMP
+
+// Macro for logging a formatted string, the function must printf raw string without any color, prefix, newline or
+// timestamp
+    
+
+#define BLE_QIOT_LOG_PRINT(...) printf(__VA_ARGS__)
+
+    
+#define BLE_QIOT_LLSYNC_STANDARD    1   // support llsync standard
+
+
+#if BLE_QIOT_LLSYNC_STANDARD
+// nrf52832xxAA Flash size is 512KB, nrf52832xxAB Flash size is 512KB, be carefol of the address!
+#define BLE_QIOT_RECORD_FLASH_ADDR     0x7e000  // qiot data storage address
+#define BLE_QIOT_RECORD_FLASH_PAGESIZE 4096     // flash page size, see chip datasheet
+#define BLE_QIOT_RECORD_FLASH_PAGENUM  2        // how many pages qiot use
+
+#define APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shouldn't need to modify this value. */
+#define APP_BLE_CONN_CFG_TAG  1 /**< A tag identifying the SoftDevice BLE configuration. */
+
+#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
+#define APP_ADV_DURATION                                                                                              \
+    BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising time-out (in units of seconds). When set to 0, we will \
+                                             never time out. */
+
+// define user develop version, pick from "a-zA-Z0-9.-_" and length limits 1~32 bytes.
+// must be consistent with the firmware version that user write in the iot-explorer console
+// refer https://cloud.tencent.com/document/product/1081/40296
+
+
+#define BLE_QIOT_USER_DEVELOPER_VERSION "0.0.1"
+#endif // BLE_QIOT_LLSYNC_STANDARD
+
+
+#if (1 == BLE_QIOT_LLSYNC_STANDARD) && (1 == BLE_QIOT_LLSYNC_CONFIG_NETX)
+    #error "llsync standard and llsync configure network is incompatible"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // QCLOUD_BLE_QIOT_CONFIG_H

+ 36 - 0
hal/nimble/flash_storage.c

@@ -0,0 +1,36 @@
+/*
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-01-29     supperthomas first version
+ *
+ */
+
+#include "flash_storage.h"
+#include "ble_qiot_config.h"
+
+//FLASH not init first
+
+void fstorage_init(void)
+{
+
+}
+
+int fstorage_read(uint32_t addr, uint32_t read_len, void *p_data)
+{
+    return read_len;
+}
+
+int fstorage_erase(uint32_t addr)
+{
+    return 0;
+}
+
+int fstorage_write(uint32_t addr, uint32_t write_len, void const *p_data)
+{
+    return write_len;
+}
+
+

+ 46 - 0
hal/nimble/flash_storage.h

@@ -0,0 +1,46 @@
+/*
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-01-29     supperthomas first version
+ *
+ */
+
+#include <stdint.h>
+
+/**
+ * @brief initialize of flash storage
+ *
+ */
+void fstorage_init(void);
+
+/**
+ * @brief read data from flash
+ *
+ * @param addr read address from flash
+ * @param read_len length of data to read
+ * @param p_data point to read buf
+ * @return read length is success, other is error
+ */
+int fstorage_read(uint32_t addr, uint32_t read_len, void *p_data);
+
+/**
+ * @brief write data to flash, must erase before write
+ *
+ * @param addr write address in flash
+ * @param write_len length of data to write
+ * @param p_data point to write buf
+ * @return write length is success, other is error
+ */
+int fstorage_write(uint32_t addr, uint32_t write_len, void const *p_data);
+
+/**
+ * @brief erase one page
+ *
+ * @param addr address must align to page. For example, one page is 4096 bytes,
+ * you want to erase address 0x1020, you should set address 0x1000
+ * @return 0 is succcess, other is error
+ */
+int fstorage_erase(uint32_t addr);

+ 259 - 0
hal/nimble/mcu_service.c

@@ -0,0 +1,259 @@
+/*
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-01-29     supperthomas first version
+ *
+ */
+
+#include "mcu_service.h"
+#ifdef __RTTHREAD__
+#include "rtthread.h"
+#endif
+#include <stdint.h>
+#include <string.h>
+
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_import.h"
+#ifdef PKG_USING_NIMBLE
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+#include "nimble/ble.h"
+#endif
+
+
+//IOT_BLE_UUID_BASE + IOT_BLE_UUID_SERVICE
+#define SERVICE_BASE                                                                              \
+        0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xE0, 0xFF, 0x00, 0x00
+
+
+//IOT_BLE_UUID_BASE + IOT_BLE_UUID_DEVICE_INFO
+#define SDEVICE_INFO_BASE                                                                              \
+        0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xE1, 0xFF, 0x00, 0x00
+
+
+//IOT_BLE_UUID_BASE + IOT_BLE_UUID_DATA
+#define SDEVICE_DATA_BASE                                                                              \
+        0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xE2, 0xFF, 0x00, 0x00
+
+//IOT_BLE_UUID_BASE + IOT_BLE_UUID_EVENT
+#define SDEVICE_DATA_EVENT                                                                           \
+        0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xE3, 0xFF, 0x00, 0x00
+
+
+static uint16_t device_info_handle;
+static uint16_t device_data_handle;
+static uint16_t device_event_handle;
+
+
+//============================service====================
+static int
+gatt_svr_chr_access_q_device_info(uint16_t conn_handle, uint16_t attr_handle,
+                                  struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    MODLOG_DFLT(INFO, "===%s==%d====\n", __func__, __LINE__);
+    uint16_t uuid;
+    uuid = ble_uuid_u16(ctxt->chr->uuid);
+    uint8_t data[32];
+    os_mbuf_copydata(ctxt->om, 0, ctxt->om->om_len, data);
+
+    ble_device_info_write_cb(data, ctxt->om->om_len);
+    return 0;
+}
+
+static int
+gatt_svr_chr_access_device_data(uint16_t conn_handle, uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    /* Sensor location, set to "Chest" */
+    MODLOG_DFLT(INFO, "===%s==%d====\n", __func__, __LINE__);
+    uint16_t uuid;
+    uuid = ble_uuid_u16(ctxt->chr->uuid);
+    uint8_t data[32];
+    os_mbuf_copydata(ctxt->om, 0, ctxt->om->om_len, data);
+    ble_lldata_write_cb(data, ctxt->om->om_len);
+
+    return 0;
+}
+
+static int
+gatt_svr_chr_access_event_cb(uint16_t conn_handle, uint16_t attr_handle,
+                             struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    MODLOG_DFLT(INFO, "===%s==%d====\n", __func__, __LINE__);
+    return 0;
+}
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] =
+{
+    {
+        /* Service: Heart-rate */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = BLE_UUID128_DECLARE(SERVICE_BASE),
+        .characteristics = (struct ble_gatt_chr_def[])
+        {
+            {
+                /* Characteristic: Heart-rate measurement */
+                .uuid = BLE_UUID128_DECLARE(SDEVICE_INFO_BASE),
+                .access_cb = gatt_svr_chr_access_q_device_info,
+                .val_handle = &device_info_handle,
+                .flags = BLE_GATT_CHR_F_WRITE,
+            },
+            {
+                /* Characteristic: Body sensor location */
+                .uuid = BLE_UUID128_DECLARE(SDEVICE_DATA_BASE),
+                .access_cb = gatt_svr_chr_access_device_data,
+                .flags = BLE_GATT_CHR_F_WRITE,
+            },
+            {
+                /* Characteristic: Body sensor location */
+                .uuid = BLE_UUID128_DECLARE(SDEVICE_DATA_EVENT),
+                .access_cb = gatt_svr_chr_access_event_cb,
+                .flags = BLE_GATT_CHR_F_NOTIFY,
+            },
+            {
+                0, /* No more characteristics in this service */
+            },
+        }
+    },
+
+    {
+        0, /* No more services */
+    },
+};
+
+static int
+gatt_svr_init(void)
+{
+    int rc;
+
+    rc = ble_gatts_count_cfg(gatt_svr_svcs);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    return 0;
+}
+
+//============================================
+
+uint8_t blehr_addr_type;
+
+static bool notify_state;
+uint16_t notify_conn_handle;
+static const char *device_name = "blehr_sensor";
+
+int
+blehr_gap_event(struct ble_gap_event *event, void *arg);
+//=======================adv====================
+static void
+blehr_advertise(void)
+{
+    ble_qiot_advertising_start();
+    return;
+}
+//==============================================
+
+int
+blehr_gap_event(struct ble_gap_event *event, void *arg)
+{
+    switch (event->type)
+    {
+    case BLE_GAP_EVENT_CONNECT:
+        /* A new connection was established or a connection attempt failed */
+        MODLOG_DFLT(INFO, "connection %s; status=%d, handle:%x\n",
+                    event->connect.status == 0 ? "established" : "failed",
+                    event->connect.status, event->connect.conn_handle);
+
+        if (event->connect.status != 0)
+        {
+            /* Connection failed; resume advertising */
+            blehr_advertise();
+        }
+        else
+        {
+            ble_gap_connect_cb();
+        }
+        break;
+
+    case BLE_GAP_EVENT_DISCONNECT:
+        MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
+
+        /* Connection terminated; resume advertising */
+        blehr_advertise();
+        break;
+
+    case BLE_GAP_EVENT_ADV_COMPLETE:
+        MODLOG_DFLT(INFO, "adv complete\n");
+        blehr_advertise();
+        break;
+
+    case BLE_GAP_EVENT_SUBSCRIBE:
+        MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
+                    "val_handle=%d\n",
+                    event->subscribe.cur_notify, event->subscribe.attr_handle);
+        if (event->subscribe.attr_handle == 7)
+        {
+            notify_state = event->subscribe.cur_notify;
+            notify_conn_handle = event->subscribe.conn_handle;
+        }
+        break;
+
+    case BLE_GAP_EVENT_MTU:
+        MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
+                    event->mtu.conn_handle,
+                    event->mtu.value);
+        break;
+
+    }
+
+    return 0;
+}
+
+static void
+blehr_on_sync(void)
+{
+    int rc;
+
+    /* Use privacy */
+    rc = ble_hs_id_infer_auto(0, &blehr_addr_type);
+    assert(rc == 0);
+
+    ble_qiot_explorer_init();
+    /* Begin advertising */
+    blehr_advertise();
+
+}
+// add services and characteristic
+void ble_services_add(const qiot_service_init_s *p_service)
+{
+    int rc;
+    static int init_flag = 0;
+
+    //repeat init
+    if (init_flag)
+        return;
+    init_flag = 1;
+
+    /* Initialize the NimBLE host configuration */
+    ble_hs_cfg.sync_cb = blehr_on_sync;
+
+    rc = gatt_svr_init();
+
+    /* startup bluetooth host stack*/
+    ble_hs_thread_startup();
+}
+#ifdef __RTTHREAD__
+MSH_CMD_EXPORT_ALIAS(ble_services_add, ble_services_add, "bluetoooth SERVICE senson sample");
+#endif

+ 18 - 0
hal/nimble/mcu_service.h

@@ -0,0 +1,18 @@
+
+#ifndef __MCU_SERVICE_H
+#define __MCU_SERVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "ble_qiot_export.h"
+void            ble_services_add(const qiot_service_init_s *p_service);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 285 - 0
qcloud_iot_explorer_ble/inc/ble_qiot_export.h

@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_EXPORT_H
+#define QCLOUD_BLE_QIOT_EXPORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#define TENCENT_COMPANY_IDENTIFIER  0xFEE7  // Tencent Company ID, another is 0xFEBA
+
+#define IOT_BLE_UUID_BASE                                                                              \
+    {                                                                                                  \
+        0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0x00, 0x00, 0x00, 0x00 \
+    }
+
+// llsync services uuid
+#if BLE_QIOT_LLSYNC_STANDARD
+    #define IOT_BLE_UUID_SERVICE 0xFFE0
+#endif //BLE_QIOT_LLSYNC_STANDARD
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+    #define IOT_BLE_UUID_SERVICE 0xFFF0
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+// characteristics uuid
+#define IOT_BLE_UUID_DEVICE_INFO 0xFFE1  // used to connection and identity authentication
+#define IOT_BLE_UUID_EVENT       0xFFE3  // used to send data to the server from device
+
+#if BLE_QIOT_LLSYNC_STANDARD
+    #define IOT_BLE_UUID_DATA        0xFFE2  // used to send data to the device from server
+    #define IOT_BLE_UUID_OTA         0xFFE4  // used to send ota data to the device from server
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+typedef enum {
+    GATT_CHAR_BROADCAST      = (1 << 0),  // Broadcasting of the value permitted.
+    GATT_CHAR_READ           = (1 << 1),  // Reading the value permitted.
+    GATT_CHAR_WRITE_WO_RESP  = (1 << 2),  // Writing the value with Write Command permitted.
+    GATT_CHAR_WRITE          = (1 << 3),  // Writing the value with Write Request permitted.
+    GATT_CHAR_NOTIFY         = (1 << 4),  // Notification of the value permitted.
+    GATT_CHAR_INDICATE       = (1 << 5),  // Indications of the value permitted.
+    GATT_CHAR_AUTH_SIGNED_WR = (1 << 6),  // Writing the value with Signed Write Command permitted.
+} char_props_s;
+
+// the callback function prototype definition for the characteristics
+typedef void (*ble_on_write_cb)(const uint8_t *buf, uint16_t len);
+
+// the characteristics attributes
+typedef struct {
+    uint16_t        uuid16;
+    uint8_t         gatt_char_props;
+    ble_on_write_cb on_write;
+} qiot_char_s;
+
+// the service attributes
+typedef struct {
+    uint16_t service_uuid16;
+    uint8_t  service_uuid128[16];
+    uint16_t gatt_max_mtu;
+
+    qiot_char_s device_info;
+    qiot_char_s data;
+    qiot_char_s event;
+    qiot_char_s ota;
+} qiot_service_init_s;
+
+typedef enum {
+    BLE_QIOT_RS_OK             = 0,   // success
+    BLE_QIOT_RS_ERR            = -1,  // normal error
+    BLE_QIOT_RS_ERR_FLASH      = -2,  // flash error
+    BLE_QIOT_RS_ERR_PARA       = -3,  // parameters error
+    BLE_QIOT_RS_VALID_SIGN_ERR = -4,
+} ble_qiot_ret_status_t;
+
+/**
+ * @brief get llsync services context
+ *
+ * @return llsync services struct
+ */
+const qiot_service_init_s *ble_get_qiot_services(void);
+
+/**
+ * @brief llsync sdck initialize
+ * @note  you should called it before any other sdk api
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_qiot_explorer_init(void);
+
+/**
+ * @brief  report mtu of the device to the server
+ * @note   report mtu to the server to set the mtu
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_device_info(void);
+
+/**
+ * @brief  sync the device mtu to The Tencent Lianlian.
+ * @note   if BLE_QIOT_REMOTE_SET_MTU is 1, The Tencent Lianlian will set the mtu get from function
+ * ble_get_user_data_mtu_size(), but The Tencent Lianlian can not know the effective value even if the setting is
+ * successful, so llsync need sync the mtu again. The user call this function in the BLE mtu callback.
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_sync_mtu(uint16_t llsync_mtu);
+
+/**
+ * @brief  start llsync advertising
+ * @note   broadcast data according to the device bind state, reference to llsync protocol
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_qiot_advertising_start(void);
+
+/**
+ * @brief  stop advertising
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_qiot_advertising_stop(void);
+
+/**
+ * @brief device info write callbcak, call the function when characteristic IOT_BLE_UUID_DEVICE_INFO received data
+ * @param buf a pointer point to the data
+ * @param len data length
+ * @return none
+ */
+void ble_device_info_write_cb(const uint8_t *buf, uint16_t len);
+
+/**
+ * @brief gap event connect call-back, when gap get ble connect event, use this function
+ *       tell qiot ble sdk
+ * @return none
+ */
+void ble_gap_connect_cb(void);
+
+/**
+ * @brief gap event disconnect call-back, when gap get ble disconnect event, use this function
+ *       tell qiot ble sdk
+ * @return none
+ */
+void ble_gap_disconnect_cb(void);
+
+#ifdef BLE_QIOT_LLSYNC_STANDARD
+/**
+ * @brief  get property of the device from the server
+ * @note   the property will be received from IOT_BLE_UUID_DATA if success
+ * @return BLE_QIOT_RS_OK is success, other is error. if success, the data from server will come to
+ */
+ble_qiot_ret_status_t ble_event_get_status(void);
+
+/**
+ * @brief  report property of the device to the server
+ * @note   the reply will be received from IOT_BLE_UUID_DATA if success
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_property(void);
+
+/**
+ * @brief  post event to the server
+ * @param  event_id id of the event
+ * @note   the reply will be received from IOT_BLE_UUID_DATA if success
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_post(uint8_t event_id);
+
+/**
+ * @brief data write callback, call the function when characteristic IOT_BLE_UUID_DATA received data
+ * @param buf a pointer point to the data
+ * @param len data length
+ * @return none
+ */
+void ble_lldata_write_cb(const uint8_t *buf, uint16_t len);
+
+/**
+ * @brief ota data write callback, call the function when characteristic IOT_BLE_UUID_OTA received data
+ * @param buf a pointer point to the data
+ * @param len data length
+ * @return none
+ */
+void ble_ota_write_cb(const uint8_t *buf, uint16_t len);
+
+typedef enum {
+    BLE_QIOT_SECURE_BIND_CONFIRM = 0,
+    BLE_QIOT_SECURE_BIND_REJECT  = 1,
+} ble_qiot_secure_bind_t;
+
+/**
+ * @brief  user choose whether to connect
+ * @note   call the function when the user choose connect or not
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_secure_bind_user_confirm(ble_qiot_secure_bind_t choose);
+
+// inform user the ota start
+typedef void (*ble_ota_start_callback)(void);
+
+enum {
+    BLE_QIOT_OTA_SUCCESS     = 0,  // ota success
+    BLE_QIOT_OTA_ERR_CRC     = 1,  // ota failed because crc error
+    BLE_QIOT_OTA_ERR_TIMEOUT = 2,  // ota failed because download timeout
+    BLE_QIOT_OTA_DISCONNECT  = 3,  // ota failed because ble disconnect
+    BLE_QIOT_OTA_ERR_FILE    = 4,  // ota failed because the file mismatch the device
+};
+// inform user the ota stop and the result
+typedef void (*ble_ota_stop_callback)(uint8_t result);
+
+// llsync only valid the file crc, also allow the user valid the file by their way
+typedef ble_qiot_ret_status_t (*ble_ota_valid_file_callback)(uint32_t file_size, char *file_version);
+/**
+ * @brief register ota callback
+ * @param start_cb called before ota start, set null if not used
+ * @param stop_cb called after ota stop, set null if not used
+ * @param valid_file_cb called after the crc valid, set null if not used
+ * @return none
+ */
+void ble_ota_callback_reg(ble_ota_start_callback start_cb, ble_ota_stop_callback stop_cb,
+                          ble_ota_valid_file_callback valid_file_cb);
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+
+typedef enum {
+    BLE_WIFI_MODE_NULL = 0,  // invalid mode
+    BLE_WIFI_MODE_STA  = 1,  // station
+    BLE_WIFI_MODE_AP   = 2,  // ap
+} BLE_WIFI_MODE;
+
+typedef enum {
+    BLE_WIFI_STATE_CONNECT = 0,  // wifi connect
+    BLE_WIFI_STATE_OTHER   = 1,  // other state
+} BLE_WIFI_STATE;
+
+/**
+ * @brief report wifi-mode setting result
+ * @param result setting result, 0 is success, other failed
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_mode(uint8_t result);
+
+/**
+ * @brief report wifi-info setting result
+ * @param result setting result, 0 is success, other failed
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_info(uint8_t result);
+
+/**
+ * @brief report wifi connection status
+ * @param mode current wifi mode, reference BLE_WIFI_MODE
+ * @param state current wifi state, reference BLE_WIFI_STATE
+ * @param ssid_len length of ssid
+ * @param ssid the ssid currently connected
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_connect(BLE_WIFI_MODE mode, BLE_WIFI_STATE state, uint8_t ssid_len,
+const char *ssid);
+
+/**
+ * @brief report wifi-token setting result
+ * @param result setting result, 0 is success, other failed
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_token(uint8_t result);
+
+/**
+ * @brief report wifi-log
+ * @param log log message
+ * @param log_size length of log
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_event_report_wifi_log(const uint8_t *log, uint16_t log_size);
+
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // QCLOUD_BLE_QIOT_EXPORT_H

+ 254 - 0
qcloud_iot_explorer_ble/inc/ble_qiot_import.h

@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_IMPORT_H
+#define QCLOUD_BLE_QIOT_IMPORT_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "ble_qiot_export.h"
+
+// 16 bits service UUIDs list, use advertising type 0x02 or 0x03
+typedef struct {
+    uint8_t   uuid_num;
+    uint16_t *uuids;
+} uuid_list_s;
+
+// advertise manufacture specific data, use advertising type 0xFF
+typedef struct {
+    uint16_t company_identifier;
+    uint8_t *adv_data;
+    uint8_t  adv_data_len;
+} manufacturer_data_s;
+
+typedef struct {
+    uuid_list_s         uuid_info;
+    manufacturer_data_s manufacturer_info;
+} adv_info_s;
+
+/**
+ * @brief  get mac address
+ * @param  mac     the buf storage mac, 6 bytes permanent
+ * @return 0 is success, other is error
+ */
+int ble_get_mac(char *mac);
+
+/**
+ * @brief add llsync services to ble stack
+ * @param qiot_service_init_s llsync service
+ * @return none
+ */
+void ble_services_add(const qiot_service_init_s *p_service);
+
+/**
+ * @brief start llsync advertising
+ * @param adv a pointer point to advertising data
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv);
+
+/**
+ * @brief stop advertising
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_advertising_stop(void);
+
+/**
+ * @brief get the ATT_MTU user want to used
+ * @return the value
+ */
+uint16_t ble_get_user_data_mtu_size(void);
+
+/**
+ * @brief send a notification to host, use characteristic IOT_BLE_UUID_EVENT
+ * @param buf a pointer point to indication information
+ * @param len indication information length
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len);
+
+// timer type
+enum {
+    BLE_TIMER_ONE_SHOT_TYPE = 0,
+    BLE_TIMER_PERIOD_TYPE,
+    BLE_TIMER_BUTT,
+};
+typedef void *ble_timer_t;
+
+// timer callback prototype
+typedef void (*ble_timer_cb)(void *param);
+
+/**
+ * @brief create a timer
+ * @param type timer type
+ * @param timeout_handle timer callback
+ * @return timer identifier is return, NULL is error
+ */
+ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle);
+
+/**
+ * @brief start a timer
+ * @param timer_id Timer identifier
+ * @param period timer period(unit: ms)
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period);
+
+/**
+ * @brief stop a timer
+ * @param timer_id Timer identifier
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id);
+
+/**
+ * @brief delete a timer
+ * @param timer_id Timer identifier
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id);
+
+#ifdef BLE_QIOT_LLSYNC_STANDARD
+/**
+ * @brief  get device product id
+ * @param  product_id  the buf storage product id, 10 bytes permanent
+ * @return 0 is success, other is error
+ */
+int ble_get_product_id(char *product_id);
+
+/**
+ * @brief  get device name
+ * @param  device_name     the buf storage device name, the max length of the device name is 48 bytes
+ * @return length of device name, 0 is error
+ */
+int ble_get_device_name(char *device_name);
+
+/**
+ * @brief  get device secret
+ * @param  psk         the buf storage secret, 24 bytes permanent
+ * @return 0 is success, other is error
+ */
+int ble_get_psk(char *psk);
+
+/**
+ * @brief write data to flash
+ * @param flash_addr write address in flash
+ * @param write_buf  point to write buf
+ * @param write_len  length of data to write
+ * @return write_len is success, other is error
+ */
+int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len);
+
+/**
+ * @brief read data from flash
+ * @param flash_addr read address from flash
+ * @param read_buf   point to read buf
+ * @param read_len   length of data to read
+ * @return read_len is success, other is error
+ */
+int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len);
+
+/**
+ * @brief secure binding user callback
+ * @note when the secure binding is activated, the function notify user the connecting is coming, the function is
+ * no-block
+ * @return None
+ */
+void ble_secure_bind_user_cb(void);
+
+enum {
+    BLE_SECURE_BIND_CANCEL  = 0,  // user cancel in Tencent Lianlian
+    BLE_SECURE_BIND_TIMEOUT = 1,  // the binding timeout
+};
+/**
+ * @brief secure binding user notify
+ * @note notify user when the secure bind timeout or cancel
+ * @return None
+ */
+void ble_secure_bind_user_notify(uint8_t result);
+
+enum {
+    BLE_OTA_ENABLE              = 1,  // ota enable
+    BLE_OTA_DISABLE_LOW_POWER   = 2,  // the device low power can not upgrade
+    BLE_OTA_DISABLE_LOW_VERSION = 3,  // disable upgrade low version
+};
+/**
+ * @brief get ota is enable
+ * @param version the ota file version
+ * @return BLE_OTA_ENABLE is enable, others disable
+ * @note can not be blocking, the reason defined by users
+ */
+uint8_t ble_ota_is_enable(const char *version);
+
+/**
+ * @brief get the address the ota file will be saved
+ * @return the flash address
+ */
+uint32_t ble_ota_get_download_addr(void);
+
+/**
+ * @brief write data to flash
+ * @param flash_addr write address in flash
+ * @param write_buf  point to write buf
+ * @param write_len  length of data to write
+ * @return write_len is success, other is error
+ */
+int ble_ota_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len);
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+/**
+ * @brief set wifi mode
+ * @param mode the target mode
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_mode_set(BLE_WIFI_MODE mode);
+
+/**
+ * @brief set wifi info
+ * @param ssid wifi ssid
+ * @param ssid_len the length of ssid
+ * @param passwd wifi password
+ * @param passwd_len the length of password
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_info_set(const char *ssid, uint8_t ssid_len, const char *passwd, uint8_t passwd_len);
+
+/**
+ * @brief connect wifi
+ * @param none
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_connect();
+
+/**
+ * @brief set wifi token
+ * @param token token message
+ * @param token_len length of token
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_token_set(const char *token, uint16_t token_len);
+
+/**
+ * @brief get wifi log
+ * @param none
+ * @return BLE_QIOT_RS_OK is success, other is error
+ */
+ble_qiot_ret_status_t ble_combo_wifi_log_get(void);
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif  // QCLOUD_BLE_QIOT_IMPORT_H

+ 346 - 0
qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_data.c

@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ble_qiot_config.h"
+
+#if BLE_QIOT_LLSYNC_STANDARD
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_llsync_data.h"
+
+// parse tlv data and return the length parsed
+int ble_lldata_parse_tlv(const char *buf, int buf_len, e_ble_tlv *tlv)
+{
+    int      ret_len  = 0;
+    uint16_t type_len = 0;
+
+    tlv->type = BLE_QIOT_PARSE_TLV_HEAD_TYPE(buf[0]);
+    if (tlv->type >= BLE_QIOT_DATA_TYPE_BUTT) {
+        ble_qiot_log_e("lldata parse invalid type: %d", tlv->type);
+        return -1;
+    }
+    tlv->id = BLE_QIOT_PARSE_TLV_HEAD_ID(buf[0]);
+    ret_len++;
+
+    switch (tlv->type) {
+        case BLE_QIOT_DATA_TYPE_BOOL:
+            tlv->len = sizeof(uint8_t);
+            tlv->val = (char *)buf + ret_len;
+            ret_len += sizeof(uint8_t);
+            break;
+        case BLE_QIOT_DATA_TYPE_ENUM:
+            tlv->len = sizeof(uint16_t);
+            tlv->val = (char *)buf + ret_len;
+            ret_len += sizeof(uint16_t);
+            break;
+        case BLE_QIOT_DATA_TYPE_INT:
+        case BLE_QIOT_DATA_TYPE_FLOAT:
+        case BLE_QIOT_DATA_TYPE_TIME:
+            tlv->len = sizeof(uint32_t);
+            tlv->val = (char *)buf + ret_len;
+            ret_len += sizeof(uint32_t);
+            break;
+        case BLE_QIOT_DATA_TYPE_STRUCT:
+        case BLE_QIOT_DATA_TYPE_STRING:
+            if (buf_len < BLE_QIOT_MIN_STRING_TYPE_LEN) {
+                ble_qiot_log_e("lldata len invalid, type: %d, len: %d", tlv->type, buf_len);
+                return -1;
+            }
+            memcpy(&type_len, &buf[ret_len], sizeof(uint16_t));
+            tlv->len = NTOHS(type_len);
+            ret_len += sizeof(uint16_t);
+            tlv->val = (char *)buf + ret_len;
+            ret_len += tlv->len;
+            break;
+        default:
+            break;
+    }
+    ble_qiot_log_d("tlv parsed, type: %d, id: %d, len: %d", tlv->type, tlv->id, tlv->len);
+
+    return ret_len;
+}
+
+// handle property data, method is control or get status
+static ble_qiot_ret_status_t ble_lldata_property_data_handle(bool is_request, const char *in_buf, int buf_len)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+    uint16_t  parse_len = 0;
+    int       ret_len   = 0;
+    e_ble_tlv tlv;
+    int8_t    ret = BLE_QIOT_REPLY_SUCCESS;
+
+    ble_qiot_ret_status_t inform_ret = BLE_QIOT_RS_OK;
+
+    ble_qiot_log_d("handle property data");
+    while (parse_len < buf_len) {
+        memset(&tlv, 0, sizeof(e_ble_tlv));
+        ret_len = ble_lldata_parse_tlv(in_buf + parse_len, buf_len - parse_len, &tlv);
+        if (ret_len < 0) {
+            return BLE_QIOT_RS_ERR;
+        }
+
+        parse_len += ret_len;
+        if (parse_len > buf_len) {
+            ble_qiot_log_e("invalid peroperty data, %d(property len) > %d(buf len)", parse_len, buf_len);
+            ret = BLE_QIOT_REPLY_DATA_ERR;
+            break;
+        }
+
+        if (BLE_QIOT_RS_OK != ble_user_property_set_data(&tlv)) {
+            ret = BLE_QIOT_REPLY_FAIL;
+            break;
+        }
+    }
+    if (is_request) {
+        return ble_event_notify(BLE_QIOT_EVENT_UP_CONTROL_REPLY, NULL, 0, (const char *)&ret, sizeof(int8_t));
+    } else {
+        return (BLE_QIOT_REPLY_SUCCESS == ret) ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
+    }
+#else
+    ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+    return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+}
+
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+// post property
+ble_qiot_ret_status_t ble_user_property_get_report_data(void)
+{
+    uint8_t  property_id   = 0;
+    uint8_t  property_type = 0;
+    int      property_len  = 0;
+    uint16_t type_len      = 0;
+    uint16_t data_len      = 0;
+    uint16_t data_buf_off  = 0;
+
+    uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
+
+    ble_qiot_log_d("report property");
+    for (property_id = 0; property_id < BLE_QIOT_PROPERTY_ID_BUTT; property_id++) {
+        property_type = ble_get_property_type_by_id(property_id);
+        if (property_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+            ble_qiot_log_e("property(%d) type(%d) invalid", property_id, property_type);
+            return BLE_QIOT_RS_ERR;
+        }
+
+        data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(property_type, property_id);
+        data_buf_off         = data_len;
+        if ((BLE_QIOT_DATA_TYPE_STRING == property_type) || (BLE_QIOT_DATA_TYPE_STRUCT == property_type)) {
+            // reserved 2 bytes for string/struct length
+            data_buf_off += BLE_QIOT_STRING_TYPE_LEN;
+        }
+        property_len = ble_user_property_get_data_by_id(property_id, (char *)&data_buf[data_buf_off],
+                                                        sizeof(data_buf) - data_buf_off);
+        if (property_len < 0) {
+            return BLE_QIOT_RS_ERR;
+        } else if (property_len == 0) {
+            // clean the property head cause no data to post
+            data_len--;
+            data_buf[data_len] = '0';
+            ble_qiot_log_d("property: %d no data to post", property_id);
+        } else {
+            if ((BLE_QIOT_DATA_TYPE_STRING == property_type) || (BLE_QIOT_DATA_TYPE_STRUCT == property_type)) {
+                // filling the payload length
+                type_len = HTONS(property_len);
+                memcpy(data_buf + data_len, &type_len, sizeof(uint16_t));
+                data_len += sizeof(uint16_t);
+            }
+            data_len += property_len;
+        }
+    }
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "user data", data_buf, data_len);
+
+    return ble_event_notify(BLE_QIOT_EVENT_UP_PROPERTY_REPORT, NULL, 0, (const char *)data_buf, data_len);
+}
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+
+// handle control
+ble_qiot_ret_status_t ble_lldata_property_request_handle(const char *in_buf, int buf_len)
+{
+    return ble_lldata_property_data_handle(true, in_buf, buf_len);
+}
+
+// handle report_reply
+static ble_qiot_ret_status_t ble_lldata_property_report_reply(const char *in_buf, int buf_len)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+    (void)ble_user_property_report_reply_handle(in_buf[0]);
+#else
+    ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+    return BLE_QIOT_RS_OK;
+}
+
+// handle get_status_reply
+static ble_qiot_ret_status_t ble_lldata_property_get_status_reply(const char *in_buf, int buf_len)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+    uint8_t  result    = 0;
+    uint16_t reply_len = 0;
+
+    result = in_buf[0];
+    ble_qiot_log_d("get status reply result: %d", result);
+    if (BLE_QIOT_REPLY_SUCCESS == result) {
+        memcpy(&reply_len, &in_buf[1], sizeof(uint16_t));
+        return ble_lldata_property_data_handle(false, in_buf + sizeof(uint8_t) + sizeof(uint16_t), NTOHS(reply_len));
+    } else {
+        return BLE_QIOT_RS_ERR;
+    }
+#else
+    ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+    return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+}
+
+// handle reply from remote
+ble_qiot_ret_status_t ble_lldata_property_reply_handle(uint8_t type, const char *in_buf, int buf_len)
+{
+    switch (type) {
+        case BLE_QIOT_DATA_DOWN_REPORT_REPLY:
+            return ble_lldata_property_report_reply(in_buf, buf_len);
+        case BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY:
+            return ble_lldata_property_get_status_reply(in_buf, buf_len);
+        default:
+            ble_qiot_log_e("invalid property reply type");
+            return BLE_QIOT_RS_ERR;
+    }
+}
+
+// handle event_post_reply
+ble_qiot_ret_status_t ble_lldata_event_handle(uint8_t id, const char *in_buf, int len)
+{
+#ifdef BLE_QIOT_INCLUDE_EVENT
+    (void)ble_user_event_reply_handle(id, in_buf[0]);
+#else
+    ble_qiot_log_e("event" BLE_QIOT_NOT_SUPPORT_WARN);
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+    return BLE_QIOT_RS_OK;
+}
+
+// handle action
+ble_qiot_ret_status_t ble_lldata_action_handle(uint8_t action_id, const char *in_buf, int len)
+{
+#ifdef BLE_QIOT_INCLUDE_ACTION
+    POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+
+    uint16_t parse_len        = 0;
+    uint8_t  tlv_index        = 0;
+    int      ret_len          = 0;
+    int      handle_ret       = BLE_QIOT_REPLY_SUCCESS;
+    uint8_t  output_id        = 0;
+    uint8_t  output_type      = 0;
+    uint16_t data_len         = 0;
+    uint16_t data_buf_off     = 0;
+    int      output_param_len = 0;
+    uint16_t string_len       = 0;
+    uint8_t  header_buf[2]    = {0};
+
+    e_ble_tlv tlv[BLE_QIOT_ACTION_INPUT_ID_BUTT]                = {0};
+    uint8_t   output_flag_array[BLE_QIOT_ACTION_OUTPUT_ID_BUTT] = {0};  // set true if the id have output
+    uint8_t   data_buf[BLE_QIOT_EVENT_MAX_SIZE]                 = {0};
+
+    header_buf[0] = BLE_QIOT_REPLY_SUCCESS;
+    header_buf[1] = action_id;
+
+    ble_qiot_log_d("input action: %d", action_id);
+    while (parse_len < len) {
+        if (tlv_index >= BLE_QIOT_ACTION_INPUT_ID_BUTT) {
+            ble_qiot_log_e("invalid action(id: %d) data", action_id);
+            handle_ret = BLE_QIOT_REPLY_DATA_ERR;
+            goto end;
+        }
+        ret_len = ble_lldata_parse_tlv(in_buf + parse_len, len - parse_len, &tlv[tlv_index]);
+        if (ret_len < 0) {
+            handle_ret = BLE_QIOT_REPLY_DATA_ERR;
+            goto end;
+        }
+        parse_len += ret_len;
+        tlv_index++;
+        if (parse_len > len) {
+            ble_qiot_log_e("action data parse failed, parse len: %d > data len: %d", parse_len, len);
+            handle_ret = BLE_QIOT_REPLY_DATA_ERR;
+            goto end;
+        }
+    }
+    if (0 != ble_action_user_handle_input_param(action_id, tlv, tlv_index, output_flag_array)) {
+        handle_ret = BLE_QIOT_REPLY_FAIL;
+        goto end;
+    }
+
+    for (output_id = 0; output_id < BLE_QIOT_ACTION_OUTPUT_ID_BUTT; output_id++) {
+        if (output_flag_array[output_id]) {
+            output_type = ble_action_get_output_type_by_id(action_id, output_id);
+            if (output_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+                ble_qiot_log_e("action id(%d:%d) type invalid", action_id, output_id);
+                handle_ret = BLE_QIOT_REPLY_FAIL;
+                goto end;
+            }
+            data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(output_type, output_id);
+            data_buf_off         = data_len;
+            if (BLE_QIOT_DATA_TYPE_STRING == output_type) {
+                data_buf_off += BLE_QIOT_STRING_TYPE_LEN;
+            }
+            output_param_len = ble_action_user_handle_output_param(
+                action_id, output_id, (char *)data_buf + data_buf_off, sizeof(data_buf) - data_buf_off);
+            if (output_param_len < 0) {
+                handle_ret = BLE_QIOT_REPLY_FAIL;
+                goto end;
+            } else if (output_param_len == 0) {
+                // clean the head cause no data to post
+                data_len--;
+                data_buf[data_len] = '0';
+                ble_qiot_log_d("action id(%d: %d) no data to post", action_id, output_id);
+            } else {
+                if (BLE_QIOT_DATA_TYPE_STRING == output_type) {
+                    string_len = HTONS(output_param_len);
+                    memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
+                    data_len += sizeof(uint16_t);
+                }
+                data_len += output_param_len;
+            }
+        }
+    }
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "user data", data_buf, data_len);
+    return ble_event_notify(BLE_QIOT_EVENT_UP_ACTION_REPLY, header_buf, sizeof(header_buf), (const char *)data_buf,
+                            data_len);
+
+end:
+    header_buf[0] = BLE_QIOT_REPLY_FAIL;
+    ble_event_notify(BLE_QIOT_EVENT_UP_ACTION_REPLY, header_buf, sizeof(header_buf), (const char *)&handle_ret,
+                     sizeof(uint8_t));
+    return BLE_QIOT_RS_ERR;
+#else
+    ble_qiot_log_e("action" BLE_QIOT_NOT_SUPPORT_WARN);
+    return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_PROPERTY
+}
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif

+ 391 - 0
qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_device.c

@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ble_qiot_common.h"
+#include "ble_qiot_config.h"
+#include "ble_qiot_export.h"
+#include "ble_qiot_hmac.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_md5.h"
+#include "ble_qiot_llsync_device.h"
+
+#define BLE_GET_EXPIRATION_TIME(_cur_time) ((_cur_time) + BLE_EXPIRATION_TIME)
+
+static ble_core_data             sg_core_data;                // ble data storage in flash
+static ble_device_info           sg_device_info;              // device info storage in flash
+static e_llsync_bind_state       sg_llsync_bind_state;        // llsync bind state in used
+static e_llsync_connection_state sg_llsync_connection_state;  // llsync connection state in used
+static e_ble_connection_state    sg_ble_connection_state;     // ble connection state in used
+static uint16_t                  sg_llsync_mtu;               // the mtu for llsync slice data
+
+uint16_t llsync_mtu_get(void)
+{
+    // return default mtu if llsync mtu not set
+    if (0 == sg_llsync_mtu) {
+        sg_llsync_mtu = ATT_MTU_TO_LLSYNC_MTU(ATT_DEFAULT_MTU);
+    }
+    return sg_llsync_mtu;
+}
+
+void llsync_mtu_update(uint16_t llsync_mtu)
+{
+    sg_llsync_mtu = llsync_mtu;
+}
+
+void llsync_bind_state_set(e_llsync_bind_state new_state)
+{
+    ble_qiot_log_d("bind state: %d ---> %d", sg_llsync_bind_state, new_state);
+    sg_llsync_bind_state = new_state;
+}
+
+e_llsync_bind_state llsync_bind_state_get(void)
+{
+    return sg_llsync_bind_state;
+}
+
+void llsync_connection_state_set(e_llsync_connection_state new_state)
+{
+    ble_qiot_log_d("llsync state: %d ---> %d", sg_llsync_connection_state, new_state);
+    sg_llsync_connection_state = new_state;
+}
+
+bool llsync_is_connected(void)
+{
+    return sg_llsync_connection_state == E_LLSYNC_CONNECTED;
+}
+
+void ble_connection_state_set(e_ble_connection_state new_state)
+{
+    ble_qiot_log_d("ble state: %d ---> %d", sg_llsync_connection_state, new_state);
+    sg_ble_connection_state = new_state;
+}
+
+bool ble_is_connected(void)
+{
+    return sg_ble_connection_state == E_BLE_CONNECTED;
+}
+
+// [1byte bind state] + [6 bytes mac] + [8bytes identify string]/[10 bytes product id]
+int ble_get_my_broadcast_data(char *out_buf, int buf_len)
+{
+    POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(buf_len, BLE_BIND_IDENTIFY_STR_LEN + BLE_QIOT_MAC_LEN + 1, BLE_QIOT_RS_ERR_PARA);
+    int     ret_len                      = 0;
+#if BLE_QIOT_LLSYNC_STANDARD
+    int     i                            = 0;
+    uint8_t md5_in_buf[128]              = {0};
+    uint8_t md5_in_len                   = 0;
+    uint8_t md5_out_buf[MD5_DIGEST_SIZE] = {0};
+
+    out_buf[ret_len++] = llsync_bind_state_get() | (BLE_QIOT_LLSYNC_PROTOCOL_VERSION << LLSYNC_PROTO_VER_BIT);
+    if (E_LLSYNC_BIND_SUCC == llsync_bind_state_get()) {
+        // 1 bytes state + 8 bytes device identify_str + 8 bytes identify_str
+        memcpy((char *)md5_in_buf, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+        md5_in_len += sizeof(sg_device_info.product_id);
+        memcpy((char *)md5_in_buf + md5_in_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+        md5_in_len += strlen(sg_device_info.device_name);
+        utils_md5(md5_in_buf, md5_in_len, md5_out_buf);
+        for (i = 0; i < MD5_DIGEST_SIZE / 2; i++) {
+            out_buf[i + ret_len] = md5_out_buf[i] ^ md5_out_buf[i + MD5_DIGEST_SIZE / 2];
+        }
+        ret_len += MD5_DIGEST_SIZE / 2;
+        memcpy(out_buf + ret_len, sg_core_data.identify_str, sizeof(sg_core_data.identify_str));
+        ret_len += sizeof(sg_core_data.identify_str);
+    } else
+#endif //BLE_QIOT_LLSYNC_STANDARD
+    {
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+        out_buf[ret_len++] = BLE_QIOT_LLSYNC_PROTOCOL_VERSION;
+#endif // BLE_QIOT_LLSYNC_CONFIG_NET
+        // 1 bytes state + 6 bytes mac + 10 bytes product id
+        memcpy(out_buf + ret_len, sg_device_info.mac, BLE_QIOT_MAC_LEN);
+        ret_len += BLE_QIOT_MAC_LEN;
+        memcpy(out_buf + ret_len, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+        ret_len += sizeof(sg_device_info.product_id);
+    }
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "broadcast", out_buf, ret_len);
+
+    return ret_len;
+}
+
+int ble_inform_mtu_result(const char *result, uint16_t data_len)
+{
+    uint16_t ret = 0;
+
+    memcpy(&ret, result, sizeof(uint16_t));
+    ret = NTOHS(ret);
+    ble_qiot_log_i("mtu setting result: %02x", ret);
+
+    if (LLSYNC_MTU_SET_RESULT_ERR == ret) {
+        return ble_event_sync_mtu(ATT_DEFAULT_MTU);
+    } else if (0 == ret) {
+        return BLE_QIOT_RS_OK;
+    } else {
+        llsync_mtu_update(ATT_MTU_TO_LLSYNC_MTU(ret));
+        return BLE_QIOT_RS_OK;
+    }
+}
+
+#if BLE_QIOT_LLSYNC_STANDARD
+static int memchk(const uint8_t *buf, int len)
+{
+    int i = 0;
+
+    for (i = 0; i < len; i++) {
+        if (buf[i] != 0xFF) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static ble_qiot_ret_status_t ble_write_core_data(ble_core_data *core_data)
+{
+    memcpy(&sg_core_data, core_data, sizeof(ble_core_data));
+    if (sizeof(ble_core_data) !=
+        ble_write_flash(BLE_QIOT_RECORD_FLASH_ADDR, (char *)&sg_core_data, sizeof(ble_core_data))) {
+        ble_qiot_log_e("llsync write core failed");
+        return BLE_QIOT_RS_ERR_FLASH;
+    }
+
+    return BLE_QIOT_RS_OK;
+}
+
+int ble_bind_get_authcode(const char *bind_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
+{
+    POINTER_SANITY_CHECK(bind_data, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_bind_data), BLE_QIOT_RS_ERR_PARA);
+    POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN, BLE_QIOT_RS_ERR_PARA);
+
+    char    out_sign[SHA1_DIGEST_SIZE]       = {0};
+    char    sign_info[80]                    = {0};
+    int     sign_info_len                    = 0;
+    int     time_expiration                  = 0;
+    int     nonce                            = 0;
+    int     ret_len                          = 0;
+    uint8_t secret[BLE_QIOT_PSK_LEN / 4 * 3] = {0};
+    int     secret_len                       = 0;
+
+    // if the pointer "char *bind_data" is not aligned with 4 byte, in some cpu convert it to
+    // pointer "ble_bind_data *" work correctly, but some cpu will get wrong value, or cause
+    // other "Unexpected Error". Here copy it to a local variable make sure aligned with 4 byte.
+    ble_bind_data bind_data_aligned;
+    memcpy(&bind_data_aligned, bind_data, sizeof(ble_bind_data));
+
+    nonce           = NTOHL(bind_data_aligned.nonce);
+    time_expiration = BLE_GET_EXPIRATION_TIME(NTOHL(bind_data_aligned.timestamp));
+
+    // [10 bytes product_id] + [x bytes device name] + ';' + [4 bytes nonce] + ';' + [4 bytes timestamp]
+    memcpy(sign_info, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+    sign_info_len += sizeof(sg_device_info.product_id);
+    memcpy(sign_info + sign_info_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+    sign_info_len += strlen(sg_device_info.device_name);
+    snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, ";%u", nonce);
+    sign_info_len += strlen(sign_info + sign_info_len);
+    snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, ";%u", time_expiration);
+    sign_info_len += strlen(sign_info + sign_info_len);
+
+    qcloud_iot_utils_base64decode(secret, sizeof(secret), (size_t *)&secret_len,
+                                  (const unsigned char *)sg_device_info.psk, sizeof(sg_device_info.psk));
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind sign in", sign_info, sign_info_len);
+    utils_hmac_sha1((const char *)sign_info, sign_info_len, out_sign, (const char *)secret, secret_len);
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind sign out", out_sign, sizeof(out_sign));
+
+    // return [20 bytes sign] + [x bytes device_name]
+    memset(out_buf, 0, buf_len);
+    memcpy(out_buf, out_sign, SHA1_DIGEST_SIZE);
+    ret_len = SHA1_DIGEST_SIZE;
+
+    memcpy(out_buf + ret_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+    ret_len += strlen(sg_device_info.device_name);
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind auth code", out_buf, ret_len);
+
+    return ret_len;
+}
+
+ble_qiot_ret_status_t ble_bind_write_result(const char *result, uint16_t len)
+{
+    POINTER_SANITY_CHECK(result, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(len, (int32_t)sizeof(ble_core_data), BLE_QIOT_RS_ERR_PARA);
+
+    ble_core_data *bind_result = (ble_core_data *)result;
+
+    llsync_bind_state_set((e_llsync_bind_state)bind_result->bind_state);
+    return ble_write_core_data(bind_result);
+}
+
+ble_qiot_ret_status_t ble_unbind_write_result(void)
+{
+    ble_core_data bind_result;
+
+    llsync_connection_state_set(E_LLSYNC_DISCONNECTED);
+    llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
+    memset(&bind_result, 0, sizeof(bind_result));
+    return ble_write_core_data(&bind_result);
+}
+
+int ble_conn_get_authcode(const char *conn_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
+{
+    POINTER_SANITY_CHECK(conn_data, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_conn_data), BLE_QIOT_RS_ERR_PARA);
+    POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN, BLE_QIOT_RS_ERR_PARA);
+
+    char sign_info[64]              = {0};
+    char out_sign[SHA1_DIGEST_SIZE] = {0};
+    int  sign_info_len              = 0;
+    int  timestamp                  = 0;
+    int  ret_len                    = 0;
+
+    // if the pointer "char *bind_data" is not aligned with 4 byte, in some cpu convert it to
+    // pointer "ble_bind_data *" work correctly, but some cpu will get wrong value, or cause
+    // other "Unexpected Error". Here copy it to a local variable make sure aligned with 4 byte.
+    ble_conn_data conn_data_aligned;
+    memcpy(&conn_data_aligned, conn_data, sizeof(ble_conn_data));
+
+    // valid sign
+    timestamp = NTOHL(conn_data_aligned.timestamp);
+    snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, "%d", timestamp);
+    sign_info_len = strlen(sign_info + sign_info_len);
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign in", sign_info, sign_info_len);
+    utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign out", out_sign, SHA1_DIGEST_SIZE);
+    if (0 != memcmp(&conn_data_aligned.sign_info, out_sign, SHA1_DIGEST_SIZE)) {
+        ble_qiot_log_e("llsync invalid connect sign");
+        return BLE_QIOT_RS_VALID_SIGN_ERR;
+    }
+
+    // calc sign
+    memset(sign_info, 0, sizeof(sign_info));
+    sign_info_len = 0;
+
+    // expiration time + product id + device name
+    timestamp = BLE_GET_EXPIRATION_TIME(NTOHL(conn_data_aligned.timestamp));
+    snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, "%d", timestamp);
+    sign_info_len += strlen(sign_info + sign_info_len);
+    memcpy(sign_info + sign_info_len, sg_device_info.product_id, sizeof(sg_device_info.product_id));
+    sign_info_len += sizeof(sg_device_info.product_id);
+    memcpy(sign_info + sign_info_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+    sign_info_len += strlen(sg_device_info.device_name);
+
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn sign in", sign_info, sign_info_len);
+    utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn sign out", out_sign, sizeof(out_sign));
+
+    // return authcode
+    memset(out_buf, 0, buf_len);
+    memcpy(out_buf, out_sign, SHA1_DIGEST_SIZE);
+    ret_len += SHA1_DIGEST_SIZE;
+    memcpy(out_buf + ret_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
+    ret_len += strlen(sg_device_info.device_name);
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn auth code", out_buf, ret_len);
+
+    return ret_len;
+}
+
+int ble_unbind_get_authcode(const char *unbind_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
+{
+    POINTER_SANITY_CHECK(unbind_data, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_unbind_data), BLE_QIOT_RS_ERR_PARA);
+    POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
+    BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE, BLE_QIOT_RS_ERR_PARA);
+
+    char sign_info[32]              = {0};
+    char out_sign[SHA1_DIGEST_SIZE] = {0};
+    int  sign_info_len              = 0;
+    int  ret_len                    = 0;
+
+    // valid sign
+    memcpy(sign_info, BLE_UNBIND_REQUEST_STR, BLE_UNBIND_REQUEST_STR_LEN);
+    sign_info_len = BLE_UNBIND_REQUEST_STR_LEN;
+    utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign out", out_sign, SHA1_DIGEST_SIZE);
+
+    if (0 != memcmp(((ble_unbind_data *)unbind_data)->sign_info, out_sign, SHA1_DIGEST_SIZE)) {
+        ble_qiot_log_e("llsync invalid unbind sign");
+        return BLE_QIOT_RS_VALID_SIGN_ERR;
+    }
+
+    // calc sign
+    memset(sign_info, 0, sizeof(sign_info));
+    sign_info_len = 0;
+
+    memcpy(sign_info, BLE_UNBIND_RESPONSE, strlen(BLE_UNBIND_RESPONSE));
+    sign_info_len += BLE_UNBIND_RESPONSE_STR_LEN;
+    utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "unbind auth code", out_sign, SHA1_DIGEST_SIZE);
+
+    memset(out_buf, 0, buf_len);
+    memcpy(out_buf, out_sign, sizeof(out_sign));
+    ret_len += sizeof(out_sign);
+
+    return ret_len;
+}
+
+#endif
+
+ble_qiot_ret_status_t ble_init_flash_data(void)
+{
+#if BLE_QIOT_LLSYNC_STANDARD
+    if (sizeof(sg_core_data) !=
+        ble_read_flash(BLE_QIOT_RECORD_FLASH_ADDR, (char *)&sg_core_data, sizeof(sg_core_data))) {
+        ble_qiot_log_e("llsync read flash failed");
+        return BLE_QIOT_RS_ERR_FLASH;
+    }
+    if (0 == memchk((const uint8_t *)&sg_core_data, sizeof(sg_core_data))) {
+        memset(&sg_core_data, 0, sizeof(sg_core_data));
+    }
+
+    if (0 != ble_get_psk(sg_device_info.psk)) {
+        ble_qiot_log_e("llsync get secret key failed");
+        return BLE_QIOT_RS_ERR_FLASH;
+    }
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+    if (0 != ble_get_mac(sg_device_info.mac)) {
+        ble_qiot_log_e("llsync get mac failed");
+        return BLE_QIOT_RS_ERR_FLASH;
+    }
+    if (0 != ble_get_product_id(sg_device_info.product_id)) {
+        ble_qiot_log_e("llsync get product id failed");
+        return BLE_QIOT_RS_ERR_FLASH;
+    }
+    if (0 == ble_get_device_name(sg_device_info.device_name)) {
+        ble_qiot_log_e("llsync get device name failed");
+        return BLE_QIOT_RS_ERR_FLASH;
+    }
+
+#if BLE_QIOT_LLSYNC_STANDARD
+    llsync_bind_state_set((e_llsync_bind_state)sg_core_data.bind_state);
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "core_data", (char *)&sg_core_data, sizeof(sg_core_data));
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "device_info", (char *)&sg_device_info, sizeof(sg_device_info));
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+    return BLE_QIOT_RS_OK;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 269 - 0
qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_event.c

@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "ble_qiot_import.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_llsync_device.h"
+#include "ble_qiot_llsync_event.h"
+
+// report device info
+ble_qiot_ret_status_t ble_event_report_device_info(void)
+{
+    char     device_info[56] = {0};  // 1 byte llsync proto version + 2 bytes mtu size + 1 byte length of develop version
+    uint16_t mtu_size       = 0;
+
+#if BLE_QIOT_REMOTE_SET_MTU
+    mtu_size = LLSYNC_MTU_SET_MASK;
+#endif //BLE_QIOT_REMOTE_SET_MTU
+    mtu_size |= ble_get_user_data_mtu_size();
+    mtu_size       = HTONS(mtu_size);
+    device_info[0] = BLE_QIOT_LLSYNC_PROTOCOL_VERSION;
+    memcpy(&device_info[1], &mtu_size, sizeof(mtu_size));
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+    device_info[3] = (char)ble_get_device_name(&device_info[4]);
+#else
+    device_info[3] = (char)strlen(BLE_QIOT_USER_DEVELOPER_VERSION);
+    memcpy(&device_info[4], BLE_QIOT_USER_DEVELOPER_VERSION, device_info[3]);
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+    return ble_event_notify(BLE_QIOT_EVENT_UP_REPORT_MTU, NULL, 0, device_info, 4 + device_info[3]);
+}
+
+// sync mtu
+ble_qiot_ret_status_t ble_event_sync_mtu(uint16_t att_mtu)
+{
+    uint16_t mtu_size = 0;
+
+    mtu_size = ATT_MTU_TO_LLSYNC_MTU(att_mtu);
+    llsync_mtu_update(mtu_size);
+    mtu_size = HTONS(mtu_size);
+    return ble_event_notify(BLE_QIOT_EVENT_UP_SYNC_MTU, NULL, 0, (const char*)&mtu_size, sizeof(uint16_t));
+}
+
+ble_qiot_ret_status_t ble_event_notify2(uint8_t type, uint8_t length_flag, uint8_t *header, uint8_t header_len,
+                                        const char *buf, uint16_t buf_len)
+{
+    char *   p              = (char *)buf;
+    uint16_t left_len       = buf_len;
+    uint16_t send_len       = 0;
+    uint16_t mtu_size       = 0;
+    uint8_t  slice_state    = BLE_QIOT_EVENT_NO_SLICE;
+    uint16_t send_buf_index = 0;
+    uint16_t tmp_len        = 0;
+
+    uint8_t send_buf[BLE_QIOT_EVENT_BUF_SIZE] = {0};
+
+    if (!llsync_is_connected() && type != BLE_QIOT_EVENT_UP_BIND_SIGN_RET && type != BLE_QIOT_EVENT_UP_CONN_SIGN_RET &&
+        type != BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET && type != BLE_QIOT_EVENT_UP_SYNC_WAIT_TIME) {
+        ble_qiot_log_e("upload msg negate, device not connected");
+        return BLE_QIOT_RS_ERR;
+    }
+
+    // reserve event header length, 3 bytes fixed length + n bytes header
+    mtu_size = llsync_mtu_get();
+    mtu_size = mtu_size > sizeof(send_buf) ? sizeof(send_buf) : mtu_size;
+    mtu_size -= (BLE_QIOT_EVENT_FIXED_HEADER_LEN + header_len);
+    // ble_qiot_log_d("mtu size %d", mtu_size);
+
+    do {
+        memset(send_buf, 0, sizeof(send_buf));
+        send_buf_index = 0;
+        send_len       = left_len > mtu_size ? mtu_size : left_len;
+
+        send_buf[send_buf_index++] = type;
+        if (NULL != buf) {
+            tmp_len = HTONS(send_len + header_len);
+            memcpy(send_buf + send_buf_index, &tmp_len, sizeof(uint16_t));
+            send_buf_index += sizeof(uint16_t);
+            if (NULL != header) {
+                memcpy(send_buf + send_buf_index, header, header_len);
+                send_buf_index += header_len;
+            }
+            memcpy(send_buf + send_buf_index, p, send_len);
+            send_buf_index += send_len;
+
+            p += send_len;
+            left_len -= send_len;
+            send_len += (BLE_QIOT_EVENT_FIXED_HEADER_LEN + header_len);
+
+            if (0 == left_len) {
+                slice_state =
+                    (BLE_QIOT_EVENT_NO_SLICE == slice_state) ? BLE_QIOT_EVENT_NO_SLICE : BLE_QIOT_EVENT_SLICE_FOOT;
+            } else {
+                slice_state =
+                    (BLE_QIOT_EVENT_NO_SLICE == slice_state) ? BLE_QIOT_EVENT_SLICE_HEAD : BLE_QIOT_EVENT_SLICE_BODY;
+            }
+            // the high 2 bits means slice state, and the left 14 bits is data length
+            send_buf[1] |= slice_state << 6;
+            send_buf[1] |= length_flag;
+        } else {
+            send_len = send_buf_index;
+        }
+
+        ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "post data", (char *)send_buf, send_len);
+        if (0 != ble_send_notify(send_buf, send_len)) {
+            ble_qiot_log_e("event(type: %d) post failed, len: %d", type, send_len);
+            return BLE_QIOT_RS_ERR;
+        }
+    } while (left_len != 0);
+
+    return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_event_notify(uint8_t type, uint8_t *header, uint8_t header_len, const char *buf,
+                                       uint16_t buf_len)
+{
+    return ble_event_notify2(type, 0, header, header_len, buf, buf_len);
+}
+
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+ble_qiot_ret_status_t ble_event_report_wifi_mode(uint8_t result)
+{
+    return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_MODE, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_info(uint8_t result)
+{
+    return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_INFO, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_connect(BLE_WIFI_MODE mode, BLE_WIFI_STATE state, uint8_t ssid_len,
+                                                    const char *ssid)
+{
+    char    buf[40] = {0};
+    uint8_t pos     = 0;
+
+    buf[pos++] = mode;
+    buf[pos++] = state;
+    buf[pos++] = 0;
+    buf[pos++] = ssid_len;
+    memcpy(buf + pos, ssid, ssid_len);
+
+    return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_CONNECT, NULL, 0, (const char *)buf, pos + ssid_len);
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_token(uint8_t result)
+{
+    return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_TOKEN, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+
+ble_qiot_ret_status_t ble_event_report_wifi_log(const uint8_t *log, uint16_t log_size)
+{
+    return ble_event_notify(BLE_QIOT_EVENT_UP_WIFI_LOG, NULL, 0, (const char *)log, log_size);
+}
+#endif //BLE_QIOT_LLSYNC_CONFIG_NET
+
+#if BLE_QIOT_LLSYNC_STANDARD
+// get_status
+ble_qiot_ret_status_t ble_event_get_status(void)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+    return ble_event_notify(BLE_QIOT_EVENT_UP_GET_STATUS, NULL, 0, NULL, 0);
+#else
+    ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+    return BLE_QIOT_RS_OK;
+#endif
+}
+
+// report
+ble_qiot_ret_status_t ble_event_report_property(void)
+{
+#ifdef BLE_QIOT_INCLUDE_PROPERTY
+    return ble_user_property_get_report_data();
+#else
+    ble_qiot_log_e("property" BLE_QIOT_NOT_SUPPORT_WARN);
+    return BLE_QIOT_RS_OK;
+#endif
+}
+
+#if BLE_QIOT_SECURE_BIND
+ble_qiot_ret_status_t ble_event_sync_wait_time(void)
+{
+    uint16_t time = BLE_QIOT_BIND_WAIT_TIME;
+
+    time = HTONS(time);
+    return ble_event_notify(BLE_QIOT_EVENT_UP_SYNC_WAIT_TIME, NULL, 0, (const char*)&time, sizeof(uint16_t));
+}
+#endif //BLE_QIOT_SECURE_BIND
+
+ble_qiot_ret_status_t ble_event_post(uint8_t event_id)
+{
+#ifdef BLE_QIOT_INCLUDE_EVENT
+    uint8_t  param_id      = 0;
+    uint8_t  param_id_size = 0;
+    uint8_t  param_type    = 0;
+    int      param_len     = 0;
+    uint16_t data_len      = 0;
+    uint16_t data_buf_off  = 0;
+    uint16_t string_len    = 0;
+    uint8_t  header_buf    = {0};
+
+    uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
+
+    ble_qiot_log_d("post event: %d", event_id);
+    param_id_size = ble_event_get_id_array_size(event_id);
+    // get all data
+    for (param_id = 0; param_id < param_id_size; param_id++) {
+        param_type = ble_event_get_param_id_type(event_id, param_id);
+        if (param_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+            ble_qiot_log_e("invalid event(%d:%d) type", event_id, param_id);
+            return BLE_QIOT_RS_ERR;
+        }
+
+        data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(param_type, param_id);
+        data_buf_off         = data_len;
+        if (BLE_QIOT_DATA_TYPE_STRING == param_type) {
+            // reserved 2 bytes for string type, other type have fixed length
+            data_buf_off += BLE_QIOT_STRING_TYPE_LEN;
+        }
+        param_len = ble_event_get_data_by_id(event_id, param_id, (char *)data_buf + data_buf_off,
+                                             sizeof(data_buf) - data_buf_off);
+        if (param_len < 0) {
+            return BLE_QIOT_RS_ERR;
+        } else if (param_len == 0) {
+            // clean the header cause no data to post
+            data_len--;
+            data_buf[data_len] = '0';
+            ble_qiot_log_d("event(%d: %d) no data to post", event_id, param_id);
+        } else {
+            if (BLE_QIOT_DATA_TYPE_STRING == param_type) {
+                string_len = HTONS(param_len);
+                memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
+                data_len += sizeof(uint16_t);
+            }
+            data_len += param_len;
+        }
+    }
+    header_buf = event_id;
+
+    return ble_event_notify(BLE_QIOT_EVENT_UP_EVENT_POST, &header_buf, sizeof(header_buf), (const char *)data_buf,
+                            data_len);
+#else
+    ble_qiot_log_e("event" BLE_QIOT_NOT_SUPPORT_WARN);
+    return BLE_QIOT_RS_OK;
+#endif //BLE_QIOT_INCLUDE_EVENT
+}
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif

+ 491 - 0
qcloud_iot_explorer_ble/src/core/ble_qiot_llsync_ota.c

@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+#if BLE_QIOT_LLSYNC_STANDARD
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_common.h"
+#include "ble_qiot_llsync_data.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_crc.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_llsync_ota.h"
+
+#if BLE_QIOT_SUPPORT_OTA
+static ble_ota_user_callback sg_ota_user_cb;  // user callback
+// 1. monitor the data and request from the server if data lost; 2. call the user function if no data for a long time
+static ble_timer_t sg_ota_timer                           = NULL;
+static uint8_t     sg_ota_timeout_cnt                     = 0;    // count the number of no data times
+static uint8_t     sg_ota_data_buf[BLE_QIOT_OTA_BUF_SIZE] = {0};  // storage ota data and write to the flash at once
+static uint16_t    sg_ota_data_buf_size                   = 0;    // the data size in the buffer
+static uint32_t    sg_ota_download_file_size              = 0;    // the data size download from the server
+static uint8_t     sg_ota_next_seq                        = 0;    // the next expect seq
+static uint32_t    sg_ota_download_address                = 0;    // the address saved ota file
+static uint8_t     sg_ota_download_percent                = 0;    // the percent of file had download
+static uint8_t     sg_ota_flag                            = 0;    // ota control info
+static ble_ota_info_record sg_ota_info;                           // the ota info storage in flash if support resuming
+static ble_ota_reply_t     sg_ota_reply_info;                     // record the last reply info
+
+#define BLE_QIOT_OTA_FLAG_SET(_BIT)    (sg_ota_flag |= (_BIT));
+#define BLE_QIOT_OTA_FLAG_CLR(_BIT)    (sg_ota_flag &= ~(_BIT));
+#define BLE_QIOT_OTA_FLAG_IS_SET(_BIT) ((sg_ota_flag & (_BIT)) == (_BIT))
+
+static inline bool ble_qiot_ota_info_valid(void)
+{
+    return sg_ota_info.valid_flag == BLE_QIOT_OTA_PAGE_VALID_VAL;
+}
+static inline uint8_t ble_ota_next_seq_get(void)
+{
+    return sg_ota_next_seq;
+}
+static inline void ble_ota_next_seq_inc(void)
+{
+    sg_ota_next_seq++;
+}
+static inline uint32_t ble_ota_download_address_get(void)
+{
+    return sg_ota_download_address;
+}
+static inline void ble_ota_download_address_set(void)
+{
+    sg_ota_download_address = ble_ota_get_download_addr();
+    return;
+}
+static inline uint32_t ble_ota_download_size_get(void)
+{
+    return sg_ota_download_file_size;
+}
+static inline void ble_ota_download_size_inc(uint32_t size)
+{
+    sg_ota_download_file_size += size;
+}
+static inline uint8_t ble_ota_file_percent_get(void)
+{
+    return sg_ota_download_percent;
+}
+static inline void ble_ota_file_percent_set(uint8_t percent)
+{
+    sg_ota_download_percent = percent;
+}
+void ble_ota_callback_reg(ble_ota_start_callback start_cb, ble_ota_stop_callback stop_cb,
+                          ble_ota_valid_file_callback valid_file_cb)
+{
+    sg_ota_user_cb.start_cb      = start_cb;
+    sg_ota_user_cb.stop_cb       = stop_cb;
+    sg_ota_user_cb.valid_file_cb = valid_file_cb;
+}
+static inline void ble_ota_user_start_cb(void)
+{
+    if (NULL != sg_ota_user_cb.start_cb) {
+        ble_qiot_log_i("start callback begin");
+        sg_ota_user_cb.start_cb();
+        ble_qiot_log_i("start callback end");
+    }
+}
+static inline void ble_ota_user_stop_cb(uint8_t result)
+{
+    if (NULL != sg_ota_user_cb.stop_cb) {
+        ble_qiot_log_i("stop callback begin");
+        sg_ota_user_cb.stop_cb(result);
+        ble_qiot_log_i("stop callback end");
+    }
+}
+static inline ble_qiot_ret_status_t ble_ota_user_valid_cb(void)
+{
+    if (NULL != sg_ota_user_cb.valid_file_cb) {
+        ble_qiot_log_i("valid callback begin");
+        return sg_ota_user_cb.valid_file_cb(sg_ota_info.download_file_info.file_size,
+                                            (char *)sg_ota_info.download_file_info.file_version);
+    }
+    return BLE_QIOT_RS_OK;
+}
+static inline ble_qiot_ret_status_t ble_ota_write_info(void)
+{
+#if BLE_QIOT_SUPPORT_RESUMING
+    sg_ota_info.valid_flag     = BLE_QIOT_OTA_PAGE_VALID_VAL;
+    sg_ota_info.last_file_size = ble_ota_download_size_get();
+    sg_ota_info.last_address   = ble_ota_download_address_get();
+    if (sizeof(ble_ota_info_record) !=
+        ble_write_flash(BLE_QIOT_OTA_INFO_FLASH_ADDR, (const char *)&sg_ota_info, sizeof(ble_ota_info_record))) {
+        ble_qiot_log_e("write ota info failed");
+        return BLE_QIOT_RS_ERR;
+    }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+    return BLE_QIOT_RS_OK;
+}
+static inline void ble_ota_clear_info(void)
+{
+#if BLE_QIOT_SUPPORT_RESUMING
+    sg_ota_info.valid_flag = ~BLE_QIOT_OTA_PAGE_VALID_VAL;
+    if (sizeof(ble_ota_info_record) !=
+        ble_write_flash(BLE_QIOT_OTA_INFO_FLASH_ADDR, (const char *)&sg_ota_info, sizeof(ble_ota_info_record))) {
+        ble_qiot_log_e("clear ota info failed");
+    }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+    return;
+}
+static inline ble_qiot_ret_status_t ble_ota_reply_ota_data(void)
+{
+    uint8_t  req       = ble_ota_next_seq_get();
+    uint32_t file_size = ble_ota_download_size_get();
+
+    if (sg_ota_reply_info.file_size != file_size) {
+        sg_ota_reply_info.file_size = file_size;
+        sg_ota_reply_info.req       = req;
+    } else {
+        // in the case that the device reply info missed, the timer reply info again but the seq increased, so we need
+        // saved the last reply info and used in the time
+        req = sg_ota_reply_info.req;
+        // ble_qiot_log_d("used old file size %d, req %d", file_size, req);
+    }
+
+    file_size = HTONL(file_size);
+    return ble_event_notify(BLE_QIOT_EVENT_UP_REPLY_OTA_DATA, &req, sizeof(uint8_t), (const char *)&file_size,
+                            sizeof(uint32_t));
+}
+static inline ble_qiot_ret_status_t ble_ota_report_check_result(uint8_t firmware_valid, uint8_t error_code)
+{
+    uint8_t result = firmware_valid | error_code;
+    return ble_event_notify(BLE_QIOT_EVENT_UP_REPORT_CHECK_RESULT, NULL, 0, (const char *)&result, sizeof(uint8_t));
+}
+static inline void ble_ota_timer_delete(void)
+{
+    if (NULL == sg_ota_timer) {
+        ble_qiot_log_e("ble ota timer invalid, delete failed");
+        return;
+    }
+    if (BLE_QIOT_RS_OK != ble_timer_delete(sg_ota_timer)) {
+        ble_qiot_log_e("ble ota timer delete failed");
+    }
+    sg_ota_timer = NULL;
+    return;
+}
+static ble_qiot_ret_status_t ble_ota_write_data_to_flash(void)
+{
+    int ret        = 0;
+    int write_addr = 0;
+
+    // the download size include the data size, so the write address exclude the data size
+    write_addr = ble_ota_download_address_get() + ble_ota_download_size_get() - sg_ota_data_buf_size;
+    ret        = ble_ota_write_flash(write_addr, (const char *)sg_ota_data_buf, sg_ota_data_buf_size);
+    if (ret != sg_ota_data_buf_size) {
+        ble_qiot_log_e("ota data write flash failed");
+        return BLE_QIOT_RS_ERR;
+    }
+    return BLE_QIOT_RS_OK;
+}
+static void ble_ota_timer_callback(void *param)
+{
+    if (BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_RECV_DATA_BIT)) {
+        BLE_QIOT_OTA_FLAG_CLR(BLE_QIOT_OTA_RECV_DATA_BIT);
+        return;
+    }
+    sg_ota_timeout_cnt++;
+
+    ble_qiot_log_w("reply in the timer, count: %d", sg_ota_timeout_cnt);
+    ble_ota_reply_ota_data();
+
+    if (sg_ota_timeout_cnt >= BLE_QIOT_OTA_MAX_RETRY_COUNT) {
+        sg_ota_flag = 0;
+        ble_ota_timer_delete();
+        // inform the user ota failed because timeout
+        ble_ota_user_stop_cb(BLE_QIOT_OTA_ERR_TIMEOUT);
+    }
+}
+static inline void ble_ota_timer_start(void)
+{
+    if (NULL == sg_ota_timer) {
+        sg_ota_timer = ble_timer_create(BLE_TIMER_PERIOD_TYPE, ble_ota_timer_callback);
+        if (NULL == sg_ota_timer) {
+            ble_qiot_log_e("ble ota timer create failed");
+            return;
+        }
+    }
+    if (BLE_QIOT_RS_OK != ble_timer_start(sg_ota_timer, BLE_QIOT_RETRY_TIMEOUT * 1000)) {
+        ble_qiot_log_e("ble ota timer start failed");
+    }
+    return;
+}
+static ble_qiot_ret_status_t ble_ota_init(void)
+{
+    uint32_t size_align   = 0;
+    uint8_t  file_percent = 0;
+
+    // init the ota env
+    memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+    sg_ota_data_buf_size = 0;
+    sg_ota_timeout_cnt   = 0;
+    memset(&sg_ota_info, 0, sizeof(ble_ota_info_record));
+    sg_ota_download_file_size = 0;
+    sg_ota_next_seq           = 0;
+    sg_ota_download_percent   = 0;
+    sg_ota_flag               = 0;
+    ble_ota_download_address_set();
+    memset(&sg_ota_reply_info, 0, sizeof(sg_ota_reply_info));
+
+#if BLE_QIOT_SUPPORT_RESUMING
+    // start from 0 if read flash fail, but ota will continue so ignored the return code
+    ble_read_flash(BLE_QIOT_OTA_INFO_FLASH_ADDR, (char *)&sg_ota_info, sizeof(sg_ota_info));
+    ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "ota info", &sg_ota_info, sizeof(sg_ota_info));
+    // check if the valid flag legalled
+    if (ble_qiot_ota_info_valid()) {
+        // the ota info write to flash may be mismatch the file write to flash, we should download file from the byte
+        // align the flash page
+        if (ble_ota_download_address_get() == sg_ota_info.last_address) {
+            size_align = sg_ota_info.last_file_size / BLE_QIOT_RECORD_FLASH_PAGESIZE * BLE_QIOT_RECORD_FLASH_PAGESIZE;
+            ble_ota_download_size_inc(size_align);
+            file_percent = size_align * 100 / sg_ota_info.download_file_info.file_size;
+            ble_ota_file_percent_set(file_percent);
+            ble_qiot_log_i("align file size: %x, the percent: %d", size_align, file_percent);
+        } else {
+            memset(&sg_ota_info, 0, sizeof(ble_ota_info_record));
+        }
+    } else {
+        memset(&sg_ota_info, 0, sizeof(ble_ota_info_record));
+    }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+    return BLE_QIOT_RS_OK;
+}
+// stop ota if ble disconnect
+void ble_ota_stop(void)
+{
+    if (!BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_REQUEST_BIT)) {
+        ble_qiot_log_w("ota not start");
+        return;
+    }
+    sg_ota_flag = 0;
+    ble_ota_timer_delete();
+    // write data to flash if the ota stop
+    ble_ota_write_data_to_flash();
+    ble_ota_write_info();
+    // inform user ota failed because ble disconnect
+    ble_ota_user_stop_cb(BLE_QIOT_OTA_DISCONNECT);
+}
+ble_qiot_ret_status_t ble_ota_request_handle(const char *in_buf, int buf_len)
+{
+    BUFF_LEN_SANITY_CHECK(buf_len, sizeof(ble_ota_file_info) - BLE_QIOT_OTA_MAX_VERSION_STR, BLE_QIOT_RS_ERR_PARA);
+
+    uint8_t            ret         = 0;
+    uint8_t            reply_flag  = 0;
+    uint32_t           file_size   = 0;
+    uint32_t           file_crc    = 0;
+    uint8_t            version_len = 0;
+    char *             p           = (char *)in_buf;
+    char *             notify_data = NULL;
+    uint16_t           notify_len  = 0;
+    ble_ota_reply_info ota_reply_info;
+
+    ble_ota_init();
+
+    memcpy(&file_size, p, sizeof(file_size));
+    p += sizeof(file_size);
+    memcpy(&file_crc, p, sizeof(file_crc));
+    p += sizeof(file_crc);
+    version_len = *p++;
+    file_size   = NTOHL(file_size);
+    file_crc    = NTOHL(file_crc);
+    ble_qiot_log_i("request ota, size: %x, crc: %x, version: %s", file_size, file_crc, p);
+
+    // check if the ota is allowed
+    ret = ble_ota_is_enable((const char *)p);
+    if (BLE_OTA_ENABLE == ret) {
+        reply_flag                      = BLE_QIOT_OTA_ENABLE;
+        ota_reply_info.package_nums     = BLE_QIOT_TOTAL_PACKAGES;
+        ota_reply_info.package_size     = BLE_QIOT_PACKAGE_LENGTH + BLE_QIOT_OTA_DATA_HEADER_LEN;
+        ota_reply_info.retry_timeout    = BLE_QIOT_RETRY_TIMEOUT;
+        ota_reply_info.reboot_timeout   = BLE_QIOT_REBOOT_TIME;
+        ota_reply_info.last_file_size   = 0;
+        ota_reply_info.package_interval = BLE_QIOT_PACKAGE_INTERVAL;
+#if BLE_QIOT_SUPPORT_RESUMING
+        reply_flag |= BLE_QIOT_OTA_RESUME_ENABLE;
+        // check file crc to determine its the same file, download the new file if its different
+        if (ble_qiot_ota_info_valid() && (file_crc == sg_ota_info.download_file_info.file_crc) &&
+            (file_size == sg_ota_info.download_file_info.file_size)) {
+            ota_reply_info.last_file_size = HTONL(ble_ota_download_size_get());
+        }
+#endif //BLE_QIOT_SUPPORT_RESUMING
+
+        sg_ota_info.download_file_info.file_size = file_size;
+        sg_ota_info.download_file_info.file_crc  = file_crc;
+        memcpy(sg_ota_info.download_file_info.file_version, p, version_len);
+
+        ble_ota_user_start_cb();
+        ble_ota_timer_start();
+        // handler the ota data after ota request
+        BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_REQUEST_BIT);
+        notify_data = (char *)&ota_reply_info;
+        notify_len  = sizeof(ble_ota_reply_info) - sizeof(ota_reply_info.rsv);
+    } else {
+        reply_flag &= ~BLE_QIOT_OTA_ENABLE;
+        notify_data = (char *)&ret;
+        notify_len  = sizeof(uint8_t);
+    }
+    return ble_event_notify(BLE_QIOT_EVENT_UP_REPLY_OTA_REPORT, &reply_flag, sizeof(uint8_t), (const char *)notify_data,
+                            notify_len);
+}
+// call the function after the server inform or the device receive the last package
+ble_qiot_ret_status_t ble_ota_file_end_handle(void)
+{
+    int      crc_buf_len  = 0;
+    uint32_t crc_file_len = 0;
+    uint32_t crc          = 0;
+
+    // the function called only once in the same ota process
+    sg_ota_flag = 0;
+    ble_ota_timer_delete();
+
+    ble_qiot_log_i("calc crc start");
+    while (crc_file_len < sg_ota_info.download_file_info.file_size) {
+        crc_buf_len = sizeof(sg_ota_data_buf) > (sg_ota_info.download_file_info.file_size - crc_file_len)
+                          ? (sg_ota_info.download_file_info.file_size - crc_file_len)
+                          : sizeof(sg_ota_data_buf);
+        memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+        ble_read_flash(ble_ota_download_address_get() + crc_file_len, (char *)sg_ota_data_buf, crc_buf_len);
+        crc_file_len += crc_buf_len;
+        crc = ble_qiot_crc32(crc, (const uint8_t *)sg_ota_data_buf, crc_buf_len);
+        // maybe need task delay
+    }
+    ble_qiot_log_i("calc crc %x, file crc %x", crc, sg_ota_info.download_file_info.file_crc);
+
+    if (crc == sg_ota_info.download_file_info.file_crc) {
+        if (BLE_QIOT_RS_OK == ble_ota_user_valid_cb()) {
+            int ret = ble_ota_report_check_result(BLE_QIOT_OTA_VALID_SUCCESS, 0);
+            ble_ota_user_stop_cb(BLE_QIOT_OTA_SUCCESS);
+        } else {
+            ble_ota_report_check_result(BLE_QIOT_OTA_VALID_FAIL, BLE_QIOT_OTA_FILE_ERROR);
+            ble_ota_user_stop_cb(BLE_QIOT_OTA_ERR_FILE);
+        }
+    } else {
+        ble_ota_report_check_result(BLE_QIOT_OTA_VALID_FAIL, BLE_QIOT_OTA_CRC_ERROR);
+        ble_ota_user_stop_cb(BLE_QIOT_OTA_ERR_CRC);
+    }
+    ble_ota_clear_info();
+    return BLE_QIOT_RS_OK;
+}
+
+static ble_qiot_ret_status_t ble_qiot_ota_data_saved(char *data, uint16_t data_len)
+{
+    int     ret     = 0;
+    uint8_t percent = 0;
+
+    // write data to flash if the buffer overflow
+    if ((data_len + sg_ota_data_buf_size) > sizeof(sg_ota_data_buf)) {
+        // ble_qiot_log_e("data buf overflow, write data");
+        if (BLE_QIOT_RS_OK != ble_ota_write_data_to_flash()) {
+            return BLE_QIOT_RS_ERR;
+        }
+        // update the ota info if support resuming
+        percent = (ble_ota_download_size_get() + sg_ota_data_buf_size) * 100 / sg_ota_info.download_file_info.file_size;
+        if (percent > ble_ota_file_percent_get()) {
+            ble_ota_file_percent_set(percent);
+            ret = ble_ota_write_info();
+            if (ret != BLE_QIOT_RS_OK) {
+                ble_qiot_log_e("update ota info failed");
+                return BLE_QIOT_RS_ERR;
+            }
+        }
+        memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+        sg_ota_data_buf_size = 0;
+    }
+
+    memcpy(sg_ota_data_buf + sg_ota_data_buf_size, data, data_len);
+    sg_ota_data_buf_size += data_len;
+    ble_ota_download_size_inc(data_len);
+
+    // if the last package, write to flash and reply the server
+    if (ble_ota_download_size_get() == sg_ota_info.download_file_info.file_size) {
+        ble_qiot_log_i("receive the last package");
+        if (BLE_QIOT_RS_OK != ble_ota_write_data_to_flash()) {
+            return BLE_QIOT_RS_ERR;
+        }
+        ble_ota_reply_ota_data();
+        // set the file receive end bit
+        BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_RECV_END_BIT);
+        memset(sg_ota_data_buf, 0, sizeof(sg_ota_data_buf));
+        sg_ota_data_buf_size = 0;
+    }
+
+    return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_ota_data_handle(const char *in_buf, int buf_len)
+{
+    POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+
+    uint8_t  seq      = 0;
+    char *   data     = NULL;
+    uint16_t data_len = 0;
+
+    if (!BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_REQUEST_BIT)) {
+        ble_qiot_log_w("ota request is need first");
+        return BLE_QIOT_RS_ERR;
+    }
+
+    seq      = in_buf[0];
+    data     = (char *)in_buf + 1;
+    data_len = (uint16_t)buf_len - 1;
+
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_ERR, "data", in_buf, buf_len);
+    if (seq == ble_ota_next_seq_get()) {
+        BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_RECV_DATA_BIT);
+        BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_FIRST_RETRY_BIT);
+        sg_ota_timeout_cnt = 0;
+        ble_ota_next_seq_inc();
+
+        if (BLE_QIOT_RS_OK != ble_qiot_ota_data_saved(data, data_len)) {
+            // stop ota and inform the server
+            ble_qiot_log_e("stop ota because save data failed");
+            return BLE_QIOT_RS_ERR;
+        }
+        if (BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_RECV_END_BIT)) {
+            return BLE_QIOT_RS_OK;
+        }
+        // reply the server if received the last package in the loop
+        if (BLE_QIOT_TOTAL_PACKAGES == ble_ota_next_seq_get()) {
+            // ble_qiot_log_e("reply loop");
+            ble_ota_reply_ota_data();
+            sg_ota_next_seq = 0;
+        }
+        BLE_QIOT_OTA_FLAG_SET(BLE_QIOT_OTA_RECV_DATA_BIT);
+    } else {
+        // request data only once in the loop, controlled by the flag
+        ble_qiot_log_w("unexpect seq %d, expect seq %d", seq, ble_ota_next_seq_get());
+        if (BLE_QIOT_OTA_FLAG_IS_SET(BLE_QIOT_OTA_FIRST_RETRY_BIT)) {
+            BLE_QIOT_OTA_FLAG_CLR(BLE_QIOT_OTA_FIRST_RETRY_BIT);
+            BLE_QIOT_OTA_FLAG_CLR(BLE_QIOT_OTA_RECV_DATA_BIT);
+            ble_ota_reply_ota_data();
+            // refresh the timer
+            ble_ota_timer_start();
+        }
+    }
+    return BLE_QIOT_RS_OK;
+}
+#endif //BLE_QIOT_SUPPORT_OTA
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif

+ 634 - 0
qcloud_iot_explorer_ble/src/core/ble_qiot_service.c

@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+#include "ble_qiot_config.h"
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_import.h"
+#include "ble_qiot_llsync_data.h"
+#include "ble_qiot_llsync_device.h"
+#include "ble_qiot_llsync_event.h"
+#include "ble_qiot_log.h"
+#include "ble_qiot_llsync_ota.h"
+#include "ble_qiot_param_check.h"
+#include "ble_qiot_service.h"
+#include "ble_qiot_template.h"
+#include "ble_qiot_service.h"
+
+// llsync support data fragment, so we need to package all the data before parsing if the data is slice
+static ble_event_slice_t sg_ble_slice_data;
+
+#if BLE_QIOT_BUTTON_BROADCAST
+static ble_timer_t sg_bind_timer = NULL;
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+#if BLE_QIOT_SECURE_BIND
+static ble_bind_data sg_bind_auth_data;
+#endif //BLE_QIOT_SECURE_BIND
+
+static qiot_service_init_s service_info = {
+    .service_uuid16  = IOT_BLE_UUID_SERVICE,
+    .service_uuid128 = IOT_BLE_UUID_BASE,
+    .device_info =
+        {
+            .uuid16          = IOT_BLE_UUID_DEVICE_INFO,
+            .gatt_char_props = GATT_CHAR_WRITE,
+            .on_write        = ble_device_info_write_cb,
+        },
+    .event =
+        {
+            .uuid16          = IOT_BLE_UUID_EVENT,
+            .gatt_char_props = GATT_CHAR_NOTIFY,
+            .on_write        = NULL,
+        },
+#if BLE_QIOT_LLSYNC_STANDARD
+    .data =
+        {
+            .uuid16          = IOT_BLE_UUID_DATA,
+            .gatt_char_props = GATT_CHAR_WRITE,
+            .on_write        = ble_lldata_write_cb,
+        },
+    .ota =
+    {
+        .uuid16          = IOT_BLE_UUID_OTA,
+        .gatt_char_props = GATT_CHAR_WRITE_WO_RESP,
+        .on_write        = ble_ota_write_cb,
+    },
+#endif //BLE_QIOT_LLSYNC_STANDARD
+};
+
+const qiot_service_init_s *ble_get_qiot_services(void)
+{
+    return &service_info;
+}
+
+#if BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_SECURE_BIND
+static ble_qiot_ret_status_t ble_secure_bind_handle(const char *data, uint16_t len)
+{
+    memset(&sg_bind_auth_data, 0, sizeof(ble_bind_data));
+    memcpy(&sg_bind_auth_data, data, sizeof(ble_bind_data));
+    ble_event_sync_wait_time();
+    ble_secure_bind_user_cb();
+
+    return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_secure_bind_user_confirm(ble_qiot_secure_bind_t choose)
+{
+    char    out_buf[80] = {0};
+    int     ret_len     = 0;
+    uint8_t flag        = 0;
+
+    ble_qiot_log_i("user choose: %d", choose);
+    ret_len = ble_bind_get_authcode(&sg_bind_auth_data, sizeof(ble_bind_data), out_buf, sizeof(out_buf));
+    if (ret_len <= 0) {
+        ble_qiot_log_e("get bind authcode failed");
+        return BLE_QIOT_RS_ERR;
+    }
+    flag = choose << 5;
+    return ble_event_notify2((uint8_t)BLE_QIOT_EVENT_UP_BIND_SIGN_RET, flag, NULL, 0, out_buf, ret_len);
+}
+#endif //BLE_QIOT_SECURE_BIND
+
+void ble_lldata_write_cb(const uint8_t *buf, uint16_t len)
+{
+    (void)ble_lldata_msg_handle((const char *)buf, len);
+}
+
+void ble_ota_write_cb(const uint8_t *buf, uint16_t len)
+{
+    (void)ble_ota_msg_handle((const char *)buf, len);
+}
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#if BLE_QIOT_BUTTON_BROADCAST
+static void ble_bind_timer_callback(void *param)
+{
+    ble_qiot_log_i("timer timeout");
+    if (E_LLSYNC_BIND_WAIT == llsync_bind_state_get()) {
+        ble_advertising_stop();
+        llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
+        ble_qiot_log_i("stop advertising");
+    }
+}
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+ble_qiot_ret_status_t ble_qiot_advertising_start(void)
+{
+    adv_info_s my_adv_info;
+    uint16_t   uuids[1];
+    uint8_t    adv_data[32] = {0};
+    uint8_t    adv_data_len = 0;
+
+    uuids[0]                       = IOT_BLE_UUID_SERVICE;
+    my_adv_info.uuid_info.uuid_num = 1;
+    my_adv_info.uuid_info.uuids    = uuids;
+
+    if (E_LLSYNC_BIND_IDLE == llsync_bind_state_get()) {
+#if BLE_QIOT_BUTTON_BROADCAST
+        if (NULL == sg_bind_timer) {
+            sg_bind_timer = ble_timer_create(BLE_TIMER_ONE_SHOT_TYPE, ble_bind_timer_callback);
+            if (NULL == sg_bind_timer) {
+                ble_qiot_log_e("create bind timer failed");
+                return BLE_QIOT_RS_ERR;
+            }
+        }
+#endif //BLE_QIOT_BUTTON_BROADCAST
+
+        ble_advertising_stop();
+
+        llsync_bind_state_set(E_LLSYNC_BIND_WAIT);
+        adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
+        my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
+        my_adv_info.manufacturer_info.adv_data           = adv_data;
+        my_adv_info.manufacturer_info.adv_data_len       = adv_data_len;
+        ble_advertising_start(&my_adv_info);
+        ble_qiot_log_i("start wait advertising");
+
+#if BLE_QIOT_BUTTON_BROADCAST
+        ble_timer_start(sg_bind_timer, BLE_QIOT_BIND_TIMEOUT);
+#endif //BLE_QIOT_BUTTON_BROADCAST
+    } else if (E_LLSYNC_BIND_WAIT == llsync_bind_state_get()) {
+        ble_advertising_stop();
+        adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
+        my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
+        my_adv_info.manufacturer_info.adv_data           = adv_data;
+        my_adv_info.manufacturer_info.adv_data_len       = adv_data_len;
+        ble_advertising_start(&my_adv_info);
+        ble_qiot_log_i("restart wait advertising");
+
+#if BLE_QIOT_BUTTON_BROADCAST
+        ble_timer_stop(sg_bind_timer);
+        ble_timer_start(sg_bind_timer, BLE_QIOT_BIND_TIMEOUT);
+#endif //BLE_QIOT_BUTTON_BROADCAST
+    } else if (E_LLSYNC_BIND_SUCC == llsync_bind_state_get()) {
+        ble_advertising_stop();
+        adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
+        my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
+        my_adv_info.manufacturer_info.adv_data           = adv_data;
+        my_adv_info.manufacturer_info.adv_data_len       = adv_data_len;
+        ble_advertising_start(&my_adv_info);
+        ble_qiot_log_i("start bind advertising");
+    } else {
+        // do nothing
+    }
+
+    return BLE_QIOT_RS_OK;
+}
+
+ble_qiot_ret_status_t ble_qiot_advertising_stop(void)
+{
+    return 0 == ble_advertising_stop() ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
+}
+
+ble_qiot_ret_status_t ble_qiot_explorer_init(void)
+{
+    ble_qiot_ret_status_t      ret_code     = BLE_QIOT_RS_OK;
+    const qiot_service_init_s *service_info = NULL;
+
+    ble_qiot_set_log_level(BLE_QIOT_LOG_LEVEL_INFO);
+
+    service_info = ble_get_qiot_services();
+    ble_services_add(service_info);
+
+    ret_code = ble_init_flash_data();
+    if (ret_code != BLE_QIOT_RS_OK) {
+        ble_qiot_log_e("flash init failed, ret code %d", ret_code);
+        return ret_code;
+    }
+
+    return ret_code;
+}
+
+void ble_device_info_write_cb(const uint8_t *buf, uint16_t len)
+{
+    (void)ble_device_info_msg_handle((const char *)buf, len);
+}
+
+// when gap get ble connect event, use this function
+void ble_gap_connect_cb(void)
+{
+    ble_connection_state_set(E_BLE_CONNECTED);
+}
+
+// when gap get ble disconnect event, use this function
+void ble_gap_disconnect_cb(void)
+{
+    llsync_mtu_update(0);
+    llsync_connection_state_set(E_LLSYNC_DISCONNECTED);
+    ble_connection_state_set(E_BLE_DISCONNECTED);
+#if BLE_QIOT_SUPPORT_OTA
+    ble_ota_stop();
+#endif //BLE_QIOT_SUPPORT_OTA
+}
+
+static uint8_t ble_msg_type_header_len(uint8_t type)
+{
+    if (type == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) {
+        return BLE_QIOT_GET_STATUS_REPLY_HEADER_LEN;
+    } else {
+        return BLE_QIOT_DATA_FIXED_HEADER_LEN;
+    }
+}
+
+static int8_t ble_package_slice_data(uint8_t data_type, uint8_t flag, uint8_t header_len, const char *in_buf,
+                                      int in_len)
+{
+    if (!BLE_QIOT_IS_SLICE_HEADER(flag)) {
+        if (!sg_ble_slice_data.have_data) {
+            ble_qiot_log_e("slice no header");
+            return -1;
+        }
+        if (data_type != sg_ble_slice_data.type) {
+            ble_qiot_log_e("msg type: %d != %d", data_type, sg_ble_slice_data.type);
+            return -1;
+        }
+        if (sg_ble_slice_data.buf_len + (in_len - header_len) > sizeof(sg_ble_slice_data.buf)) {
+            ble_qiot_log_e("too long data: %d > %d", sg_ble_slice_data.buf_len + (in_len - header_len),
+                           sizeof(sg_ble_slice_data.buf));
+            return -1;
+        }
+    }
+
+    if (BLE_QIOT_IS_SLICE_HEADER(flag)) {
+        if (sg_ble_slice_data.have_data) {
+            ble_qiot_log_i("new data coming, clean the package buffer");
+            memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+        }
+        sg_ble_slice_data.have_data = true;
+        sg_ble_slice_data.type      = data_type;
+        // reserved space for payload length field
+        sg_ble_slice_data.buf_len += header_len;
+        sg_ble_slice_data.buf[0] = in_buf[0];
+        memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
+        sg_ble_slice_data.buf_len += (in_len - header_len);
+
+        return 1;
+    } else if (BLE_QIOT_IS_SLICE_BODY(flag)) {
+        memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
+        sg_ble_slice_data.buf_len += (in_len - header_len);
+        return 1;
+    } else {
+        memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
+        sg_ble_slice_data.buf_len += (in_len - header_len);
+
+        return 0;
+    }
+}
+
+int ble_device_info_msg_handle(const char *in_buf, int in_len)
+{
+    POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+    uint8_t  ch;
+    char     out_buf[80] = {0};
+    char *   p_data      = NULL;
+    int      p_data_len  = 0;
+    int      ret_len     = 0;
+    uint16_t tmp_len     = 0;
+    uint8_t  header_len  = 0;
+    int      ret         = BLE_QIOT_RS_OK;
+    char *   p_ssid      = NULL;
+    char *   p_passwd    = NULL;
+    // This flag is use to avoid attacker jump "ble_conn_get_authcode()" step, then
+    // send 'E_DEV_MSG_CONN_SUCC' msg, and device straightly set 'E_LLSYNC_CONNECTED' flag.
+    // This behavior make signature check useless lead to risk.
+    static bool conn_flag = false;
+
+    p_data     = (char *)in_buf;
+    p_data_len = in_len;
+
+    // E_DEV_MSG_SYNC_TIME, E_DEV_MSG_CONN_VALID, E_DEV_MSG_BIND_SUCC, E_DEV_MSG_UNBIND this 4 type
+    // of message has more than one bytes data, it may cut to several slices, here need to merge them
+    // together, other type message only has 1 byte data, not need merge.
+    if ((in_len > 3) && BLE_QIOT_IS_SLICE_PACKAGE(in_buf[1])) {
+        // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "slice", p_data, p_data_len);
+        header_len = ble_msg_type_header_len(in_buf[0]);
+        ret        = ble_package_slice_data(in_buf[0], in_buf[1], header_len, in_buf, in_len);
+        if (ret < 0) {
+            return BLE_QIOT_RS_ERR;
+        } else if (ret == 0) {
+            tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
+            memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
+            p_data     = sg_ble_slice_data.buf;
+            p_data_len = sg_ble_slice_data.buf_len;
+        } else if (ret > 0) {
+            return BLE_QIOT_RS_OK;
+        }
+    }
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+
+    ch = p_data[0];
+    switch (ch) {
+#if BLE_QIOT_LLSYNC_STANDARD
+        case E_DEV_MSG_SYNC_TIME:
+#if BLE_QIOT_SECURE_BIND
+            ret = ble_secure_bind_handle(p_data + 3, p_data_len - 3);
+#else
+            ret_len = ble_bind_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
+            if (ret_len <= 0) {
+                ble_qiot_log_e("get bind authcode failed");
+                ret = BLE_QIOT_RS_ERR;
+                break;
+            }
+            ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_BIND_SIGN_RET, NULL, 0, out_buf, ret_len);
+#endif //BLE_QIOT_SECURE_BIND
+            break;
+        case E_DEV_MSG_CONN_VALID:
+            ret_len = ble_conn_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
+            if (ret_len <= 0) {
+                ble_qiot_log_e("get connect authcode failed");
+                ret = BLE_QIOT_RS_ERR;
+                break;
+            }
+            ret       = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_CONN_SIGN_RET, NULL, 0, out_buf, ret_len);
+            conn_flag = true;
+            break;
+        case E_DEV_MSG_BIND_SUCC:
+            if (BLE_QIOT_RS_OK != ble_bind_write_result(p_data + 3, p_data_len - 3)) {
+                ble_qiot_log_e("write bind result failed");
+                ret = BLE_QIOT_RS_ERR;
+            }
+            break;
+        case E_DEV_MSG_BIND_FAIL:
+            ble_qiot_log_i("get msg bind fail");
+            break;
+        case E_DEV_MSG_UNBIND:
+            ret_len = ble_unbind_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
+            if (ret_len <= 0) {
+                ble_qiot_log_e("get unbind authcode failed");
+                ret = BLE_QIOT_RS_ERR;
+                break;
+            }
+            ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET, NULL, 0, out_buf, ret_len);
+            break;
+        case E_DEV_MSG_CONN_SUCC:
+            if (!conn_flag) {
+                break;
+            }
+            conn_flag = false;
+            ble_qiot_log_i("get msg connect success");
+            llsync_connection_state_set(E_LLSYNC_CONNECTED);
+            ret = ble_event_report_device_info();
+            break;
+        case E_DEV_MSG_CONN_FAIL:
+            ble_qiot_log_i("get msg connect fail");
+            break;
+        case E_DEV_MSG_UNBIND_SUCC:
+            ble_qiot_log_i("get msg unbind success");
+            if (BLE_QIOT_RS_OK != ble_unbind_write_result()) {
+                ble_qiot_log_e("write unbind result failed");
+                ret = BLE_QIOT_RS_ERR;
+            }
+            break;
+        case E_DEV_MSG_UNBIND_FAIL:
+            ble_qiot_log_i("get msg unbind fail");
+            break;
+        case E_DEV_MSG_BIND_TIMEOUT:
+            ble_qiot_log_i("get msg bind result: %d", p_data[1]);
+        #if (1 == BLE_QIOT_SECURE_BIND)
+            ble_secure_bind_user_notify(p_data[1]);
+        #endif
+            break;
+#endif //BLE_QIOT_LLSYNC_STANDARD
+#if BLE_QIOT_LLSYNC_CONFIG_NET
+        case E_DEV_MSG_GET_DEV_INFO:
+            llsync_connection_state_set(E_LLSYNC_CONNECTED);
+            ret = ble_event_report_device_info();
+            break;
+        case E_DEV_MSG_SET_WIFI_MODE:
+            ret = ble_combo_wifi_mode_set(p_data[1]);
+            break;
+        case E_DEV_MSG_SET_WIFI_INFO:
+            // 1 byte ssid len + N bytes ssid + 1 byte pwd len + N bytes pwd
+            p_ssid = &p_data[3];
+            p_passwd = &p_ssid[p_ssid[0] + 1];
+            ret = ble_combo_wifi_info_set((const char *)&p_ssid[1], p_ssid[0], (const char *)&p_passwd[1], p_passwd[0]);
+            break;
+        case E_DEV_MSG_SET_WIFI_CONNECT:
+            ret = ble_combo_wifi_connect();
+            break;
+        case E_DEV_MSG_SET_WIFI_TOKEN:
+            ret = ble_combo_wifi_token_set(p_data + 3, p_data_len - 3);
+            break;
+        case E_DEV_MSG_GET_DEV_LOG:
+            ret = ble_combo_wifi_log_get();
+            break;
+#endif
+        case E_DEV_MSG_SET_MTU_RESULT:
+            ble_inform_mtu_result(p_data + 1, p_data_len - 1);
+            break;
+        default:
+            ble_qiot_log_e("unknow type %d", ch);
+            break;
+    }
+    memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+
+    return ret;
+}
+
+#if BLE_QIOT_LLSYNC_STANDARD
+// lldata message from remote
+int ble_lldata_msg_handle(const char *in_buf, int in_len)
+{
+    POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
+
+    uint8_t  data_type   = 0;
+    uint8_t  data_effect = 0;
+    uint8_t  id          = 0;
+    uint8_t  slice_flag  = 0;
+    uint8_t  header_len  = 0;
+    uint8_t  slice_type  = 0;
+    uint16_t tmp_len     = 0;
+    char *   p_data      = NULL;
+    int      p_data_len  = 0;
+    int      ret         = 0;
+
+    if (!llsync_is_connected()) {
+        ble_qiot_log_e("operation negate, device not connected");
+        return BLE_QIOT_RS_ERR;
+    }
+
+    p_data     = (char *)in_buf;
+    p_data_len = in_len;
+
+    data_type = BLE_QIOT_PARSE_MSG_HEAD_TYPE(in_buf[0]);
+    if (data_type >= BLE_QIOT_DATA_TYPE_BUTT) {
+        ble_qiot_log_e("invalid data type: %d", data_type);
+        return BLE_QIOT_RS_ERR;
+    }
+    data_effect = BLE_QIOT_PARSE_MSG_HEAD_EFFECT(in_buf[0]);
+    if (data_effect >= BLE_QIOT_EFFECT_BUTT) {
+        ble_qiot_log_e("invalid data eff: ect");
+        return BLE_QIOT_RS_ERR;
+    }
+    id = BLE_QIOT_PARSE_MSG_HEAD_ID(in_buf[0]);
+    ble_qiot_log_d("data type: %d, effect: %d, id: %d", data_type, data_effect, id);
+
+    // if data is action_reply, control or get_status_reply, the data maybe need package
+    if ((data_type == BLE_QIOT_MSG_TYPE_ACTION) || (in_buf[0] == BLE_QIOT_CONTROL_DATA_TYPE) ||
+        (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE)) {
+        slice_flag = (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) ? in_buf[2] : in_buf[1];
+        slice_type = (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) ? in_buf[0] : data_type;
+
+        // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "slice", p_data, p_data_len);
+        if (BLE_QIOT_IS_SLICE_PACKAGE(slice_flag)) {
+            header_len = ble_msg_type_header_len(slice_type);
+            ret        = ble_package_slice_data(slice_type, slice_flag, header_len, in_buf, in_len);
+            if (ret < 0) {
+                return BLE_QIOT_RS_ERR;
+            } else if (ret == 0) {
+                tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
+                if (BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE == slice_type) {
+                    sg_ble_slice_data.buf[1] = in_buf[1];
+                    memcpy(&sg_ble_slice_data.buf[2], &tmp_len, sizeof(tmp_len));
+                } else {
+                    memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
+                }
+                p_data     = sg_ble_slice_data.buf;
+                p_data_len = sg_ble_slice_data.buf_len;
+            } else if (ret > 0) {
+                return BLE_QIOT_RS_OK;
+            }
+        }
+    }
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+
+    switch (data_type) {
+        case BLE_QIOT_MSG_TYPE_PROPERTY:
+            if (BLE_QIOT_EFFECT_REQUEST == data_effect) {
+                // default E_BLE_DATA_DOWN_TYPE_CONTROL
+                ret = ble_lldata_property_request_handle(p_data + 3, p_data_len - 3);
+            } else if (BLE_QIOT_EFFECT_REPLY == data_effect) {
+                // id means BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY or BLE_QIOT_DATA_DOWN_REPORT_REPLY
+                ret = ble_lldata_property_reply_handle(id, p_data + 1, p_data_len - 1);
+            } else {
+                ret = BLE_QIOT_RS_ERR;
+            }
+            break;
+        case BLE_QIOT_MSG_TYPE_EVENT:
+            if (BLE_QIOT_EFFECT_REPLY == data_effect) {
+                ret = ble_lldata_event_handle(id, p_data + 1, p_data_len - 1);
+            } else {
+                ble_qiot_log_e("invalid event data effect");
+                ret = BLE_QIOT_RS_ERR;
+            }
+            break;
+        case BLE_QIOT_MSG_TYPE_ACTION:
+            if (BLE_QIOT_EFFECT_REQUEST == data_effect) {
+                ret = ble_lldata_action_handle(id, p_data + 3, p_data_len - 3);
+            } else {
+                ble_qiot_log_e("invalid action data effect");
+                ret = BLE_QIOT_RS_ERR;
+            }
+            break;
+        default:
+            break;
+    }
+    memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+
+    return ret;
+}
+
+#if BLE_QIOT_SUPPORT_OTA
+static uint8_t ble_ota_type_header_len(uint8_t type)
+{
+    return BLE_QIOT_GET_OTA_REQUEST_HEADER_LEN;
+}
+
+int ble_ota_msg_handle(const char *buf, uint16_t len)
+{
+    POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
+
+    uint8_t  data_type  = 0;
+    int      ret        = BLE_QIOT_RS_OK;
+    uint8_t  header_len = 0;
+    uint8_t  slice_flag = 0;
+    char *   p_data     = NULL;
+    int      p_data_len = 0;
+    uint16_t tmp_len    = 0;
+
+    if (!llsync_is_connected()) {
+        ble_qiot_log_e("upgrade forbidden, device not connected");
+        return BLE_QIOT_RS_ERR;
+    }
+
+    data_type  = (buf[0] == BLE_QIOT_OTA_MSG_REQUEST) ? BLE_QIOT_OTA_MSG_REQUEST : buf[0];
+    slice_flag = (buf[0] == BLE_QIOT_OTA_MSG_REQUEST) ? buf[1] : buf[0];
+    if (data_type >= BLE_QIOT_OTA_MSG_BUTT) {
+        ble_qiot_log_e("invalid data type %d", data_type);
+        return BLE_QIOT_RS_ERR;
+    }
+    p_data     = (char *)buf;
+    p_data_len = len;
+
+    // ble_qiot_log_i("ota data type %d, flag %d", data_type, slice_flag);
+    if (BLE_QIOT_IS_SLICE_PACKAGE(slice_flag)) {
+        ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+        header_len = ble_ota_type_header_len(data_type);
+        ret        = ble_package_slice_data(data_type, slice_flag, header_len, buf, len);
+        if (ret < 0) {
+            return BLE_QIOT_RS_ERR;
+        } else if (ret == 0) {
+            if (data_type == BLE_QIOT_OTA_MSG_REQUEST) {
+                tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
+                memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
+            } else {
+                sg_ble_slice_data.buf[1] = sg_ble_slice_data.buf_len - header_len;
+            }
+            if (data_type == BLE_QIOT_OTA_MSG_DATA) {
+                sg_ble_slice_data.buf[2] = buf[2];
+            }
+            p_data     = sg_ble_slice_data.buf;
+            p_data_len = sg_ble_slice_data.buf_len;
+        } else if (ret > 0) {
+            return BLE_QIOT_RS_OK;
+        }
+    }
+
+    // ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
+    switch (data_type) {
+        case BLE_QIOT_OTA_MSG_REQUEST:
+            ret = ble_ota_request_handle(p_data + 3, p_data_len);
+            break;
+        case BLE_QIOT_OTA_MSG_DATA:
+            ret = ble_ota_data_handle(p_data + 2, p_data_len - 2);
+            break;
+        case BLE_QIOT_OTA_MSG_END:
+            ret = ble_ota_file_end_handle();
+            break;
+        default:
+            break;
+    }
+    memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
+
+    return ret;
+}
+#else
+int ble_ota_msg_handle(const char *buf, uint16_t len)
+{
+    return BLE_QIOT_RS_OK;
+}
+#endif  //BLE_QIOT_SUPPORT_OTA
+
+#endif //BLE_QIOT_LLSYNC_STANDARD
+
+#ifdef __cplusplus
+}
+#endif

+ 45 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_common.h

@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_COMMON_H
+#define QCLOUD_BLE_QIOT_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_QIOT_PRODUCT_ID_LEN  (10)  // fixed length of product id
+#define BLE_QIOT_DEVICE_NAME_LEN (48)  // max length of device name
+#define BLE_QIOT_PSK_LEN         (24)  // fixed length of secret key
+#define BLE_QIOT_MAC_LEN         (6)   // fixed length of mac
+
+#define SWAP_32(x) \
+    ((((x)&0xFF000000) >> 24) | (((x)&0x00FF0000) >> 8) | (((x)&0x0000FF00) << 8) | (((x)&0x000000FF) << 24))
+#define SWAP_16(x) ((((x)&0xFF00) >> 8) | (((x)&0x00FF) << 8))
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define HTONL(x) SWAP_32(x)
+#define HTONS(x) SWAP_16(x)
+#define NTOHL(x) SWAP_32(x)
+#define NTOHS(x) SWAP_16(x)
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define HTONL(x) (x)
+#define HTONS(x) (x)
+#define NTOHL(x) (x)
+#define NTOHS(x) (x)
+#else
+#error "undefined byte order"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // QCLOUD_BLE_QIOT_COMMON_H

+ 31 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_crc.h

@@ -0,0 +1,31 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_CRC_H
+#define QCLOUD_BLE_QIOT_CRC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+
+uint32_t ble_qiot_crc32(uint32_t crc, const uint8_t *buf, int len);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif  // QCLOUD_BLE_QIOT_HMAC_H

+ 32 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_hmac.h

@@ -0,0 +1,32 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_HMAC_H
+#define QCLOUD_BLE_QIOT_HMAC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <string.h>
+
+#define SHA1_DIGEST_SIZE 20
+
+void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif  // QCLOUD_BLE_QIOT_HMAC_H

+ 44 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_data.h

@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_DATA_H
+#define QCLOUD_BLE_QIOT_LLSYNC_DATA_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <ble_qiot_export.h>
+
+#define BLE_QIOT_CONTROL_DATA_TYPE          (0x00)
+#define BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE (0x22)
+
+#define BLE_QIOT_GET_STATUS_REPLY_HEADER_LEN (4)
+#define BLE_QIOT_DATA_FIXED_HEADER_LEN       (3)
+
+// handle property request
+ble_qiot_ret_status_t ble_lldata_property_request_handle(const char *in_buf, int buf_len);
+
+// handle property reply
+ble_qiot_ret_status_t ble_lldata_property_reply_handle(uint8_t type, const char *in_buf, int buf_len);
+
+// handle event data
+ble_qiot_ret_status_t ble_lldata_event_handle(uint8_t id, const char *in_buf, int len);
+
+// handle action data
+ble_qiot_ret_status_t ble_lldata_action_handle(uint8_t id, const char *in_buf, int len);
+
+// get report data
+ble_qiot_ret_status_t ble_user_property_get_report_data(void);
+#ifdef __cplusplus
+}
+#endif
+#endif  // QCLOUD_BLE_QIOT_LLSYNC_DATA_H

+ 173 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_device.h

@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_DEVICE_H
+#define QCLOUD_BLE_QIOT_LLSYNC_DEVICE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble_qiot_common.h"
+#include "ble_qiot_export.h"
+#include "ble_qiot_hmac.h"
+#include "ble_qiot_llsync_event.h"
+
+#define LLSYNC_BIND_STATE_MASK       0x03
+#define LLSYNC_PROTO_VER_BIT         0x04
+#define LLSYNC_PROTOCOL_VERSION_MASK 0xF0
+#define LLSYNC_MTU_SET_MASK          0x8000
+
+#define LLSYNC_MTU_SET_RESULT_ERR 0xFFFF  // some error when setting mtu
+
+#define BLE_QIOT_LLSYNC_PROTOCOL_VERSION (2)  // llsync protocol version, equal or less than 15
+
+#define ATT_DEFAULT_MTU                 23  // default att mtu
+#define ATT_MTU_TO_LLSYNC_MTU(_att_mtu) ((_att_mtu)-3)
+
+#define BLE_LOCAL_PSK_LEN           4
+#define BLE_BIND_IDENTIFY_STR_LEN   8
+#define BLE_EXPIRATION_TIME         60  // timestamp expiration value
+#define BLE_UNBIND_REQUEST_STR      "UnbindRequest"
+#define BLE_UNBIND_REQUEST_STR_LEN  (sizeof("UnbindRequest") - 1)
+#define BLE_UNBIND_RESPONSE         "UnbindResponse"
+#define BLE_UNBIND_RESPONSE_STR_LEN (sizeof("UnbindResponse") - 1)
+
+typedef enum {
+    E_DEV_MSG_SYNC_TIME = 0,  // sync info before bind
+    E_DEV_MSG_CONN_VALID,     // connect request
+    E_DEV_MSG_BIND_SUCC,      // inform bind success
+    E_DEV_MSG_BIND_FAIL,      // inform bind failed
+    E_DEV_MSG_UNBIND,         // unbind request
+    E_DEV_MSG_CONN_SUCC,      // inform connect result
+    E_DEV_MSG_CONN_FAIL,
+    E_DEV_MSG_UNBIND_SUCC,  // inform unbind result
+    E_DEV_MSG_UNBIND_FAIL,
+    E_DEV_MSG_SET_MTU_RESULT,  // inform set mtu result
+    E_DEV_MSG_BIND_TIMEOUT,    // inform bind timeout
+    E_DEV_MSG_GET_DEV_INFO = 0xE0,  // configure network start
+    E_DEV_MSG_SET_WIFI_MODE,
+    E_DEV_MSG_SET_WIFI_INFO,
+    E_DEV_MSG_SET_WIFI_CONNECT,
+    E_DEV_MSG_SET_WIFI_TOKEN,
+    E_DEV_MSG_GET_DEV_LOG,
+    E_DEV_MSG_MSG_BUTT,
+} e_dev_info_msg_type;
+
+typedef enum {
+    E_LLSYNC_BIND_IDLE = 0,  // no bind
+    E_LLSYNC_BIND_WAIT,      // wait bind, return idle state if no bind in the period
+    E_LLSYNC_BIND_SUCC,      // bound
+} e_llsync_bind_state;
+
+typedef enum {
+    E_LLSYNC_DISCONNECTED = 0,
+    E_LLSYNC_CONNECTED,
+} e_llsync_connection_state;
+
+typedef enum {
+    E_BLE_DISCONNECTED = 0,
+    E_BLE_CONNECTED,
+} e_ble_connection_state;
+
+typedef struct ble_device_info_t_ {
+    char product_id[BLE_QIOT_PRODUCT_ID_LEN];
+    char device_name[BLE_QIOT_DEVICE_NAME_LEN + 1];
+    char psk[BLE_QIOT_PSK_LEN];
+    char mac[BLE_QIOT_MAC_LEN];
+} ble_device_info;
+
+typedef struct ble_core_data_ {
+    uint8_t bind_state;
+    char    local_psk[BLE_LOCAL_PSK_LEN];
+    char    identify_str[BLE_BIND_IDENTIFY_STR_LEN];
+} ble_core_data;
+
+// write to uuid FEE1 before bind
+typedef struct ble_bind_data_t_ {
+    int nonce;
+    int timestamp;
+} ble_bind_data;
+
+// connect data struct
+typedef struct ble_conn_data_t_ {
+    int  timestamp;
+    char sign_info[SHA1_DIGEST_SIZE];
+} ble_conn_data;
+
+// unbind data struct
+typedef struct ble_unbind_data_t_ {
+    char sign_info[SHA1_DIGEST_SIZE];
+} ble_unbind_data;
+
+typedef struct {
+    bool     have_data;  // start received package
+    uint8_t  type;       // event type
+    uint16_t buf_len;    // the length of data
+    char     buf[BLE_QIOT_EVENT_MAX_SIZE];
+} ble_event_slice_t;
+
+// read sdk data from flash
+ble_qiot_ret_status_t ble_init_flash_data(void);
+
+// set llsync bind state
+void llsync_bind_state_set(e_llsync_bind_state new_state);
+
+// get llsync bind state
+e_llsync_bind_state llsync_bind_state_get(void);
+
+// set llsync connection state
+void llsync_connection_state_set(e_llsync_connection_state new_state);
+
+// set ble connection state
+void ble_connection_state_set(e_ble_connection_state new_state);
+
+// get llsync connection state
+bool llsync_is_connected(void);
+
+// get ble connection state
+bool ble_is_connected(void);
+
+// get broadcast data
+int ble_get_my_broadcast_data(char *out_buf, int buf_len);
+
+// get bind authcode, return authcode length;
+// out_buf length must greater than  SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN
+int ble_bind_get_authcode(const char *bind_data, uint16_t data_len, char *out_buf, uint16_t buf_len);
+
+// write bind result to flash, return 0 is success
+ble_qiot_ret_status_t ble_bind_write_result(const char *result, uint16_t len);
+
+// write unbind result to flash, return 0 is success
+ble_qiot_ret_status_t ble_unbind_write_result(void);
+
+// get connect authcode, return authcode length;
+// out_buf length must greater than  SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN
+int ble_conn_get_authcode(const char *conn_data, uint16_t data_len, char *out_buf, uint16_t buf_len);
+
+// get connect authcode, return authcode length;
+// out_buf length must greater than  SHA1_DIGEST_SIZE + BLE_UNBIND_RESPONSE_STR_LEN
+int ble_unbind_get_authcode(const char *unbind_data, uint16_t data_len, char *out_buf, uint16_t buf_len);
+
+// inform device the result of mtu setting
+int ble_inform_mtu_result(const char *result, uint16_t data_len);
+
+// get llsync mtu
+uint16_t llsync_mtu_get(void);
+
+// update llsync mtu
+void llsync_mtu_update(uint16_t sync_mtu);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // QCLOUD_BLE_QIOT_LLSYNC_DEVICE_H

+ 56 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_event.h

@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_EVENT_H
+#define QCLOUD_BLE_QIOT_LLSYNC_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "ble_qiot_config.h"
+#include "ble_qiot_export.h"
+
+enum {
+    BLE_QIOT_EVENT_NO_SLICE   = 0,
+    BLE_QIOT_EVENT_SLICE_HEAD = 1,
+    BLE_QIOT_EVENT_SLICE_BODY = 2,
+    BLE_QIOT_EVENT_SLICE_FOOT = 3,
+};
+
+// 1 byte type + 2 bytes payload-length
+#define BLE_QIOT_EVENT_FIXED_HEADER_LEN (3)
+
+// the bit 15 - 14 is slice flag, bit 13 - 0 is tlv length
+#define BLE_QIOT_IS_SLICE_PACKAGE(_C) ((_C)&0XC0)
+#define BLE_QIOT_IS_SLICE_HEADER(_C)  (((_C)&0XC0) == 0X40)
+#define BLE_QIOT_IS_SLICE_BODY(_C)    (((_C)&0XC0) == 0X80)
+#define BLE_QIOT_IS_SLICE_TAIL(_C)    (((_C)&0XC0) == 0XC0)
+
+#define BLE_QIOT_STRING_TYPE_LEN     2                               // string/struct type length
+#define BLE_QIOT_MIN_STRING_TYPE_LEN (BLE_QIOT_STRING_TYPE_LEN + 1)  // at least 2 bytes length and 1 byte payload
+#define BLE_QIOT_NOT_SUPPORT_WARN    " not support, please check the data template"
+
+ble_qiot_ret_status_t ble_event_notify(uint8_t type, uint8_t *header, uint8_t header_len, const char *buf,
+                                       uint16_t buf_len);
+
+ble_qiot_ret_status_t ble_event_notify2(uint8_t type, uint8_t length_flag, uint8_t *header, uint8_t header_len,
+                                        const char *buf, uint16_t buf_len);
+
+ble_qiot_ret_status_t ble_event_sync_wait_time(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // QCLOUD_BLE_QIOT_LLSYNC_EVENT_H

+ 124 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_llsync_ota.h

@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LLSYNC_OTA_H
+#define QCLOUD_BLE_QIOT_LLSYNC_OTA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "ble_qiot_config.h"
+#include "ble_qiot_export.h"
+
+#define BLE_QIOT_GET_OTA_REQUEST_HEADER_LEN 3  // the ota request header len
+#define BLE_QIOT_OTA_DATA_HEADER_LEN        3  // the ota data header len
+
+// ota feature
+#define BLE_QIOT_OTA_ENABLE        (1 << 0)
+#define BLE_QIOT_OTA_RESUME_ENABLE (1 << 1)
+
+// ota file valid result
+#define BLE_QIOT_OTA_VALID_SUCCESS (1 << 7)
+#define BLE_QIOT_OTA_VALID_FAIL    (0 << 7)
+
+#define BLE_QIOT_OTA_MAX_VERSION_STR (32)  // max ota version length
+#define BLE_QIOT_OTA_PAGE_VALID_VAL  0x5A  // ota info valid flag
+
+#define BLE_QIOT_OTA_FIRST_TIMEOUT   (1)
+#define BLE_QIOT_OTA_MAX_RETRY_COUNT 5  // disconnect if retry times more than BLE_QIOT_OTA_MAX_RETRY_COUNT
+
+// ota control bits
+#define BLE_QIOT_OTA_REQUEST_BIT     (1 << 0)
+#define BLE_QIOT_OTA_RECV_END_BIT    (1 << 1)
+#define BLE_QIOT_OTA_RECV_DATA_BIT   (1 << 2)
+#define BLE_QIOT_OTA_FIRST_RETRY_BIT (1 << 3)
+#define BLE_QIOT_OTA_DO_VALID_BIT    (1 << 4)
+#define BLE_QIOT_OTA_HAVE_DATA_BIT   (1 << 5)
+
+// the reason of ota file error
+enum {
+    BLE_QIOT_OTA_CRC_ERROR        = 0,
+    BLE_QIOT_OTA_READ_FLASH_ERROR = 1,
+    BLE_QIOT_OTA_FILE_ERROR       = 2,
+};
+
+// ota data type
+enum {
+    BLE_QIOT_OTA_MSG_REQUEST = 0,
+    BLE_QIOT_OTA_MSG_DATA    = 1,
+    BLE_QIOT_OTA_MSG_END     = 2,
+    BLE_QIOT_OTA_MSG_BUTT,
+};
+
+// ota request reply
+typedef struct ble_ota_reply_info_ {
+    uint8_t  package_nums;      // package numbers in a loop
+    uint8_t  package_size;      // each package size
+    uint8_t  retry_timeout;     // data retry
+    uint8_t  reboot_timeout;    // max time of device reboot
+    uint32_t last_file_size;    // the file already received
+    uint8_t  package_interval;  // package send interval on the server
+    uint8_t  rsv[3];
+} ble_ota_reply_info;
+
+typedef struct ble_ota_file_info_ {
+    uint32_t file_size;
+    uint32_t file_crc;
+    uint8_t  file_version[BLE_QIOT_OTA_MAX_VERSION_STR];
+} ble_ota_file_info;
+
+// ota info saved in flash if support resuming
+typedef struct ble_ota_info_record_ {
+    uint8_t           valid_flag;
+    uint8_t           rsv[3];
+    uint32_t          last_file_size;  // the file size already write in flash
+    uint32_t          last_address;    // the address file saved
+    ble_ota_file_info download_file_info;
+} ble_ota_info_record;
+
+// ota user callback
+typedef struct ble_ota_user_callback_ {
+    ble_ota_start_callback      start_cb;
+    ble_ota_stop_callback       stop_cb;
+    ble_ota_valid_file_callback valid_file_cb;
+} ble_ota_user_callback;
+
+// ota request package: 1 byte type + 2 bytes length + 4 bytes size + 4 bytes crc + 1 byte version length + 1 ~ 32 bytes
+// version
+typedef struct {
+    bool     have_data;  // start received package
+    uint8_t  type;       // event type
+    uint16_t buf_len;    // the length of data
+    char     buf[BLE_QIOT_GET_OTA_REQUEST_HEADER_LEN + 4 + 4 + 1 + BLE_QIOT_OTA_MAX_VERSION_STR];
+} ble_ota_request_slice_t;
+
+// ota reply info
+typedef struct ble_ota_reply_t_ {
+    uint32_t file_size;
+    uint8_t  req;
+} ble_ota_reply_t;
+
+ble_qiot_ret_status_t ble_ota_request_handle(const char *in_buf, int buf_len);
+
+ble_qiot_ret_status_t ble_ota_data_handle(const char *in_buf, int buf_len);
+
+ble_qiot_ret_status_t ble_ota_file_end_handle(void);
+
+void ble_ota_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // QCLOUD_BLE_QIOT_LLSYNC_OTA_H

+ 103 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_log.h

@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_QIOT_LOG_H
+#define QCLOUD_BLE_QIOT_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_config.h"
+
+typedef enum {
+    BLE_QIOT_LOG_LEVEL_NONE = 0,
+    BLE_QIOT_LOG_LEVEL_ERR,
+    BLE_QIOT_LOG_LEVEL_WARN,
+    BLE_QIOT_LOG_LEVEL_INFO,
+    BLE_QIOT_LOG_LEVEL_DEBUG,
+    BLE_QIOT_LOG_LEVEL_ALL,
+} e_ble_qiot_log_level;
+
+// log new line feed type
+#define LINE_NONE
+#define LINE_LF   "\n"
+#define LINE_CR   "\r"
+#define LINE_CRLF "\r\n"
+
+// log new line feed type config
+#define LOG_LINE_FEED_TYPE LINE_CRLF
+
+extern e_ble_qiot_log_level g_log_level;
+
+#ifndef ble_qiot_log_d
+#define ble_qiot_log_d(fmt, args...)                                       \
+    do {                                                                   \
+        if (g_log_level < BLE_QIOT_LOG_LEVEL_DEBUG)                        \
+            break;                                                         \
+        BLE_QIOT_LOG_PRINT("qiot debug: " fmt LOG_LINE_FEED_TYPE, ##args); \
+    } while (0)
+#endif
+
+#ifndef ble_qiot_log_i
+#define ble_qiot_log_i(fmt, args...)                                      \
+    do {                                                                  \
+        if (g_log_level < BLE_QIOT_LOG_LEVEL_INFO)                        \
+            break;                                                        \
+        BLE_QIOT_LOG_PRINT("qiot info: " fmt LOG_LINE_FEED_TYPE, ##args); \
+    } while (0)
+#endif
+
+#ifndef ble_qiot_log_w
+#define ble_qiot_log_w(fmt, args...)                                                                 \
+    do {                                                                                             \
+        if (g_log_level < BLE_QIOT_LOG_LEVEL_WARN)                                                   \
+            break;                                                                                   \
+        BLE_QIOT_LOG_PRINT("qiot warn(%s|%d): " fmt LOG_LINE_FEED_TYPE, __FILE__, __LINE__, ##args); \
+    } while (0)
+#endif
+
+#ifndef ble_qiot_log_e
+#define ble_qiot_log_e(fmt, args...)                                                                \
+    do {                                                                                            \
+        if (g_log_level < BLE_QIOT_LOG_LEVEL_ERR)                                                   \
+            break;                                                                                  \
+        BLE_QIOT_LOG_PRINT("qiot err(%s|%d): " fmt LOG_LINE_FEED_TYPE, __FILE__, __LINE__, ##args); \
+    } while (0)
+#endif
+
+#ifndef ble_qiot_log
+#define ble_qiot_log(level, fmt, args...)                                                           \
+    do {                                                                                            \
+        if (g_log_level < level)                                                                    \
+            break;                                                                                  \
+        BLE_QIOT_LOG_PRINT("qiot log(%s|%d): " fmt LOG_LINE_FEED_TYPE, __FILE__, __LINE__, ##args); \
+    } while (0)
+#endif
+
+// this function only use for ble_qiot_log_hex
+#ifndef ble_qiot_log_raw
+#define ble_qiot_log_raw(fmt, args...)   \
+    do {                                 \
+        BLE_QIOT_LOG_PRINT(fmt, ##args); \
+    } while (0)
+#endif
+
+void ble_qiot_set_log_level(e_ble_qiot_log_level level);
+
+#if !BLE_QIOT_USER_DEFINE_HEXDUMP
+void ble_qiot_log_hex(e_ble_qiot_log_level level, const char *hex_name, const char *data, uint32_t data_len);
+#endif  // BLE_QIOT_USER_DEFINE_HEXDUMP
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // QCLOUD_BLE_QIOT_LOG_H

+ 94 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_md5.h

@@ -0,0 +1,94 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_QIOT_MD5_H
+#define QCLOUD_BLE_QIOT_MD5_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_DIGEST_SIZE 16
+
+typedef struct {
+    unsigned int  total[2];   /*!< number of bytes processed  */
+    unsigned int  state[4];   /*!< intermediate digest state  */
+    unsigned char buffer[64]; /*!< data block being processed */
+} iot_md5_context;
+
+/**
+ * @brief init MD5 context
+ *
+ * @param ctx   MD5 context
+ */
+void utils_md5_init(iot_md5_context *ctx);
+
+/**
+ * @brief free MD5 context
+ *
+ * @param ctx   MD5 context
+ */
+void utils_md5_free(iot_md5_context *ctx);
+
+/**
+ * @brief clone MD5 context
+ *
+ * @param dst   destination MD5 context
+ * @param src   source MD5 context
+ */
+void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src);
+
+/**
+ * @brief start MD5 calculation
+ *
+ * @param ctx   MD5 context
+ */
+void utils_md5_starts(iot_md5_context *ctx);
+
+/**
+ * @brief MD5 update
+ *
+ * @param ctx MD5 context
+ * @param input    input data
+ * @param ilen     data length
+ */
+void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, unsigned int ilen);
+
+/**
+ * @brief          finish MD5 calculation
+ *
+ * @param ctx      MD5 context
+ * @param output   MD5 result
+ */
+void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16]);
+
+/* MD5 internal process */
+void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64]);
+
+/**
+ * @brief          Output = MD5( input buffer )
+ *
+ * @param input    data input
+ * @param ilen     data lenght
+ * @param output   MD5 result
+ */
+void utils_md5(const unsigned char *input, unsigned int ilen, unsigned char output[16]);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 93 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_param_check.h

@@ -0,0 +1,93 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_IOT_PARAM_CHECK_H_
+#define QCLOUD_BLE_IOT_PARAM_CHECK_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "ble_qiot_log.h"
+
+#define NUMBERIC_SANITY_CHECK(num, err)                    \
+    do {                                                   \
+        if (0 == (num)) {                                  \
+            ble_qiot_log_e("Invalid argument, numeric 0"); \
+            return (err);                                  \
+        }                                                  \
+    } while (0)
+
+#define NUMBERIC_SANITY_CHECK_RTN(num)                     \
+    do {                                                   \
+        if (0 == (num)) {                                  \
+            ble_qiot_log_e("Invalid argument, numeric 0"); \
+            return;                                        \
+        }                                                  \
+    } while (0)
+
+#define BUFF_LEN_SANITY_CHECK(num, min, err)                        \
+    do {                                                            \
+        if ((min) > (num)) {                                        \
+            ble_qiot_log_e("Invalid argument, %d <= %d", min, num); \
+            return (err);                                           \
+        }                                                           \
+    } while (0)
+
+#define POINTER_SANITY_CHECK(ptr, err)                              \
+    do {                                                            \
+        if (NULL == (ptr)) {                                        \
+            ble_qiot_log_e("Invalid argument, %s = %p", #ptr, ptr); \
+            return (err);                                           \
+        }                                                           \
+    } while (0)
+
+#define POINTER_SANITY_CHECK_RTN(ptr)                               \
+    do {                                                            \
+        if (NULL == (ptr)) {                                        \
+            ble_qiot_log_e("Invalid argument, %s = %p", #ptr, ptr); \
+            return;                                                 \
+        }                                                           \
+    } while (0)
+
+#define STRING_PTR_SANITY_CHECK(ptr, err)                               \
+    do {                                                                \
+        if (NULL == (ptr)) {                                            \
+            ble_qiot_log_e("Invalid argument, %s = %p", #ptr, (ptr));   \
+            return (err);                                               \
+        }                                                               \
+        if (0 == strlen((ptr))) {                                       \
+            ble_qiot_log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \
+            return (err);                                               \
+        }                                                               \
+    } while (0)
+
+#define STRING_PTR_SANITY_CHECK_RTN(ptr)                                \
+    do {                                                                \
+        if (NULL == (ptr)) {                                            \
+            ble_qiot_log_e("Invalid argument, %s = %p", #ptr, (ptr));   \
+            return;                                                     \
+        }                                                               \
+        if (0 == strlen((ptr))) {                                       \
+            ble_qiot_log_e("Invalid argument, %s = '%s'", #ptr, (ptr)); \
+            return;                                                     \
+        }                                                               \
+    } while (0)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* QCLOUD_BLE_IOT_PARAM_CHECK_H_ */

+ 97 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_service.h

@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef QCLOUD_BLE_IOT_SERVICE_H_
+#define QCLOUD_BLE_IOT_SERVICE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "ble_qiot_export.h"
+#include "ble_qiot_llsync_data.h"
+#include "ble_qiot_template.h"
+
+// message type, reference data template
+enum {
+    BLE_QIOT_MSG_TYPE_PROPERTY = 0,
+    BLE_QIOT_MSG_TYPE_EVENT,
+    BLE_QIOT_MSG_TYPE_ACTION,
+    BLE_QIOT_MSG_TYPE_BUTT,
+};
+
+// define reply result
+enum {
+    BLE_QIOT_REPLY_SUCCESS = 0,
+    BLE_QIOT_REPLY_FAIL,
+    BLE_QIOT_REPLY_DATA_ERR,
+    BLE_QIOT_REPLY_BUTT,
+};
+
+// define message type that from server to device
+enum {
+    BLE_QIOT_DATA_DOWN_REPORT_REPLY = 0,
+    BLE_QIOT_DATA_DOWN_CONTROL,
+    BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY,
+    BLE_QIOT_DATA_DOWN_ACTION,
+    BLE_QIOT_DATA_DOWN_EVENT_REPLY,
+};
+
+// define message type that from device to server
+enum {
+    BLE_QIOT_EVENT_UP_PROPERTY_REPORT = 0,
+    BLE_QIOT_EVENT_UP_CONTROL_REPLY,
+    BLE_QIOT_EVENT_UP_GET_STATUS,
+    BLE_QIOT_EVENT_UP_EVENT_POST,
+    BLE_QIOT_EVENT_UP_ACTION_REPLY,
+    BLE_QIOT_EVENT_UP_BIND_SIGN_RET,
+    BLE_QIOT_EVENT_UP_CONN_SIGN_RET,
+    BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET,
+    BLE_QIOT_EVENT_UP_REPORT_MTU,
+    BLE_QIOT_EVENT_UP_REPLY_OTA_REPORT,
+    BLE_QIOT_EVENT_UP_REPLY_OTA_DATA,
+    BLE_QIOT_EVENT_UP_REPORT_CHECK_RESULT,
+    BLE_QIOT_EVENT_UP_SYNC_MTU,
+    BLE_QIOT_EVENT_UP_SYNC_WAIT_TIME,
+    BLE_QIOT_EVENT_UP_WIFI_MODE = 0xE0,
+    BLE_QIOT_EVENT_UP_WIFI_INFO,
+    BLE_QIOT_EVENT_UP_WIFI_CONNECT,
+    BLE_QIOT_EVENT_UP_WIFI_TOKEN,
+    BLE_QIOT_EVENT_UP_WIFI_LOG,
+    BLE_QIOT_EVENT_UP_BUTT,
+};
+
+// msg header define, bit 7-6 is msg type, bit 5 means request or reply, bit 4 - 0 is id
+#define	BLE_QIOT_PARSE_MSG_HEAD_TYPE(_C)        	(((_C) & 0XFF) >> 6)
+#define	BLE_QIOT_PARSE_MSG_HEAD_EFFECT(_C)      	((((_C) & 0XFF) & 0X20) ? BLE_QIOT_EFFECT_REPLY : BLE_QIOT_EFFECT_REQUEST)
+#define	BLE_QIOT_PARSE_MSG_HEAD_ID(_C)          	((_C) & 0X1F)
+
+// tlv header define, bit 7 - 5 is type, bit 4 - 0 depends on type of data template
+#define	BLE_QIOT_PARSE_TLV_HEAD_TYPE(_C)        	(((_C) & 0XFF) >> 5)
+#define	BLE_QIOT_PARSE_TLV_HEAD_ID(_C)          	((_C) & 0X1F)
+
+// handle llsync device info
+// return 0 is success, other is error
+int ble_device_info_msg_handle(const char *in_buf, int in_len);
+
+// lldata message from remote
+// return 0 is success, other is error
+int ble_lldata_msg_handle(const char *in_buf, int in_len);
+
+// ota message from remote
+// return 0 is success, other is error
+int ble_ota_msg_handle(const char *buf, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // QCLOUD_BLE_IOT_SERVICE_H_

+ 93 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_sha1.h

@@ -0,0 +1,93 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_LLSYNC_BLE_QIOT_SHA1_H
+#define QCLOUD_BLE_LLSYNC_BLE_QIOT_SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * \brief          SHA-1 context structure
+ */
+typedef struct {
+    uint32_t      total[2];   /*!< number of bytes processed  */
+    uint32_t      state[5];   /*!< intermediate digest state  */
+    unsigned char buffer[64]; /*!< data block being processed */
+} iot_sha1_context;
+
+/**
+ * \brief          Initialize SHA-1 context
+ *
+ * \param ctx      SHA-1 context to be initialized
+ */
+void utils_sha1_init(iot_sha1_context *ctx);
+
+/**
+ * \brief          Clear SHA-1 context
+ *
+ * \param ctx      SHA-1 context to be cleared
+ */
+void utils_sha1_free(iot_sha1_context *ctx);
+
+/**
+ * \brief          Clone (the state of) a SHA-1 context
+ *
+ * \param dst      The destination context
+ * \param src      The context to be cloned
+ */
+void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src);
+
+/**
+ * \brief          SHA-1 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void utils_sha1_starts(iot_sha1_context *ctx);
+
+/**
+ * \brief          SHA-1 process buffer
+ *
+ * \param ctx      SHA-1 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen);
+
+/**
+ * \brief          SHA-1 final digest
+ *
+ * \param ctx      SHA-1 context
+ * \param output   SHA-1 checksum result
+ */
+void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]);
+
+/* Internal use */
+void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]);
+
+/**
+ * \brief          Output = SHA-1( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-1 checksum result
+ */
+void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]);
+
+#endif  // QCLOUD_BLE_LLSYNC_BLE_QIOT_SHA1_H

+ 36 - 0
qcloud_iot_explorer_ble/src/internal_inc/ble_qiot_utils_base64.h

@@ -0,0 +1,36 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef QCLOUD_BLE_IOT_UTILS_BASE64_H_
+#define QCLOUD_BLE_IOT_UTILS_BASE64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "ble_qiot_export.h"
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen,
+                                                    const unsigned char *src, size_t slen);
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen,
+                                                    const unsigned char *src, size_t slen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* QCLOUD_BLE_IOT_UTILS_BASE64_H_ */

+ 180 - 0
qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_base64.c

@@ -0,0 +1,180 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_utils_base64.h"
+#include "ble_qiot_export.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+static const unsigned char base64_enc_map[64] = {
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+    'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+    's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
+
+static const unsigned char base64_dec_map[128] = {
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62,
+    127, 127, 127, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  127, 127, 127, 64,  127, 127, 127, 0,
+    1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,
+    23,  24,  25,  127, 127, 127, 127, 127, 127, 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
+    39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  127, 127, 127, 127, 127};
+
+#define BASE64_SIZE_T_MAX ((size_t)-1) /* SIZE_T_MAX is not standard */
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen,
+                                                    const unsigned char *src, size_t slen)
+{
+    size_t         i, n;
+    unsigned char *p;
+
+    if (slen == 0) {
+        *olen = 0;
+        return (BLE_QIOT_RS_OK);
+    }
+
+    n = slen / 3 + (slen % 3 != 0);
+
+    if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
+        *olen = BASE64_SIZE_T_MAX;
+        return (BLE_QIOT_RS_ERR);
+    }
+
+    n *= 4;
+
+    if ((dlen < n + 1) || (NULL == dst)) {
+        *olen = n + 1;
+        return (BLE_QIOT_RS_ERR);
+    }
+
+    n = (slen / 3) * 3;
+
+    int C1, C2, C3;
+    for (i = 0, p = dst; i < n; i += 3) {
+        C1 = *src++;
+        C2 = *src++;
+        C3 = *src++;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+        *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+        *p++ = base64_enc_map[C3 & 0x3F];
+    }
+
+    if (i < slen) {
+        C1 = *src++;
+        C2 = ((i + 1) < slen) ? *src++ : 0;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+        if ((i + 1) < slen)
+            *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+        else
+            *p++ = '=';
+
+        *p++ = '=';
+    }
+
+    *olen = p - dst;
+    *p    = 0;
+
+    return (BLE_QIOT_RS_OK);
+}
+
+ble_qiot_ret_status_t qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen,
+                                                    const unsigned char *src, size_t slen)
+{
+    size_t         i, n;
+    uint32_t       j, x;
+    unsigned char *p;
+
+    /* First pass: check for validity and get output length */
+    for (i = n = j = 0; i < slen; i++) {
+        /* Skip spaces before checking for EOL */
+        x = 0;
+        while (i < slen && src[i] == ' ') {
+            ++i;
+            ++x;
+        }
+
+        /* Spaces at end of buffer are OK */
+        if (i == slen)
+            break;
+
+        if ((slen - i) >= 2 && src[i] == '\r' && src[i + 1] == '\n')
+            continue;
+
+        if (src[i] == '\n')
+            continue;
+
+        /* Space inside a line is an error */
+        if (x != 0)
+            return (BLE_QIOT_RS_ERR);
+
+        if (src[i] == '=' && ++j > 2)
+            return (BLE_QIOT_RS_ERR);
+
+        if (src[i] > 127 || base64_dec_map[src[i]] == 127)
+            return (BLE_QIOT_RS_ERR);
+
+        if (base64_dec_map[src[i]] < 64 && j != 0)
+            return (BLE_QIOT_RS_ERR);
+
+        n++;
+    }
+
+    if (n == 0) {
+        *olen = 0;
+        return (BLE_QIOT_RS_OK);
+    }
+
+    n = ((n * 6) + 7) >> 3;
+    n -= j;
+
+    if (dst == NULL || dlen < n) {
+        *olen = n;
+        return (BLE_QIOT_RS_ERR);
+    }
+
+    for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
+        if (*src == '\r' || *src == '\n' || *src == ' ')
+            continue;
+
+        j -= (base64_dec_map[*src] == 64);
+        x = (x << 6) | (base64_dec_map[*src] & 0x3F);
+
+        if (++n == 4) {
+            n = 0;
+            if (j > 0)
+                *p++ = (unsigned char)(x >> 16);
+            if (j > 1)
+                *p++ = (unsigned char)(x >> 8);
+            if (j > 2)
+                *p++ = (unsigned char)(x);
+        }
+    }
+
+    *olen = p - dst;
+
+    return (BLE_QIOT_RS_OK);
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 69 - 0
qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_crc.c

@@ -0,0 +1,69 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_crc.h"
+
+#include <stdio.h>
+
+const uint32_t crc32_tab[] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
+    0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
+    0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
+    0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
+    0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
+    0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
+    0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
+    0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
+    0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
+    0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
+    0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
+    0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+
+uint32_t ble_qiot_crc32(uint32_t crc, const uint8_t *buf, int len)
+{
+    const uint8_t *p;
+
+    p   = buf;
+    crc = crc ^ ~0U;
+
+    while (len--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+    return crc ^ ~0U;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 83 - 0
qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_hmac.c

@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "ble_qiot_log.h"
+#include "ble_qiot_sha1.h"
+#include "ble_qiot_hmac.h"
+
+#define KEY_IOPAD_SIZE 64
+
+int8_t utils_hb2hex(uint8_t hb)
+{
+    hb = hb & 0xF;
+    return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
+}
+
+void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
+{
+    if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
+        ble_qiot_log_e("parameter is Null,failed!");
+        return;
+    }
+
+    if (key_len > KEY_IOPAD_SIZE) {
+        ble_qiot_log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
+        return;
+    }
+
+    iot_sha1_context context;
+    unsigned char    k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad  */
+    unsigned char    k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
+    unsigned char    out[SHA1_DIGEST_SIZE];
+    int              i;
+
+    /* start out by storing key in pads */
+    memset(k_ipad, 0, sizeof(k_ipad));
+    memset(k_opad, 0, sizeof(k_opad));
+    memcpy(k_ipad, key, key_len);
+    memcpy(k_opad, key, key_len);
+
+    /* XOR key with ipad and opad values */
+    for (i = 0; i < KEY_IOPAD_SIZE; i++) {
+        k_ipad[i] ^= 0x36;
+        k_opad[i] ^= 0x5c;
+    }
+
+    /* perform inner SHA */
+    utils_sha1_init(&context);                                  /* init context for 1st pass */
+    utils_sha1_starts(&context);                                /* setup context for 1st pass */
+    utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE);        /* start with inner pad */
+    utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
+    utils_sha1_finish(&context, out);                           /* finish up 1st pass */
+
+    /* perform outer SHA */
+    utils_sha1_init(&context);                           /* init context for 2nd pass */
+    utils_sha1_starts(&context);                         /* setup context for 2nd pass */
+    utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
+    utils_sha1_update(&context, out, SHA1_DIGEST_SIZE);  /* then results of 1st hash */
+    utils_sha1_finish(&context, out);                    /* finish up 2nd pass */
+
+    memcpy(digest, out, SHA1_DIGEST_SIZE);
+    /*    for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
+            digest[i * 2]     = utils_hb2hex(out[i] >> 4);
+            digest[i * 2 + 1] = utils_hb2hex(out[i]);
+        }*/
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 83 - 0
qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_log.c

@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_log.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#define HEX_DUMP_BYTE_PER_LINE 16
+
+e_ble_qiot_log_level g_log_level = BLE_QIOT_LOG_LEVEL_INFO;
+
+void ble_qiot_set_log_level(e_ble_qiot_log_level level)
+{
+    g_log_level = level;
+    return;
+}
+
+#if !BLE_QIOT_USER_DEFINE_HEXDUMP
+void ble_qiot_log_hex(e_ble_qiot_log_level level, const char *hex_name, const char *data, uint32_t data_len)
+{
+    char buf[HEX_DUMP_BYTE_PER_LINE * 5] = {0};
+    int  line_count = 0, line = 0, byte = 0, rest = 0, start_byte = 0;
+
+    if (g_log_level < level)
+        return;
+
+    line_count = data_len / HEX_DUMP_BYTE_PER_LINE;
+    if (data_len % HEX_DUMP_BYTE_PER_LINE) {
+        line_count += 1;
+    }
+
+    ble_qiot_log_raw("\r\nble qiot dump: %s, length: %d\r\n", hex_name, data_len);
+    ble_qiot_log_raw(" 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15\r\n");
+    ble_qiot_log_raw("===============================================\r\n");
+    for (line = 0; line < line_count; line++) {
+        start_byte = line * HEX_DUMP_BYTE_PER_LINE;
+        if (data_len - start_byte < HEX_DUMP_BYTE_PER_LINE) {
+            rest = data_len % HEX_DUMP_BYTE_PER_LINE;
+        } else {
+            rest = HEX_DUMP_BYTE_PER_LINE;
+        }
+
+        for (byte = 0; byte < HEX_DUMP_BYTE_PER_LINE; byte++) {
+            if (byte < rest) {
+                sprintf(&buf[byte * 3], "%02X ", data[start_byte + byte]);
+            } else {
+                sprintf(&buf[byte * 3], "   ");
+            }
+        }
+
+        sprintf(&buf[HEX_DUMP_BYTE_PER_LINE * 3], "| ");
+        for (byte = 0; byte < rest; byte++) {
+            if (data[start_byte + byte] >= ' ' && data[start_byte + byte] <= '~') {
+                buf[HEX_DUMP_BYTE_PER_LINE * 3 + 2 + byte] = data[start_byte + byte];
+            } else {
+                buf[HEX_DUMP_BYTE_PER_LINE * 3 + 2 + byte] = '.';
+            }
+        }
+        sprintf(&buf[HEX_DUMP_BYTE_PER_LINE * 3 + 2 + rest], "\r\n");
+
+        ble_qiot_log_raw("%s", buf);  // do not use printf(buf), that cause '%' transfer next character
+    }
+    ble_qiot_log_raw("\r\n");
+}
+#endif  // BLE_QIOT_USER_DEFINE_HEXDUMP
+
+#ifdef __cplusplus
+}
+#endif

+ 299 - 0
qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_md5.c

@@ -0,0 +1,299 @@
+/*
+ * Tencent is pleased to support the open source community by making IoT Hub available.
+ * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_md5.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Implementation that should never be optimized out by the compiler */
+static void _utils_md5_zeroize(void *v, size_t n)
+{
+    volatile unsigned char *p = v;
+    while (n--) *p++ = 0;
+}
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef IOT_MD5_GET_UINT32_LE
+#define IOT_MD5_GET_UINT32_LE(n, b, i)                                                                \
+    {                                                                                                 \
+        (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | \
+              ((uint32_t)(b)[(i) + 3] << 24);                                                         \
+    }
+#endif
+
+#ifndef IOT_MD5_PUT_UINT32_LE
+#define IOT_MD5_PUT_UINT32_LE(n, b, i)                      \
+    {                                                       \
+        (b)[(i)]     = (unsigned char)(((n)) & 0xFF);       \
+        (b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF);  \
+        (b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF); \
+        (b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF); \
+    }
+#endif
+
+void utils_md5_init(iot_md5_context *ctx)
+{
+    memset(ctx, 0, sizeof(iot_md5_context));
+}
+
+void utils_md5_free(iot_md5_context *ctx)
+{
+    if (ctx == NULL) {
+        return;
+    }
+
+    _utils_md5_zeroize(ctx, sizeof(iot_md5_context));
+}
+
+void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src)
+{
+    *dst = *src;
+}
+
+/*
+ * MD5 context setup
+ */
+void utils_md5_starts(iot_md5_context *ctx)
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+}
+
+void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64])
+{
+    uint32_t X[16], A, B, C, D;
+
+    IOT_MD5_GET_UINT32_LE(X[0], data, 0);
+    IOT_MD5_GET_UINT32_LE(X[1], data, 4);
+    IOT_MD5_GET_UINT32_LE(X[2], data, 8);
+    IOT_MD5_GET_UINT32_LE(X[3], data, 12);
+    IOT_MD5_GET_UINT32_LE(X[4], data, 16);
+    IOT_MD5_GET_UINT32_LE(X[5], data, 20);
+    IOT_MD5_GET_UINT32_LE(X[6], data, 24);
+    IOT_MD5_GET_UINT32_LE(X[7], data, 28);
+    IOT_MD5_GET_UINT32_LE(X[8], data, 32);
+    IOT_MD5_GET_UINT32_LE(X[9], data, 36);
+    IOT_MD5_GET_UINT32_LE(X[10], data, 40);
+    IOT_MD5_GET_UINT32_LE(X[11], data, 44);
+    IOT_MD5_GET_UINT32_LE(X[12], data, 48);
+    IOT_MD5_GET_UINT32_LE(X[13], data, 52);
+    IOT_MD5_GET_UINT32_LE(X[14], data, 56);
+    IOT_MD5_GET_UINT32_LE(X[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a, b, c, d, k, s, t)      \
+    {                               \
+        a += F(b, c, d) + X[k] + t; \
+        a = S(a, s) + b;            \
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+
+    P(A, B, C, D, 0, 7, 0xD76AA478);
+    P(D, A, B, C, 1, 12, 0xE8C7B756);
+    P(C, D, A, B, 2, 17, 0x242070DB);
+    P(B, C, D, A, 3, 22, 0xC1BDCEEE);
+    P(A, B, C, D, 4, 7, 0xF57C0FAF);
+    P(D, A, B, C, 5, 12, 0x4787C62A);
+    P(C, D, A, B, 6, 17, 0xA8304613);
+    P(B, C, D, A, 7, 22, 0xFD469501);
+    P(A, B, C, D, 8, 7, 0x698098D8);
+    P(D, A, B, C, 9, 12, 0x8B44F7AF);
+    P(C, D, A, B, 10, 17, 0xFFFF5BB1);
+    P(B, C, D, A, 11, 22, 0x895CD7BE);
+    P(A, B, C, D, 12, 7, 0x6B901122);
+    P(D, A, B, C, 13, 12, 0xFD987193);
+    P(C, D, A, B, 14, 17, 0xA679438E);
+    P(B, C, D, A, 15, 22, 0x49B40821);
+
+#undef F
+
+#define F(x, y, z) (y ^ (z & (x ^ y)))
+
+    P(A, B, C, D, 1, 5, 0xF61E2562);
+    P(D, A, B, C, 6, 9, 0xC040B340);
+    P(C, D, A, B, 11, 14, 0x265E5A51);
+    P(B, C, D, A, 0, 20, 0xE9B6C7AA);
+    P(A, B, C, D, 5, 5, 0xD62F105D);
+    P(D, A, B, C, 10, 9, 0x02441453);
+    P(C, D, A, B, 15, 14, 0xD8A1E681);
+    P(B, C, D, A, 4, 20, 0xE7D3FBC8);
+    P(A, B, C, D, 9, 5, 0x21E1CDE6);
+    P(D, A, B, C, 14, 9, 0xC33707D6);
+    P(C, D, A, B, 3, 14, 0xF4D50D87);
+    P(B, C, D, A, 8, 20, 0x455A14ED);
+    P(A, B, C, D, 13, 5, 0xA9E3E905);
+    P(D, A, B, C, 2, 9, 0xFCEFA3F8);
+    P(C, D, A, B, 7, 14, 0x676F02D9);
+    P(B, C, D, A, 12, 20, 0x8D2A4C8A);
+
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+
+    P(A, B, C, D, 5, 4, 0xFFFA3942);
+    P(D, A, B, C, 8, 11, 0x8771F681);
+    P(C, D, A, B, 11, 16, 0x6D9D6122);
+    P(B, C, D, A, 14, 23, 0xFDE5380C);
+    P(A, B, C, D, 1, 4, 0xA4BEEA44);
+    P(D, A, B, C, 4, 11, 0x4BDECFA9);
+    P(C, D, A, B, 7, 16, 0xF6BB4B60);
+    P(B, C, D, A, 10, 23, 0xBEBFBC70);
+    P(A, B, C, D, 13, 4, 0x289B7EC6);
+    P(D, A, B, C, 0, 11, 0xEAA127FA);
+    P(C, D, A, B, 3, 16, 0xD4EF3085);
+    P(B, C, D, A, 6, 23, 0x04881D05);
+    P(A, B, C, D, 9, 4, 0xD9D4D039);
+    P(D, A, B, C, 12, 11, 0xE6DB99E5);
+    P(C, D, A, B, 15, 16, 0x1FA27CF8);
+    P(B, C, D, A, 2, 23, 0xC4AC5665);
+
+#undef F
+
+#define F(x, y, z) (y ^ (x | ~z))
+
+    P(A, B, C, D, 0, 6, 0xF4292244);
+    P(D, A, B, C, 7, 10, 0x432AFF97);
+    P(C, D, A, B, 14, 15, 0xAB9423A7);
+    P(B, C, D, A, 5, 21, 0xFC93A039);
+    P(A, B, C, D, 12, 6, 0x655B59C3);
+    P(D, A, B, C, 3, 10, 0x8F0CCC92);
+    P(C, D, A, B, 10, 15, 0xFFEFF47D);
+    P(B, C, D, A, 1, 21, 0x85845DD1);
+    P(A, B, C, D, 8, 6, 0x6FA87E4F);
+    P(D, A, B, C, 15, 10, 0xFE2CE6E0);
+    P(C, D, A, B, 6, 15, 0xA3014314);
+    P(B, C, D, A, 13, 21, 0x4E0811A1);
+    P(A, B, C, D, 4, 6, 0xF7537E82);
+    P(D, A, B, C, 11, 10, 0xBD3AF235);
+    P(C, D, A, B, 2, 15, 0x2AD7D2BB);
+    P(B, C, D, A, 9, 21, 0xEB86D391);
+
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+}
+
+/*
+ * MD5 process buffer
+ */
+void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, unsigned int ilen)
+{
+    uint32_t fill;
+    uint32_t left;
+
+    if (ilen == 0) {
+        return;
+    }
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += (uint32_t)ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if (ctx->total[0] < (uint32_t)ilen) {
+        ctx->total[1]++;
+    }
+
+    if (left && ilen >= fill) {
+        memcpy((void *)(ctx->buffer + left), input, fill);
+        utils_md5_process(ctx, ctx->buffer);
+        input += fill;
+        ilen -= fill;
+        left = 0;
+    }
+
+    while (ilen >= 64) {
+        utils_md5_process(ctx, input);
+        input += 64;
+        ilen -= 64;
+    }
+
+    if (ilen > 0) {
+        memcpy((void *)(ctx->buffer + left), input, ilen);
+    }
+}
+
+static const unsigned char iot_md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                                  0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                                  0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+/*
+ * MD5 final digest
+ */
+void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16])
+{
+    uint32_t      last, padn;
+    uint32_t      high, low;
+    unsigned char msglen[8];
+
+    high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+    low  = (ctx->total[0] << 3);
+
+    IOT_MD5_PUT_UINT32_LE(low, msglen, 0);
+    IOT_MD5_PUT_UINT32_LE(high, msglen, 4);
+
+    last = ctx->total[0] & 0x3F;
+    padn = (last < 56) ? (56 - last) : (120 - last);
+
+    utils_md5_update(ctx, iot_md5_padding, padn);
+    utils_md5_update(ctx, msglen, 8);
+
+    IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0);
+    IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4);
+    IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8);
+    IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12);
+}
+
+/*
+ * output = MD5( input buffer )
+ */
+void utils_md5(const unsigned char *input, unsigned int ilen, unsigned char output[16])
+{
+    iot_md5_context ctx;
+
+    utils_md5_init(&ctx);
+    utils_md5_starts(&ctx);
+    utils_md5_update(&ctx, input, ilen);
+    utils_md5_finish(&ctx, output);
+    utils_md5_free(&ctx);
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 327 - 0
qcloud_iot_explorer_ble/src/utils/ble_qiot_utils_sha1.c

@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * Licensed under the MIT License (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://opensource.org/licenses/MIT
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ble_qiot_sha1.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Implementation that should never be optimized out by the compiler */
+static void utils_sha1_zeroize(void *v, size_t n)
+{
+    volatile unsigned char *p = v;
+    while (n--) {
+        *p++ = 0;
+    }
+}
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef IOT_SHA1_GET_UINT32_BE
+#define IOT_SHA1_GET_UINT32_BE(n, b, i)                                                                     \
+    {                                                                                                       \
+        (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | \
+              ((uint32_t)(b)[(i) + 3]);                                                                     \
+    }
+#endif
+
+#ifndef IOT_SHA1_PUT_UINT32_BE
+#define IOT_SHA1_PUT_UINT32_BE(n, b, i)            \
+    {                                              \
+        (b)[(i)]     = (unsigned char)((n) >> 24); \
+        (b)[(i) + 1] = (unsigned char)((n) >> 16); \
+        (b)[(i) + 2] = (unsigned char)((n) >> 8);  \
+        (b)[(i) + 3] = (unsigned char)((n));       \
+    }
+#endif
+
+void utils_sha1_init(iot_sha1_context *ctx)
+{
+    memset(ctx, 0, sizeof(iot_sha1_context));
+}
+
+void utils_sha1_free(iot_sha1_context *ctx)
+{
+    if (ctx == NULL) {
+        return;
+    }
+
+    utils_sha1_zeroize(ctx, sizeof(iot_sha1_context));
+}
+
+void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src)
+{
+    *dst = *src;
+}
+
+/*
+ * SHA-1 context setup
+ */
+void utils_sha1_starts(iot_sha1_context *ctx)
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64])
+{
+    uint32_t temp, W[16], A, B, C, D, E;
+
+    IOT_SHA1_GET_UINT32_BE(W[0], data, 0);
+    IOT_SHA1_GET_UINT32_BE(W[1], data, 4);
+    IOT_SHA1_GET_UINT32_BE(W[2], data, 8);
+    IOT_SHA1_GET_UINT32_BE(W[3], data, 12);
+    IOT_SHA1_GET_UINT32_BE(W[4], data, 16);
+    IOT_SHA1_GET_UINT32_BE(W[5], data, 20);
+    IOT_SHA1_GET_UINT32_BE(W[6], data, 24);
+    IOT_SHA1_GET_UINT32_BE(W[7], data, 28);
+    IOT_SHA1_GET_UINT32_BE(W[8], data, 32);
+    IOT_SHA1_GET_UINT32_BE(W[9], data, 36);
+    IOT_SHA1_GET_UINT32_BE(W[10], data, 40);
+    IOT_SHA1_GET_UINT32_BE(W[11], data, 44);
+    IOT_SHA1_GET_UINT32_BE(W[12], data, 48);
+    IOT_SHA1_GET_UINT32_BE(W[13], data, 52);
+    IOT_SHA1_GET_UINT32_BE(W[14], data, 56);
+    IOT_SHA1_GET_UINT32_BE(W[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+    (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = S(temp, 1)))
+
+#define P(a, b, c, d, e, x)                \
+    {                                      \
+        e += S(a, 5) + F(b, c, d) + K + x; \
+        b = S(b, 30);                      \
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+#define K          0x5A827999
+
+    P(A, B, C, D, E, W[0]);
+    P(E, A, B, C, D, W[1]);
+    P(D, E, A, B, C, W[2]);
+    P(C, D, E, A, B, W[3]);
+    P(B, C, D, E, A, W[4]);
+    P(A, B, C, D, E, W[5]);
+    P(E, A, B, C, D, W[6]);
+    P(D, E, A, B, C, W[7]);
+    P(C, D, E, A, B, W[8]);
+    P(B, C, D, E, A, W[9]);
+    P(A, B, C, D, E, W[10]);
+    P(E, A, B, C, D, W[11]);
+    P(D, E, A, B, C, W[12]);
+    P(C, D, E, A, B, W[13]);
+    P(B, C, D, E, A, W[14]);
+    P(A, B, C, D, E, W[15]);
+    P(E, A, B, C, D, R(16));
+    P(D, E, A, B, C, R(17));
+    P(C, D, E, A, B, R(18));
+    P(B, C, D, E, A, R(19));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K          0x6ED9EBA1
+
+    P(A, B, C, D, E, R(20));
+    P(E, A, B, C, D, R(21));
+    P(D, E, A, B, C, R(22));
+    P(C, D, E, A, B, R(23));
+    P(B, C, D, E, A, R(24));
+    P(A, B, C, D, E, R(25));
+    P(E, A, B, C, D, R(26));
+    P(D, E, A, B, C, R(27));
+    P(C, D, E, A, B, R(28));
+    P(B, C, D, E, A, R(29));
+    P(A, B, C, D, E, R(30));
+    P(E, A, B, C, D, R(31));
+    P(D, E, A, B, C, R(32));
+    P(C, D, E, A, B, R(33));
+    P(B, C, D, E, A, R(34));
+    P(A, B, C, D, E, R(35));
+    P(E, A, B, C, D, R(36));
+    P(D, E, A, B, C, R(37));
+    P(C, D, E, A, B, R(38));
+    P(B, C, D, E, A, R(39));
+
+#undef K
+#undef F
+
+#define F(x, y, z) ((x & y) | (z & (x | y)))
+#define K          0x8F1BBCDC
+
+    P(A, B, C, D, E, R(40));
+    P(E, A, B, C, D, R(41));
+    P(D, E, A, B, C, R(42));
+    P(C, D, E, A, B, R(43));
+    P(B, C, D, E, A, R(44));
+    P(A, B, C, D, E, R(45));
+    P(E, A, B, C, D, R(46));
+    P(D, E, A, B, C, R(47));
+    P(C, D, E, A, B, R(48));
+    P(B, C, D, E, A, R(49));
+    P(A, B, C, D, E, R(50));
+    P(E, A, B, C, D, R(51));
+    P(D, E, A, B, C, R(52));
+    P(C, D, E, A, B, R(53));
+    P(B, C, D, E, A, R(54));
+    P(A, B, C, D, E, R(55));
+    P(E, A, B, C, D, R(56));
+    P(D, E, A, B, C, R(57));
+    P(C, D, E, A, B, R(58));
+    P(B, C, D, E, A, R(59));
+
+#undef K
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+#define K          0xCA62C1D6
+
+    P(A, B, C, D, E, R(60));
+    P(E, A, B, C, D, R(61));
+    P(D, E, A, B, C, R(62));
+    P(C, D, E, A, B, R(63));
+    P(B, C, D, E, A, R(64));
+    P(A, B, C, D, E, R(65));
+    P(E, A, B, C, D, R(66));
+    P(D, E, A, B, C, R(67));
+    P(C, D, E, A, B, R(68));
+    P(B, C, D, E, A, R(69));
+    P(A, B, C, D, E, R(70));
+    P(E, A, B, C, D, R(71));
+    P(D, E, A, B, C, R(72));
+    P(C, D, E, A, B, R(73));
+    P(B, C, D, E, A, R(74));
+    P(A, B, C, D, E, R(75));
+    P(E, A, B, C, D, R(76));
+    P(D, E, A, B, C, R(77));
+    P(C, D, E, A, B, R(78));
+    P(B, C, D, E, A, R(79));
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen)
+{
+    size_t   fill;
+    uint32_t left;
+
+    if (ilen == 0) {
+        return;
+    }
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += (uint32_t)ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if (ctx->total[0] < (uint32_t)ilen) {
+        ctx->total[1]++;
+    }
+
+    if (left && ilen >= fill) {
+        memcpy((void *)(ctx->buffer + left), input, fill);
+        utils_sha1_process(ctx, ctx->buffer);
+        input += fill;
+        ilen -= fill;
+        left = 0;
+    }
+
+    while (ilen >= 64) {
+        utils_sha1_process(ctx, input);
+        input += 64;
+        ilen -= 64;
+    }
+
+    if (ilen > 0) {
+        memcpy((void *)(ctx->buffer + left), input, ilen);
+    }
+}
+
+static const unsigned char iot_sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                                   0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                                   0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+/*
+ * SHA-1 final digest
+ */
+void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20])
+{
+    uint32_t      last, padn;
+    uint32_t      high, low;
+    unsigned char msglen[8];
+
+    high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+    low  = (ctx->total[0] << 3);
+
+    IOT_SHA1_PUT_UINT32_BE(high, msglen, 0);
+    IOT_SHA1_PUT_UINT32_BE(low, msglen, 4);
+
+    last = ctx->total[0] & 0x3F;
+    padn = (last < 56) ? (56 - last) : (120 - last);
+
+    utils_sha1_update(ctx, iot_sha1_padding, padn);
+    utils_sha1_update(ctx, msglen, 8);
+
+    IOT_SHA1_PUT_UINT32_BE(ctx->state[0], output, 0);
+    IOT_SHA1_PUT_UINT32_BE(ctx->state[1], output, 4);
+    IOT_SHA1_PUT_UINT32_BE(ctx->state[2], output, 8);
+    IOT_SHA1_PUT_UINT32_BE(ctx->state[3], output, 12);
+    IOT_SHA1_PUT_UINT32_BE(ctx->state[4], output, 16);
+}
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20])
+{
+    iot_sha1_context ctx;
+
+    utils_sha1_init(&ctx);
+    utils_sha1_starts(&ctx);
+    utils_sha1_update(&ctx, input, ilen);
+    utils_sha1_finish(&ctx, output);
+    utils_sha1_free(&ctx);
+}
+
+#ifdef __cplusplus
+}
+#endif