支持BLE设备接入“腾讯连连”小程序

This commit is contained in:
zekwang
2020-12-01 20:11:07 +08:00
parent 2a06226767
commit a6ff5bb42b
151 changed files with 47376 additions and 7 deletions

View File

@@ -0,0 +1,78 @@
/*
* 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.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 0
#if (1 == BLE_QIOT_USER_DEFINE_HEDUMP)
// add your code here like this
// #define ble_qiot_log_hex(level, hex_name, data, data_len) \
// do { \
// MY_RAW_LOG("\r\nble qiot dump: %s, length: %d\r\n", hex_name, data_len); \
// MY_RAW_HEXDUMP_(data, data_len); \
// } while(0)
// or use your own hexdump function with same definition
// 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_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 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
// 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)
#define BLE_QIOT_INCLUDE_PROPERTY
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_CONFIG_H

View 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;
}

View File

@@ -0,0 +1,541 @@
/*
* 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 <string.h>
#include <stdbool.h>
#include "ble_qiot_export.h"
#include "ble_qiot_common.h"
#include "ble_qiot_param_check.h"
extern void property_power_switch(const char *data, uint16_t len);
extern void action_led_blink(int ms);
extern void report_reply_blink(void);
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;
}
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

View File

@@ -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 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 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 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 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 tlv struct
typedef struct {
uint8_t type;
uint8_t id;
uint16_t len;
char * val;
} e_ble_tlv;
// 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
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);
// event module
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);
// action module
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);
#ifdef __cplusplus
}
#endif
#endif // BLE_QIOT_TEMPLATE_H_

View File

@@ -0,0 +1,183 @@
{
"version": "1.0",
"profile": {
"ProductId": "DHZX03IQAZ",
"CategoryId": "141"
},
"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
}
]
}

View File

@@ -0,0 +1,209 @@
/*
* 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 "flash_storage.h"
#include "ble_qiot_config.h"
#include "nrf_fstorage.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_fstorage_nvmc.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include <stdlib.h>
#ifdef SOFTDEVICE_PRESENT
#include "nrf_fstorage_sd.h"
#else
#include "nrf_fstorage_nvmc.h"
#endif
static void fstorage_evt_handler(nrf_fstorage_evt_t *p_evt);
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) = {
/* Set a handler for fstorage events. */
.evt_handler = fstorage_evt_handler,
/* These below are the boundaries of the flash space assigned to this instance of fstorage.
* You must set these manually, even at runtime, before nrf_fstorage_init() is called.
* The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
* last page of flash available to write data. */
.start_addr = 0x7e000,
.end_addr = 0x7ffff,
};
static void *p_write_buf = NULL;
void fstorage_init(void)
{
nrf_fstorage_api_t *p_fs_api;
ret_code_t rc;
#ifdef SOFTDEVICE_PRESENT
NRF_LOG_INFO("SoftDevice is present.");
NRF_LOG_INFO("Initializing nrf_fstorage_sd implementation...");
/* Initialize an fstorage instance using the nrf_fstorage_sd backend.
* nrf_fstorage_sd uses the SoftDevice to write to flash. This implementation can safely be
* used whenever there is a SoftDevice, regardless of its status (enabled/disabled). */
p_fs_api = &nrf_fstorage_sd;
#else
NRF_LOG_INFO("SoftDevice not present.");
NRF_LOG_INFO("Initializing nrf_fstorage_nvmc implementation...");
/* Initialize an fstorage instance using the nrf_fstorage_nvmc backend.
* nrf_fstorage_nvmc uses the NVMC peripheral. This implementation can be used when the
* SoftDevice is disabled or not present.
*
* Using this implementation when the SoftDevice is enabled results in a hardfault. */
p_fs_api = &nrf_fstorage_nvmc;
#endif
p_write_buf = NULL;
rc = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
APP_ERROR_CHECK(rc);
}
/**@brief Helper function to obtain the last address on the last page of the on-chip flash that
* can be used to write user data.
* It is possible to set the start and end addresses of an fstorage instance at runtime.
* They can be set multiple times, should it be needed. The helper function below can
* be used to determine the last address on the last page of flash memory available to
* store data.
*/
/*
static uint32_t nrf5_flash_end_addr_get()
{
uint32_t const bootloader_addr = NRF_UICR->NRFFW[0];
uint32_t const page_sz = NRF_FICR->CODEPAGESIZE;
uint32_t const code_sz = NRF_FICR->CODESIZE;
return (bootloader_addr != 0xFFFFFFFF ?
bootloader_addr : (code_sz * page_sz));
}
*/
/**@brief Sleep until an event is received. */
static void power_manage(void)
{
#ifdef SOFTDEVICE_PRESENT
(void)sd_app_evt_wait();
#else
__WFE();
#endif
}
int fstorage_read(uint32_t addr, uint32_t read_len, void *p_data)
{
ret_code_t rc;
/* Read data. */
rc = nrf_fstorage_read(&fstorage, addr, p_data, read_len);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_read() returned: %s\n", nrf_strerror_get(rc));
return 0;
}
return read_len;
}
static uint32_t round_up_u32(uint32_t len)
{
if (len % sizeof(uint32_t)) {
return (len + sizeof(uint32_t) - (len % sizeof(uint32_t)));
}
return len;
}
int fstorage_erase(uint32_t addr)
{
ret_code_t rc;
rc = nrf_fstorage_erase(&fstorage, addr, BLE_QIOT_RECORD_FLASH_PAGENUM, NULL);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_erase() returned: %s\n", nrf_strerror_get(rc));
return rc;
}
return 0;
}
int fstorage_write(uint32_t addr, uint32_t write_len, void const *p_data)
{
/* The following code snippet make sure that the length of the data we are writing to flash
* is a multiple of the program unit of the flash peripheral (4 bytes).
*/
uint32_t len = round_up_u32(write_len);
ret_code_t rc;
rc = nrf_fstorage_erase(&fstorage, addr, BLE_QIOT_RECORD_FLASH_PAGENUM, NULL);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_erase() returned: %s\n", nrf_strerror_get(rc));
}
/* Copy the data to write in flash.
* Because the fstorage interface is asynchrounous, the data must be kept in memory before get
* the NRF_FSTORAGE_EVT_WRITE_RESULT event. This memory will be free in fstorage_evt_handler().
*/
p_write_buf = (void *)malloc(len);
if (NULL == p_write_buf) {
NRF_LOG_ERROR("fstorage_write() malloc size %d error", len);
return 0;
}
memset(p_write_buf, 0, len);
memcpy(p_write_buf, p_data, write_len);
rc = nrf_fstorage_write(&fstorage, addr, p_write_buf, len, NULL);
if (rc != NRF_SUCCESS) {
NRF_LOG_ERROR("nrf_fstorage_write() returned: %s\n", nrf_strerror_get(rc));
return 0;
}
return write_len;
}
static void fstorage_evt_handler(nrf_fstorage_evt_t *p_evt)
{
if (p_evt->result != NRF_SUCCESS) {
NRF_LOG_INFO("fstorage event received: ERROR while executing an fstorage operation.");
return;
}
switch (p_evt->id) {
case NRF_FSTORAGE_EVT_WRITE_RESULT: {
free(p_write_buf);
p_write_buf = NULL;
NRF_LOG_INFO("fstorage event received: wrote %d bytes at address 0x%x.", p_evt->len, p_evt->addr);
} break;
case NRF_FSTORAGE_EVT_ERASE_RESULT: {
NRF_LOG_INFO("fstorage event received: erased %d page from address 0x%x.", p_evt->len, p_evt->addr);
} break;
default:
break;
}
}
/**
* @brief While fstorage is busy, sleep and wait for an event.
*
* @param p_fstorage nrf_fstorage_t obj
*/
void wait_for_flash_ready(nrf_fstorage_t const *p_fstorage)
{
/* While fstorage is busy, sleep and wait for an event. */
while (nrf_fstorage_is_busy(p_fstorage)) {
power_manage();
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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 <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);

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_FPRINTF)
#include <stdarg.h>
#include "nrf_assert.h"
#include "nrf_fprintf_format.h"
void nrf_fprintf_buffer_flush(nrf_fprintf_ctx_t * const p_ctx)
{
ASSERT(p_ctx != NULL);
if (p_ctx->io_buffer_cnt == 0)
{
return;
}
p_ctx->fwrite(p_ctx->p_user_ctx,
p_ctx->p_io_buffer,
p_ctx->io_buffer_cnt);
p_ctx->io_buffer_cnt = 0;
}
void nrf_fprintf(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
...)
{
ASSERT(p_ctx != NULL);
ASSERT(p_ctx->fwrite != NULL);
ASSERT(p_ctx->p_io_buffer != NULL);
ASSERT(p_ctx->io_buffer_size > 0);
if (p_fmt == NULL)
{
return;
}
va_list args = {0};
va_start(args, p_fmt);
nrf_fprintf_fmt(p_ctx, p_fmt, &args);
va_end(args);
}
#endif // NRF_MODULE_ENABLED(NRF_FPRINTF)

