支持BLE设备接入“腾讯连连”小程序
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(llsync)
|
@@ -0,0 +1,28 @@
|
||||
if (CONFIG_QCLOUD_LLSYNC_SUPPORT)
|
||||
set(srcs
|
||||
src/core/ble_qiot_llsync_data.c
|
||||
src/core/ble_qiot_llsync_device.c
|
||||
src/core/ble_qiot_llsync_event.c
|
||||
src/core/ble_qiot_service.c
|
||||
src/utils/ble_qiot_utils_base64.c
|
||||
src/utils/ble_qiot_utils_hmac.c
|
||||
src/utils/ble_qiot_utils_log.c
|
||||
src/utils/ble_qiot_utils_md5.c
|
||||
src/utils/ble_qiot_utils_sha1.c)
|
||||
|
||||
list(APPEND srcs
|
||||
date_template/ble_qiot_template.c)
|
||||
|
||||
list(APPEND srcs
|
||||
hal/ble_qiot_ble_device.c
|
||||
hal/ble_qiot_ble_service.c)
|
||||
|
||||
set(includes inc src/internal_inc)
|
||||
set(priv_includes date_template src/internal_inc hal)
|
||||
|
||||
endif ()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${includes}"
|
||||
PRIV_INCLUDE_DIRS "${priv_includes}"
|
||||
REQUIRES bt)
|
@@ -0,0 +1,7 @@
|
||||
menu "QCloud LLSync"
|
||||
config QCLOUD_LLSYNC_SUPPORT
|
||||
|
||||
bool "QCloud LLSync support."
|
||||
default "y"
|
||||
|
||||
endmenu
|
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
float sg_ch20_ppm = 0.0;
|
||||
static int ble_property_ch20_ppm_value_set(const char *data, uint16_t len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ble_property_ch20_ppm_value_get(char *data, uint16_t buf_len)
|
||||
{
|
||||
memcpy(data, &sg_ch20_ppm, sizeof(float));
|
||||
return sizeof(float);
|
||||
}
|
||||
|
||||
static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
|
||||
{ble_property_ch20_ppm_value_set, ble_property_ch20_ppm_value_get, BLE_QIOT_PROPERTY_AUTH_READ,
|
||||
BLE_QIOT_DATA_TYPE_FLOAT},
|
||||
};
|
||||
|
||||
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", id);
|
||||
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);
|
||||
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
|
||||
// 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_BUTT,
|
||||
};
|
||||
|
||||
// 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 property authority, not used
|
||||
enum {
|
||||
BLE_QIOT_PROPERTY_AUTH_RW = 0,
|
||||
BLE_QIOT_PROPERTY_AUTH_READ,
|
||||
BLE_QIOT_PROPERTY_AUTH_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 flow direction
|
||||
enum {
|
||||
BLE_QIOT_EFFECT_REQUEST = 0,
|
||||
BLE_QIOT_EFFECT_REPLY,
|
||||
BLE_QIOT_EFFECT_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_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)
|
||||
#define BLE_QIOT_PACKAGE_MSG_HEAD(_TYPE, _REPLY, _ID) (((_TYPE) << 6) | (((_REPLY) == BLE_QIOT_EFFECT_REPLY) << 5) | ((_ID) & 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)
|
||||
#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_CH20_PPM_VALUE = 0,
|
||||
BLE_QIOT_PROPERTY_ID_BUTT,
|
||||
};
|
||||
|
||||
// define ch20_ppm_value attributes
|
||||
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_MIN (0)
|
||||
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_MAX (2)
|
||||
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_START (0)
|
||||
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_STEP (0.001)
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
#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_
|
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"profile": {
|
||||
"ProductId": "1NBPCQ7L2O",
|
||||
"CategoryId": "1"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "ch20_ppm_value",
|
||||
"name": "甲醛浓度值",
|
||||
"desc": "",
|
||||
"mode": "r",
|
||||
"define": {
|
||||
"type": "float",
|
||||
"min": "0",
|
||||
"max": "2",
|
||||
"start": "0",
|
||||
"step": "0.001",
|
||||
"unit": "ppm(mg/m3)"
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"events": [],
|
||||
"actions": []
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ble_qiot_export.h"
|
||||
#include "ble_qiot_service.h"
|
||||
#include "ble_qiot_import.h"
|
||||
|
||||
// add std head file here
|
||||
#include <stdint.h>
|
||||
|
||||
// add ble qiot head file here
|
||||
#include "ble_qiot_import.h"
|
||||
|
||||
#include "ble_qiot_config.h"
|
||||
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_spi_flash.h"
|
||||
|
||||
// divece info which defined in explorer platform
|
||||
#define PRODUCT_ID "1NBPCQ7L2O"
|
||||
#define DEVICE_NAME "123"
|
||||
#define SECRET_KEY "q/WQFemC2ejNZTNWMqHerA=="
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
char *address = (char *)esp_bt_dev_get_address();
|
||||
memcpy(mac, address, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
|
||||
{
|
||||
int ret = spi_flash_erase_range(flash_addr, BLE_QIOT_RECORD_FLASH_PAGESIZE);
|
||||
ret = spi_flash_write(flash_addr, write_buf, write_len);
|
||||
|
||||
return ret == ESP_OK ? write_len : ret;
|
||||
}
|
||||
|
||||
int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
|
||||
{
|
||||
int ret = spi_flash_read(flash_addr, read_buf, read_len);
|
||||
|
||||
return ret == ESP_OK ? read_len : ret;
|
||||
}
|
||||
|
||||
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period)
|
||||
{
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id)
|
||||
{
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id)
|
||||
{
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
// should return ATT_MTU - 3
|
||||
uint16_t ble_get_user_data_mtu_size(void)
|
||||
{
|
||||
// esp32 can not get mtu,use default mtu
|
||||
return 20;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gatts_api.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
|
||||
#include "ble_qiot_config.h"
|
||||
#include "ble_qiot_export.h"
|
||||
#include "ble_qiot_service.h"
|
||||
#include "ble_qiot_import.h"
|
||||
|
||||
#define LLSYNC_LOG_TAG "LLSYNC"
|
||||
|
||||
/* Attributes State Machine */
|
||||
enum
|
||||
{
|
||||
IDX_SVC,
|
||||
IDX_CHAR_A,
|
||||
IDX_CHAR_VAL_A,
|
||||
|
||||
IDX_CHAR_B,
|
||||
IDX_CHAR_VAL_B,
|
||||
|
||||
IDX_CHAR_C,
|
||||
IDX_CHAR_VAL_C,
|
||||
IDX_CHAR_CFG_C,
|
||||
|
||||
HRS_IDX_NB,
|
||||
};
|
||||
|
||||
#define PROFILE_NUM 1
|
||||
#define PROFILE_APP_IDX 0
|
||||
#define LLSYNC_APP_ID 0x55
|
||||
#define SAMPLE_DEVICE_NAME "l"
|
||||
#define SVC_INST_ID 0
|
||||
|
||||
/* The max length of characteristic value. When the GATT client performs a write or prepare write operation,
|
||||
* the data length must be less than LLSYNC_CHAR_VAL_LEN_MAX.
|
||||
*/
|
||||
#define LLSYNC_CHAR_VAL_LEN_MAX 500
|
||||
#define PREPARE_BUF_MAX_SIZE 1024
|
||||
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
|
||||
|
||||
#define ADV_CONFIG_FLAG (1 << 0)
|
||||
|
||||
static uint8_t adv_config_done = 0;
|
||||
|
||||
uint16_t llsync_handle_table[HRS_IDX_NB];
|
||||
|
||||
typedef struct {
|
||||
uint8_t *prepare_buf;
|
||||
int prepare_len;
|
||||
uint16_t handle;
|
||||
} prepare_type_env_t;
|
||||
|
||||
static prepare_type_env_t prepare_write_env;
|
||||
|
||||
static uint8_t raw_adv_data[32] = {
|
||||
/* flags */
|
||||
0x02, 0x01, 0x06,
|
||||
/* service uuid */
|
||||
0x03, 0x03, 0xE0, 0xFF,
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x20,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
struct gatts_profile_inst {
|
||||
esp_gatts_cb_t gatts_cb;
|
||||
uint16_t gatts_if;
|
||||
uint16_t app_id;
|
||||
uint16_t conn_id;
|
||||
uint16_t service_handle;
|
||||
esp_gatt_srvc_id_t service_id;
|
||||
uint16_t char_handle;
|
||||
esp_bt_uuid_t char_uuid;
|
||||
esp_gatt_perm_t perm;
|
||||
esp_gatt_char_prop_t property;
|
||||
uint16_t descr_handle;
|
||||
esp_bt_uuid_t descr_uuid;
|
||||
};
|
||||
|
||||
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
|
||||
{
|
||||
uint8_t usr_adv_data[31] = {0};
|
||||
uint8_t len = 0;
|
||||
uint8_t index = 0;
|
||||
|
||||
memcpy(usr_adv_data, &adv->manufacturer_info.company_identifier, sizeof(uint16_t));
|
||||
len = sizeof(uint16_t);
|
||||
memcpy(usr_adv_data + len, adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
|
||||
len += adv->manufacturer_info.adv_data_len;
|
||||
|
||||
index = 7;
|
||||
raw_adv_data[index++] = len + 1;
|
||||
raw_adv_data[index++] = 0xFF;
|
||||
memcpy(raw_adv_data + index, usr_adv_data, len);
|
||||
index += len;
|
||||
|
||||
raw_adv_data[index++] = strlen(SAMPLE_DEVICE_NAME) + 1;
|
||||
raw_adv_data[index++] = 0x09;
|
||||
memcpy(raw_adv_data + index, SAMPLE_DEVICE_NAME, strlen(SAMPLE_DEVICE_NAME));
|
||||
index += strlen(SAMPLE_DEVICE_NAME);
|
||||
|
||||
esp_log_buffer_hex("adv", raw_adv_data, index);
|
||||
//config adv data
|
||||
esp_err_t ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, index);
|
||||
if (ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "config adv data failed, error code = %x", ret);
|
||||
}
|
||||
adv_config_done |= ADV_CONFIG_FLAG;
|
||||
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "start advertising");
|
||||
esp_ble_gap_start_advertising(&adv_params);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ble_qiot_ret_status_t ble_advertising_stop(void)
|
||||
{
|
||||
esp_ble_gap_stop_advertising();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
|
||||
|
||||
/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
|
||||
static struct gatts_profile_inst llsync_profile_tab[PROFILE_NUM] = {
|
||||
[PROFILE_APP_IDX] = {
|
||||
.gatts_cb = gatts_profile_event_handler,
|
||||
.gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
|
||||
},
|
||||
};
|
||||
|
||||
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
esp_ble_gatts_send_indicate(llsync_profile_tab[PROFILE_APP_IDX].gatts_if, llsync_profile_tab[PROFILE_APP_IDX].conn_id,
|
||||
llsync_handle_table[IDX_CHAR_VAL_C],len, buf, false);
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
|
||||
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
|
||||
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
|
||||
static const uint8_t char_prop_write = ESP_GATT_CHAR_PROP_BIT_WRITE;
|
||||
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
|
||||
static const uint8_t heart_measurement_ccc[2] = {0x00, 0x00};
|
||||
|
||||
/* service_uuid and Characteristic_uuid*/
|
||||
static uint8_t llsync_service_uuid[16] = {
|
||||
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe0, 0xff, 0x00, 0x00,
|
||||
};
|
||||
static uint8_t llsync_device_info_uuid[16] = {
|
||||
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe1, 0xff, 0x00, 0x00,
|
||||
};
|
||||
static uint8_t llsync_data_uuid[16] = {
|
||||
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe2, 0xff, 0x00, 0x00,
|
||||
};
|
||||
static uint8_t llsync_event_uuid[16] = {
|
||||
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe3, 0xff, 0x00, 0x00,
|
||||
};
|
||||
|
||||
|
||||
/* Full Database Description - Used to add attributes into the database */
|
||||
static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
|
||||
{
|
||||
// Service Declaration
|
||||
[IDX_SVC] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
|
||||
sizeof(llsync_service_uuid), sizeof(llsync_service_uuid), (uint8_t *)llsync_service_uuid}},
|
||||
|
||||
/* Characteristic Declaration */
|
||||
[IDX_CHAR_A] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
|
||||
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},
|
||||
/* Characteristic Value */
|
||||
[IDX_CHAR_VAL_A] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)llsync_device_info_uuid, ESP_GATT_PERM_WRITE,
|
||||
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
|
||||
|
||||
/* Characteristic Declaration */
|
||||
[IDX_CHAR_B] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
|
||||
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},
|
||||
/* Characteristic Value */
|
||||
[IDX_CHAR_VAL_B] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)llsync_data_uuid, ESP_GATT_PERM_WRITE,
|
||||
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
|
||||
|
||||
/* Characteristic Declaration */
|
||||
[IDX_CHAR_C] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
|
||||
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
|
||||
/* Characteristic Value */
|
||||
[IDX_CHAR_VAL_C] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)llsync_event_uuid, 0,
|
||||
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
|
||||
/* Characteristic User Descriptor */
|
||||
[IDX_CHAR_CFG_C] =
|
||||
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
|
||||
sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
|
||||
};
|
||||
|
||||
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT");
|
||||
adv_config_done &= (~ADV_CONFIG_FLAG);
|
||||
if (adv_config_done == 0) {
|
||||
ble_qiot_advertising_start();
|
||||
adv_config_done = 2;
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
|
||||
/* advertising start complete event to indicate advertising start successfully or failed */
|
||||
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "advertising start failed");
|
||||
}else{
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "advertising start successfully");
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
||||
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "Advertising stop failed");
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "Stop adv successfully\n");
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
|
||||
param->update_conn_params.status,
|
||||
param->update_conn_params.min_int,
|
||||
param->update_conn_params.max_int,
|
||||
param->update_conn_params.conn_int,
|
||||
param->update_conn_params.latency,
|
||||
param->update_conn_params.timeout);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void example_prepare_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "prepare write, handle = %d, value len = %d", param->write.handle, param->write.len);
|
||||
esp_gatt_status_t status = ESP_GATT_OK;
|
||||
if (prepare_write_env->prepare_buf == NULL) {
|
||||
prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
|
||||
prepare_write_env->prepare_len = 0;
|
||||
prepare_write_env->handle = 0;
|
||||
if (prepare_write_env->prepare_buf == NULL) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "%s, Gatt_server prep no mem", __func__);
|
||||
status = ESP_GATT_NO_RESOURCES;
|
||||
}
|
||||
} else {
|
||||
if(param->write.offset > PREPARE_BUF_MAX_SIZE) {
|
||||
status = ESP_GATT_INVALID_OFFSET;
|
||||
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
|
||||
status = ESP_GATT_INVALID_ATTR_LEN;
|
||||
}
|
||||
}
|
||||
/*send response when param->write.need_rsp is true */
|
||||
if (param->write.need_rsp){
|
||||
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
|
||||
if (gatt_rsp != NULL){
|
||||
gatt_rsp->attr_value.len = param->write.len;
|
||||
gatt_rsp->attr_value.handle = param->write.handle;
|
||||
gatt_rsp->attr_value.offset = param->write.offset;
|
||||
gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
|
||||
memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
|
||||
esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
|
||||
if (response_err != ESP_OK){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "Send response error");
|
||||
}
|
||||
free(gatt_rsp);
|
||||
}else{
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "%s, malloc failed", __func__);
|
||||
}
|
||||
}
|
||||
if (status != ESP_GATT_OK){
|
||||
return;
|
||||
}
|
||||
memcpy(prepare_write_env->prepare_buf + param->write.offset,
|
||||
param->write.value,
|
||||
param->write.len);
|
||||
prepare_write_env->prepare_len += param->write.len;
|
||||
prepare_write_env->handle = param->write.handle;
|
||||
}
|
||||
|
||||
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC && prepare_write_env->prepare_buf){
|
||||
if (prepare_write_env->handle == llsync_handle_table[IDX_CHAR_VAL_A]){
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ble_device_info_write_cb");
|
||||
ble_device_info_write_cb(prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
|
||||
}else if (prepare_write_env->handle == llsync_handle_table[IDX_CHAR_VAL_B]){
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ble_lldata_write_cb");
|
||||
ble_lldata_write_cb(prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
|
||||
}
|
||||
esp_log_buffer_hex(LLSYNC_LOG_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
|
||||
}else{
|
||||
ESP_LOGI(LLSYNC_LOG_TAG,"ESP_GATT_PREP_WRITE_CANCEL");
|
||||
}
|
||||
if (prepare_write_env->prepare_buf) {
|
||||
free(prepare_write_env->prepare_buf);
|
||||
prepare_write_env->prepare_buf = NULL;
|
||||
}
|
||||
prepare_write_env->prepare_len = 0;
|
||||
}
|
||||
|
||||
|
||||
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GATTS_REG_EVT:
|
||||
{
|
||||
esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
|
||||
if (set_dev_name_ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "set device name failed, error code = %x", set_dev_name_ret);
|
||||
}
|
||||
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, 7);
|
||||
if (raw_adv_ret){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
|
||||
}
|
||||
adv_config_done |= ADV_CONFIG_FLAG;
|
||||
esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, HRS_IDX_NB, SVC_INST_ID);
|
||||
if (create_attr_ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "create attr table failed, error code = %x", create_attr_ret);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_GATTS_READ_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_READ_EVT");
|
||||
break;
|
||||
case ESP_GATTS_WRITE_EVT:
|
||||
if (!param->write.is_prep){
|
||||
// the data length of gattc write must be less than LLSYNC_CHAR_VAL_LEN_MAX.
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len);
|
||||
esp_log_buffer_hex(LLSYNC_LOG_TAG, param->write.value, param->write.len);
|
||||
if (param->write.handle == llsync_handle_table[IDX_CHAR_VAL_A]){
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ble_device_info_write_cb");
|
||||
ble_device_info_write_cb(param->write.value, param->write.len);
|
||||
}else if (param->write.handle == llsync_handle_table[IDX_CHAR_VAL_B]){
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ble_lldata_write_cb");
|
||||
ble_lldata_write_cb(param->write.value, param->write.len);
|
||||
}
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "GATT_WRITE_EVT OVER");
|
||||
/* send response when param->write.need_rsp is true*/
|
||||
if (param->write.need_rsp){
|
||||
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
|
||||
}
|
||||
}else{
|
||||
example_prepare_write_event_env(gatts_if, &prepare_write_env, param);
|
||||
}
|
||||
break;
|
||||
case ESP_GATTS_EXEC_WRITE_EVT:
|
||||
// the length of gattc prepare write data must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_EXEC_WRITE_EVT");
|
||||
example_exec_write_event_env(&prepare_write_env, param);
|
||||
break;
|
||||
case ESP_GATTS_MTU_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
|
||||
break;
|
||||
case ESP_GATTS_CONF_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_CONF_EVT, status = %d, attr_handle %d", param->conf.status, param->conf.handle);
|
||||
break;
|
||||
case ESP_GATTS_START_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
|
||||
break;
|
||||
case ESP_GATTS_CONNECT_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
|
||||
esp_log_buffer_hex(LLSYNC_LOG_TAG, param->connect.remote_bda, 6);
|
||||
esp_ble_conn_update_params_t conn_params = {0};
|
||||
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
|
||||
/* For the iOS system, please refer to Apple official documents about the BLE connection parameters restrictions. */
|
||||
conn_params.latency = 0;
|
||||
conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms
|
||||
conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms
|
||||
conn_params.timeout = 400; // timeout = 400*10ms = 4000ms
|
||||
//start sent the update connection parameters to the peer device.
|
||||
esp_ble_gap_update_conn_params(&conn_params);
|
||||
break;
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
|
||||
ble_qiot_advertising_start();
|
||||
break;
|
||||
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
|
||||
if (param->add_attr_tab.status != ESP_GATT_OK){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
|
||||
}
|
||||
else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "create attribute table abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB);
|
||||
}
|
||||
else {
|
||||
ESP_LOGI(LLSYNC_LOG_TAG, "create attribute table successfully, the number handle = %d\n",param->add_attr_tab.num_handle);
|
||||
memcpy(llsync_handle_table, param->add_attr_tab.handles, sizeof(llsync_handle_table));
|
||||
esp_ble_gatts_start_service(llsync_handle_table[IDX_SVC]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_STOP_EVT:
|
||||
case ESP_GATTS_OPEN_EVT:
|
||||
case ESP_GATTS_CANCEL_OPEN_EVT:
|
||||
case ESP_GATTS_CLOSE_EVT:
|
||||
case ESP_GATTS_LISTEN_EVT:
|
||||
case ESP_GATTS_CONGEST_EVT:
|
||||
case ESP_GATTS_UNREG_EVT:
|
||||
case ESP_GATTS_DELETE_EVT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
/* If event is register event, store the gatts_if for each profile */
|
||||
if (event == ESP_GATTS_REG_EVT) {
|
||||
if (param->reg.status == ESP_GATT_OK) {
|
||||
llsync_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
|
||||
} else {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
int idx;
|
||||
for (idx = 0; idx < PROFILE_NUM; idx++) {
|
||||
/* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
|
||||
if (gatts_if == ESP_GATT_IF_NONE || gatts_if == llsync_profile_tab[idx].gatts_if) {
|
||||
if (llsync_profile_tab[idx].gatts_cb) {
|
||||
llsync_profile_tab[idx].gatts_cb(event, gatts_if, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
|
||||
void ble_services_add(const qiot_service_init_s *p_service)
|
||||
{
|
||||
// do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
void ble_qiot_service_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
// init llsync sdk
|
||||
ble_qiot_explorer_init();
|
||||
|
||||
ret = esp_ble_gatts_register_callback(gatts_event_handler);
|
||||
if (ret){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "gatts register error, error code = %x", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (ret){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "gap register error, error code = %x", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = esp_ble_gatts_app_register(LLSYNC_APP_ID);
|
||||
if (ret){
|
||||
ESP_LOGE(LLSYNC_LOG_TAG, "gatts app register error, error code = %x", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#define BLE_QIOT_SDK_VERSION "1.2.0" // 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 (1 == BLE_QIOT_BUTTON_BROADCAST)
|
||||
#define BLE_QIOT_BIND_TIMEOUT (2 * 60 * 1000) // unit: ms
|
||||
#endif
|
||||
|
||||
// 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__
|
||||
|
||||
// in some BLE stack ble_qiot_log_hex() maybe not work, user can use there own hexdump function
|
||||
#define BLE_QIOT_USER_DEFINE_HEDUMP 1
|
||||
|
||||
#if (1 == BLE_QIOT_USER_DEFINE_HEDUMP)
|
||||
#define ble_qiot_log_hex(level, hex_name, data, data_len) \
|
||||
do { \
|
||||
esp_log_buffer_hex(hex_name, data, data_len); \
|
||||
} while (0)
|
||||
#endif // BLE_QIOT_USER_DEFINE_HEDUMP
|
||||
|
||||
// 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__)
|
||||
|
||||
// nrf52832xxAA Flash size is 512KB, nrf52832xxAB Flash size is 512KB, be carefol of the address!
|
||||
#define BLE_QIOT_RECORD_FLASH_ADDR 0xFE000 // qiot data storage address
|
||||
#define BLE_QIOT_RECORD_FLASH_PAGESIZE 4096 // flash page size, see chip datasheet
|
||||
|
||||
// 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 __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // QCLOUD_BLE_QIOT_CONFIG_H
|
@@ -0,0 +1 @@
|
||||
idf_component_register(SRCS "app_main.c" INCLUDE_DIRS "")
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "ble_qiot_export.h"
|
||||
|
||||
extern void ble_qiot_service_init(void);
|
||||
extern float sg_ch20_ppm;
|
||||
|
||||
static void test_task(void *pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
sg_ch20_ppm += 0.001;
|
||||
printf("report ppm %.3f\n", sg_ch20_ppm);
|
||||
ble_event_report_property();
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
nvs_flash_init();
|
||||
|
||||
ble_qiot_service_init();
|
||||
xTaskCreate(test_task, "tsk1", 4 * 1024, NULL, 5, NULL);
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
otadata,data,ota, 0x10000, 8K
|
||||
nvs,data,nvs, 0x12000, 56K
|
||||
ota_0,app, ota_0, 0x100000,0x180000
|
||||
ota_1,app, ota_1, 0x280000,0x180000
|
|
@@ -0,0 +1,36 @@
|
||||
## 说明
|
||||
本工程模拟了一个甲醛监测场景,ESP32任务定期模拟甲醛数据(也可以通过甲醛监测传感器实时获取),ESP32通过BLE和腾讯连连小程序连接,使用LLSync协议传输数据,由腾讯连连小程序将甲醛数据上传到物联网开发平台。
|
||||
|
||||
## 使用说明
|
||||
1. 安装`ESP-IDF`,请参考[官网文档](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#step-2-get-esp-idf)
|
||||
```c
|
||||
mkdir -p ~/esp
|
||||
cd ~/esp
|
||||
git clone --recursive https://github.com/espressif/esp-idf.git
|
||||
```
|
||||
2. 抽取`qcloud-iot-ble-esp32`组件
|
||||
```c
|
||||
cd scripts
|
||||
python3 code_extract/code_extract.py esp32
|
||||
```
|
||||
3. 拷贝`qcloud-iot-ble-esp32`组件到`ESP-IDF`目录下
|
||||
```c
|
||||
cp -r scripts/code_extract/qcloud-iot-ble-esp32 $IDF_PATH
|
||||
cd $IDF_PATH/qcloud-iot-ble-esp32
|
||||
```
|
||||
4. 登陆[物联网开发平台](https://cloud.tencent.com/product/iotexplorer), 使用`qcloud_llsync/date_template/esp32.json`作为数据模版创建设备。
|
||||
使用新设备的三元信息替换`qcloud_llsync/hal/ble_qiot_ble_device.c`中宏定义中的设备信息,编译并烧录到开发板。
|
||||
```c
|
||||
idf.py flash
|
||||
```
|
||||
5. 打开腾讯连连小程序,添加设备,观察串口输出和小程序界面,串口输出如下:
|
||||
```c
|
||||
report ppm 0.028
|
||||
I (271165) post data: 00 00 05 60 43 60 e5 3c
|
||||
I (271165) LLSYNC: ESP_GATTS_CONF_EVT, status = 0, attr_handle 46
|
||||
I (271445) LLSYNC: GATT_WRITE_EVT, handle = 44, value len = 2, value :
|
||||
I (271445) LLSYNC: 20 00
|
||||
I (271445) LLSYNC: ble_lldata_write_cb
|
||||
I (271445) LLSYNC: GATT_WRITE_EVT OVER
|
||||
```
|
||||
可以观察到小程序界面甲醛数据同步变化。
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user