支持BLE设备接入“腾讯连连”小程序
This commit is contained in:
78
examples/nimble_llsync/ble_qiot_config.h
Normal file
78
examples/nimble_llsync/ble_qiot_config.h
Normal 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
|
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;
|
||||
}
|
541
examples/nimble_llsync/date_template/ble_qiot_template.c
Normal file
541
examples/nimble_llsync/date_template/ble_qiot_template.c
Normal 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
|
285
examples/nimble_llsync/date_template/ble_qiot_template.h
Normal file
285
examples/nimble_llsync/date_template/ble_qiot_template.h
Normal 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_
|
183
examples/nimble_llsync/date_template/nrf52832.json
Normal file
183
examples/nimble_llsync/date_template/nrf52832.json
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
209
examples/nimble_llsync/flash_storage.c
Normal file
209
examples/nimble_llsync/flash_storage.c
Normal 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();
|
||||
}
|
||||
}
|
48
examples/nimble_llsync/flash_storage.h
Normal file
48
examples/nimble_llsync/flash_storage.h
Normal 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);
|
85
examples/nimble_llsync/fprintf/nrf_fprintf.c
Normal file
85
examples/nimble_llsync/fprintf/nrf_fprintf.c
Normal 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)
|
||||
|
114
examples/nimble_llsync/fprintf/nrf_fprintf.h
Normal file
114
examples/nimble_llsync/fprintf/nrf_fprintf.h
Normal 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__ */
|
||||
|
516
examples/nimble_llsync/fprintf/nrf_fprintf_format.c
Normal file
516
examples/nimble_llsync/fprintf/nrf_fprintf_format.c
Normal 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)
|
||||
|
86
examples/nimble_llsync/fprintf/nrf_fprintf_format.h
Normal file
86
examples/nimble_llsync/fprintf/nrf_fprintf_format.h
Normal 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__ */
|
||||
|
155
examples/nimble_llsync/gatt_svr.c
Normal file
155
examples/nimble_llsync/gatt_svr.c
Normal 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;
|
||||
}
|
||||
|
142
examples/nimble_llsync/main.c
Normal file
142
examples/nimble_llsync/main.c
Normal 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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user