View File

@@ -0,0 +1,114 @@
/**
* Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_FPRINTF_H__
#define NRF_FPRINTF_H__
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (* nrf_fprintf_fwrite)(void const * p_user_ctx, char const * p_str, size_t length);
/**
* @brief fprintf context
*/
typedef struct nrf_fprintf_ctx
{
char * const p_io_buffer; ///< Pointer to IO buffer.
size_t const io_buffer_size; ///< IO buffer size.
size_t io_buffer_cnt; ///< IO buffer usage.
bool auto_flush; ///< Auto flush configurator.
void const * const p_user_ctx; ///< Pointer to user data to be passed to the fwrite funciton.
nrf_fprintf_fwrite fwrite; ///< Pointer to function sending data stream.
} nrf_fprintf_ctx_t;
/**
* @brief Macro for defining nrf_fprintf instance.
*
* @param name Instance name.
* @param _p_user_ctx Pointer to user data.
* @param _p_io_buffer Pointer to IO buffer
* @param _io_buffer_size Size of IO buffer.
* @param _auto_flush Indicator if IO buffer shall be automatically flush.
* @param _fwrite Pointer to function sending data stream.
* */
#define NRF_FPRINTF_DEF(name, _p_user_ctx, _p_io_buffer, _io_buffer_size, _auto_flush, _fwrite) \
static nrf_fprintf_ctx_t name = \
{ \
.p_io_buffer = _p_io_buffer, \
.io_buffer_size = _io_buffer_size, \
.io_buffer_cnt = 0, \
.auto_flush = _auto_flush, \
.p_user_ctx = _p_user_ctx, \
.fwrite = _fwrite \
}
/**
* @brief fprintf like function which send formated data stream to output specified by user
* @ref nrf_fprintf_ctx_t
*
* @param p_ctx fprintf context.
* @param p_fmt Format string.
* @param ... List of parameters to print.
* */
void nrf_fprintf(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
...);
/**
* @brief function flushing data stored in io_buffer @ref nrf_fprintf_ctx_t
*
* @param p_ctx fprintf context
*/
void nrf_fprintf_buffer_flush(nrf_fprintf_ctx_t * const p_ctx);
#ifdef __cplusplus
}
#endif
#endif /* NRF_FPRINTF_H__ */

