支持BLE设备接入“腾讯连连”小程序
This commit is contained in:
428
examples/nimble_llsync/ble_qiot_import.c
Normal file
428
examples/nimble_llsync/ble_qiot_import.c
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// #include "nrf52832_xxaa_service.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ble_qiot_import.h"
|
||||
|
||||
// #include "host/ble_hs.h"
|
||||
// #include "host/ble_uuid.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/ble_gatt.h"
|
||||
|
||||
#include "flash_storage.h"
|
||||
#include "ble_qiot_log.h"
|
||||
|
||||
|
||||
// divece configs
|
||||
// this only for reference, please create your own device and replace it!
|
||||
// https://cloud.tencent.com/product/iotexplorer
|
||||
// #define PRODUCT_ID "PRODUCT_ID" // 10 Bytes
|
||||
// #define DEVICE_NAME "YOUR_DEVICE_NAME" // equal or lesser than 48 Bytes
|
||||
// #define SECRET_KEY "YOUR_PRODUCT_SECRET_KEY_" // 24 Bytes
|
||||
|
||||
#define PRODUCT_ID "RF1EOUKV5C"
|
||||
#define DEVICE_NAME "ble_device_02"
|
||||
#define SECRET_KEY "3zDmA91czLhz9+XsuPeSzw=="
|
||||
|
||||
#define ADV_DEVICE_NAME "tos_llsync"
|
||||
|
||||
|
||||
#define IOT_BLE_UUID_BASE96 0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, \
|
||||
0x20, 0x4e, 0xd0, 0x65
|
||||
|
||||
#define UINT16_TO_BYTES(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8))
|
||||
#define UINT32_TO_BYTES(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8)), ((uint8_t)((n) >> 16)), ((uint8_t)((n) >> 24))
|
||||
|
||||
#define UINT16_TO_UUID32(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8)), ((uint8_t)((n) >> 16)), ((uint8_t)((n) >> 24))
|
||||
#define IOT_BLE_UUID128_BUILD(uuid) IOT_BLE_UUID_BASE96, UINT16_TO_UUID32(uuid)
|
||||
|
||||
#define IOT_BLE_UUID128_SERVICE IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_SERVICE)
|
||||
#define IOT_BLE_UUID128_DEVICE_INFO IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_DEVICE_INFO)
|
||||
#define IOT_BLE_UUID128_DATA IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_DATA)
|
||||
#define IOT_BLE_UUID128_EVENT IOT_BLE_UUID128_BUILD(IOT_BLE_UUID_EVENT)
|
||||
|
||||
static ble_uuid128_t ble_uuid128_t_service = BLE_UUID128_INIT(IOT_BLE_UUID128_SERVICE);
|
||||
static ble_uuid128_t ble_uuid128_t_device_info = BLE_UUID128_INIT(IOT_BLE_UUID128_DEVICE_INFO);
|
||||
static ble_uuid128_t ble_uuid128_t_data = BLE_UUID128_INIT(IOT_BLE_UUID128_DATA);
|
||||
static ble_uuid128_t ble_uuid128_t_event = BLE_UUID128_INIT(IOT_BLE_UUID128_EVENT);
|
||||
|
||||
static uint16_t qiot_gap_connect_handle;
|
||||
|
||||
static uint16_t qiot_device_info_handle;
|
||||
static uint16_t qiot_data_handle;
|
||||
static uint16_t qiot_event_handle;
|
||||
|
||||
static int ble_svc_qiot_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
// LLsync BLE services and characteristics
|
||||
static const struct ble_gatt_svc_def ble_svc_qiot_defs[] = {
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &ble_uuid128_t_service.u,
|
||||
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_SERVICE),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) {
|
||||
{
|
||||
.uuid = &ble_uuid128_t_device_info.u,
|
||||
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_DEVICE_INFO),
|
||||
.access_cb = ble_svc_qiot_access,
|
||||
// .val_handle = &qiot_device_info_handle,
|
||||
// .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
// .flags = 0xFFF,
|
||||
},
|
||||
{
|
||||
.uuid = &ble_uuid128_t_data.u,
|
||||
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_DATA),
|
||||
.access_cb = ble_svc_qiot_access,
|
||||
// .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
},
|
||||
{
|
||||
.uuid = &ble_uuid128_t_event.u,
|
||||
// .uuid = BLE_UUID16_DECLARE(IOT_BLE_UUID_EVENT),
|
||||
.access_cb = ble_svc_qiot_access,
|
||||
.val_handle = &qiot_event_handle,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
},
|
||||
|
||||
// end of characteristics
|
||||
{.uuid = 0},
|
||||
},
|
||||
},
|
||||
|
||||
// end of services
|
||||
{.type = 0},
|
||||
};
|
||||
|
||||
static int ble_svc_qiot_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
// int rand_num;
|
||||
int rc, ret;
|
||||
uint16_t len = 0;
|
||||
uint8_t buf[256] = {0};
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
|
||||
if(ble_uuid_cmp(uuid, &ble_uuid128_t_device_info.u) == 0)
|
||||
{
|
||||
switch (ctxt->op)
|
||||
{
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, buf, sizeof(buf), &len);
|
||||
if (rc != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble att err, ret: %d", ret);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_DEBUG, "device info raw", (char *)buf, len);
|
||||
ble_device_info_write_cb(buf, len);
|
||||
default:
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
}
|
||||
else if(ble_uuid_cmp(uuid, &ble_uuid128_t_data.u) == 0)
|
||||
{
|
||||
switch (ctxt->op)
|
||||
{
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, buf, sizeof(buf), &len);
|
||||
if (rc != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble att err, ret: %d", ret);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_DEBUG, "lldata raw", (char *)buf, len);
|
||||
ble_lldata_write_cb(buf, len);
|
||||
default:
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
}
|
||||
else if(ble_uuid_cmp(uuid, &ble_uuid128_t_event.u) == 0)
|
||||
{
|
||||
// this characteristic not have read or write attribute
|
||||
}
|
||||
else
|
||||
{
|
||||
ble_qiot_log_e("unknown service or characteristic");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add services and characteristic
|
||||
void ble_services_add(const qiot_service_init_s *p_service)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = ble_gatts_count_cfg(ble_svc_qiot_defs);
|
||||
if(ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_gatts_count_cfg() err, ret: %d", ret);
|
||||
}
|
||||
|
||||
ret = ble_gatts_add_svcs(ble_svc_qiot_defs);
|
||||
if(ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_gatts_add_svcs() err, ret: %d", ret);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
memcpy(mac, MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR, sizeof(MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR));
|
||||
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_DEBUG, "mac_addr", mac, 6);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int ble_qiot_gap_event_fn(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
ble_qiot_log_d("get event, type: %d", event->type);
|
||||
|
||||
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\n",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
ble_qiot_advertising_start();
|
||||
qiot_gap_connect_handle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
qiot_gap_connect_handle = event->connect.conn_handle;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
|
||||
|
||||
/* Connection terminated; resume advertising */
|
||||
ble_qiot_advertising_start();
|
||||
qiot_gap_connect_handle = 0;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "adv complete\n");
|
||||
ble_qiot_advertising_start();
|
||||
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, hrs_hrm_handle);
|
||||
// if (event->subscribe.attr_handle == hrs_hrm_handle) {
|
||||
// notify_state = event->subscribe.cur_notify;
|
||||
// notify_conn_handle = event->subscribe.conn_handle;
|
||||
// blehr_tx_hrate_reset();
|
||||
// } else if (event->subscribe.attr_handle != hrs_hrm_handle) {
|
||||
// notify_state = event->subscribe.cur_notify;
|
||||
// notify_conn_handle = 0;
|
||||
// blehr_tx_hrate_stop();
|
||||
// }
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
#define ADV_MAX_UUID16_NUM 15
|
||||
static uint8_t ble_addr_type;
|
||||
|
||||
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
struct ble_hs_adv_fields rsp_fields;
|
||||
uint8_t adv_manufacture_data[32] = {0};
|
||||
ble_uuid16_t adv_uuids16_list[ADV_MAX_UUID16_NUM];
|
||||
|
||||
memset(&fields, 0, sizeof(fields));
|
||||
memset(&rsp_fields, 0, sizeof(rsp_fields));
|
||||
|
||||
// set advertising data
|
||||
/* 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.uuids16 = (ble_uuid16_t)adv->uuid_info.uuids;??
|
||||
if (adv->uuid_info.uuid_num > ADV_MAX_UUID16_NUM)
|
||||
{
|
||||
printf("err: too many uuids16 in adv data! (uuids num %d)\r\n", adv->uuid_info.uuid_num);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
for (i=0; i<adv->uuid_info.uuid_num; i++)
|
||||
{
|
||||
adv_uuids16_list[i].u.type = BLE_UUID_TYPE_16;
|
||||
adv_uuids16_list[i].value = adv->uuid_info.uuids[i];
|
||||
}
|
||||
fields.uuids16 = adv_uuids16_list;
|
||||
fields.num_uuids16 = adv->uuid_info.uuid_num;
|
||||
fields.uuids16_is_complete = 1;
|
||||
|
||||
memcpy(&adv_manufacture_data[0], (uint8_t *)&adv->manufacturer_info.company_identifier, 2);
|
||||
memcpy(&adv_manufacture_data[2], adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
|
||||
fields.mfg_data = adv_manufacture_data;
|
||||
fields.mfg_data_len = adv->manufacturer_info.adv_data_len + 2;
|
||||
|
||||
ret = ble_gap_adv_set_fields(&fields);
|
||||
if (ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_gap_adv_set_fields() err, ret: %d", ret);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
// set advertising respond data
|
||||
rsp_fields.name = ADV_DEVICE_NAME;
|
||||
rsp_fields.name_len = strlen(ADV_DEVICE_NAME);
|
||||
rsp_fields.name_is_complete = 1;
|
||||
ret = ble_gap_adv_rsp_set_fields(&rsp_fields);
|
||||
if(ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_gap_adv_rsp_set_fields() err, ret: %d", ret);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
ret = ble_hs_id_infer_auto(0, &ble_addr_type);
|
||||
if (ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_hs_id_infer_auto() err, ret: %d", ret);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
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;
|
||||
ret = ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, ble_qiot_gap_event_fn, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_gap_adv_start() err, ret: %d", ret);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
ble_qiot_ret_status_t ble_advertising_stop(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ble_gap_adv_stop();
|
||||
if(ret != 0)
|
||||
{
|
||||
ble_qiot_log_e("ble_gap_adv_stop() err, ret: %d", ret);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
struct os_mbuf *om;
|
||||
int rc = 0;
|
||||
|
||||
om = ble_hs_mbuf_from_flat(buf, len);
|
||||
|
||||
rc = ble_gattc_notify_custom(qiot_gap_connect_handle, qiot_event_handle, om);
|
||||
if(rc)
|
||||
{
|
||||
ble_qiot_log_e("send notify err, return %d", rc);
|
||||
return BLE_QIOT_RS_ERR;
|
||||
}
|
||||
|
||||
return BLE_QIOT_RS_OK;
|
||||
}
|
||||
|
||||
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
|
||||
{
|
||||
return (ble_timer_t)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)
|
||||
{
|
||||
// this is an example, the default mtu is 23, user should get real mtu and return it
|
||||
int mtu = 23;
|
||||
|
||||
return mtu - 3;
|
||||
}
|
Reference in New Issue
Block a user