View File

@@ -0,0 +1,516 @@
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
**********************************************************************
* *
* (c) 2014 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* conditions are met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* o Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the following *
* disclaimer in the documentation and/or other materials provided *
* with the distribution. *
* *
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
* nor the names of its contributors may be used to endorse or *
* promote products derived from this software without specific *
* prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
* *
* RTT version: 6.14d *
* *
*********************************************************************/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_FPRINTF)
#include <stdarg.h>
#include "nrf_assert.h"
#include "nrf_fprintf.h"
#include "nrf_fprintf_format.h"
#define NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
#define NRF_CLI_FORMAT_FLAG_PAD_ZERO (1u << 1)
#define NRF_CLI_FORMAT_FLAG_PRINT_SIGN (1u << 2)
static void buffer_add(nrf_fprintf_ctx_t * const p_ctx, char c)
{
#if NRF_MODULE_ENABLED(NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF)
if (c == '\n')
{
buffer_add(p_ctx, '\r');
}
#endif
p_ctx->p_io_buffer[p_ctx->io_buffer_cnt++] = c;
if (p_ctx->io_buffer_cnt >= p_ctx->io_buffer_size)
{
nrf_fprintf_buffer_flush(p_ctx);
}
}
static void string_print(nrf_fprintf_ctx_t * const p_ctx,
char const * p_str,
uint32_t FieldWidth,
uint32_t FormatFlags)
{
uint32_t Width = 0;
char c;
if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
{
while ((c = *p_str) != '\0')
{
p_str++;
Width++;
buffer_add(p_ctx, c);
}
while ((FieldWidth > Width) && (FieldWidth > 0))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
}
else
{
if (p_str != 0)
{
Width = strlen(p_str);
}
while ((FieldWidth > Width) && (FieldWidth > 0))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
while ((c = *p_str) != '\0')
{
p_str++;
Width++;
buffer_add(p_ctx, c);
}
}
}
static void unsigned_print(nrf_fprintf_ctx_t * const p_ctx,
uint32_t v,
uint32_t Base,
uint32_t NumDigits,
uint32_t FieldWidth,
uint32_t FormatFlags)
{
static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };
uint32_t Div;
uint32_t Value;
uint32_t Width;
char c;
Value = v;
//
// Get actual field width
//
Width = 1u;
while (Value >= Base)
{
Value = (Value / Base);
Width++;
}
if (NumDigits > Width)
{
Width = NumDigits;
}
//
// Print leading chars if necessary
//
if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u)
{
if (FieldWidth != 0u)
{
if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
(NumDigits == 0u))
{
c = '0';
}
else
{
c = ' ';
}
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, c);
}
}
}
Value = 1;
/*
* Compute Digit.
* Loop until Digit has the value of the highest digit required.
* Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
*/
while (1)
{
/* User specified a min number of digits to print? => Make sure we loop at least that
* often, before checking anything else (> 1 check avoids problems with NumDigits
* being signed / unsigned)
*/
if (NumDigits > 1u)
{
NumDigits--;
}
else
{
Div = v / Value;
// Is our divider big enough to extract the highest digit from value? => Done
if (Div < Base)
{
break;
}
}
Value *= Base;
}
//
// Output digits
//
do
{
Div = v / Value;
v -= Div * Value;
buffer_add(p_ctx, _aV2C[Div]);
Value /= Base;
} while (Value);
//
// Print trailing spaces if necessary
//
if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
{
if (FieldWidth != 0u)
{
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
}
}
}
static void int_print(nrf_fprintf_ctx_t * const p_ctx,
int32_t v,
uint32_t Base,
uint32_t NumDigits,
uint32_t FieldWidth,
uint32_t FormatFlags)
{
uint32_t Width;
int32_t Number;
Number = (v < 0) ? -v : v;
//
// Get actual field width
//
Width = 1u;
while (Number >= (int32_t)Base)
{
Number = (Number / (int32_t)Base);
Width++;
}
if (NumDigits > Width)
{
Width = NumDigits;
}
if ((FieldWidth > 0u) && ((v < 0) ||
((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)))
{
FieldWidth--;
}
//
// Print leading spaces if necessary
//
if ((((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) &&
((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u))
{
if (FieldWidth != 0u)
{
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, ' ');
}
}
}
//
// Print sign if necessary
//
if (v < 0)
{
v = -v;
buffer_add(p_ctx, '-');
}
else if ((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)
{
buffer_add(p_ctx, '+');
}
else
{
/* do nothing */
}
//
// Print leading zeros if necessary
//
if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u))
{
if (FieldWidth != 0u)
{
while ((FieldWidth != 0u) && (Width < FieldWidth))
{
FieldWidth--;
buffer_add(p_ctx, '0');
}
}
}
//
// Print number without sign
//
unsigned_print(p_ctx, (uint32_t)v, Base, NumDigits, FieldWidth, FormatFlags);
}
void nrf_fprintf_fmt(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
va_list * p_args)
{
ASSERT(p_ctx != NULL);
ASSERT(p_ctx->fwrite != NULL);
ASSERT(p_ctx->p_io_buffer != NULL);
ASSERT(p_ctx->io_buffer_size > 0);
if (p_fmt == NULL)
{
return;
}
char c;
int32_t v;
uint32_t NumDigits;
uint32_t FormatFlags;
uint32_t FieldWidth;
do
{
c = *p_fmt;
p_fmt++;
if (c == 0u)
{
break;
}
if (c == '%')
{
//
// Filter out flags
//
FormatFlags = 0u;
v = 1;
do
{
c = *p_fmt;
switch (c)
{
case '-':
FormatFlags |= NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY;
p_fmt++;
break;
case '0':
FormatFlags |= NRF_CLI_FORMAT_FLAG_PAD_ZERO;
p_fmt++;
break;
case '+':
FormatFlags |= NRF_CLI_FORMAT_FLAG_PRINT_SIGN;
p_fmt++;
break;
default:
v = 0;
break;
}
} while (v);
//
// filter out field width
//
FieldWidth = 0u;
do
{
if (c == '*')
{
/*lint -save -e64 -e56*/
FieldWidth += va_arg(*p_args, unsigned);
/*lint -restore*/
p_fmt++;
break;
}
c = *p_fmt;
if ((c < '0') || (c > '9'))
{
break;
}
p_fmt++;
FieldWidth = (FieldWidth * 10u) + (c - '0');
} while (1);
//
// Filter out precision (number of digits to display)
//
NumDigits = 0u;
c = *p_fmt;
if (c == '.')
{
p_fmt++;
do
{
c = *p_fmt;
if ((c < '0') || (c > '9'))
{
break;
}
p_fmt++;
NumDigits = NumDigits * 10u + (c - '0');
} while (1);
}
//
// Filter out length modifier
//
c = *p_fmt;
do
{
if ((c == 'l') || (c == 'h'))
{
p_fmt++;
c = *p_fmt;
}
else
{
break;
}
} while (1);
//
// Handle specifiers
//
/*lint -save -e64*/
switch (c)
{
case 'c':
{
char c0;
v = va_arg(*p_args, int32_t);
c0 = (char)v;
buffer_add(p_ctx, c0);
break;
}
case 'd':
case 'i':
v = va_arg(*p_args, int32_t);
int_print(p_ctx,
v,
10u,
NumDigits,
FieldWidth,
FormatFlags);
break;
case 'u':
v = va_arg(*p_args, int32_t);
unsigned_print(p_ctx,
(uint32_t)v,
10u,
NumDigits,
FieldWidth,
FormatFlags);
break;
case 'x':
case 'X':
v = va_arg(*p_args, int32_t);
unsigned_print(p_ctx,
(uint32_t)v,
16u,
NumDigits,
FieldWidth,
FormatFlags);
break;
case 's':
{
char const * p_s = va_arg(*p_args, const char *);
string_print(p_ctx, p_s, FieldWidth, FormatFlags);
break;
}
case 'p':
v = va_arg(*p_args, int32_t);
buffer_add(p_ctx, '0');
buffer_add(p_ctx, 'x');
unsigned_print(p_ctx, (uint32_t)v, 16u, 8u, 8u, 0);
break;
case '%':
buffer_add(p_ctx, '%');
break;
default:
break;
}
/*lint -restore*/
p_fmt++;
}
else
{
buffer_add(p_ctx, c);
}
} while (*p_fmt != '\0');
if (p_ctx->auto_flush)
{
nrf_fprintf_buffer_flush(p_ctx);
}
}
#endif // NRF_MODULE_ENABLED(NRF_FPRINTF)

View File

@@ -0,0 +1,86 @@
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
**********************************************************************
* *
* (c) 2014 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* conditions are met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* o Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the following *
* disclaimer in the documentation and/or other materials provided *
* with the distribution. *
* *
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
* nor the names of its contributors may be used to endorse or *
* promote products derived from this software without specific *
* prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
* *
* RTT version: 6.14d *
* *
*********************************************************************/
#ifndef NRF_FPRINTF_FORMAT_H__
#define NRF_FPRINTF_FORMAT_H__
#include <stdarg.h>
#include "nrf_fprintf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Printf like function which sends formated data stream to output.
*
* @param nrf_fprintf_ctx_t Print context.
* @param p_fmt Format string.
* @param p_args List of parameters to print.
* */
void nrf_fprintf_fmt(nrf_fprintf_ctx_t * const p_ctx,
char const * p_fmt,
va_list * p_args);
#ifdef __cplusplus
}
#endif
#endif /* NRF_FPRINTF_FORMAT_H__ */

View File

@@ -0,0 +1,155 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
// #include "blehr_sens.h"
#include "services/dis/ble_svc_dis.h"
#include "services/bas/ble_svc_bas.h"
#define GATT_DEVICE_INFO_UUID 0x180A
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
#define GATT_MODEL_NUMBER_UUID 0x2A24
#define REPLY_BUFFER_SIZE 100
static char reply[REPLY_BUFFER_SIZE];
static int gatt_svr_chr_access_device_info_manufacturer(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int gatt_svr_chr_access_device_info_model(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
/* define several bluetooth services for our device */
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
/*
* access_cb defines a callback for read and write access events on
* given characteristics
*/
{
/* Service: Device Information */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: * Manufacturer name */
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
.access_cb = gatt_svr_chr_access_device_info_manufacturer,
.flags = BLE_GATT_CHR_F_READ,
}, {
/* Characteristic: Model number string */
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
.access_cb = gatt_svr_chr_access_device_info_model,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* No more characteristics in this service */
}, }
},
{
0, /* No more services */
},
};
static int gatt_svr_chr_access_device_info_manufacturer(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'device info: manufacturer' callback triggered\n");
snprintf(reply, REPLY_BUFFER_SIZE, "This is TencentOS tiny\n");
printf("reply: %s\n", reply);
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
printf("\n");
return rc;
}
static int gatt_svr_chr_access_device_info_model(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("service 'device info: model' callback triggered\n");
snprintf(reply, REPLY_BUFFER_SIZE, "running TencentOS tiny on nordic ble board");
printf("reply: %s\n", reply);
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
printf("\n");
return rc;
}
void
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
ctxt->svc.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
ctxt->chr.def_handle,
ctxt->chr.val_handle);
break;
case BLE_GATT_REGISTER_OP_DSC:
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
ctxt->dsc.handle);
break;
default:
assert(0);
break;
}
}
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;
}

View File

@@ -0,0 +1,142 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nimble/nimble_port_tencentos_tiny.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "boards.h"
#include "ble_qiot_config.h"
#include "flash_storage.h"
#include "ble_qiot_export.h"
#include "ble_qiot_import.h"
extern int gatt_svr_init(void);
extern void board_init(void);
extern void nimble_port_init(void);
static const char device_name[] = "TOS LLSync";
static uint8_t ble_addr_type;
void ble_boot(void *arg)
{
int rc = 0;
extern void nimble_port_run(void);
nimble_port_tencentos_tiny_init(nimble_port_run);
/* make sure synchronization of host and controller is done */
while (!ble_hs_synced()) {
;
}
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
rc = ble_hs_id_infer_auto(0, &ble_addr_type);
assert(rc == 0);
ble_svc_gap_init();
ble_svc_gatt_init();
/* verify and add our custom services */
rc = gatt_svr_init();
assert(rc == 0);
/* init llsync, add llsync services */
ble_qiot_explorer_init();
/* set the device name */
rc = ble_svc_gap_device_name_set(device_name);
assert(rc == 0);
/* reload the GATT server to link our added services */
ble_gatts_start();
/* llsync start advertising */
ble_qiot_advertising_start();
return;
}
static void leds_init(void)
{
bsp_board_init(BSP_INIT_LEDS);
}
void property_power_switch(const char *data, uint16_t len)
{
if (data[0]) {
bsp_board_led_on(BSP_BOARD_LED_0);
printf("Received LED ON!");
} else {
bsp_board_led_off(BSP_BOARD_LED_0);
printf("Received LED OFF!");
}
return;
}
void action_led_blink(int ms)
{
bsp_board_led_on(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_on(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_on(BSP_BOARD_LED_1);
tos_sleep_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
}
void report_reply_blink(void)
{
bsp_board_led_on(BSP_BOARD_LED_2);
tos_sleep_ms(200);
bsp_board_led_off(BSP_BOARD_LED_2);
tos_sleep_ms(200);
bsp_board_led_on(BSP_BOARD_LED_2);
tos_sleep_ms(200);
bsp_board_led_off(BSP_BOARD_LED_2);
}
k_task_t ble_boot_task;
k_stack_t ble_boot_stack[2048];
int main(void)
{
board_init();
// other devices init
leds_init();
/* init flash that llsync need to save some device info */
fstorage_init();
/* Initialize OS */
tos_knl_init();
nimble_port_init();
/*
in this case, ble_boot_task's priority must lower than MYNEWT_VAL_BLE_HOST_TASK_PRIORITY && MYNEWT_VAL_BLE_LL_TASK_PRIORITY,
numerically bigger
to give the host and ll task a chance to run first just after the nimble_port_tencentos_tiny_init.
*/
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
6,
ble_boot_stack, sizeof(ble_boot_stack),
0);
tos_knl_start();
}